Compare commits

...
Sign in to create a new pull request.

29 commits

Author SHA1 Message Date
8afcc9c321 chore: refresh Warden work-record indexes
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a058f3-8ba0-7692-a042-9a870fc3d663
2026-09-01 01:27:55 +02:00
repo-manager
529feeac49 repo.work.assign_missing_identifiers
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
source: repo-manager
reason: deterministic projection registration

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a058f3-8ba0-7692-a042-9a870fc3d663
2026-09-01 00:51:59 +02:00
9770d6ad66 docs: close Warden credential workplans
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a058f3-8ba0-7692-a042-9a870fc3d663
2026-09-01 00:51:52 +02:00
custodian-sync
31694ab64d chore(consistency): sync task status from DB [auto]
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Updated by fix-consistency on 2026-09-01:
  - update .custodian-brief.md for ops-warden

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a058f3-8ba0-7692-a042-9a870fc3d663
2026-09-01 00:50:08 +02:00
eddb5d426b chore: refresh high-risk credential paths
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a058f3-8ba0-7692-a042-9a870fc3d663
2026-09-01 00:47:25 +02:00
4fee839b11 feat: route Policy Nexus source credential
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a058f3-8ba0-7692-a042-9a870fc3d663
2026-09-01 00:46:28 +02:00
8f01eefb1e Preserve Warden config in attended child
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a058f3-8ba0-7692-a042-9a870fc3d663
2026-09-01 00:24:18 +02:00
b4c1d3900a Fix contained OpenBao login handoff
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a058f3-8ba0-7692-a042-9a870fc3d663
2026-09-01 00:13:26 +02:00
repo-manager
4e267179db chore(registrar): assign State Hub identifiers
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4014535@bnt-lap001
Assistant-Session: d0036016-73e8-4da1-8e47-563e3ab39a3c
2026-08-29 14:56:21 +02:00
custodian-sync
d18d18e313 chore(consistency): sync task status from DB [auto]
Some checks failed
CI Smoke / host-smoke (push) Has been cancelled
CI Smoke / container-smoke (push) Has been cancelled
Updated by fix-consistency on 2026-08-29:
  - update .custodian-brief.md for ops-warden

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4014535@bnt-lap001
Assistant-Session: d0036016-73e8-4da1-8e47-563e3ab39a3c
2026-08-29 14:56:20 +02:00
2e3ff772f4 Refresh work-record index for WARDEN-WP-0034
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YWBMovyFoy9RRrfL7zKvPJ

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4014535@bnt-lap001
Assistant-Session: d0036016-73e8-4da1-8e47-563e3ab39a3c
2026-08-29 14:55:36 +02:00
fd08950231 Align INTENT and SCOPE to layer model v0.7; assess gaps; open WARDEN-WP-0034
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
The standard is accepted at v0.7, with SECURITY-COMPANION.md v0.2 as its
operative form. Four ops-warden findings were adopted between v0.4 and v0.7 —
§9.1's two marks, §5's Tooling scope rule, §6.4 obligation 1's second limb, and
§13.1's existence — and both ops-warden declaration artifacts are now cited in
the text as the estate's reference forms.

INTENT.md gains frontmatter (layer: Staff, pep_shaped: true) because §11 requires
a machine-readable declaration and prose cannot distinguish a declaration from a
transcribed review. The note now covers the agent principal (§3.4), the PEP
shape, the attributive evidence position, and the role the companion assigns:
the estate is told to ask ops-warden which lane, which credential, which route.

SCOPE.md records what is actually shipped against v0.7 and the honest conformance
state — declared gap, which is tracked non-conformance, not conformance.

The assessment checked every obligation against shipped code rather than intent.
Three gaps survive:

- §9.7.2 requires a PEP to state one revocation visibility deadline. Ours is
  unstated, and the honest value is uncomfortable: the cert TTL, up to 48h. A
  cert outlives revocation of the decision that authorized it — no CRL, no KRL
  distribution. That is a design property never written down, which is exactly
  what §9.7.2 exists to force into the open.
- §3.4 rule 1 forbids standing credentials and requires issued, attributable
  authority. ADR-0004's boundary keys on WARDEN_AGENT_ID, which an agent sets
  about itself. key-cape now issues a real coding-agent identity, so the
  ops-warden half can stop being advisory.
- §9.6 cadence remains undeclared. Attributive, so SHOULD not MUST, but silence
  through two reviews is the one outcome that is not defensible.

WARDEN-WP-0034 addresses all three, plus the discoverability gap the companion
creates and two items to route rather than absorb.

402 tests pass, ruff clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YWBMovyFoy9RRrfL7zKvPJ

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4014535@bnt-lap001
Assistant-Session: d0036016-73e8-4da1-8e47-563e3ab39a3c
2026-08-29 14:50:55 +02:00
94f32bd160 Review layer model v0.6; publish the PEP stance map §6.4 requires
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
All three v0.4 findings were acted on — §9.1 split into pending/declared-gap and
§5's scope rule adopted as recommended and credited, and §9.6 ruled via the
load-bearing/attributive distinction with ops-warden's `# audit must not block
signing` named as the estate's live example.

Checked the favourable ruling rather than accepting it. §9.6's test is "no
control branches on its presence": the only consumer of audit.jsonl is `warden
activity`, which displays. Nothing gates on a signing record, so the lane is
genuinely attributive. AuditTrail.md now records the ruling instead of the open
question, and states that the trade must be revisited if a control ever gates on
the trail.

CONFORMANCE ACTION. §6.4 obligation 3 requires a stance map "published rather
than held in code", and requires every PEP-shaped consumer to publish one so the
maps can be inventoried — naming ADR-0009 as the reference shape. ops-warden was
not doing it: the map lived in PolicyConfig.failure_modes, a dataclass default.
Not a code comment, but not published either.

pep-stance.yaml publishes it, and the test asserts the published map EQUALS the
shipped default. A published map that may drift from the code is worse than no
map, because it invites reliance it cannot support.

Two findings sent to gate-house, in history/2026-08-29-layer-model-v06-review.md:
§6.4 obligation 1 (no side effect without a decision record) contradicts
obligation 3 and §9.3, with ops-warden's blessed fail-open stance as the
instance; and §6.4 mandates a stance-map inventory in §13 that §13 does not
implement — where ops-warden is currently the only PEP to have published one.

402 tests pass, ruff clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YWBMovyFoy9RRrfL7zKvPJ

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4014535@bnt-lap001
Assistant-Session: d0036016-73e8-4da1-8e47-563e3ab39a3c
2026-08-29 10:20:49 +02:00
ec625873fb Review layer model v0.4; correct an unsound audit claim it exposes
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assessment in history/2026-08-29-layer-model-v04-review.md. No objection to the
ruling; both ops-warden amendments were adopted (5.2 conduit, 5.3 declared gap).
Three findings, one against us.

The one against us is real. 9.6 requires emission atomic with the state change
for load-bearing evidence. ops-warden ca.py carries `pass  # audit must not block
signing` and AuditTrail.md advertises that the trail never blocks the primary
action, so a failed append loses the event while the cert still issues -- a
suppressed event leaving the chain intact, which is exactly what 9.6 describes.

Whether to make it atomic is gate-house doctrine, not ops-wardens call: it would
give the estates operational access lane a new dependency on its own evidence
store. But one half of the fix is ours regardless -- the trail must not be read
as complete. AuditTrail.md now says absence of a record is not evidence of
absence, which it did not.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YWBMovyFoy9RRrfL7zKvPJ

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4014535@bnt-lap001
Assistant-Session: d0036016-73e8-4da1-8e47-563e3ab39a3c
2026-08-29 02:46:50 +02:00
f815bb35ca Implement §5.3 machine-readably — layer.yaml, checker, conformance tests
The security layer model moved v0.1 -> v0.4 (accepted) after ops-warden's
assent. Both §5 asks from ADR-0010 were adopted: §5.2 now sanctions the conduit
shape on the supplied-authority property, and §5.3 is the declared engine gap
amendment, carrying the four fields verbatim and crediting ops-warden's
delegation machinery as prior art.

Which creates an obligation. §5.3 requires those fields MACHINE-READABLY, and
§11 makes "every direct Tooling client maps to a declared §5.1/§5.2/§5.3 entry"
a mechanical check. ops-warden's declaration was prose in INTENT.md — the repo
that proposed the shape was not implementing it.

layer.yaml is the map: 5 contacts (2 declared gaps, 1 read-only observation,
2 conduits) plus the non-Tooling clients recorded explicitly so the check is
total rather than silently selective.

scripts/check_layer_conformance.py enforces it and found three undeclared
modules on its first run — all false positives (help text, a docstring, and the
doubles library that SIMULATES bao rather than calling it), which is why the
scan now matches invocation shapes instead of the word: an httpx call built
against the configured OpenBao address, or an argv whose first element is the
bao binary.

tests/test_layer_conformance.py adds the §5.2 test the standard says SHOULD
exist: _caller_env() returns the caller's environment unchanged, and proxy.py
is asserted not to reference X-Vault-Token, approle login, or token create — a
conduit that presents its own token is not a conduit.

No assertion on review dates, deliberately: a date-triggered failure breaks the
build on a calendar day with no code change, the same reasoning WP-0033-T05
recorded for blocker staleness.

398 tests pass, ruff clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YWBMovyFoy9RRrfL7zKvPJ

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4014535@bnt-lap001
Assistant-Session: d0036016-73e8-4da1-8e47-563e3ab39a3c
2026-08-29 02:45:29 +02:00
57d39ede0f Refresh work-record index
Regenerated by fix-consistency; adds the inbound v0.3 review intake.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 2564823@bnt-lap001
Assistant-Session: 2a7ed827-4928-4b9f-8613-9135c9cadfe9
2026-08-28 22:43:06 +02:00
repo-manager
f289465b90 repo.work.create_intake WARDEN-IN-0002
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
correlation_id: 676e92a9-dc2e-4101-a31c-a584962c25df
reason: Propose layer model v0.3 for review
source: repo-manager

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 2564823@bnt-lap001
Assistant-Session: 2a7ed827-4928-4b9f-8613-9135c9cadfe9
2026-08-28 22:40:24 +02:00
custodian-sync
a45280f30d chore(consistency): sync task status from DB [auto]
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Updated by fix-consistency on 2026-08-28:
  - update .custodian-brief.md for ops-warden

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4014535@bnt-lap001
Assistant-Session: d0036016-73e8-4da1-8e47-563e3ab39a3c
2026-08-28 22:02:58 +02:00
61c992923c WARDEN-WP-0027-T02: the owner gate closed five days ago
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
railiance-platform accepted ops-warden revision 0fae0904 on 2026-08-23, in
RPF-WP-0017 (status: finished), together with railiance-infra approval at
186b030 and all five acceptance criteria met. T02 has been sitting `progress`
on a gate that was already open.

Verified rather than trusted: the receipt at bc1966da hashes to
d2ba444ed16989590325697e69d25283dc75a9432c29a72e627e80bf9fd987e4, matching
their record exactly.

One reason it went unnoticed is an identifier mismatch — T02 cites the
remediation interface as RAILIANCE-WP-0026-T01, but it is RPF-WP-0017-T01 in
the owner repo, and the cited id resolves to an unrelated workplan there.

Their acceptance is source acceptance only and authorizes no live drill, so
T02 stays progress: what unblocks is preparing a NEW scenario, which needs a
fresh human GO and is the platform owner s to execute. Surfaced, not taken.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YWBMovyFoy9RRrfL7zKvPJ

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4014535@bnt-lap001
Assistant-Session: d0036016-73e8-4da1-8e47-563e3ab39a3c
2026-08-28 22:01:47 +02:00
ee94c18938 WARDEN-WP-0033 finished — key-cape accepted the issuance question five days ago
T04 was the last open task, waiting on key-cape to accept or refuse ownership of
the coding-agent OpenBao issuance identity. They accepted, in KEY-WP-0009-T03,
on 2026-08-23: codex-railiance-platform is published in their
config/service-clients.example.yaml with subject service:codex:railiance-platform,
role coding-agent, scope openbao:login, 15m lifetime, and the service-auth
semantics in docs/openbao-service-auth-contract.md. The split is the one we
routed for — KeyCape issues, railiance-platform binds the OpenBao role, OpenBao
enforces, no secret value in either repo.

We found it by reading their repository. KEY-WP-0009-T04 records replying to
ops-warden; the inbox has zero messages from key-cape, read or unread. The task
sat `wait` on an answer that already existed.

That is T05's own lesson arriving on T04: a blocker is a claim about the world at
a date. So the same pass re-verified the two lanes pointing at key-cape against
their source instead of bumping dates:

- rapp-qonto-keycape-client -> verified: source-read. KEY-WP-0009-T02 did add
  bounded service-auth, but that is client_credentials JWT issuance for OpenBao
  machine login and does not front this client_secret_basic exchange or its
  rotation. Blocker stands, now with evidence rather than memory.
- key-cape-oidc-login -> asked of key-cape today, which the entry had recorded
  as still outstanding since 2026-08-21.

Also cleared the inbox that hid this: 9 stale unread, all superseded by shipped
work, with late closes sent to secrets-engine and llm-connect on the two threads
that had asked ops-warden something and never got an answer.

391 tests pass, ruff clean, boundary coverage 0 uncovered.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YWBMovyFoy9RRrfL7zKvPJ

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4014535@bnt-lap001
Assistant-Session: d0036016-73e8-4da1-8e47-563e3ab39a3c
2026-08-28 22:00:09 +02:00
d7f4ebcfe0 Re-emit the high-risk path artifact after the NetKingdom SSO lanes
c374d41 added net-kingdom-lldap-bind-credential and
net-kingdom-privacyidea-admin-token as `risk: high` and did not re-run the
emitter, so registry/generated/high-risk-data-paths.yaml still described the
catalog at 0fae090. railiance-platform consumes that file instead of
hand-maintaining its deny list, and it has been reading a census two lanes short
since 2026-08-23.

This is precisely the drift WARDEN-WP-0033-T03 built the guard for — a lane
graded high after the last emit silently failing to reach the consumer. The
guard fired; nothing had acted on it.

The deny list itself does not move: both lanes are blocked on their OpenBao path
being published, so they land in `no_concrete_path` and concrete_path_count
stays 14. What changes is the count the consumer sees — 23 high-risk lanes, two
of which have no address yet. That is the honest signal and the reason the
bucket is listed rather than omitted.

check_agent_read_boundary.py still reports 0 uncovered.

The workload-join census moves 9 -> 11 not-applicable: both lanes are
provider/control-plane credentials rather than workload delivery lanes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YWBMovyFoy9RRrfL7zKvPJ

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4014535@bnt-lap001
Assistant-Session: d0036016-73e8-4da1-8e47-563e3ab39a3c
2026-08-28 21:55:33 +02:00
repo-manager
f766400563 chore(registrar): assign State Hub identifiers
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4014535@bnt-lap001
Assistant-Session: d0036016-73e8-4da1-8e47-563e3ab39a3c
2026-08-28 21:52:03 +02:00
70d8b503f0 Assent to the NetKingdom security layer model (WARDEN-IN-0001)
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
gate-house asked ops-warden to assent to three boundary items ratified in
GH-DEC-2026-001. All three are assented in ADR-0010.

Staff: accepted. Grepping section 5 as it invites turned up a real
non-conformance — src/warden/vault.py is a direct OpenBao client performing a
write, and so is `warden desk`'s `bao kv put`. Section 5's only escape hatch is
read-only diagnostics, which does not cover a signing write, so both are
declared in INTENT.md as an engine gap with intended owner secrets-engine and
the blocker "no engine exposes an SSH-CA surface" — ADR-0003 turned inward
rather than an exemption argued for. taint.py is metadata-only and declared
under the read-only allowance; `warden access` proxies run under the caller's
identity and supply no authority of their own.

Doctrine versus runbook: accepted. NetKingdom Security Literacy becomes a lane
routing runbook that references gate-house doctrine instead of restating it. It
had also become a prose second source for registry/routing/catalog.yaml, which
ADR-0001 already rules against.

Lane versus rule: assented unconditionally, and the access-engine veto is not
exercised. One request on sequencing only — a window where both names resolve.

gate-house added to the routing tables in INTENT.md and SCOPE.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YWBMovyFoy9RRrfL7zKvPJ

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4014535@bnt-lap001
Assistant-Session: d0036016-73e8-4da1-8e47-563e3ab39a3c
2026-08-28 21:47:44 +02:00
85d3078bae Refresh work-record index
Regenerated by fix-consistency; adds the inbound assent intake.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 2564823@bnt-lap001
Assistant-Session: 2a7ed827-4928-4b9f-8613-9135c9cadfe9
2026-08-28 21:35:57 +02:00
repo-manager
467635e84b repo.work.create_intake WARDEN-IN-0001
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
correlation_id: 65d40cdd-5894-440e-9c95-c6bcfe259b66
reason: Request assent for GH-DEC-2026-001 boundaries
source: repo-manager

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 2564823@bnt-lap001
Assistant-Session: 2a7ed827-4928-4b9f-8613-9135c9cadfe9
2026-08-28 21:30:28 +02:00
15730bb650 Point layering note at the published standard
The layer model is now published as
net-kingdom/canon/standards/security-layer-model_v0.1.md (proposed) and
ratified by gate-house GH-DEC-2026-001. The note previously said the
standard was not yet written.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 2564823@bnt-lap001
Assistant-Session: 2a7ed827-4928-4b9f-8613-9135c9cadfe9
2026-08-28 21:21:08 +02:00
347e47ce8e Note NetKingdom layering review in INTENT
Records this repository's layer in the NetKingdom IT-security layer model
(Taxonomy / Tooling / Engines / Staff) and what should change in this INTENT
as a result. Links to the review that established the model:
gate-house/history/2026-08-28-security-layer-model-and-gate-house-recut.md

The note flags pending adaptation only; the body is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 2564823@bnt-lap001
Assistant-Session: 2a7ed827-4928-4b9f-8613-9135c9cadfe9
2026-08-28 20:33:43 +02:00
37c387bd34 fix(workplans): qualify archived ad-hoc identifiers
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
The live-file pass missed these: archived ad-hocs carry a YYMMDD- filename
prefix, so the ADHOC-* glob did not match them. They still derive from the
forge, so they are live records rather than dead files.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 2583210@bnt-lap001
Assistant-Session: f2bff2d5-e9b2-4338-92ca-10282a927006
2026-08-28 00:34:02 +02:00
030362085a fix(workplans): qualify ad-hoc identifiers with the repository prefix
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
`ADHOC-YYYY-MM-DD` is unique per date but not per repository, so any two repos
opening an ad-hoc on the same day collide. The 2026-08-26 fleet projection
reset refused 9 records for exactly this reason.

Canon (work-record-types_v0.1, CUST-WP-0066) settled the form as
`{PREFIX}-WP-ADHOC-YYYY-MM-DD`, filename unchanged, and grandfathered existing
ids on the condition they are never *silently* re-derived. This is the explicit
migration that clause allows for.

The hub id is derived from the record id, so a changed id is a different
record: stale state_hub_*_id fields are dropped and fix-consistency re-derives.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 2583210@bnt-lap001
Assistant-Session: f2bff2d5-e9b2-4338-92ca-10282a927006
2026-08-28 00:28:23 +02:00
35 changed files with 4431 additions and 91 deletions

View file

@ -16,6 +16,8 @@ distinction that matters here.
| `ADR-0006` | Enforcement is zone-scoped, never a global flag |
| `ADR-0007` | Build-stage permissiveness stops at credential disclosure; every lane carries an explicit `risk` grade |
| `ADR-0008` | A lane's risk grade covers every field its path discloses, not just the field it is named after |
| `ADR-0009` | Adopt security-zones v0.1 as a consumer; membership is compiled, never inferred |
| `ADR-0010` | ops-warden is Staff: it owns access lanes, never access rules; doctrine belongs to gate-house |
### Owned versus inherited — check `owner:` before changing anything

View file

@ -2,16 +2,20 @@
# Custodian Brief — ops-warden
**Domain:** infotech
**Last synced:** 2026-08-25 18:17 UTC
**Last synced:** 2026-08-31 22:49 UTC
**State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)*
## Active Workstreams
### Native lane handoff — review secrets-engine's catalog admission, and fix what it exposed
Progress: 5/6 done | workplan_id: `4627d89b-4b00-562a-81e9-76e96f90fa7e`
### Layer model v0.7 conformance — state the deadline, bind the agent boundary, steward the estate's newest rule
Progress: 0/5 done | workplan_id: `ae3ff76f-883d-5e2f-b6aa-144d61e8fdef`
**Open tasks:**
- ! Tasks `5acac140`
- · Tasks `8b3bdb9f`
- · Tasks `3318ee1a`
- · Tasks `a891b32c`
- · Tasks `94e73daa`
- · Tasks `7d1b3c82`
### Tamper-resistant credential governance + mass rotation/lockdown (Strand B)
Progress: 2/3 done | workplan_id: `21528e8d-a049-523d-9ae1-da7a27cb8bbf`
@ -21,9 +25,8 @@ Progress: 2/3 done | workplan_id: `21528e8d-a049-523d-9ae1-da7a27cb8bbf`
## Inbox Hygiene
**Stale unread:** 9 message(s) older than 3 day(s) — triage at session start.
**Missing thread_id:** 7 unread message(s) lack supersession chains.
- ! secrets-engine: Re: Need the warden-sign live apply/handoff (FLEX-WP-0007 T4) `80456912`
**Stale unread:** 1 message(s) older than 3 day(s) — triage at session start.
**Missing thread_id:** 6 unread message(s) lack supersession chains.
---
## MCP Orientation (when available)

2360
.repo-manager/index.json Normal file

File diff suppressed because it is too large Load diff

120
INTENT.md
View file

@ -1,5 +1,68 @@
---
layer: Staff
role: null # Engines only: PDP | PIP | Evidence | Lifecycle
pep_shaped: true # §6.4 — issuing a certificate is a protected side effect
standard: net-kingdom/canon/standards/security-layer-model_v0.7.md
standard_version: "0.7"
companion: net-kingdom/SECURITY-COMPANION.md
declaration: layer.yaml
pep_stance: pep-stance.yaml
assent: docs/adr/ADR-0010
---
# INTENT
> **ops-warden is Staff, and PEP-shaped.** Declared here in its own voice, per
> `security-layer-model_v0.7` §11 — a layer stated *about* a repository by another
> repository is not a declaration. The standard is **accepted**; its operative form
> is `net-kingdom/SECURITY-COMPANION.md`. ops-warden's assent is `ADR-0010`, and its
> reviews of v0.4, v0.6 and v0.7 are in `history/`.
>
> **Staff** because ops-warden's core function is judgement, not computation: it
> decides which lane a need belongs to and stewards the paths through the estate's
> rules. Its artifacts are runbooks, routing decisions, workplans. **PEP-shaped**
> because issuing a certificate is a protected side effect — a shape, not a layer
> (§6.4). ops-warden renders no authorization decision and never will; it consumes
> them from `access-engine`.
>
> **The estate's front door for paths.** The companion routes the whole estate here:
> *"For how to get something done — which lane, which credential, which route — ask
> `ops-warden`. This document says what the rules are; ops-warden stewards the paths
> through them."* That is a standing obligation, not a compliment: every rule
> gate-house writes needs a path someone can actually walk, and ops-warden owes the
> estate that path.
>
> **The declarations are files, not this note** — prose cannot distinguish a
> declaration from a transcribed review (§11):
>
> | File | Declares | Enforced by |
> | --- | --- | --- |
> | `layer.yaml` | every Tooling contact, mapped to a §5.1/§5.2/§5.3 shape, plus the non-Tooling clients so the check is total | `scripts/check_layer_conformance.py`, `tests/test_layer_conformance.py` |
> | `pep-stance.yaml` | the unreachable-engine stance map (§6.4 obl. 3), total per zone | test asserts the published map **equals** the shipped default |
> | `tenancy.yaml` | tenancy posture, and `z1-operational` zone membership | `ADR-0009` |
>
> Both are cited in the standard as the estate's reference forms (§11, §6.4, §13.1).
>
> **Two declared engine gaps (§5.3), tracked non-conformance and not conformance.**
> `VaultCA` signs over a direct OpenBao client and `warden desk` shells `bao kv put`.
> Intended owner **secrets-engine**; blocked on no engine exposing an SSH-CA or
> attended-provisioning surface; reviewed quarterly; registered in statute §13.
> ops-warden keeps signing while the gap is open — refusing would remove production
> host access to close a documentation gap.
>
> **The agent principal (§3.4).** ops-warden is operated by agents as well as people,
> and they share the layer but not the blast radius. No standing credential; tool use
> is a conduit or an engine API and there is no third route; **tool availability is
> not permission**, which is exactly what `ADR-0004`'s read-boundary enforces; agent
> memory is not a state plane. Session semantics belong to `glas-harness`, not here.
>
> **Evidence (§9.6).** ops-warden's audit trail is **attributive**, not load-bearing:
> no control branches on the presence of a signing record. Emission is deliberately
> non-atomic so an audit-store failure cannot remove production host access — a trade
> the standard sanctions, declared in `wiki/AuditTrail.md`, registered in §13. If any
> future control ever gates on this trail, that trade must be revisited before it
> ships.
> This file captures **why this repository exists**, the **direction it is
> moving toward**, and the **kind of system it is meant to become**.
> It is intentionally **aspirational and stable**, not a description of
@ -77,30 +140,52 @@ owns one lane and points at the rest:
---
## NetKingdom Security Literacy
## Lane routing — who owns which need
ops-warden should be fluent in the platform architecture documented in
`net-kingdom` — especially:
**This is a runbook, not doctrine.** Security doctrine, the authority model, and the
security curriculum are **gate-house's** (`security-layer-model_v0.7` §8).
ops-warden references them and does not restate them. What follows is lane
stewardship: which subsystem owns which need, and what ops-warden does about it.
| Plane / component | Role in access | ops-warden relationship |
| --- | --- | --- |
| **key-cape / Keycloak** | Identity — who is the actor, MFA, IAM Profile claims | Instruct identity path; do not re-implement OIDC |
| **flex-auth + Topaz** | Authorization — may this actor perform this action | Caller-side policy gate shipped (opt-in); production flip is flex-auth's |
| **OpenBao** | Runtime secrets — API keys, dynamic creds, leases, audit | Instruct custody paths; SSH engine is signing backend only; proxy reads as caller when `exec_capable` |
| **secrets-engine** | Owner-native secret-exec (`secrets-engine exec`) | Route provisioned exec lanes (e.g. npm publish); ops-warden does not hold tokens |
| **railiance-platform** (credential broker) | Scoped lease grants (`credential exec`) | Route `warden-sign` token needs; ops-warden does not mint OpenBao tokens |
| **tenant-engine** | Tenant/client secret custody and front door | Route tenant lanes once fronted; ops-warden's current tenant proxies are interim (§9) |
| **user-engine** | End-user identity and account lifecycle | No ops-warden lane today; route rather than absorb |
| **ops-warden** | Operational SSH certificates — short-lived host access | **Own and issue** this lane |
| **ops-bridge** | Tunnel transport — consumes certs via `cert_command` | Primary consumer; document integration |
| **railiance-infra** | Host principals, force-command, SSH hardening | Instruct host-side deployment; do not own Ansible |
| **railiance-platform** (deploy) | OpenBao/K8s/platform service deployment | Instruct production endpoints; do not deploy clusters |
The machine-readable form is `registry/routing/catalog.yaml`, and the executable form
is `warden plan "<need>"` / `warden route find`. Prefer either over this table — it is
orientation, and the catalog is the source of truth (`ADR-0001`).
| Component | Layer | Owns | ops-warden relationship |
| --- | --- | --- | --- |
| **gate-house** | Staff | Security doctrine, invariants, authority ceilings, authority context, conformance review, curriculum | **Route doctrine and authority-model questions here.** Not policy decisions — those go to access-engine |
| **access-engine** (`flex-auth`) | Engine | **The policy decision** — whether an actor may act. The only decision point in NetKingdom | Consume decisions; caller-side pre-sign gate. ops-warden never renders or caches one |
| **key-cape / Keycloak** | Tooling | Identity — who the actor is, MFA, IAM Profile claims | Instruct the identity path; do not re-implement OIDC |
| **OpenBao** | Tooling | Runtime secrets — API keys, dynamic creds, leases, audit | Instruct custody paths; proxy reads as the caller when `exec_capable`. Direct client use is the declared exception above |
| **secrets-engine** | Engine | Credential abstraction, custody, lifecycle; owner-native exec | Route provisioned exec lanes (e.g. npm publish). **Intended owner of the SSH-CA surface** |
| **tenant-engine** | Engine | Tenant/client secret custody and front door | Route tenant lanes once fronted; current tenant proxies are interim (section 9) |
| **user-engine** | Engine | Users, accounts, memberships | No ops-warden lane today; route rather than absorb |
| **zone-engine** | Engine | Zone identity and membership | Consume compiled membership; ops-warden declares `z1-operational` (`ADR-0009`) |
| **railiance-platform** (broker) | — | Scoped lease grants (`credential exec`) | Route `warden-sign` token needs; ops-warden does not mint OpenBao tokens |
| **ops-mason** | Staff | Building and tearing down access routes and perimeters | Peer lane owner; same lane/rule demarcation applies |
| **ops-warden** | Staff | **Operational access lanes** — short-lived SSH certificates, routing, stewardship, runbooks | **Own and issue** the SSH lane |
| **ops-bridge** | Staff | Tunnel transport — consumes certs via `cert_command` | Primary consumer; document integration |
| **railiance-infra** | — | Host principals, force-command, SSH hardening | Instruct host-side deployment; do not own Ansible |
| **kings-guard** | Staff | Adaptive defence, observation, containment; publishes posture | Posture may reduce authority, never manufacture it |
### Access lane versus access rule
Normative, per `security-layer-model_v0.7` §8 and assented to in `ADR-0010`:
- **access lane** — ops-warden and ops-mason. *How* a worker reaches a host.
- **access rule** — access-engine. *Whether* they may.
ops-warden owns the route and never the decision. A question about whether an actor
may do something is not an ops-warden question, however it arrives.
Canonical references:
- `net-kingdom/SECURITY-COMPANION.md` — the operative form; start here
- `net-kingdom/canon/standards/security-layer-model_v0.7.md` (accepted; §5 shapes, §6.4 PEP, §8 vocabulary)
- `net-kingdom/docs/platform-identity-security-architecture.md`
- `net-kingdom/docs/responsibility-map.md`
- `wiki/AccessManagementDirective.md` (ops SSH actor model)
- `.claude/rules/credential-routing.md` (agent-facing runbook — stays inline by design)
---
@ -123,7 +208,8 @@ Canonical references:
| Need | Route to |
| --- | --- |
| OIDC login, MFA, human identity claims | key-cape / Keycloak (NetKingdom IAM Profile) |
| Policy decision — may actor X access resource Y | flex-auth |
| Security doctrine, invariants, authority model | gate-house |
| Policy decision — may actor X access resource Y | access-engine (`flex-auth`) |
| API keys, provider secrets, DB creds, object-storage STS | OpenBao (+ flex-auth policy where required) |
| Inter-Hub operator keys, LLM provider credentials | OpenBao or approved operator secret store |
| Tunnel lifecycle, port forwarding | ops-bridge |

View file

@ -85,6 +85,28 @@ cutover, flex-auth publishing the zone-aware pre-sign stance package,
the owner-driven WP-0015 canon landing, and — newly named — the missing owner front
doors that keep ops-warden holding interim lanes (secrets-engine, tenant-engine).
### Layer-model conformance (v0.7, accepted)
ops-warden declares **Staff**, **PEP-shaped**, in `INTENT.md` frontmatter and in its
own voice — `security-layer-model_v0.7` §11. Shipped declaration artifacts, both
cited in the standard as the estate's reference forms:
| Artifact | Declares | Status |
| --- | --- | --- |
| `layer.yaml` | 5 Tooling contacts mapped to §5.1/§5.2/§5.3 shapes + non-Tooling clients so the check is total | shipped; named reference form (§11) |
| `pep-stance.yaml` | unreachable-engine stance map, total per zone | shipped; registered in statute §13.1 (§6.4 obl. 3) |
| `scripts/check_layer_conformance.py` | every direct Tooling client maps to a declared shape | shipped; CI-enforced |
| `tests/test_layer_conformance.py` | the §5.2 no-authority property, and published stance map **equals** shipped default | shipped, 11 tests |
Conformance state under §11: **declared gap** — tracked non-conformance, not
conformance. Two §5.3 contacts (`VaultCA` signing write, `warden desk` `bao kv put`),
intended owner `secrets-engine`, registered in statute §13.
Four ops-warden findings have been adopted into the standard: §9.1's two marks
(`pending` vs `declared-gap`), §5's Tooling scope rule, §6.4 obligation 1's second
limb, and §13.1's existence. Reviews: `history/2026-08-29-layer-model-v04-review.md`,
`-v06-review.md`, `-v07-scope-intent-assessment.md`.
### Issue vs route
ops-warden executes exactly one lane with its own authority and routes/assists the rest.
@ -156,6 +178,7 @@ superseding ADR, never an in-place edit.
| `ADR-0007` | Build-stage permissiveness stops at credential disclosure; every lane carries an explicit `risk` grade |
| `ADR-0008` | A lane's risk grade covers every field its path discloses, not just the field it is named after |
| `ADR-0009` | Adopt security-zones v0.1 and compile explicit workload membership; PEP failure mode is per zone |
| `ADR-0010` | ops-warden is Staff and PEP-shaped — it owns access lanes, never access rules; the direct OpenBao client is a declared engine gap, not an exemption |
Rules we follow but do not own — NetKingdom canon, the IAM profile, the
credential-management standard, the-custodian's ADR-001 workplan convention — are
@ -433,11 +456,12 @@ Downstream: `ops-bridge` (primary), kaizen agents, CI automations, human operato
| Repo | Relationship |
| --- | --- |
| `gate-house` | Owns the security layer model, doctrine, invariants, authority context, and conformance review. ops-warden routes doctrine questions there, and the companion routes the estate's *path* questions back to ops-warden (`ADR-0010`) |
| `net-kingdom` | Canonical security architecture; ops-warden aligns to it |
| `ops-bridge` | Primary cert_command consumer |
| `railiance-infra` | Host-side SSH principals and hardening |
| `railiance-platform` | OpenBao deployment and platform secrets |
| `flex-auth` | Authorization; policy package shipped (FLEX-WP-0006); runtime deploy FLEX-WP-0007 |
| `flex-auth` | Authorization — ruled name `access-engine`; the only policy decision point. Policy package shipped (FLEX-WP-0006); runtime deploy FLEX-WP-0007 |
| `key-cape` | Identity / IAM Profile lightweight mode |
| `secrets-engine` | Owner-native secret-exec front door (`secrets-engine exec/route`); ops-warden routes provisioned secret lanes to it (WP-0019) and holds 6 more as interim proxies pending its front doors |
| `tenant-engine` | Intended owner of tenant/client secret front doors; ops-warden holds 3 tenant lanes as interim proxies (WP-0028 pattern, WP-0030 register) |
@ -486,6 +510,9 @@ keywords: [access, credential, secret, npm, token, api-key, openbao, key-cape, l
| `wiki/CredentialRouting.md` | Which subsystem for each credential need |
| `wiki/WorkloadSecurityPosture.md` | Secret-store posture, workload maturity, and blocker triage |
| `registry/routing/catalog.yaml` | Machine-readable routing pointer catalog |
| `net-kingdom/SECURITY-COMPANION.md` | **The estate's operative security rules — start here** |
| `layer.yaml` | Layer declaration: every Tooling contact and its §5 shape |
| `pep-stance.yaml` | Unreachable-engine stance map (§6.4); equals shipped behaviour by test |
| `tenancy.yaml` | Declared tenancy posture (`I1 A1 E0 P n/a R n/a V0`) and why each axis sits where it does |
| `wiki/NetKingdomSecurityMap.md` | Platform security component map |
| `examples/warden.production.example.yaml` | Production warden.yaml template |

View file

@ -8,10 +8,10 @@
| Kind | ID | Status | Lane | Source |
| --- | --- | --- | --- | --- |
| workplan | ADHOC-2026-06-27 | finished | — | workplans/ADHOC-2026-06-27.md |
| workplan | ADHOC-2026-06-29 | finished | — | workplans/ADHOC-2026-06-29.md |
| workplan | ADHOC-2026-08-11 | finished | — | workplans/ADHOC-2026-08-11.md |
| workplan | ADHOC-2026-08-17 | finished | — | workplans/ADHOC-2026-08-17.md |
| workplan | WARDEN-WP-ADHOC-2026-06-27 | finished | — | workplans/ADHOC-2026-06-27.md |
| workplan | WARDEN-WP-ADHOC-2026-06-29 | finished | — | workplans/ADHOC-2026-06-29.md |
| workplan | WARDEN-WP-ADHOC-2026-08-11 | finished | — | workplans/ADHOC-2026-08-11.md |
| workplan | WARDEN-WP-ADHOC-2026-08-17 | finished | — | workplans/ADHOC-2026-08-17.md |
| workplan | WARDEN-WP-0016 | finished | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md |
| workplan | WARDEN-WP-0017 | finished | — | workplans/WARDEN-WP-0017-access-front-door-discoverability.md |
| workplan | WARDEN-WP-0018 | finished | — | workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md |
@ -29,16 +29,19 @@
| workplan | WARDEN-WP-0030 | finished | — | workplans/WARDEN-WP-0030-delegation-register.md |
| workplan | WARDEN-WP-0031 | finished | — | workplans/WARDEN-WP-0031-policy-caller-identity.md |
| workplan | WARDEN-WP-0032 | finished | — | workplans/WARDEN-WP-0032-security-zones.md |
| workplan | WARDEN-WP-0033 | active | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
| task | ADHOC-2026-06-27-T01 | done | — | workplans/ADHOC-2026-06-27.md |
| task | ADHOC-2026-06-29-T01 | done | — | workplans/ADHOC-2026-06-29.md |
| task | ADHOC-2026-08-11-T01 | done | — | workplans/ADHOC-2026-08-11.md |
| task | ADHOC-2026-08-11-T02 | done | — | workplans/ADHOC-2026-08-11.md |
| task | ADHOC-2026-08-11-T03 | done | — | workplans/ADHOC-2026-08-11.md |
| task | ADHOC-2026-08-17-T01 | done | — | workplans/ADHOC-2026-08-17.md |
| task | ADHOC-2026-08-17-T02 | done | — | workplans/ADHOC-2026-08-17.md |
| task | ADHOC-2026-08-17-T03 | done | — | workplans/ADHOC-2026-08-17.md |
| task | ADHOC-2026-08-17-T04 | done | — | workplans/ADHOC-2026-08-17.md |
| workplan | WARDEN-WP-0033 | finished | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
| workplan | WARDEN-WP-0034 | ready | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
| workplan | WARDEN-WP-0035 | finished | — | workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md |
| workplan | WARDEN-WP-0036 | finished | — | workplans/WARDEN-WP-0036-attended-login-openbao-output.md |
| task | WARDEN-WP-ADHOC-2026-06-27-T01 | done | — | workplans/ADHOC-2026-06-27.md |
| task | WARDEN-WP-ADHOC-2026-06-29-T01 | done | — | workplans/ADHOC-2026-06-29.md |
| task | WARDEN-WP-ADHOC-2026-08-11-T01 | done | — | workplans/ADHOC-2026-08-11.md |
| task | WARDEN-WP-ADHOC-2026-08-11-T02 | done | — | workplans/ADHOC-2026-08-11.md |
| task | WARDEN-WP-ADHOC-2026-08-11-T03 | done | — | workplans/ADHOC-2026-08-11.md |
| task | WARDEN-WP-ADHOC-2026-08-17-T01 | done | — | workplans/ADHOC-2026-08-17.md |
| task | WARDEN-WP-ADHOC-2026-08-17-T02 | done | — | workplans/ADHOC-2026-08-17.md |
| task | WARDEN-WP-ADHOC-2026-08-17-T03 | done | — | workplans/ADHOC-2026-08-17.md |
| task | WARDEN-WP-ADHOC-2026-08-17-T04 | done | — | workplans/ADHOC-2026-08-17.md |
| task | WARDEN-WP-0016-T01 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md |
| task | WARDEN-WP-0016-T02 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md |
| task | WARDEN-WP-0016-T03 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md |
@ -126,6 +129,17 @@
| task | WARDEN-WP-0033-T01 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
| task | WARDEN-WP-0033-T02 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
| task | WARDEN-WP-0033-T03 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
| task | WARDEN-WP-0033-T04 | wait | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
| task | WARDEN-WP-0033-T04 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
| task | WARDEN-WP-0033-T05 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
| task | WARDEN-WP-0033-T06 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
| task | WARDEN-WP-0034-T01 | todo | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
| task | WARDEN-WP-0034-T02 | todo | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
| task | WARDEN-WP-0034-T03 | todo | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
| task | WARDEN-WP-0034-T04 | todo | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
| task | WARDEN-WP-0034-T05 | todo | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
| task | WARDEN-WP-0035-T01 | done | — | workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md |
| task | WARDEN-WP-0035-T02 | done | — | workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md |
| task | WARDEN-WP-0036-T01 | done | — | workplans/WARDEN-WP-0036-attended-login-openbao-output.md |
| task | WARDEN-WP-0036-T02 | done | — | workplans/WARDEN-WP-0036-attended-login-openbao-output.md |
| intake | WARDEN-IN-0001 | closed | — | intakes/intakes.md |
| intake | WARDEN-IN-0002 | open | — | intakes/intakes.md |

View file

@ -0,0 +1,109 @@
---
id: ops-warden-adr-0010
type: adr
title: "ADR-0010 — ops-warden is Staff: lanes, not rules, and one declared engine gap"
domain: infotech
repo: ops-warden
status: accepted
version: "1.0"
revision: "1"
owner: ops-warden
binds: "ops-warden"
created: "2026-08-28"
updated: "2026-08-28"
last_reviewed: "2026-08-28"
review_interval: 3m
enforced_by: "INTENT.md layer declaration; docs/adr/ADR-0002; docs/adr/ADR-0003; docs/adr/ADR-0005; registry/routing/catalog.yaml delegation fields"
supersedes: ""
successor: ""
---
# ADR-0010 — ops-warden is Staff: lanes, not rules, and one declared engine gap
## Status
Accepted 2026-08-28, answering intake `WARDEN-IN-0001` from gate-house, which
carries decision `GH-DEC-2026-001`. The standard being adopted —
`net-kingdom/canon/standards/security-layer-model_v0.1.md` — is `proposed`, and was
proposed pending assent from flex-auth, kings-guard, and ops-warden. This ADR is
ops-warden's half of that assent.
## Context
The estate acquired overlapping claims to the same responsibility, most visibly two
repositories describing themselves as the authorization control plane. The layer
model resolves the overlap by layering repositories on determinism — Taxonomy,
Tooling, Engines, Staff — and by two rules: Staff never touches Tooling directly
(§5), and `access-engine` is the only policy decision point (§6).
ops-warden is assigned Staff. Two demarcations follow that touch this repository:
the security curriculum it had been carrying belongs to gate-house, and the words
*access lane* and *access rule* are bound to different owners.
Full reasoning: `history/2026-08-28-security-layer-model-assent.md`.
## Decision
**1. ops-warden is Staff and declares it.** `INTENT.md` carries the layer label and
the §5 invariant. ops-warden holds no state another layer depends on at runtime and
renders no authorization decision — it consumes them.
**2. Lanes, not rules.** ops-warden owns *how* a worker reaches a host: SSH
certificate issuance, the routing catalog, `warden access`, `warden plan`,
`cert_command`. It never owns *whether* a worker may — that is `access-engine`
(today `flex-auth`), and ops-warden neither renders nor caches that decision. This
restates what `ADR-0002` and `ADR-0005` already bind; it is recorded here because
the demarcation is now normative estate-wide and other repositories rely on
ops-warden holding to it. The ruled rename `flex-auth``access-engine` is assented
to; ops-warden asks only for a window in which both names resolve.
**3. Doctrine goes to gate-house; runbooks stay here.** ops-warden does not restate
security doctrine, the authority model, or the curriculum. It references
gate-house's. It keeps everything operational about the lanes it stewards: which
subsystem owns which need, how to obtain a credential lane by lane, and conformance
evidence for its own lanes. `.claude/rules/credential-routing.md` is runbook, not
curriculum, and stays inlined in this and every other repository.
**4. One declared engine gap, not an exemption.** `src/warden/vault.py` (`VaultCA`)
is a direct OpenBao client performing a write from a Staff repository. It is a §5
non-conformance. ops-warden declares it rather than arguing it away:
- **intended owner:** `secrets-engine` (credential abstraction, custody, lifecycle)
- **blocked on:** no engine exposes an SSH certificate signing surface
- **review:** with this ADR, every 3 months
Until that surface exists, ops-warden continues to sign — refusing to would remove
production host access to close a documentation gap — and reports the position as
open. `warden desk`'s `bao kv put` is declared on the same terms. `taint.py` is
metadata-only observation, declared under §5's read-only allowance. `proxy.py`
supplies no authority of its own: it runs the owner's tool under the caller's
identity and is governed by `ADR-0002`.
This is `ADR-0003` turned inward. ops-warden has required an intended owner and a
blocker on 27 catalog lanes it holds for other repositories; it holds itself to the
same record.
## Consequences
ops-warden's conformance under §10 is *declared non-conformant with a tracked
closure path*, not clean. That is the accurate state and it is the state that gets
fixed, because it names an owner who can fix it.
An amendment to §5 has been offered to gate-house — a second sanctioned shape
alongside read-only diagnostics: a declared engine gap carrying intended owner,
blocker, and review date, machine-readable so §10 can tell a tracked gap from an
undeclared violation. It is offered, not assumed; §5 stays gate-house's to write. If
gate-house declines it, ops-warden's position is a plain non-conformance and is
reported as one.
The `NetKingdom Security Literacy` section stops being a prose second source for
`registry/routing/catalog.yaml`, which `ADR-0001` had already ruled against for
catalog procedure.
## Related
- `net-kingdom/canon/standards/security-layer-model_v0.1.md` (proposed, gate-house)
- `gate-house/decisions/decisions.md``GH-DEC-2026-001`
- `history/2026-08-28-security-layer-model-assent.md`
- `ADR-0001`, `ADR-0002`, `ADR-0003`, `ADR-0005`, `ADR-0009`
- `WARDEN-IN-0001`

View file

@ -71,3 +71,4 @@ and the publication is a defect.
| `ADR-0007` | Build-stage permissiveness stops at credential disclosure | ops-warden |
| `ADR-0008` | A lane's risk grade covers every field its path discloses | ops-warden |
| `ADR-0009` | Adopt security-zones v0.1; compile explicit membership and select PEP failure mode per zone | ops-warden |
| `ADR-0010` | ops-warden is Staff: it owns access lanes, never access rules; the direct OpenBao client is a declared engine gap | ops-warden, and gate-house as the standard's owner |

View file

@ -0,0 +1,171 @@
# Security layer model — ops-warden's assent (WARDEN-IN-0001)
**Date:** 2026-08-28
**Intake:** `WARDEN-IN-0001`
**Requested by:** gate-house, ratified as `GH-DEC-2026-001`
**Standard:** `net-kingdom/canon/standards/security-layer-model_v0.1.md` (proposed)
**Outcome:** assent to all three items; one declared non-conformance and one
proposed amendment to the standard.
---
## What was asked
gate-house asked ops-warden to assent to three boundary items:
1. **ops-warden is Staff**, bound by §5 — Staff acts only through Engine APIs and
never holds a direct Tooling client.
2. **Doctrine versus runbook** — the security curriculum moves to gate-house; the
`NetKingdom Security Literacy` section in `INTENT.md` becomes lane-specific
runbooks that reference gate-house doctrine rather than restating it.
3. **The access lane / access rule demarcation** (§8) — ops-warden and ops-mason own
*lanes* (how a worker reaches a host); access-engine owns *rules* (whether they
may). This is the condition attached to renaming flex-auth to access-engine, so
ops-warden effectively holds a veto on that name.
Plus: add gate-house to the literacy and routing tables, and say so if moving the
curriculum out leaves ops-warden unable to instruct its own workers.
---
## Item 1 — Staff, and the §5 problem it exposes
**Assent to the layer.** Staff is the right assignment and not a demotion.
ops-warden's artifacts are exactly what §3.4 describes: routing decisions,
workplans, runbooks, an audit trail. Its one production lane is non-deterministic
in the sense that matters — it is an operator front door, not a contract.
**But §5 is violated today, and by the one lane ops-warden permanently owns.**
The rule is deliberately greppable, so grepping is the honest response:
| Path | Tooling contact | Kind | Whose credential |
| --- | --- | --- | --- |
| `src/warden/vault.py` (`VaultCA.sign`) | `POST <bao>/v1/<mount>/sign/<role>` | **write** | broker-issued token held by ops-warden's process |
| `src/warden/desk.py` | `bao kv put` (paste-once provisioning) | **write** | founder's, at the desk |
| `src/warden/taint.py` | `bao kv metadata get` | read (metadata only, never data) | caller's |
| `src/warden/proxy.py` (`warden access --fetch/--exec/--wrap`) | catalog `fetch_command` | read | **the caller's own** |
Two of these are not really ops-warden's clients. `proxy.py` runs the owner's tool
under the caller's identity and supplies no authority of its own — that is
`ADR-0002`, conduit not broker, and it is arguably outside §5's target. `taint.py`
reads metadata only, and fits §5's read-only-observation allowance once declared.
**`VaultCA` does not have that defence.** It is a direct OpenBao client, in a Staff
repository, performing a write, presenting a token from its own environment. It is
production-verified and it is the SSH lane — the single thing ops-warden owns
permanently. Under §5 as written, adopting this standard puts ops-warden's core
lane in violation on the day it is adopted.
The escape hatch §5 offers does not fit: it covers *read-only observation for
diagnostics*, and signing is a write. The route §5 prescribes does fit —
> *A Staff repository needing a capability no engine exposes MUST raise that as an
> engine gap, not solve it locally.*
— and no engine exposes SSH certificate signing. `secrets-engine` owns credential
abstraction, custody and lifecycle, which is the layer this belongs in, but it
fronts no SSH-CA API today.
**So ops-warden assents and declares the non-conformance rather than negotiating an
exemption.** `VaultCA` is recorded in `INTENT.md` as a declared §5 exception with a
named intended owner (`secrets-engine`), a blocker (no SSH-CA engine surface), and a
review date. That is `ADR-0003` — cover gaps, never silently own them — applied to
ops-warden itself instead of to someone else's lane.
### Proposed amendment to the standard
§5 has exactly one shape for a Staff repository that legitimately touches Tooling:
read-only diagnostics. That shape is too narrow to describe the estate as it exists,
and a rule with no lane for a real, sanctioned case gets satisfied by relabelling
rather than by closing the gap.
Recommend §5 gain a second shape: a **declared engine gap** — a Staff repository MAY
hold a Tooling client for a capability no engine exposes, provided it is declared in
`INTENT.md` with an intended owner, the blocker, and a review date, and provided the
declaration is machine-readable so the conformance check in §10 can distinguish a
tracked gap from an undeclared violation.
ops-warden already runs this machinery for other repositories' lanes: 27 catalog
entries carry `delegation:` with `intended_owner` and `blocked_on`, and
`warden route gaps` lists them (WP-0030). It is offered, not imposed — the standard
is gate-house's.
---
## Item 2 — Doctrine versus runbook
**Assent.** The `NetKingdom Security Literacy` section is what gate-house says it is:
evidence that the curriculum had no owner, so it accreted in whatever `INTENT.md`
was open. That is the same failure `risk-nexus` names for findings and the same one
`ADR-0001` prevents for catalog procedure. ops-warden has argued this rule twice
against other repositories; it applies here.
The boundary, drawn precisely:
| Moves to gate-house | Stays with ops-warden |
| --- | --- |
| Why the planes are separated; the authority model | Which subsystem owns which credential need |
| What "posture", "zone", "authority ceiling" mean | How to obtain a cert, a lease, a login — per lane |
| The security curriculum a worker is taught | The runbook a worker executes |
| Doctrine a lane must conform to | Evidence of conformance for ops-warden's lanes |
**gate-house's test question, answered: no, it does not leave ops-warden unable to
instruct its workers — and the reason is worth recording.** What actually instructs
an ops-warden worker is not the prose in `INTENT.md`. It is `warden plan "<need>"`,
`warden route find`, and `.claude/rules/credential-routing.md`, which is inlined into
every repository's agent instructions precisely because credential routing is
high-frequency and high-risk. That surface is executable, lane-specific, and
unambiguously runbook. It does not depend on the literacy table, and moving doctrine
out does not weaken it.
If anything the move improves it: the literacy table has been a second, prose copy of
what `registry/routing/catalog.yaml` states machine-readably, which is the
double-source failure `ADR-0001` exists to stop.
**One thing must not move with it.** `.claude/rules/credential-routing.md` stays
inline in this repository and in every other. It is not doctrine and not a
curriculum; it is the anti-pattern list an agent needs *before* it acts, and a
reference to a document in another repository would not be read in time.
---
## Item 3 — Access lane versus access rule
**Assent, unconditionally, and the veto on `access-engine` is not exercised.**
ops-warden is already built this way. `ADR-0005` implements one lane narrowly and
routes everything else; `ADR-0002` makes it a conduit that never decides; `ADR-0009`
has ops-warden compile membership attributes and apply a zone's failure mode while
flex-auth owns the stance. ops-warden consumes decisions; it has never rendered one.
The demarcation costs nothing because it describes what is already true.
`access-engine` is also the better name. ops-warden's own routing table has had to
say "authorization" for the decision and "access" for the route for a year, and the
collision is visible in every playbook.
**One operational condition, on execution rather than on the ruling.** The rename is
598 references across 82 files in this repository alone — catalog `owner:` fields,
`registry/flex-auth/`, `src/warden/policy.py`, the production registry snapshot
builder, playbooks, and the `.claude/rules/` files that other repositories inline.
Ops-warden asks for a deprecation window in which both names resolve, rather than a
flag day; ops-warden will do its own migration inside that window. This is a request
about sequencing, not a reservation about the name.
---
## Item 4 — gate-house is missing from every table
Correct, and fixed in this pass. gate-house is added to the literacy/routing table
in `INTENT.md` as the owner of doctrine, invariants, authority context, and
conformance review — with the routing rule stated explicitly: **doctrine and
authority-model questions go to gate-house; policy decisions continue to go to
access-engine.** Those are different questions and the distinction is the whole
point of §6.
---
## Recorded as
- `ADR-0010` — ops-warden is Staff; lanes not rules; the declared §5 exception
- `INTENT.md` — layer declaration, reworked routing table, gate-house row
- `WARDEN-IN-0001` — closed, outcome `assented`

View file

@ -0,0 +1,136 @@
# Security Layer Model v0.4 — ops-warden's review
**Date:** 2026-08-29
**Reviewed:** `net-kingdom/canon/standards/security-layer-model_v0.4.md` (accepted)
**Prior position:** `ADR-0010`, assent to v0.1 (`WARDEN-IN-0001`)
**Outcome:** no objection to the ruling; three findings, one of them against ops-warden.
---
## What v0.4 did with ops-warden's amendment
Both §5 asks from `ADR-0010` were adopted.
**§5.3 declared engine gap** is the amendment ops-warden offered, adopted with the
four fields intact (`capability`, `intended_owner`, `blocked_on`, `review`), the
rationale preserved — *a rule offering no lane for a real sanctioned case gets
satisfied by relabelling rather than by closing the gap* — and the framing that
matters most kept explicit: **a declared gap is tracked non-conformance, not
conformance**. ops-warden's delegation machinery is cited as prior art.
**§5.2 conduit** resolves the question ops-warden flagged rather than assumed. The
test is the supplied-authority property, which is the right test: it turns on what
the repository presents, not on what it touches. *"A conduit that presents its own
token is not a conduit"* is a sharper statement of `ADR-0002` than `ADR-0002` makes.
**This created an obligation ops-warden had not met.** §5.3 requires the fields
*machine-readably* and §11 makes the mapping a mechanical check; ops-warden's
declaration was prose in `INTENT.md`. Fixed in this pass: `layer.yaml`,
`scripts/check_layer_conformance.py`, `tests/test_layer_conformance.py`. The
checker found three undeclared modules on first run, all false positives — help
text, a docstring, and the doubles library that *simulates* `bao` — which is why
it now matches invocation shapes rather than the word.
---
## Finding 1 — §9.1 and §5.3 disagree, and ops-warden's §4 row is the instance
§9.1: *a Staff repository MUST NOT be catalogued in §4 as owning a capability that
requires a Tooling contact no engine exposes*; where intended but unbuilt, the
entry **MUST be marked pending** and the gap declared under §5.3.
ops-warden's §4 row reads `operational access lanes, stewardship, runbooks; SSH
certificate issuance` — with no pending mark. And §13 lists *SSH-CA signing write
(`VaultCA`, `bao kv put`) — declared by ops-warden — intended owner secrets-engine*.
So the catalog asserts ownership of a capability that requires a Tooling contact no
engine exposes, unmarked. By §9.1's own text that is a defect. But the available
fix is worse than the defect: **marking it pending would be false.** SSH issuance is
production-verified and in daily use. `pending` would tell a reader ops-warden does
not yet do the one thing it demonstrably does.
The root cause is that §9.1 collapses two different states:
| State | Example | Capability today |
| --- | --- | --- |
| No route exists at all | kings-guard containment (§9.2) | **zero** |
| Route exists via a declared §5.3 gap | ops-warden SSH issuance | **working, tracked** |
§5.3 exists precisely to sanction the second. §9.1 was written for the first — it
was raised by kings-guard, about containment, and correctly fixed *for that case*.
Applied to the adjacent case it produces a false catalog.
**Recommendation:** give §9.1 two marks rather than one — `pending` where no route
exists, and `declared-gap` where the capability is discharged under §5.3 and
registered in §13. Both are honest; today's binary forces a choice between a false
label and an unmarked violation.
This is the §12 loop working as designed, and §12 already says so: a finding that a
rule is unsatisfiable is a success of the loop.
---
## Finding 2 — §5's scope is undefined for infrastructure §4 does not catalogue
§5 forbids *a direct client for a Tooling-layer system*. §4 catalogues the security
estate, and only `key-cape` and `OpenBao` are Tooling rows.
ops-warden holds an HTTP client for the **State Hub** and for **llm-connect**
(`src/warden/worker.py`). Neither appears in §4. Both are infrastructure a Staff
repository holds a direct client for.
The question is not rhetorical, because the answers diverge sharply:
- **If they are Tooling**, then every Staff repository in the estate is in
undeclared violation on adoption day — they all write progress events — and
§11's second mechanical check fails estate-wide.
- **If they are not**, §5 should say so, because *"a Tooling-layer system"* reads
considerably broader than *"a repository in the §4 Tooling rows"*.
ops-warden has recorded both under `non_tooling_clients` in `layer.yaml` with the
reasoning stated, rather than resolving it unilaterally. The scope is gate-house's
to set.
---
## Finding 3 — §9.6 lands on ops-warden, and ops-warden does not satisfy it
This is the one against us, and it is the most consequential item in the review.
§9.6 consequence 1: *any system whose evidence is load-bearing MUST make emission
atomic with the state change it records. An archive cannot retrofit completeness.*
**ops-warden's audit emission is deliberately non-atomic.** `src/warden/ca.py:90`
carries `pass # audit must not block signing`, and `wiki/AuditTrail.md` states the
trail *"never blocks the primary action"*. If the audit append fails, the
certificate is still issued and the event is simply lost — a suppressed event that
leaves the chain perfectly intact, which is the exact failure §9.6 describes.
That was a considered availability choice: an audit-disk problem should not remove
production host access. §9.6 now makes it a conformance question, and the trade is
real in both directions:
- make emission atomic → an audit write failure fails the sign, and the estate's
operational access lane acquires a new dependency on its own evidence store;
- leave it → signing evidence cannot be treated as complete, and anything reasoning
from *"there is no record of a sign"* is unsound.
**ops-warden has not changed it, and is not going to decide this alone** — §9.6 is
estate doctrine and the question is whether SSH signing evidence is load-bearing in
gate-house's sense. What ops-warden can say is that the second horn is currently
true and undocumented: `wiki/AuditTrail.md` does not warn that absence of a record
is not evidence of absence. That correction is ops-warden's regardless of the
ruling, and is the smaller half of the fix.
Note also that §5.2 requires a conduit action to be *"reconstructable as the
caller's action in audit"* — an audit-dependent claim, and therefore bounded by
§9.6. Worth a cross-reference so the two rules do not drift apart.
---
## Offered
`layer.yaml` + `check_layer_conformance.py` + `test_layer_conformance.py` is a
working reference implementation of §5.3 and of §11's second mechanical check. Eight
of fifteen estate repositories have yet to declare (§14). If it is useful as a
pattern to point them at, it is offered — as the delegation machinery was.

View file

@ -0,0 +1,156 @@
# Security Layer Model v0.6 — ops-warden's review
**Date:** 2026-08-29
**Reviewed:** `security-layer-model_v0.6.md` (proposed), plus v0.5 and the companion
**Prior positions:** `ADR-0010` (v0.1 assent); `history/2026-08-29-layer-model-v04-review.md`
**Outcome:** no objection; one conformance action taken, two findings, one accepted SHOULD.
---
## Disposition of ops-warden's v0.4 findings
All three were acted on, two of them exactly as recommended.
| Finding | Outcome |
| --- | --- |
| §9.1 forces a false `pending` onto working capability | **Adopted** — v0.5 split it into `pending` and `declared-gap`, credited to ops-warden |
| §5 scope undefined for uncatalogued infrastructure | **Adopted** — "Tooling-layer system" now means a §4 Tooling row; the State Hub case is recorded, not policed |
| §9.6 atomicity lands on ops-warden's signing lane | **Ruled** — the load-bearing / attributive distinction, with ops-warden's `# audit must not block signing` named as the estate's live example |
The §9.6 ruling deserves a note, because it went in ops-warden's favour and that is
a reason to check it rather than accept it. The test is *"no control branches on
its presence"*. Verified: the only consumer of `audit.jsonl` is `warden activity`
(`cli.py`), which displays. Nothing gates on a signing record — not the agent
read-boundary, not `warden plan`, not the scorecard. The lane is genuinely
attributive and the trade is legitimate on the standard's own terms. The two
obligations that attach — declare it, never claim completeness — were already met
in `wiki/AuditTrail.md`, now updated to record the ruling rather than the open
question. **If a future ops-warden control ever gates on this trail, the trade has
to be revisited before that ships**, and that is recorded there.
`layer.yaml` is named in §11 as the estate's reference declaration form, including
the "record non-Tooling clients so the check is total" property. Offered again to
the repositories that have yet to declare.
---
## Conformance action taken — the stance map was not published
§6.4 obligation 3 requires a declared unreachable-engine stance that is total, per
zone, with no implicit default, *"published rather than held in code comments"*
and §6.4 requires **every** PEP-shaped consumer to publish its map so the maps can
be inventoried. `ADR-0009` is named as the reference shape.
ops-warden was not doing this. The map lived in `PolicyConfig.failure_modes`, a
dataclass default in `src/warden/config.py`. That is not a code *comment*, but it
is not published either — it is merely written down, and a consumer of the estate
had no way to read ops-warden's stance without reading ops-warden's source.
Published as `pep-stance.yaml`, with the property that makes publishing worth
anything: `tests/test_layer_conformance.py` asserts the published map is **equal to
the shipped default**. A published map that may drift from the code is worse than
no map, because it invites reliance it cannot support. The file also records the
obligation-2 position (verdict never cached; input claims cached under their own
freshness rules) and the obligation-4 bound (§9.6 attributive).
---
## Finding 1 — §6.4 obligation 1 contradicts obligation 3, and ops-warden is the instance
> **1. No side effect without a decision record.** A PEP MUST NOT perform the
> protected action unless it holds a decision from `access-engine` identifying the
> request it was rendered for.
> **3. A declared unreachable-engine stance (§9.3):** total, per zone... `ops-warden`
> `ADR-0009` is the reference shape.
These cannot both be absolute. ops-warden's declared stance — blessed by §9.3 as
*"the only thing left"* when there is no engine to ask — is `fail_open` for `z0``z2`
and `unknown`. Applying it means issuing a certificate **without holding a
decision**, which obligation 1 forbids without qualification.
So the same section names ops-warden as the reference shape for obligation 3 while
obligation 1 makes ops-warden's shipped behaviour a violation. §9.3 settled the
substance; §6.4 restates it in a form that takes it back.
**Recommendation.** Bound obligation 1 by obligation 3:
> A PEP MUST NOT perform the protected action unless it holds a decision from
> `access-engine` identifying the request it was rendered for, **or its declared
> §9.3 stance for the applicable scope permits proceeding without one and the
> application of that stance is recorded in place of the decision**.
This is not a weakening. It is stricter than today's text in the case that matters:
it makes the *recorded application of the stance* mandatory, rather than leaving
"no decision record" as a silent state. ops-warden already does this — `ca.py`
writes `policy_zone`, `policy_failure_mode` and `policy_decision_id` (present only
where a decision was rendered) into both the signatures log and `audit.jsonl`, per
`ADR-0009` rule 4: *a fail-open signing result is metadata, not silence*.
This is the same shape as the v0.4 §9.1 finding: a rule written for the clean case,
correct there, producing a false result on the adjacent case the standard has
already sanctioned elsewhere.
---
## Finding 2 — §6.4 creates a register that §13 does not implement
§6.4: *"Every PEP-shaped consumer MUST publish its stance map, and those maps MUST
be inventoried — in `maturity-engine` once it exists, **in §13 until then**."*
§13 contains no stance-map rows. It records declared contacts and unowned
capabilities; there is no column, row, or section for a PEP stance. So the
obligation names a register that does not exist yet, and the failure mode §6.4
itself warns about — *"`z0``z2` and unknown fail open" becoming the estate's real
policy without anyone having compiled it* — is exactly what the missing register
permits.
**Recommendation.** Either add a stance-map table to §13 with the same
state/owner-status discipline the gap table has, or state that the inventory waits
for `maturity-engine` and mark the obligation pending under §9.1's own logic — a
requirement whose register does not exist is a capability catalogued without a
surface. ops-warden's row is ready to paste:
| PEP | Protected action | Scope | Stance | Published |
| --- | --- | --- | --- | --- |
| `ops-warden` | SSH certificate issuance | security-zone | open `z0``z2`+unknown, closed `z3`/n-a | `ops-warden/pep-stance.yaml` |
The second half matters more than the first: **ops-warden is currently the only
PEP that has published one**, so an inventory today would contain one row and that
is itself the finding. `ops-mason` is named PEP-shaped in the same paragraph.
---
## Accepted, not yet done — §9.6 emission cadence
§9.6: *"A source SHOULD declare an expected emission cadence, and a drop below it
SHOULD become a finding in its own right."*
ops-warden declares none. This is a genuine SHOULD and the reasoning behind it is
sound — it converts the suppression blind spot into something detectable without
any Tooling contact, because the source publishes its own stream. It is not done
here because a cadence asserted without evidence is worse than none: ops-warden's
signing volume is operator-driven and bursty, and a fabricated baseline would
generate findings that mean nothing. Deriving one from the existing trail is
tractable and is recorded as ops-warden's to do, not gate-house's to chase.
---
## On the pace
Six versions in two days, with four repositories' findings absorbed and credited,
is the §12 loop working at a rate the estate has not seen before. Two cautions,
offered as an interested consumer rather than as objections:
1. **§13 already says it should not be statute, and it is right.** The register has
grown every version. Moving it to `maturity-engine` is the stated plan; until
that exists, each version of the standard is also a snapshot of a backlog, and
the two have very different review intervals.
2. **The standard is `proposed` again at v0.6**, and the four repositories that
assented did so to v0.1. ops-warden's `ADR-0010` assent covers the three
boundary items, and nothing in v0.2v0.6 has disturbed them — the layer, the
lane/rule demarcation, and doctrine-versus-runbook all stand. But the
`assented_by` list carries assent forward across five revisions, and a reader
could take it as assent to the current text. Worth distinguishing *assented to
the boundary* from *reviewed the current revision*; ops-warden has now done
both, and this note is the second.

View file

@ -0,0 +1,157 @@
# v0.7 conformance — INTENT vs SCOPE gap assessment
**Date:** 2026-08-29
**Standard:** `security-layer-model_v0.7.md` (**accepted**) + `SECURITY-COMPANION.md` v0.2
**Prior:** `ADR-0010`; v0.4 and v0.6 reviews in `history/`
**Method:** each v0.7 obligation checked against shipped code, not against intent.
---
## Summary
ops-warden is **conformant on every obligation it can discharge alone except three**,
and holds two declared §5.3 gaps that are tracked, registered and owned elsewhere.
The three genuine gaps are §9.7.2 (no stated revocation visibility deadline — a MUST),
§3.4 rule 1 (the agent read-boundary keys on an honour-system marker rather than an
issued identity), and §9.6's cadence, which is a SHOULD for an attributive source and
remains undone for an honest reason.
One new obligation is not a rule at all but a role: the companion routes the entire
estate to ops-warden for *how to get something done*. Nothing in the repo answers a
layer or declaration question today, and that is now a discoverability gap.
Four ops-warden findings were adopted into the standard between v0.4 and v0.7 — §9.1's
two marks, §5's Tooling scope rule, §6.4 obligation 1's second limb, and §13.1's
existence. That is the conformance loop working; it is not a reason to assume the next
pass finds nothing.
---
## Obligation-by-obligation
### Conformant, shipped, evidenced
| Obligation | Evidence |
| --- | --- |
| §11 declare layer in own voice, machine-readably | `INTENT.md` frontmatter (`layer: Staff`, `pep_shaped: true`) + `layer.yaml` — cited in §11 as the estate's reference form |
| §5 every Tooling contact maps to a shape; non-Tooling recorded so the check is total | `layer.yaml` 5 contacts + 2 exclusions; `scripts/check_layer_conformance.py` |
| §5.2 conduit supplies no authority | `proxy.py::_caller_env`; `tests/test_layer_conformance.py::test_conduit_supplies_no_authority_of_its_own` |
| §6.4 obl. 1 no side effect without a decision **or a recorded stance** | `ca.py` writes `policy_zone`, `policy_failure_mode`, `policy_decision_id` (present only where rendered). ops-warden is the named reference for limb two |
| §6.4 obl. 2 no verdict recaching | `policy.py` caches nothing — verified by inspection, not by claim |
| §6.4 obl. 3 stance map published, at a path named in the declaration, equal to shipped behaviour, asserted by test | `pep-stance.yaml`, named in `layer.yaml`; test asserts equality with `PolicyConfig().failure_modes`; registered in statute §13.1 |
| §9.3 stance total, per zone, no implicit default | 7 rows covering every zone plus `unknown` and `not-applicable` |
| §9.6 evidence claims bounded | `wiki/AuditTrail.md` declares the attributive trade and states absence is not evidence of absence |
| §9.7.1 every allow has an explicit lifetime | TTL enforced per `ActorType``adm` 48h, `agt` 24h, `atm` 8h |
| §3.4 rule 2 tool use is a conduit or engine API | `warden access` is the conduit; `ADR-0004` enforces that tool availability is not permission |
### Declared gaps — tracked non-conformance, owned elsewhere
Both registered in statute §13, intended owner `secrets-engine`, reviewed quarterly.
Neither is closable by ops-warden: closing them means another repository shipping a
surface.
- **`VaultCA` signing write** — no engine exposes SSH-CA signing.
- **`warden desk` `bao kv put`** — no engine exposes attended provisioning.
Nothing in v0.7 changes their status. The right ops-warden behaviour is to keep them
declared, keep the review dates honest, and not quietly grow a third.
---
## The three real gaps
### G1 — §9.7.2: no stated revocation visibility deadline (MUST)
> *A **PEP** has one boundary and MUST state one deadline… an unstated deadline is
> an unbounded replay window.*
ops-warden states none, and the honest answer is uncomfortable: **the effective
window is the certificate TTL — up to 48 hours.** A certificate issued under an allow
stays valid for its full TTL even if the decision that authorized it is revoked or
superseded the next minute. ops-warden has no revocation channel for an issued cert:
there is no CRL, no KRL distribution, and host-side `auth_principals` is
`railiance-infra`'s.
This is not a documentation gap. It is a design property that has never been written
down, and §9.7.2 exists precisely to force it into the open. Two things follow:
1. The deadline must be **stated**`adm` 48h / `agt` 24h / `atm` 8h — in
`pep-stance.yaml`, as what it is rather than as an aspiration.
2. Whether 48h is *acceptable* is a separate question, and it is partly
`railiance-infra`'s (KRL distribution) and partly ours (TTL policy). Stating it is
ours and is cheap; shortening it is a joint change.
Stating a bad number is better than stating none: an unstated deadline is an
unbounded replay window, and this one is bounded and already implemented.
### G2 — §3.4 rule 1: the agent boundary rests on an honour-system marker
> *No standing credential. Authority is issued per task, time-bounded under §9.7,
> and attributable to the principal on whose behalf it acts.*
`ADR-0004`'s read-boundary triggers when `WARDEN_AGENT_ID` is set — an environment
variable the agent sets **about itself**. An agent that does not set it is not
recognised as an agent. ops-warden has known this (`WARDEN-WP-0033-T04` recorded it
as "an honour-system marker on the ops-warden side"), and it was tolerable while no
issued agent identity existed.
One now does. `key-cape` accepted issuance ownership in `KEY-WP-0009-T03`:
`codex-railiance-platform`, subject `service:codex:railiance-platform`, role
`coding-agent`, scope `openbao:login`, 15-minute lifetime. The OpenBao side is
enforced by `railiance-platform`'s policy, which is the half that actually holds.
So the gap is narrower than it looks and worth stating precisely: **the OpenBao-side
boundary is real; the ops-warden-side boundary is advisory.** ops-warden should key
its read-boundary on the issued identity where one is present, and treat
`WARDEN_AGENT_ID` as a fallback that fails *toward* the boundary rather than away
from it. That is a change in this repo and does not need another repo to move.
### G3 — §9.6 emission cadence (SHOULD, for an attributive source)
Unchanged from the v0.6 review and still honest: ops-warden declares no expected
cadence because its signing volume is operator-driven and bursty, and a fabricated
baseline generates findings that mean nothing. v0.7 makes cadence a **MUST for
load-bearing sources**; ops-warden's trail is attributive, so it remains a SHOULD.
Deriving a real baseline from the existing trail is tractable and is ops-warden's to
do. It should be derived and declared, or explicitly deferred with a reason — not
left silent, which is what it is today.
---
## The role the companion assigns, and what it costs
> *"For how to get something done in NetKingdom — which lane, which credential, which
> route — ask `ops-warden`. This document says what the rules are; ops-warden stewards
> the paths through them."*
This is the largest change in ops-warden's INTENT surface and it is not a rule, so it
does not appear in any conformance check. The estate has been told to come here.
**Today the repo answers credential questions and no others.** `warden route` and
`warden plan` cover lanes, owners and acts. Nothing answers *"which layer am I"*,
*"how do I declare"*, *"I am PEP-shaped, what do I owe"* — the questions the companion
and the standard's adoption status (eight of fifteen repositories undeclared) actually
generate.
ops-warden has already built the reference artifacts those repositories need, and the
standard points at them by name in §11 and §6.4. What is missing is the path: a
discoverable route from *"I read the companion"* to *"here is the file to copy and the
check to run"*. That is exactly the stewardship ops-warden claims, applied to the
estate's newest rule rather than to its credential lanes.
Also worth noting, and not ops-warden's to fix: §13.1's register has one row, and
`ops-mason` — catalogued PEP-shaped in the same paragraph — has published nothing.
The standard says one row is itself the finding.
---
## What does not need doing
- **No new ADR.** `ADR-0010` holds: Staff, lanes not rules, declared gaps not
exemptions. v0.2v0.7 refined the rules around it and disturbed none of its three
positions. The reviews extend it; a superseding record would add ceremony without
changing a decision.
- **No change to the two §5.3 gaps.** They are correctly declared and owned elsewhere.
- **No re-assent.** ops-warden assented to the boundary in `ADR-0010` and has now
reviewed three revisions on their merits, which is the stronger position.

93
intakes/intakes.md Normal file
View file

@ -0,0 +1,93 @@
# Intake records
## WARDEN-IN-0001 — Assent requested: Staff layer, doctrine vs runbook, and the access lane/rule demarcation
```yaml
id: WARDEN-IN-0001
kind: intake
title: 'Assent requested: Staff layer, doctrine vs runbook, and the access lane/rule
demarcation'
status: closed
outcome: assented
origin: cross-repo
origin_ref: gate-house GH-DEC-2026-001
priority: medium
owner: ops-warden
requested_by: gate-house
standard: net-kingdom/canon/standards/security-layer-model_v0.1.md
description: 'gate-house asks ops-warden to assent to three boundary items. (1) ops-warden
is Staff, bound by the rule that Staff acts only through Engine APIs and never touches
Tooling directly (standard section 5). (2) Doctrine versus runbook: the NetKingdom
Security Literacy section in ops-warden INTENT is evidence the security curriculum
had no owner; it now has one in gate-house. Proposal is that doctrine and curriculum
move to gate-house and that section becomes lane-specific runbooks referencing gate-house
doctrine rather than restating it. ops-warden keeps the lanes it stewards and everything
operational about them. (3) The access lane/rule demarcation, normative in standard
section 8: ops-warden and ops-mason own access lanes — how a worker reaches a host;
access-engine owns access rules — whether they may. This demarcation is the condition
attached to renaming flex-auth to access-engine, so ops-warden effectively holds
a veto on that name. Also requested: add gate-house to the Security Literacy and
routing tables — currently every plane is listed and gate-house appears nowhere
— routing doctrine and authority-model questions there while continuing to route
policy decisions to access-engine. If moving the curriculum out leaves ops-warden
unable to instruct its own workers, say so; the boundary is wrong if it does.'
notes: 'Assented to all three items in ADR-0010, with reasoning in
history/2026-08-28-security-layer-model-assent.md. (1) Staff accepted; the section 5
binding rule exposed a real non-conformance — src/warden/vault.py is a direct
OpenBao client performing a write, as is warden desk''s bao kv put. Declared in
INTENT.md as an engine gap with intended owner secrets-engine and blocker "no engine
exposes an SSH-CA surface", not negotiated as an exemption; taint.py declared under
the read-only allowance; warden access proxies run under the caller''s identity.
An amendment is offered back to gate-house: a second sanctioned shape in section 5 for
a declared engine gap carrying intended owner, blocker and review date, machine-readable
so section 10 can tell a tracked gap from an undeclared violation. (2) Doctrine versus
runbook accepted; the literacy section is now a lane routing runbook referencing
gate-house doctrine. Answering gate-house''s test question: it does not leave ops-warden
unable to instruct its workers, because what instructs them is warden plan / warden route
and .claude/rules/credential-routing.md, which stays inline by design. (3) The lane/rule
demarcation assented unconditionally and the access-engine veto not exercised — ops-warden
already consumes decisions and renders none. One request on sequencing only: a deprecation
window in which both names resolve (598 references across 82 files here). gate-house added
to the routing tables in INTENT.md and SCOPE.md.'
created: '2026-08-28T19:30:28.087109Z'
updated: '2026-08-28T21:05:00Z'
state_hub_intake_id: "01a049ed-bbbc-7520-bc7c-6b0912ca534a"
```
## WARDEN-IN-0002 — Review requested: security layer model v0.3 — and does maturity-engine absorb warden route gaps?
```yaml
id: WARDEN-IN-0002
kind: intake
title: 'Review requested: security layer model v0.3 — and does maturity-engine absorb
warden route gaps?'
status: open
origin: cross-repo
origin_ref: net-kingdom security-layer-model_v0.3
priority: medium
owner: ops-warden
requested_by: gate-house
description: 'v0.3 is proposed and changes sections 4, 9 and 13 only; the v0.2 assent
record stands. Two new engines: approval-engine (section 9.4) and maturity-engine
(section 9.5). THE QUESTION FOR YOU concerns section 5.3, which exists because you
offered the amendment. v0.3 gives declared gaps an owner: maturity-engine takes
the gap register with intended_owner, blocked_on and review dates, and section 13
now says the register in the standard is interim and should not outlive that engine.
You offered warden route gaps and the 27 delegation catalog entries as reusable
prior art. So the question is whether that machinery should MOVE, be MIRRORED, or
STAY. Our tentative reading, which we want tested rather than accepted: routing
is yours and stays yours — warden route find answers where a credential need goes,
and that is lane knowledge, not maturity. What might move is the readiness half:
whether a declared gap is still within its review date, and whether an intended
owner has an engine surface yet. If splitting those creates two sources for one
fact, that is worse than either option and we would rather hear it now. Your SSH-CA
signing write would be tracked in maturity-engine as a declared gap with intended
owner secrets-engine and a review date — that is reporting your own non-conformance
to an engine, so we would rather you assent to it than discover it. Also note approval-engine
(section 9.4): it owns the approval object, not the approval workflow, so ops-warden
lanes needing approval consume a claim rather than implementing one. Assent, revision,
or rejection acceptable.'
created: '2026-08-28T20:40:24.957468Z'
updated: '2026-08-28T20:40:24.957468Z'
state_hub_intake_id: "01a04d97-94cd-7b49-8019-a91c7fce8adb"
```

128
layer.yaml Normal file
View file

@ -0,0 +1,128 @@
# ops-warden — NetKingdom security layer declaration
#
# Framework: net-kingdom/canon/standards/security-layer-model_v0.4.md
# Assent: docs/adr/ADR-0010 (ops-warden's own voice, per §11 "who must declare")
# Validate: python3 scripts/check_layer_conformance.py
#
# §11 makes one check mechanical: "every direct Tooling client in a Staff
# repository maps to a declared §5.1, §5.2, or §5.3 entry". This file is that
# map. It is machine-readable because §5.3 requires it to be — ops-warden
# proposed that shape and is implementing it rather than declaring in prose.
#
# Conformance rule inherited from tenancy.yaml: accuracy, not altitude. A
# declared gap is TRACKED NON-CONFORMANCE (§11), never a claim of conformance.
schema_version: "0.1"
framework: netkingdom-security-layer-model
standard_version: "0.4"
repository: ops-warden
layer: staff
declared_by: docs/adr/ADR-0010
declared_at: "2026-08-29"
# §6.4 — ops-warden is PEP-shaped (it causes a protected side effect: issuing a
# certificate). Its unreachable-engine stance map is published separately, and
# asserted equal to shipped behaviour by tests/test_layer_conformance.py.
pep_stance: pep-stance.yaml
# Every direct contact with a Tooling-layer system (§4), one entry each.
tooling_contacts:
- id: ssh-ca-signing-write
shape: "5.3" # declared engine gap
module: src/warden/vault.py
symbol: VaultCA.sign
tooling: OpenBao
operation: "HTTP POST <addr>/v1/<mount>/sign/<role> with X-Vault-Token"
write: true
capability: "Sign a short-lived SSH certificate for an adm/agt/atm actor"
intended_owner: secrets-engine
blocked_on: >-
No engine exposes an SSH certificate signing surface. secrets-engine owns
credential abstraction, custody and lifecycle, which is the layer this
belongs in, but fronts no SSH-CA API today.
review: "2026-11-28"
note: >-
Production-verified and in daily use. This is the one lane ops-warden owns
permanently (§4). Signing continues while the gap is open: refusing would
remove production host access to close a documentation gap.
- id: desk-paste-once-provision
shape: "5.3"
module: src/warden/desk.py
symbol: _provision_to_openbao
tooling: OpenBao
operation: "bao kv put <path> <field>=- (value on stdin, never argv)"
write: true
capability: "Founder paste-once provisioning of a secret straight into OpenBao"
intended_owner: secrets-engine
blocked_on: >-
No engine exposes an attended provisioning surface for a value the founder
holds and no automated path can produce.
review: "2026-11-28"
note: >-
Attended and founder-operated (WP-0029). The value reaches OpenBao without
passing through a terminal, an argv, or the audit log.
- id: taint-metadata-read
shape: "5.1" # read-only diagnostic observation
module: src/warden/taint.py
symbol: fetch_taint_status
tooling: OpenBao
operation: "bao kv metadata get -format=json <path>"
write: false
capability: "Report EXPOSED taint (custom_metadata) without reading secret data"
intended_owner: secrets-engine
blocked_on: >-
No engine exposes a disclosure-taint query. Metadata-only by construction —
reading the data would be the 2026-07-16 vector this exists to avoid.
review: "2026-11-28"
- id: access-proxy-conduit
shape: "5.2" # conduit
module: src/warden/proxy.py
symbol: proxy_fetch, proxy_attended_login_exec
tooling: OpenBao, key-cape
operation: "Runs the catalog-declared owner fetch_command as a child process"
write: false
capability: "warden access --fetch/--exec/--out/--wrap for exec_capable lanes"
supplied_authority: none
evidence:
no_own_credential: src/warden/proxy.py::_caller_env
test: tests/test_proxy.py::test_conduit_supplies_no_authority_of_its_own
audit: "audit.jsonl records the caller, the lane, and the outcome; never a value"
note: >-
The §5.2 test is the supplied-authority property: ops-warden presents no
credential of its own, cannot widen what the caller could already do, and
the action reconstructs as the caller's. Governed by ADR-0002.
- id: caller-identity-token
shape: "5.2"
module: src/warden/caller_identity.py
symbol: resolve_caller_token
tooling: OpenBao
operation: "Runs the operator-configured caller_auth command, or reads token env"
write: false
capability: "Establish the caller's own identity for the pre-sign policy gate"
supplied_authority: none
detection: voluntary # runs an operator-configured command, so no fixed
# argv shape to scan for; declared rather than omitted
note: >-
Obtains the CALLER's credential by the operator's configured means; adds no
authority. Never mints, and never persists what it resolves.
# Contacts that are deliberately NOT Tooling contacts, recorded so the check is
# total rather than silently selective.
non_tooling_clients:
- module: src/warden/policy.py
target: access-engine (flex-auth)
rationale: "Engine API — §5 permits it; this is the shape §5 prescribes."
- module: src/warden/worker.py
target: state-hub, llm-connect
rationale: >-
Not catalogued in §4. The layer catalog scopes the security estate, and
neither the State Hub nor llm-connect appears in it, so no §5 shape applies
on the standard's own terms. Raised with gate-house 2026-08-29 as a scope
question rather than resolved unilaterally — see the assessment note.

69
pep-stance.yaml Normal file
View file

@ -0,0 +1,69 @@
# ops-warden — PEP unreachable-engine stance map
#
# Framework: net-kingdom/canon/standards/security-layer-model_v0.6.md §6.4, §9.3
# Rule of record: docs/adr/ADR-0009
# Validate: pytest tests/test_layer_conformance.py -k stance
#
# §6.4 obligation 3 requires a declared unreachable-engine stance that is total,
# scoped per zone, carries no implicit default and no per-call discretion, and is
# "published rather than held in code comments". §6.4 further requires every
# PEP-shaped consumer to PUBLISH its map so the maps can be inventoried. This
# file is ops-warden's, published because a map that lives only in a dataclass
# default is not published — it is merely written down.
#
# The property that makes this worth reading: it is asserted equal to the shipped
# default in src/warden/config.py (PolicyConfig.failure_modes) by
# tests/test_layer_conformance.py. A published map that may drift from the code
# is worse than none, because it invites reliance it cannot support.
schema_version: "0.1"
framework: netkingdom-security-layer-model
standard_version: "0.6"
repository: ops-warden
pep_shape: true
declared_by: docs/adr/ADR-0009
protected_action: "SSH certificate issuance (warden sign / cert_command)"
decision_engine: access-engine # flex-auth until the governed rename
scope: security-zone # security-zones_v0.1 membership of the TARGET workload
# Total by construction: every zone in security-zones_v0.1, plus the two
# non-zone outcomes. No implicit default — an unlisted value is a config error,
# not a permissive fallback.
stance:
z0-experimental: fail_open
z1-operational: fail_open
z2-protected: fail_open
z2-continuity: fail_open
z3-critical: fail_closed
unknown: fail_open # versioned build profile (ADR-0009); explicit, never inferred
not-applicable: fail_closed
# What happens when the stance is applied. §6.4 obligation 1 requires a decision
# record for a protected side effect; where the engine is unreachable there is no
# decision to hold, so ops-warden records the APPLICATION OF THE STANCE instead.
# See the assessment note: obligation 1 as written admits no such case.
on_apply:
recorded_fields:
- policy_zone
- policy_failure_mode
- policy_decision_id # present only where a decision was actually rendered
- outcome
written_to:
- "signatures log (src/warden/ca.py)"
- "audit.jsonl (src/warden/audit.py)"
never_recorded: "any secret material, any certificate private key"
# §6.4 obligation 2 — the verdict is never cached. Input claims (zone membership,
# compiled from the flex-auth registry snapshot) are cached under their own
# freshness rules; the answer is not.
verdict_caching: none
input_claim_caching: "registry/flex-auth/production_registry_snapshot.json, rebuilt by scripts/build_flex_auth_registry.py"
# §6.4 obligation 4 — reconstructability, bounded by §9.6. ops-warden's audit
# emission on this lane is deliberately non-atomic and therefore ATTRIBUTIVE, not
# load-bearing: no control branches on the presence of a signing record
# (`warden activity` displays it; nothing gates on it). Registered in §13.
reconstructability:
bound: "§9.6 attributive — completeness is not claimed"
declared_at: wiki/AuditTrail.md

View file

@ -10,19 +10,21 @@
# declares it, and is null where the field set has not been established --
# null means unknown, never 'one field'.
generated_at: "2026-08-22T23:31:10Z"
generated_at: "2026-08-31T22:46:47Z"
source: ops-warden/registry/routing/catalog.yaml
catalog_revision: "0fae0904ce8d8694338dd53a8a79abec5fec788d"
catalog_revision_date: "2026-08-23T01:31:05+02:00"
catalog_revision: "4fee839b1138c60642bd6e0210cf8bf541333747"
catalog_revision_date: "2026-09-01T00:46:28+02:00"
catalog_dirty: false
high_risk_lane_count: 21
concrete_path_count: 14
high_risk_lane_count: 24
concrete_path_count: 15
# Graded high but not a single KV address -- a routing pattern, a broker
# grant, or a non-KV lane. Nothing here for a policy to deny.
no_concrete_path:
- database-dynamic-credentials
- inter-hub-bootstrap-ssh
- net-kingdom-lldap-bind-credential
- net-kingdom-privacyidea-admin-token
- object-storage-sts
- openbao-api-key
- openbao-platform-admin-login
@ -75,6 +77,11 @@ paths:
metadata_path: platform/metadata/workloads/activity-core/llm-connect/llm-connect-provider-secrets
owner_repo: railiance-platform
fields: null # field set not established -- unknown, not one
- id: policy-nexus-forgejo-source-read
data_path: platform/data/workloads/policy-nexus/forgejo-source-read
metadata_path: platform/metadata/workloads/policy-nexus/forgejo-source-read
owner_repo: railiance-platform
fields: null # field set not established -- unknown, not one
- id: railiance-backup-offsite-lane
data_path: platform/data/workloads/railiance/backup/offsite-lane
metadata_path: platform/metadata/workloads/railiance/backup/offsite-lane

View file

@ -242,6 +242,42 @@ entries:
- "Write it back: `bao kv put platform/workloads/coulomb/whynot-design/npm-publish NPM_AUTH_TOKEN=@file` (value from a mode-0600 file)."
- "Verify capabilities-safe, then confirm publish works via `secrets-engine exec --catalog whynot-design-npm-publish -- npm whoami` (value used, not printed)."
- id: policy-nexus-forgejo-source-read
title: Policy Nexus Forgejo private-source repository read token
# Read-only at Forgejo, but disclosure grants estate-wide private source access.
# Agent callers therefore remain inside Warden's sanctioned transport boundary.
risk: high
workload_ref:
applicability: applicable
unknown_reason: "policy-nexus-actions has not published an authoritative workload identity declaration."
need_keywords: [policy-nexus, policy, nexus, forgejo, private, source, repository, read, token, actions, FORGEJO_SOURCE_TOKEN]
owner_repo: railiance-platform
subsystem: OpenBao + Forgejo Actions
warden_executes: false
wiki_ref: wiki/playbooks/policy-nexus-forgejo-source-read.md#worker-checklist
canon_ref: railiance-platform/credential-change-requests/CCR-2026-0014-policy-nexus-forgejo-source-read.yaml
reviewed: "2026-09-01"
status: active
delegation:
mode: native
intended_owner: railiance-platform
reviewed: "2026-09-01"
verified: source-read
auth_method: "bao login -method=oidc -path=netkingdom role=policy-nexus-forgejo-source-workload-kv-read"
path_template: "platform/workloads/policy-nexus/forgejo-source-read"
fetch_command: "bao kv get -field=FORGEJO_SOURCE_TOKEN platform/workloads/policy-nexus/forgejo-source-read"
policy_ref: "flex-auth check secret.read:policy-nexus"
exec_capable: true
lane: secret
rotation:
method: rotate
owner: railiance-platform
automatable: false
steps:
- "Mint a replacement PAT for the restricted policy-nexus-source identity with scope exactly read:repository; retain the predecessor until verification passes."
- "Use the attended railiance-platform bootstrap to update OpenBao and the coulomb/policy-nexus FORGEJO_SOURCE_TOKEN Actions secret without exposing the value."
- "Pass one exact-commit candidate workflow, then revoke the predecessor PAT and record bounded non-secret evidence in CCR-2026-0014."
- id: flex-auth-policy-check
title: Authorization decision — may this actor perform this action
# Returns an authorization decision; no credential flows (WARDEN-WP-0032-T05).
@ -281,8 +317,8 @@ entries:
delegation:
mode: interim
intended_owner: key-cape
blocked_on: "REFUSED by secrets-engine 2026-08-21: login, MFA and identity-token issuance are key-cape/Keycloak's; secrets-engine may consume OIDC for OpenBao auth but does not own the login capability. ops-warden agrees — intended_owner corrected from secrets-engine to key-cape. Not yet asked of key-cape."
reviewed: "2026-08-21"
blocked_on: "REFUSED by secrets-engine 2026-08-21: login, MFA and identity-token issuance are key-cape/Keycloak's; secrets-engine may consume OIDC for OpenBao auth but does not own the login capability. ops-warden agrees — intended_owner corrected from secrets-engine to key-cape. Asked of key-cape 2026-08-28; KEY-WP-0009 accepting issuance ownership for machine identities is the precedent that makes it answerable."
reviewed: "2026-08-28"
verified: asked-and-waiting
# Login lane (WP-0014 T4) — interactive auth bootstrap, not a secret read. No
# secret-read gate (you have no identity yet) and no caller-auth precheck (the
@ -710,9 +746,9 @@ entries:
delegation:
mode: interim
intended_owner: key-cape
blocked_on: "client_secret_basic exchange is a key-cape protocol procedure, not a KV read; KEY-WP-0008 finished 2026-08-15 without a key-cape-native exchange/rotation command, and the workplan that would add one is not yet opened (key-cape acked interim 2026-08-15)"
reviewed: "2026-08-17"
verified: unverified
blocked_on: "client_secret_basic exchange is a key-cape protocol procedure, not a KV read; still no key-cape-native exchange/rotation command. Re-checked against key-cape source 2026-08-28: KEY-WP-0009 finished 2026-08-23 and did add bounded service-auth (per-client tokenLifetime, docs/openbao-service-auth-contract.md), but that is client_credentials JWT issuance for OpenBao machine login — it does not front this client_secret_basic exchange or its rotation. The server advertises client_secret_basic (src/internal/server/oidc/discovery.go) without exposing an owner command for it. Blocker stands."
reviewed: "2026-08-28"
verified: source-read
risk: high
workload_ref:
applicability: applicable

View file

@ -0,0 +1,164 @@
#!/usr/bin/env python3
"""Check ops-warden against the NetKingdom security layer model (§5, §11).
Read-only. Makes §11's second mechanical check real:
every direct Tooling client in a Staff repository maps to a declared
§5.1, §5.2, or §5.3 entry
The failure this catches is a *new* direct OpenBao contact appearing in
src/warden/ without an entry in layer.yaml an undeclared violation (§11),
which is a finding rather than a tracked gap. It deliberately does NOT check
the review dates: a date-triggered failure breaks the build on a calendar day
with no code change (the reasoning recorded in WARDEN-WP-0033-T05), so
staleness is reported and left to `--report`, never to CI.
Exit 0 clean, 1 undeclared contact found, 2 declaration malformed.
"""
from __future__ import annotations
import argparse
import re
import sys
from datetime import date
from pathlib import Path
import yaml
ROOT = Path(__file__).resolve().parents[1]
SRC = ROOT / "src" / "warden"
DECL = ROOT / "layer.yaml"
VALID_SHAPES = {"5.1", "5.2", "5.3"}
# A direct Tooling contact is an *invocation*, not a mention. Matching the word
# "bao" caught help text, a docstring, and the dev-tier doubles library that
# simulates bao rather than calling it — three false positives on first run.
# So match the two shapes that actually execute:
# 1. an HTTP request built against the OpenBao address
# 2. an argv list whose first element is the bao binary
TOOLING_PATTERNS = (
# httpx call whose URL is built from the configured OpenBao/Vault address
re.compile(r"""\bhttpx\.\w+\(|url\s*=\s*f?["'].*\{self\._cfg\.addr\}"""),
# argv construction: [bao_bin, ...] / ["bao", ...] / [bao_binary, ...]
re.compile(r"""\[\s*(?:["']bao["']|bao_bin\b|bao_binary\b)\s*,"""),
)
# httpx alone is not a Tooling contact — policy.py calls an Engine and worker.py
# calls the State Hub. A module matching only the httpx pattern counts as a
# contact only if it also references the OpenBao address configuration.
ADDR_HINT = re.compile(r"""_cfg\.addr|VAULT_ADDR|BAO_ADDR""")
# Modules that talk to an Engine or to something outside the §4 catalog. Listed
# in layer.yaml under non_tooling_clients and excluded from the scan with it.
def _excluded(decl: dict) -> set[str]:
return {e["module"].split("/")[-1] for e in decl.get("non_tooling_clients", [])}
def load_declaration() -> dict:
if not DECL.exists():
print(f"MISSING: {DECL} — ops-warden must declare in its own voice (§11)")
raise SystemExit(2)
decl = yaml.safe_load(DECL.read_text())
for key in ("layer", "repository", "standard_version", "tooling_contacts"):
if key not in decl:
print(f"MALFORMED: layer.yaml has no {key!r}")
raise SystemExit(2)
for c in decl["tooling_contacts"]:
if c.get("shape") not in VALID_SHAPES:
print(f"MALFORMED: {c.get('id')} has shape {c.get('shape')!r}, not one of {sorted(VALID_SHAPES)}")
raise SystemExit(2)
# §5.3 carries four fields, machine-readably. That is the whole point of
# the shape; a gap missing them is prose wearing a schema.
if c["shape"] == "5.3":
for field in ("capability", "intended_owner", "blocked_on", "review"):
if not c.get(field):
print(f"MALFORMED: §5.3 entry {c['id']!r} is missing {field!r}")
raise SystemExit(2)
# §5.2's test is the supplied-authority property.
if c["shape"] == "5.2" and c.get("supplied_authority") != "none":
print(f"MALFORMED: §5.2 conduit {c['id']!r} must declare supplied_authority: none")
raise SystemExit(2)
return decl
def scan_modules() -> dict[str, list[int]]:
"""Return {module_name: [line numbers]} for direct Tooling contacts."""
found: dict[str, list[int]] = {}
for path in sorted(SRC.rglob("*.py")):
if path.name.startswith("test_"):
continue
text = path.read_text()
hits: list[int] = []
for n, line in enumerate(text.splitlines(), 1):
stripped = line.strip()
if stripped.startswith("#") or stripped.startswith('"'):
continue
if any(p.search(line) for p in TOOLING_PATTERNS):
hits.append(n)
if hits:
# An httpx-only match needs the OpenBao address to be a Tooling
# contact; otherwise it is an Engine or non-catalogued call.
argv_shape = any(TOOLING_PATTERNS[1].search(ln) for ln in text.splitlines())
if argv_shape or ADDR_HINT.search(text):
found[path.name] = hits
return found
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--report", action="store_true", help="also print the declaration and gap review dates")
args = ap.parse_args()
decl = load_declaration()
declared = {c["module"].split("/")[-1] for c in decl["tooling_contacts"]}
excluded = _excluded(decl)
found = scan_modules()
undeclared = {m: lines for m, lines in found.items() if m not in declared and m not in excluded}
# A voluntary declaration has no fixed argv shape to detect (an
# operator-configured command). Over-declaring is safe; not reporting it as
# stale keeps the signal meaningful.
voluntary = {
c["module"].split("/")[-1]
for c in decl["tooling_contacts"]
if c.get("detection") == "voluntary"
}
stale_decls = declared - set(found) - voluntary
if args.report:
print(f"{decl['repository']} — layer: {decl['layer']} (model v{decl['standard_version']})")
print(f"declared by {decl['declared_by']}\n")
for c in decl["tooling_contacts"]:
line = f" §{c['shape']} {c['id']:<28} {c['module']}"
if c["shape"] == "5.3":
overdue = str(c["review"]) < date.today().isoformat()
line += f" -> {c['intended_owner']} review {c['review']}"
if overdue:
line += " [REVIEW OVERDUE]"
print(line)
gaps = [c for c in decl["tooling_contacts"] if c["shape"] == "5.3"]
print(f"\n{len(gaps)} declared gap(s) — tracked non-conformance, not conformance (§11).")
ok = True
if undeclared:
ok = False
print("\nUNDECLARED TOOLING CONTACT — a finding under §11, not a tracked gap:")
for m, lines in sorted(undeclared.items()):
print(f" src/warden/{m}: line(s) {', '.join(map(str, lines[:6]))}")
print("\nAdd a §5.1/§5.2/§5.3 entry to layer.yaml, or route it through an engine.")
if stale_decls:
print("\nNote: declared but no contact found (module removed or refactored?):")
for m in sorted(stale_decls):
print(f" {m}")
if ok and not args.report:
print(f"PASS — {len(found)} module(s) with Tooling contact, all declared.")
elif ok:
print("\nPASS — every direct Tooling contact maps to a declared shape.")
return 0 if ok else 1
if __name__ == "__main__":
sys.exit(main())

View file

@ -12,8 +12,9 @@ intact. Three guardrails are enforced here in code:
the tool with inherited stdout/stderr so the value never enters warden's memory;
sanctioned exec/file transports hold it only for their bounded handoff. The
high-risk attended-login lane is stricter: it captures every client byte inside
an isolated helper session, permits no output, self-revokes, and cleans up. Audit
records are metadata only.
an isolated helper session, never returns that output, requires successful
persistence to a private token helper, self-revokes, and cleans up. Audit records
are metadata only.
* **G3 policy gate before fetch.** The CLI runs ``check_fetch_policy`` before
calling anything here; this module refuses to run an unresolved command template.
@ -380,9 +381,11 @@ def proxy_attended_login_exec(
"""Run an attended login and one silent child inside a private helper home.
The default home is proven writable before the OIDC client starts. Login,
child, and revocation output are captured and discarded. Any non-empty output,
persistence defect, or non-zero result fails closed; any possibly issued token
is revoked before the isolated helper directory is removed.
child, and revocation output are captured and discarded. A successful login
may return client output only after the private helper has been populated;
persistence defects and non-zero results fail closed. The reviewed child must
remain silent. Any possibly issued token is revoked before the isolated helper
directory is removed.
"""
if not child_argv:
raise ProxyError(
@ -400,6 +403,10 @@ def proxy_attended_login_exec(
root, session, root_created = _prepare_attended_login_home()
helper = session / _TOKEN_HELPER_NAME
env = _caller_env()
if not env.get("WARDEN_CONFIG"):
caller_config = Path.home() / ".config" / "warden" / "warden.yaml"
if caller_config.is_file():
env["WARDEN_CONFIG"] = str(caller_config)
env["HOME"] = str(session)
env.pop("BAO_TOKEN", None)
env.pop("VAULT_TOKEN", None)
@ -428,7 +435,7 @@ def proxy_attended_login_exec(
except (OSError, ProxyError):
helper_valid = False
if login.returncode != 0 or login_output.strip() or not helper_valid:
if login.returncode != 0 or not helper_valid:
revoked = _revoke_contained(
resolved.argv[0], env=env, possible_output=login_output
)

View file

@ -0,0 +1,133 @@
"""Layer-model conformance (security-layer-model_v0.4 §5, §11).
Two things are checked here. §11 makes one of them mechanical: every direct
Tooling client maps to a declared shape. §5.2 asks for the other: the conduit's
supplied-authority property covered by a test.
Deliberately absent: any assertion on a §5.3 review date. A date-triggered
failure breaks the build on a calendar day with no code change, punishing
whoever commits next rather than whoever owns the gap the same reasoning
recorded in WARDEN-WP-0033-T05 for blocker staleness.
"""
from __future__ import annotations
import os
import subprocess
import sys
from pathlib import Path
import yaml
ROOT = Path(__file__).resolve().parents[1]
def _decl() -> dict:
return yaml.safe_load((ROOT / "layer.yaml").read_text())
class TestDeclaration:
def test_declares_staff_layer_in_its_own_voice(self):
d = _decl()
assert d["repository"] == "ops-warden"
assert d["layer"] == "staff"
# §11: "only the repository's own file, in its own voice, conforms."
assert d["declared_by"] == "docs/adr/ADR-0010"
def test_every_tooling_contact_maps_to_a_declared_shape(self):
"""§11 mechanical check — the guard against a new undeclared client."""
result = subprocess.run(
[sys.executable, str(ROOT / "scripts" / "check_layer_conformance.py")],
capture_output=True,
text=True,
)
assert result.returncode == 0, (
f"undeclared Tooling contact — a finding under §11, not a tracked gap:\n"
f"{result.stdout}{result.stderr}"
)
def test_declared_gaps_carry_all_four_fields(self):
"""§5.3 is machine-readable or it is prose wearing a schema."""
for c in _decl()["tooling_contacts"]:
if c["shape"] == "5.3":
for field in ("capability", "intended_owner", "blocked_on", "review"):
assert c.get(field), f"{c['id']} missing {field}"
def test_gaps_are_not_counted_as_conformance(self):
"""§11: a declared gap is tracked non-conformance. Keep that visible."""
text = (ROOT / "layer.yaml").read_text()
assert "TRACKED NON-CONFORMANCE" in text.upper()
class TestConduitSuppliesNoAuthority:
"""§5.2: 'MUST NOT present its own credential, MUST NOT widen what the
caller could already do.' The standard says this SHOULD be covered by a
test; this is that test."""
def test_conduit_supplies_no_authority_of_its_own(self, monkeypatch):
from warden import proxy
monkeypatch.setenv("VAULT_TOKEN", "caller-own-token")
monkeypatch.setenv("HOME", "/home/nobody")
before = dict(os.environ)
env = proxy._caller_env()
# The child environment IS the caller's environment — nothing added,
# nothing removed, no ops-warden credential injected.
assert env == before, (
"conduit altered the caller's environment; §5.2 requires it to "
"supply no authority of its own"
)
assert env["VAULT_TOKEN"] == "caller-own-token"
def test_conduit_declares_supplied_authority_none(self):
conduits = [c for c in _decl()["tooling_contacts"] if c["shape"] == "5.2"]
assert conduits, "no §5.2 conduit declared — proxy.py is one"
for c in conduits:
assert c["supplied_authority"] == "none"
def test_proxy_holds_no_credential_constant(self):
"""A conduit that presents its own token is not a conduit (§5.2)."""
src = (ROOT / "src" / "warden" / "proxy.py").read_text()
# It may name token ENV VARS to detect caller auth; it must not carry a
# token value or mint one.
for forbidden in ("X-Vault-Token", "auth/approle/login", "token create"):
assert forbidden not in src, (
f"proxy.py references {forbidden!r} — that is presenting or "
f"minting authority, not conducting the caller's"
)
class TestPepStanceMap:
"""§6.4: every PEP-shaped consumer MUST publish its unreachable-engine
stance map, total and per zone, 'published rather than held in code'.
ADR-0009 is named as the reference shape, so it should actually hold."""
def _stance(self) -> dict:
return yaml.safe_load((ROOT / "pep-stance.yaml").read_text())
def test_published_map_equals_shipped_behaviour(self):
"""The whole point. A published map that may drift from the code is
worse than none, because it invites reliance it cannot support."""
from warden.config import PolicyConfig
assert self._stance()["stance"] == PolicyConfig().failure_modes
def test_stance_is_total_over_the_zone_model(self):
"""§6.4 obligation 3: total, no implicit default."""
stance = self._stance()["stance"]
required = {
"z0-experimental", "z1-operational", "z2-protected",
"z2-continuity", "z3-critical", "unknown", "not-applicable",
}
assert required <= set(stance), f"stance not total; missing {required - set(stance)}"
assert set(stance.values()) <= {"fail_open", "fail_closed"}
def test_critical_zone_fails_closed(self):
"""ADR-0009's one non-negotiable row."""
assert self._stance()["stance"]["z3-critical"] == "fail_closed"
def test_verdict_is_never_cached(self):
"""§6.4 obligation 2: caching an input claim is permitted; caching the
answer is a second decision point deciding early (§6.1)."""
assert self._stance()["verdict_caching"] == "none"

View file

@ -391,6 +391,70 @@ def test_attended_login_unexpected_output_is_contained_revoked_and_cleaned(
assert not (tmp_path / ".warden-attended-login").exists()
def test_attended_login_contained_success_output_never_escapes(monkeypatch, tmp_path, capsys):
monkeypatch.setattr(Path, "home", lambda: tmp_path)
sentinel = "hvs.NONPRODUCTION_CONTAINED_LOGIN"
child_ran = False
def fake_run(argv, **kw):
nonlocal child_ran
helper = Path(kw["env"]["HOME"]) / ".vault-token"
if argv[:2] == ["bao", "login"]:
helper.write_text(sentinel)
helper.chmod(0o600)
return subprocess.CompletedProcess(
argv,
0,
stdout=json.dumps({"auth": {"client_token": sentinel}}).encode(),
stderr=b"",
)
if argv == ["reviewed-child"]:
child_ran = True
return subprocess.CompletedProcess(argv, 0, stdout=b"", stderr=b"")
if argv[:3] == ["bao", "token", "revoke"]:
return subprocess.CompletedProcess(argv, 0, stdout=b"", stderr=b"")
raise AssertionError(argv)
monkeypatch.setattr("warden.proxy.subprocess.run", fake_run)
assert proxy_attended_login_exec(
ResolvedFetch(argv=["bao", "login", "-no-print"]),
child_argv=["reviewed-child"],
) == 0
captured = capsys.readouterr()
assert child_ran is True
assert sentinel not in captured.out
assert sentinel not in captured.err
assert not (tmp_path / ".warden-attended-login").exists()
def test_attended_login_preserves_caller_warden_config_for_reviewed_child(
monkeypatch, tmp_path
):
monkeypatch.setattr(Path, "home", lambda: tmp_path)
monkeypatch.delenv("WARDEN_CONFIG", raising=False)
caller_config = tmp_path / ".config" / "warden" / "warden.yaml"
caller_config.parent.mkdir(parents=True)
caller_config.write_text("backend: local\n")
seen_config = None
def fake_run(argv, **kw):
nonlocal seen_config
helper = Path(kw["env"]["HOME"]) / ".vault-token"
if argv[:2] == ["bao", "login"]:
helper.write_text("non-production-test-double")
helper.chmod(0o600)
if argv == ["reviewed-child"]:
seen_config = kw["env"].get("WARDEN_CONFIG")
return subprocess.CompletedProcess(argv, 0, stdout=b"", stderr=b"")
monkeypatch.setattr("warden.proxy.subprocess.run", fake_run)
assert proxy_attended_login_exec(
ResolvedFetch(argv=["bao", "login", "-no-print"]),
child_argv=["reviewed-child"],
) == 0
assert seen_config == str(caller_config)
def test_real_catalog_login_entry_is_login_lane():
from warden.routing import load_catalog
e = load_catalog(_repo_catalog()).get("key-cape-oidc-login")

View file

@ -153,6 +153,32 @@ def test_whynot_design_npm_lane_is_concrete_and_resolvable():
assert "platform/workloads/coulomb/whynot-design/npm-publish" in e.fetch_command
def test_policy_nexus_source_read_lane_is_exact_high_risk_and_resolvable():
catalog = load_catalog(_repo_catalog())
entry = catalog.get("policy-nexus-forgejo-source-read")
assert entry is not None and entry.is_active and entry.exec_capable
assert entry.resolvable is True
assert entry.risk == "high"
assert entry.owner_repo == "railiance-platform"
assert entry.fetch_command == (
"bao kv get -field=FORGEJO_SOURCE_TOKEN "
"platform/workloads/policy-nexus/forgejo-source-read"
)
assert entry.path_template == "platform/workloads/policy-nexus/forgejo-source-read"
assert entry.auth_method.endswith(
"role=policy-nexus-forgejo-source-workload-kv-read"
)
assert entry.delegation is not None and entry.delegation.mode == "native"
def test_route_find_policy_nexus_source_read_prefers_concrete_lane():
catalog = load_catalog(_repo_catalog())
matches = catalog.find(
"policy nexus Forgejo private source repository read token Actions", limit=1
)
assert matches[0].id == "policy-nexus-forgejo-source-read"
def test_generic_and_template_lanes_not_resolvable():
catalog = load_catalog(_repo_catalog())
# generic openbao lane has <FIELD>/<path_template>; login lane has <domain>.

View file

@ -13,8 +13,10 @@ def test_repo_catalog_uses_only_explicit_workload_references():
report = build(ROOT / "registry/routing/catalog.yaml", Path.home())
assert report["ok"] is True
assert len(report["resolved"]) == 3
assert len(report["unknown"]) == 17
assert len(report["not_applicable"]) == 9
assert len(report["unknown"]) == 18
# 11 since WARDEN-WP-0033: the two NetKingdom SSO lanes (c374d41) are
# provider/control-plane credentials, not workload delivery lanes.
assert len(report["not_applicable"]) == 11
assert {row["lane"] for row in report["resolved"]} == {
"ops-warden-warden-sign-token",
"issue-core-ingestion-api-key",

View file

@ -32,6 +32,20 @@ fresh file starts.
high-entropy runs). Signing and proxy paths swallow audit failures so gatekeeping
never blocks the primary action — but tests prove values cannot be written.
> **Absence of a record is not evidence of absence.** Because emission never
> blocks the primary action (`src/warden/ca.py`), a failed append loses the event
> while the action still happens. This trail proves that the records it holds were
> not altered or truncated; it does **not** prove that every action produced one.
> Do not reason from a missing entry. This is the estate-wide bound in
> `security-layer-model_v0.4` §9.6 — completeness is the source's obligation, and
> **Ruled 2026-08-29** (`security-layer-model_v0.6` §9.6): this trail is
> **attributive**, not load-bearing — no control branches on the presence of a
> signing record — so the non-atomic trade is legitimate, and the obligations are
> to declare it (this note) and never to claim completeness. Atomicity is required
> only where a control's soundness depends on an event being present or absent.
> Registered in the standard's §13 open-gap table as self-declared. If a future
> control ever gates on this trail, the trade must be revisited before it ships.
---
## Query

View file

@ -0,0 +1,55 @@
# Policy Nexus Forgejo source-read token
Date: 2026-09-01
Catalog: `policy-nexus-forgejo-source-read` (status `active`, `resolvable: true`)
Owner: `railiance-platform` (OpenBao and credential lifecycle)
This lane carries the dedicated Forgejo PAT used by Policy Nexus Actions to
fetch exact archives from private owner repositories. The Forgejo identity is
restricted to organization-wide repository-code read and the PAT scope is
exactly `read:repository`. It has no repository write, package, organization
administration, instance administration, cluster, or deployment authority.
The authoritative lifecycle and evidence record is
`railiance-platform/credential-change-requests/CCR-2026-0014-policy-nexus-forgejo-source-read.yaml`.
Warden is a governed conduit and never owns, persists, caches, or logs the PAT.
## Owner-confirmed lane
| Field | Value |
| --- | --- |
| OpenBao path | `platform/workloads/policy-nexus/forgejo-source-read` |
| Primary field | `FORGEJO_SOURCE_TOKEN` |
| Read policy | `workload-kv-read-policy-nexus-forgejo-source` |
| OIDC role | `policy-nexus-forgejo-source-workload-kv-read` |
| Forgejo identity | `policy-nexus-source` |
| Forgejo team | `policy-nexus-source-readers` |
| Actions consumer | `coulomb/policy-nexus` secret `FORGEJO_SOURCE_TOKEN` |
## Worker checklist
1. Authenticate as an approved operator through the exact OIDC role. Do not
substitute the Forgejo admin PAT or a broader OpenBao identity.
2. Confirm the route before use:
```bash
warden route show policy-nexus-forgejo-source-read --json | jq .resolvable
```
The result must be `true`, and the rendered fetch must contain no placeholder.
3. Agent callers must use a sanctioned high-risk transport. Pass the value only
to the bounded source-consuming child:
```bash
warden access policy-nexus-forgejo-source-read \
--field FORGEJO_SOURCE_TOKEN --exec -- <reviewed-source-read-command>
```
Do not use raw `--fetch`, place the value on argv, or write it to chat, Git,
State Hub, workflow logs, or a persistent temporary file.
4. For rotation or compromise, follow CCR-2026-0014. A replacement is not active
until its scope and negative permissions are verified and one exact-commit
Policy Nexus candidate workflow succeeds; revoke the predecessor afterward.

View file

@ -1,5 +1,5 @@
---
id: ADHOC-2026-06-27
id: WARDEN-WP-ADHOC-2026-06-27
type: workplan
title: "Ad Hoc Tasks — 2026-06-27"
domain: infotech
@ -9,7 +9,7 @@ owner: claude
topic_slug: custodian
created: "2026-06-27"
updated: "2026-06-27"
state_hub_workstream_id: "142b171b-c34b-4a45-91a5-c77e6d07ec6f"
state_hub_workstream_id: "a222c91f-3bb5-58a4-b6b2-f0fb18cdd5c3"
---
# Ad Hoc Tasks — 2026-06-27
@ -19,10 +19,10 @@ Low-risk opportunistic fixes completed directly during the consolidation session
### T01 — Fix stale `warden` CLI install + make it usable outside the repo
```task
id: ADHOC-2026-06-27-T01
id: WARDEN-WP-ADHOC-2026-06-27-T01
status: done
priority: medium
state_hub_task_id: "867c72c9-9904-400f-8542-04264e5856c2"
state_hub_task_id: "9176b560-8ca5-5143-888d-479857fe60f0"
```
issue-core reported (msg `70bcf238`) that the `warden` CLI on `~/.local/bin` lacked

View file

@ -1,5 +1,5 @@
---
id: ADHOC-2026-06-29
id: WARDEN-WP-ADHOC-2026-06-29
type: workplan
title: "Ad Hoc Tasks — 2026-06-29"
domain: infotech
@ -9,7 +9,7 @@ owner: claude
topic_slug: custodian
created: "2026-06-29"
updated: "2026-06-29"
state_hub_workstream_id: "1c0460b7-bc8a-48db-96d4-681bce18ac91"
state_hub_workstream_id: "13fa845f-852e-55ec-a2a5-2296996e0216"
---
# Ad Hoc Tasks — 2026-06-29
@ -17,10 +17,10 @@ state_hub_workstream_id: "1c0460b7-bc8a-48db-96d4-681bce18ac91"
### T01 — Joint-smoke mode for the deployed flex-auth (assist FLEX-WP-0007 T4)
```task
id: ADHOC-2026-06-29-T01
id: WARDEN-WP-ADHOC-2026-06-29-T01
status: done
priority: medium
state_hub_task_id: "371235cc-b9d3-4103-b09f-e4e01cc83c5b"
state_hub_task_id: "62540533-f4ca-5176-9237-32adbeb292ee"
```
flex-auth (msg `ea00620b`) asked ops-warden to help close FLEX-WP-0007 T4 (joint OpenBao

View file

@ -1,5 +1,5 @@
---
id: ADHOC-2026-08-11
id: WARDEN-WP-ADHOC-2026-08-11
type: workplan
title: "Ad Hoc Tasks — 2026-08-11"
domain: infotech
@ -9,7 +9,7 @@ owner: claude
topic_slug: custodian
created: "2026-08-11"
updated: "2026-08-15"
state_hub_workstream_id: "bc6dd3e3-ab2b-567a-9574-30d2650f20a2"
state_hub_workstream_id: "9f99cc64-4682-5f20-b13e-89af2b6f7c70"
---
# Ad Hoc Tasks — 2026-08-11
@ -17,10 +17,10 @@ state_hub_workstream_id: "bc6dd3e3-ab2b-567a-9574-30d2650f20a2"
### T01 — Repair stale `rapp-qonto-keycape-client` wiki anchor (restore green routing suite)
```task
id: ADHOC-2026-08-11-T01
id: WARDEN-WP-ADHOC-2026-08-11-T01
status: done
priority: medium
state_hub_task_id: "ddd0c95c-1196-5251-a4ca-6ef441c2f377"
state_hub_task_id: "0771d121-278c-556e-9509-841cf6e657c3"
```
rapp-postgres (msg `96907986`, residual from RAPP-POSTGRES-WP-0002-T04) reported the
@ -39,10 +39,10 @@ an anchor that does not exist. The intended heading is `## Routing catalog index
### T02 — Triage the stale ops-warden inbox (11 unread, C-28/C-29)
```task
id: ADHOC-2026-08-11-T02
id: WARDEN-WP-ADHOC-2026-08-11-T02
status: done
priority: medium
state_hub_task_id: "fda35ad4-f526-5012-a2be-ef6b5dcbc8af"
state_hub_task_id: "0ed58145-732f-5102-b6a8-b931d9b6ba08"
```
`fix-consistency` flagged 11 unread messages older than 3 days, two of them as possible
@ -73,10 +73,10 @@ read. Inbox is now empty.
### T03 — warden-sign AppRole: PARKED pending WP-0027 break-glass + ops-bridge cutover
```task
id: ADHOC-2026-08-11-T03
id: WARDEN-WP-ADHOC-2026-08-11-T03
status: done
priority: medium
state_hub_task_id: "7ef4b6b0-26bf-5456-8429-8cf8458c2ddc"
state_hub_task_id: "337ae793-c6b0-59e9-8a07-3a7ccba237aa"
```
secrets-engine (msg `80456912`, 2026-06-29) is holding a validated non-mutating dry-run

View file

@ -1,5 +1,5 @@
---
id: ADHOC-2026-08-17
id: WARDEN-WP-ADHOC-2026-08-17
type: workplan
title: "Ad Hoc Tasks — 2026-08-17"
domain: infotech
@ -9,7 +9,7 @@ owner: claude
topic_slug: custodian
created: "2026-08-17"
updated: "2026-08-17"
state_hub_workstream_id: "8376eb89-36f2-52b0-a59a-2954b2e49349"
state_hub_workstream_id: "5c6c2bbb-b944-5afd-b89c-20d865518849"
---
# Ad Hoc Tasks — 2026-08-17
@ -21,10 +21,10 @@ workload-identity owner.
### T01 — Answer flex-auth: how should `/v1/check` authenticate its callers?
```task
id: ADHOC-2026-08-17-T01
id: WARDEN-WP-ADHOC-2026-08-17-T01
status: done
priority: high
state_hub_task_id: "b980d1f7-2fcc-58dd-97d8-6e9b9ba57bc9"
state_hub_task_id: "04a2f8f9-e70b-5eed-ad87-343c8f9ef501"
```
flex-auth (msg `130a148c`, FLEX-WP-0015 T02) reported that `POST /v1/check` and
@ -69,10 +69,10 @@ Their four questions answered in `wiki/NetKingdomSecurityMap.md`
### T02 — user-engine: USER_ENGINE_PROXY_SECRET stays railiance-apps; record consumer-only
```task
id: ADHOC-2026-08-17-T02
id: WARDEN-WP-ADHOC-2026-08-17-T02
status: done
priority: medium
state_hub_task_id: "e76b9b3e-189b-5a4f-8815-4ccf2057507c"
state_hub_task_id: "0e815282-2fad-5c8d-be34-398e492737d0"
```
user-engine (msg `2af4a124`) answered the open confirm question on
@ -95,10 +95,10 @@ consumes it and has no authority over custody, rotation, or issuance.
### T03 — key-cape: `rapp-qonto-keycape-client` interim accepted; refresh the blocker
```task
id: ADHOC-2026-08-17-T03
id: WARDEN-WP-ADHOC-2026-08-17-T03
status: done
priority: medium
state_hub_task_id: "edfb0626-5022-5f49-aaf9-08e0d1002b90"
state_hub_task_id: "e21781d9-a35d-5916-b335-d12131f97a22"
```
key-cape (msg `099b7cba`) acknowledged the lane staying interim on ops-warden.
@ -118,10 +118,10 @@ workplan.
### T04 — Session hygiene
```task
id: ADHOC-2026-08-17-T04
id: WARDEN-WP-ADHOC-2026-08-17-T04
status: done
priority: low
state_hub_task_id: "62109af6-f095-5e7b-9258-0fcec29d30e8"
state_hub_task_id: "b15724e0-c27a-5260-a810-4dd25bff2228"
```
- [x] `uv run pytest -q` → 338 passed, 4 deselected (routing anchor + no-double-source

View file

@ -222,6 +222,39 @@ test results, and infra acceptance. T02 remains `progress` until
that owner gate is open; acceptance will permit preparation of a new scenario,
not execution or reuse of the terminal one.
**Owner gate CLOSED — accepted 2026-08-23, found 2026-08-28.**
`railiance-platform` accepted the exact revision `0fae0904`. Recorded in their
`RPF-WP-0017-attended-login-output-containment.md` (`status: finished`), which
also records railiance-infra's independent approval at `186b030` and marks all
five acceptance criteria met. The receipt digest was verified here rather than
taken on trust: `docs/evidence/RAILIANCE-WP-0026-T01-ops-warden-receipt.json` at
ops-warden `bc1966da` hashes to
`d2ba444ed16989590325697e69d25283dc75a9432c29a72e627e80bf9fd987e4`, matching
their record exactly.
Note the identifier: the remediation interface recorded above as
`RAILIANCE-WP-0026-T01` is `RPF-WP-0017-T01` in the owner's repo. Searching for
the cited id finds an unrelated workplan, which is part of why this sat unnoticed.
**Their acceptance is source acceptance only and authorizes no live OIDC or
drill** — their words, and the boundary holds. So T02's state changes but its
`Done when` does not: what was blocked was *preparing a new scenario*, and that
is now permitted. The terminal NO-GO scenario and its receipts remain unusable.
**Third instance of the same failure this session.** The acceptance existed for
five days; no message reached ops-warden. Identically, `key-cape` accepted the
WP-0033-T04 question on 2026-08-23 with no message, and nine unread messages
were sitting on already-superseded threads. The `verified:` field added by
WP-0033-T05 was built for exactly this and it works — what does not work is
waiting for a counterparty to tell you. Re-checking a blocker means reading the
owner's repository.
**Remaining to close T02:** one attended production emergency seal/unseal drill,
requiring a new scenario id, fresh owner receipts from platform/infra/master, a
fully parameterized green preflight, and a new human GO. It is executed by the
platform owner, never by a coding agent. That is an operator decision, not an
agent one, so T02 stays `progress` and the decision is surfaced rather than taken.
## Task: Tamper-evident policy governance + reconcile
```task

View file

@ -4,14 +4,14 @@ type: workplan
title: "Native lane handoff — review secrets-engine's catalog admission, and fix what it exposed"
domain: infotech
repo: ops-warden
status: active
status: finished
owner: ops-warden
topic_slug: netkingdom
planning_priority: P1
depends_on_workplans:
- WARDEN-WP-0030
created: "2026-08-21"
updated: "2026-08-23"
updated: "2026-08-28"
state_hub_workstream_id: "4627d89b-4b00-562a-81e9-76e96f90fa7e"
---
@ -160,7 +160,7 @@ railiance-platform may deny more, deny less, or dispute a grade (`ADR-0002`).
```task
id: WARDEN-WP-0033-T04
status: wait
status: done
priority: medium
state_hub_task_id: "5acac140-a586-5db3-b231-bbf236710786"
```
@ -212,6 +212,33 @@ accept that target identity with an authoritative workplan/interface, or refuse
and name the actual owner. T04 remains `wait` until one of those two answers is
recorded; the live AppRole is operational evidence, not an ownership answer.
**Answered — accepted. Closed 2026-08-28.** `key-cape` accepted issuance
ownership in `KEY-WP-0009-T03` (`status: done`, 2026-08-23): the non-secret static
registration `codex-railiance-platform` is published in
`key-cape/config/service-clients.example.yaml` — subject
`service:codex:railiance-platform`, tenant `tenant:coulomb`, role `coding-agent`,
scope `openbao:login`, `client_credentials`, 15-minute lifetime — with the
service-auth claims, renewal, expiry and failure semantics in
`key-cape/docs/openbao-service-auth-contract.md` (`T02`). The split is exactly the
one the routing asked for: KeyCape owns JWT issuance and client disablement,
railiance-platform owns the exact-bound OpenBao role and policy, OpenBao owns
enforcement, and no secret value enters either repository.
**The answer was found by reading their repo, not by receiving it.**
`KEY-WP-0009-T04` records replying to ops-warden; no such message exists in the
ops-warden inbox — 0 messages from `key-cape`, read or unread. The acceptance had
been sitting done for five days while this task sat `wait` on it.
That is the T05 lesson landing on T04: a blocker is a claim about the world at a
date, and this one had stopped being true. `verified: source-read` is doing real
work here — it is the difference between "we asked" and "we checked". The
mechanism is right; what it needs is for someone to run it, which is why the
lanes below were re-verified in the same pass rather than date-bumped.
Consequence for `ADR-0004`: the honour-system `WARDEN_AGENT_ID` marker now has a
real issuance identity behind it on the OpenBao side. ops-warden remains a
consumer of that identity and does not own it.
```task
id: WARDEN-WP-0033-T05
status: done

View file

@ -0,0 +1,171 @@
---
id: WARDEN-WP-0034
type: workplan
title: "Layer model v0.7 conformance — state the deadline, bind the agent boundary, steward the estate's newest rule"
domain: infotech
repo: ops-warden
status: ready
owner: ops-warden
topic_slug: netkingdom
planning_priority: P1
depends_on_workplans:
- WARDEN-WP-0030
created: "2026-08-29"
updated: "2026-08-29"
state_hub_workstream_id: "ae3ff76f-883d-5e2f-b6aa-144d61e8fdef"
---
# WARDEN-WP-0034 — Layer model v0.7 conformance
`security-layer-model_v0.7` is **accepted**. ops-warden declared Staff and PEP-shaped,
shipped the two declaration artifacts the standard now cites as estate reference forms,
and had four findings adopted into the text between v0.4 and v0.7.
The assessment in `history/2026-08-29-v07-scope-intent-assessment.md` checked every
v0.7 obligation against shipped code rather than intent. Three gaps survive, plus a
role the companion assigns that no conformance check will ever catch.
## Why a workplan and not an adhoc
T01 is a `MUST` that is currently unstated. T02 changes an enforcement boundary and
touches `ADR-0004`. T04 is a cross-repo stewardship commitment against a standard eight
repositories have yet to adopt. The convention reserves adhocs for low-risk work
completed directly; none of these qualify.
## Tasks
```task
id: WARDEN-WP-0034-T01
status: todo
priority: high
state_hub_task_id: "8b3bdb9f-d2c2-5b3e-89e2-417bf3e37484"
```
**State the revocation visibility deadline (§9.7.2, a MUST).**
ops-warden states none, and the honest value is the certificate TTL: **up to 48 hours**.
A cert issued under an allow remains valid for its full TTL even if the authorizing
decision is revoked the next minute. There is no CRL, no KRL distribution, and host-side
`auth_principals` belongs to `railiance-infra`.
Add the deadline to `pep-stance.yaml` as what it is — `adm` 48h / `agt` 24h / `atm` 8h —
with the mechanism named (TTL expiry, no revocation channel) rather than implied. Assert
it against the shipped `ActorType` TTL policy by test, the same way the stance map is
asserted equal to shipped behaviour: a stated deadline free to drift from the code has
the same defect as a stated stance free to drift.
**Done when:** the deadline is published, test-bound to the TTL policy, and the absence
of a revocation channel is stated rather than left to inference.
**Not in scope:** shortening it. Whether 48h is acceptable is a joint question with
`railiance-infra` (KRL distribution) and is T05's to raise, not this task's to decide.
```task
id: WARDEN-WP-0034-T02
status: todo
priority: high
state_hub_task_id: "3318ee1a-b5d9-5d39-baf7-9c42a8bc7b55"
```
**Bind the agent read-boundary to an issued identity (§3.4 rule 1).**
`ADR-0004`'s boundary triggers on `WARDEN_AGENT_ID` — a variable the agent sets about
itself. An agent that omits it is not recognised as one. §3.4 rule 1 now requires
authority to be *issued* per task and attributable to the principal acted for.
The identity exists as of `KEY-WP-0009-T03`: `codex-railiance-platform`, subject
`service:codex:railiance-platform`, role `coding-agent`, 15-minute lifetime, with
`railiance-platform` enforcing the OpenBao-side policy.
Key the boundary on the issued identity where one is present; keep `WARDEN_AGENT_ID` as
a fallback that fails **toward** the boundary, never away from it. State plainly in the
ADR trail which half is enforced and which is advisory: the OpenBao-side deny is real,
the ops-warden-side refusal is a courtesy that a determined caller can decline.
**Done when:** an agent presenting the issued identity is recognised without setting
`WARDEN_AGENT_ID`, the fallback still refuses on `risk: high` lanes, and the
enforced/advisory split is written down.
**Watch:** do not turn this into ops-warden validating a token — that is verifying an
identity claim, adjacent to deciding, and `ADR-0002`/§6 both point away from it. Read
the identity; do not adjudicate it.
```task
id: WARDEN-WP-0034-T03
status: todo
priority: medium
state_hub_task_id: "a891b32c-b0a7-59f6-a5cd-977be65c09ca"
```
**Derive an emission cadence, or defer it with a reason (§9.6).**
ops-warden's trail is attributive, so cadence is a SHOULD rather than v0.7's MUST for
load-bearing sources. It has been silent through two reviews, which is the one outcome
that is not defensible.
Derive a baseline from the existing `audit.jsonl` and signatures log. If the signal is
too bursty to support a threshold — plausible, since volume is operator-driven — record
that as the finding with the distribution that shows it, and declare the deferral in
`pep-stance.yaml`. A measured "no useful baseline" is a result; silence is not.
**Done when:** either a declared cadence with its derivation, or a declared deferral
carrying the data that justifies it.
```task
id: WARDEN-WP-0034-T04
status: todo
priority: medium
state_hub_task_id: "94e73daa-f74d-51fd-8639-68896a4066ee"
```
**Answer the question the companion sends the estate here to ask.**
> *"For how to get something done — which lane, which credential, which route — ask
> `ops-warden`."*
Today the repo answers credential questions and no others. `warden route` and
`warden plan` cover lanes, owners and acts. Nothing answers *"which layer am I"*, *"how
do I declare"*, *"I am PEP-shaped, what do I owe"* — and eight of fifteen catalogued
repositories have yet to declare.
Provide the path, not the doctrine (that boundary is `ADR-0010`'s and does not move):
a routing entry and a short playbook that carry a reader from the companion to the files
to copy — `layer.yaml`, `pep-stance.yaml`, `check_layer_conformance.py`,
`test_layer_conformance.py` — and the check to run. The standard already names these in
§11 and §6.4; what is missing is the route to them.
**Done when:** `warden route find "how do I declare my layer"` resolves, and the
playbook is reachable from the catalog. **Not** a restatement of the companion — a
pointer layer, per `ADR-0001`.
```task
id: WARDEN-WP-0034-T05
status: todo
priority: low
state_hub_task_id: "7d1b3c82-9b96-5087-a53a-496212909029"
```
**Two things to raise rather than absorb.**
Both are other repositories' to own; ops-warden's obligation is to route them, not to
fix them (`ADR-0003`, `ADR-0005`).
1. **`ops-mason` has published no stance map.** §13.1's register has one row and the
standard says that is itself the finding. `ops-mason` is catalogued PEP-shaped in
the same paragraph and is ops-warden's peer lane owner. Offer the reference form;
do not write their map.
2. **The 48-hour replay window from T01.** Once stated, raise with `railiance-infra`
whether KRL distribution is worth building, and with `access-engine` whether a
decision lifetime shorter than the cert TTL is meaningful when nothing can recall
the cert. State the question; let the owners answer.
**Done when:** both are routed with reasoning, and the answers recorded either way —
including a refusal, which is an equally good answer.
## Related
- `history/2026-08-29-v07-scope-intent-assessment.md` — the gap analysis behind this plan
- `history/2026-08-29-layer-model-v04-review.md`, `-v06-review.md` — the two prior reviews
- `security-layer-model_v0.7.md` §3.4, §6.4, §9.6, §9.7, §11, §13.1
- `net-kingdom/SECURITY-COMPANION.md` v0.2
- `ADR-0002`, `ADR-0003`, `ADR-0004`, `ADR-0005`, `ADR-0009`, `ADR-0010`

View file

@ -0,0 +1,46 @@
---
id: WARDEN-WP-0035
type: workplan
title: "Register the Policy Nexus Forgejo source-read route"
domain: infotech
repo: ops-warden
status: finished
owner: codex
topic_slug: policy-nexus-forgejo-source-read
created: "2026-09-01"
updated: "2026-09-01"
state_hub_workstream_id: "45aec8d3-94b3-586e-b019-a47e656efafa"
---
## Register the exact high-risk lane
```task
id: WARDEN-WP-0035-T01
status: done
priority: high
state_hub_task_id: "dd84f2be-0143-540c-9c16-74f0fd129260"
```
Add the exact OpenBao path, field, OIDC role, owner pointer, and rotation
boundary from railiance-platform CCR-2026-0014. The entry must be concrete and
resolvable while remaining subject to Warden's high-risk agent read boundary.
## Verify routing and governed use
```task
id: WARDEN-WP-0035-T02
status: done
priority: high
state_hub_task_id: "1fa8f778-3e46-5f44-86c4-cab8628b7e60"
```
Pass catalog, route-selection, proxy, and policy tests; reinstall the CLI; prove
the installed route resolves and can hand the value only to a sanctioned child
transport without printing or persisting it.
Completed 2026-09-01. All 406 selected tests passed, including the generated
high-risk data-path boundary. The no-cache installed CLI resolves the exact
lane, and `warden plan` returns only sanctioned `--exec`, `--out`, and `--wrap`
transports for an agent caller. Policy Nexus Actions run 32 separately proved
the installed credential against the complete private-source fetch and release
path without exposing the value.

View file

@ -0,0 +1,43 @@
---
id: WARDEN-WP-0036
type: workplan
title: "Accept contained OpenBao login output only after helper persistence"
domain: infotech
repo: ops-warden
status: finished
owner: codex
topic_slug: attended-login-openbao-output
created: "2026-09-01"
updated: "2026-09-01"
state_hub_workstream_id: "d844c96e-152d-53fa-bff6-e072125ef66c"
---
## Repair attended-login handoff
```task
id: WARDEN-WP-0036-T01
status: done
priority: high
state_hub_task_id: "7eb8b9c9-1285-5ada-a17b-1d5bfbb8ba59"
```
Allow a successful OpenBao login to proceed when its output is fully contained
and the private mode-0600 token helper is populated. Continue failing closed on
non-zero login, missing persistence, child output, revocation failure, or cleanup
failure.
## Verify live contained operation
```task
id: WARDEN-WP-0036-T02
status: done
priority: high
state_hub_task_id: "d22bab05-c38b-561f-95de-6c146ce7c6cf"
```
Run the proxy regression suite, reinstall the CLI, and complete one governed
OpenBao platform-admin operation with deterministic self-revocation.
Completed 2026-09-01. The installed CLI completed the governed Policy Nexus
Forgejo source bootstrap with all child output contained, then revoked and
removed its isolated helper session.

View file

@ -1,5 +1,5 @@
---
id: ADHOC-2026-07-07
id: WARDEN-WP-ADHOC-2026-07-07
type: workplan
title: "Ad Hoc Tasks — 2026-07-07"
domain: infotech
@ -9,7 +9,7 @@ owner: grok
topic_slug: custodian
created: "2026-07-07"
updated: "2026-07-07"
state_hub_workstream_id: "2e8bc783-2e37-4b86-a691-177b18329783"
state_hub_workstream_id: "90568b1e-8395-5c67-9c69-851ed08ff3d3"
---
> **Terminology note:** Historical text in this archived workplan may use the legacy term "workstream". The fleet term is **workplan** (`canon/standards/workplan-terminology-fleet_v0.1.md`).
@ -19,10 +19,10 @@ state_hub_workstream_id: "2e8bc783-2e37-4b86-a691-177b18329783"
### T01 — Roll out proxy pipe fix (be3b4a2)
```task
id: ADHOC-2026-07-07-T01
id: WARDEN-WP-ADHOC-2026-07-07-T01
status: done
priority: high
state_hub_task_id: "55b6de52-b958-4b72-94eb-4ba1b8da2629"
state_hub_task_id: "bf985c95-bea6-5057-94f9-9cfa7e1c9dd8"
```
`warden access` failed on `reuse-surface-hub-write-token` because `shlex.split`