ops-warden/workplans/WARDEN-WP-0033-native-lane-handoff.md
tegwick 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

344 lines
17 KiB
Markdown

---
id: WARDEN-WP-0033
type: workplan
title: "Native lane handoff — review secrets-engine's catalog admission, and fix what it exposed"
domain: infotech
repo: ops-warden
status: finished
owner: ops-warden
topic_slug: netkingdom
planning_priority: P1
depends_on_workplans:
- WARDEN-WP-0030
created: "2026-08-21"
updated: "2026-08-28"
state_hub_workstream_id: "4627d89b-4b00-562a-81e9-76e96f90fa7e"
---
# WARDEN-WP-0033 — Native lane handoff
On 2026-08-20 `secrets-engine` accepted five of ops-warden's seven interim
proxy lanes for catalog admission (`SECRETS-WP-0006`, decision
`ae676382-1826-4e04-aa4e-bb77990c7a0d`), rejected two with reasons ops-warden
agrees with, drafted the five entries itself rather than waiting for the offered
contribution, and asked for a line-by-line review of the non-secret metadata.
In the same hour `railiance-platform` closed the `RISK-F-0009` coverage gap and
asked ops-warden for two things back.
This workplan is the response to both, plus the defect the review turned up in
ops-warden's own grading model — which is the most consequential item here and
would not have been found without the second pair of eyes.
## Why a workplan and not an adhoc
Four counterparties are waiting, one deliverable is a **cross-repo interface**
another repo will consume on a schedule, and the review carries approval
semantics — `secrets-engine` holds interim proxy ownership open until each lane
has approved native verification. The convention reserves adhocs for low-risk
work completed directly; this is none of those.
## Tasks
```task
id: WARDEN-WP-0033-T01
status: done
priority: high
state_hub_task_id: "154f2f03-387d-5fe6-a0f5-1929c46a2bd8"
```
**Review the five drafted catalog entries and reply.**
`issue-core-ingestion-api-key`, `reuse-surface-hub-write-token`,
`openrouter-llm-connect`, `forgejo-admin-api-token`,
`email-connect-transactional` at `secrets-engine@784be97`.
Review the axes they asked for: owner-repo coordinates, field grouping, workload
consumers, rotation/deactivation owners, delivery intent. Verify claims against
the authoritative `railiance-platform` CCRs — **never against a secret read**;
`bao kv get` on any of these paths is the 2026-07-16 vector and three of the five
are `risk: high`.
Accept their two rejections. `openbao-api-key` is a routing template rather than
one lane and `key-cape-oidc-login` belongs to key-cape — that is `ADR-0005`
applied to ops-warden by someone else, correctly.
```task
id: WARDEN-WP-0033-T02
status: done
priority: high
state_hub_task_id: "6996d07f-63bb-5708-a171-68c4b1bbddde"
```
**Correct ops-warden's per-path risk grading — the defect T01 exposed.**
`secrets-engine` graded `issue-core-ingestion-api-key` **high**; ops-warden grades
it **standard**, and deliberately: WP-0032-T05 regraded it *down* on 2026-08-19,
operator-sanctioned, because `test_high_risk_lanes_classified` asserted standard
and was judged right — "ordinary internal workload secrets are standard".
That reasoning was incomplete, and CCR-2026-0002 says so explicitly: the path
carries **both** `ISSUE_CORE_API_KEY` **and** `GITEA_BACKEND_TOKEN`, a Forgejo
backend token, and the CCR records keeping both as a deliberate field-set
decision.
**The root cause is structural, not a single bad call.** ops-warden grades a
*lane* by its headline field — the catalog carries one `fetch_command` naming one
field and no `fields` list at all — but the disclosure unit is the **path**: a
`bao kv get` returns every field stored there. So a lane can be graded on its
least dangerous contents. `ADR-0007` says every lane carries an explicit grade;
it does not say the grade must cover everything a read of that path would
disclose, and it should.
Fix the grade, then fix the model that produced it: record `fields` per lane and
grade on the union. Check the other 25 lanes for the same shape.
**Done 2026-08-21 — and it was two lanes, not one.** While verifying
`reuse-surface-hub-write-token` I told secrets-engine their second field was
unevidenced and asked them to confirm it. It was evidenced: `CCR-2026-0005`'s
`kv_path` block lists both fields and its notes describe the HMAC's alignment
with Forgejo org webhook id=1. A truncated grep, and a retraction sent within
twenty minutes so they would not spend time on it. That lane was under-graded on
exactly the same reasoning, and both had been regraded *down* in the same T05
pass — which is what makes this a systematic flaw rather than one bad call.
Blast radius checked and bounded: of the 8 remaining `standard` lanes, 6 have no
KV path at all (SSH, policy check, tunnel, principals, issue-sink, key-cape
login) so nothing is disclosed by a read. Two do have paths and no CCR field
evidence — `rein-openweights-openrouter-approle` and `coulomb-social-runtime-env`
(a whole k8s env Secret, which by shape almost certainly holds several fields).
Deliberately **not** regraded: `ADR-0008` §3 says an unknown field set is stated
rather than assumed, and grading is operator-sanctioned judgement, not backfill.
They are the open item on this task.
Shipped: both regrades with their evidence and the superseded reasoning kept
inline, `fields` recorded with its CCR source, the test that had been holding the
wrong answer inverted with an explanation of why it was wrong to trust it, and
**`ADR-0008`** — a lane's grade covers every field its path discloses. That is a
new binding rule, so it is a record rather than a wiki note.
```task
id: WARDEN-WP-0033-T03
status: done
priority: high
state_hub_task_id: "a736f983-94da-5a4a-aaf9-5114485518a6"
```
**Emit the generated high-risk data-path artifact for `railiance-platform`.**
They asked for a versioned artifact of concrete high-risk data paths
(`id` + `data_path` + catalog revision) to consume instead of hand-maintaining
the deny list — the half of the `RISK-F-0009` fix ops-warden explicitly declined
to build *for* them. Emitting the artifact is not the same as amending their
policy: they still own what to deny. That boundary is the point of `ADR-0002`
and must survive this task.
Must be generated, never hand-edited, and must carry the catalog revision so a
consumer can tell what it was derived from. Depends on T02 — publishing the deny
set before fixing the grades would ship the wrong list to a consumer who will
apply it.
**Done 2026-08-21.** `scripts/emit_high_risk_paths.py`
`registry/generated/high-risk-data-paths.yaml`: 19 high-risk lanes, 14 concrete
data paths, 5 with no single KV address listed separately so a consumer does not
read the absence as an omission. Carries `catalog_revision`, its date, and a
`catalog_dirty` flag — a revision that does not describe the file it came from is
worse than none.
The T02 dependency was not theoretical. The two regrades land in this artifact,
and `check_agent_read_boundary.py` now reports **2 uncovered** against a policy
railiance-platform closed to 0 yesterday. Emitting before regrading would have
handed them a list that confirmed a coverage claim that had just stopped being
true.
`fields` is emitted as `null` where no CCR declares the set, never as a
single-element guess — `ADR-0008` §3. Two CI tests: the artifact must be current,
and every high-risk lane must appear in it, so a lane graded high after the last
emit cannot silently fail to reach the consumer.
Boundary held: the header states this is an input and not a policy, and that
railiance-platform may deny more, deny less, or dispute a grade (`ADR-0002`).
```task
id: WARDEN-WP-0033-T04
status: done
priority: medium
state_hub_task_id: "5acac140-a586-5db3-b231-bbf236710786"
```
**Route the coding-agent issuance identity question.**
`RAILIANCE-WP-0017` is blocked on defining a distinct coding-agent issuance
identity and proving deny-wins when that identity is combined with workload read.
They asked ops-warden to route ownership.
Route it; do not absorb it (`ADR-0005`, `ADR-0003`). ops-warden owns actor
identity for `adm`/`agt`/`atm` **SSH certificates** and nothing else — a coding
agent's OpenBao issuance identity is an IAM question. The likely owner is
`key-cape`, with `user-engine` and `zone-engine` both plausibly involved. Say so
with reasoning rather than guessing, and record the answer either way.
Note the interaction with `ADR-0004`: the agent read-boundary already depends on
`WARDEN_AGENT_ID` being set, which is an honour-system marker on the ops-warden
side. A real issuance identity is what would make that boundary hold on the
OpenBao side too, so ops-warden is an interested consumer, not a bystander.
**Routed 2026-08-21 to `key-cape` (msg 903b2223); waiting on accept or refuse.**
Reasoning given: it is an identity and issuance question about a principal
authenticating to OpenBao, which is key-cape/Keycloak's. The precedent is an hour
old and runs the same direction — `secrets-engine` declined `key-cape-oidc-login`
as ops-warden's to hand them, on the grounds that login and identity-token
issuance stay with key-cape. Absorbing this would contradict agreeing with them.
Named the adjacent parties explicitly rather than leaving them to inference:
`zone-engine` has an interest (a coding-agent identity is a strong candidate zone
subject) and `user-engine` is **not** involved — this is a machine principal, not
an end-user account. Stated so nobody concludes it by elimination.
Asked for a refusal-with-pointer as an equally good answer. The failure mode to
avoid is the 2026-08-17 one recorded in `.claude/rules/finding-routing.md`:
ops-warden answered a question well and never routed it, and another repo ended
up filing it.
**Followed up 2026-08-23 after the immediate enforcement gap closed.**
`RAILIANCE-WP-0022` no longer waits for this ownership decision: the platform
owner deployed a dedicated coding-agent AppRole, proved deny-wins when it is
combined with workload read, and identified an exact-bound KeyCape JWT role as
the migration target. That makes the remaining question narrower and more
important rather than obsolete: who owns issuance of the durable
KeyCape/Keycloak-backed machine identity?
Direct follow-up `d25d4604-5713-42a8-8e3a-1ea31b5a5cc7` asks `key-cape` to
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
priority: medium
state_hub_task_id: "75051d17-399b-5129-860b-ae00dae91c47"
```
**Make blocker staleness a mechanism instead of an intention.**
Four stale blockers surfaced in twelve hours: an OpenBao token recorded expired
that was valid, a verification script recorded ready that had never been written,
a ten-day `secrets-engine` question answerable from their source, and
`FLEX-WP-0007` cited as blocking `policy.enabled` seven weeks after it read
`finished`. `.claude/rules/finding-routing.md` has said *re-read a blocker before
trusting it* since `RISK-F-0001`. Saying it has not worked.
`warden route gaps` had a `--stale-days` threshold defaulting to 90, which was
not loose but **inert** — the register was created 2026-08-15, so it could not
fire before November.
**Done 2026-08-21.** Two changes, and the second matters more:
1. **Split the cadences.** `DEFAULT_STALE_DAYS` (90) still governs pointer
freshness — "is this the right owner and page" genuinely is quarterly. New
`DEFAULT_BLOCKER_STALE_DAYS` (14) governs interim blockers, calibrated on the
cases that cost something: ten days for the secrets-engine lanes, one day for
`RISK-F-0001`, ~50 for `FLEX-WP-0007`. At ~15 lanes it surfaces about one a
day rather than a wall, and it fires on zero lanes on age today.
**Then scaled by risk, after risk-nexus answered.** They accepted the offer to
converge and published their convention: 14 days critical/high, 30 medium, 60
low, with fix state *read* from the owning repo rather than remembered. Their
framing — "point `warden route gaps` at those windows and the two will agree
without either of us building a shared mechanism" — is better than a joint
tool, so `blocker_stale_days()` now maps lane `risk` onto exactly those
windows. `ungraded` takes the *shortest*, not the longest: `ADR-0007` makes an
absent grade a defect, so its blocker is the least trustworthy of all.
2. **`verified:` distinguishes re-checking from re-editing.** `reviewed` records
when someone touched the entry; nothing recorded whether the claim was
re-established. `owner-confirmed` and `source-read` count;
**`asked-and-waiting` and `unverified` do not**, and a lane in those states is
stale regardless of its date. `key-cape-oidc-login` is the proof: asked today,
zero days old, correctly flagged.
Current state: 14 non-draft interim lanes — 5 `owner-confirmed`, 1
`asked-and-waiting`, 8 `unverified`. The 8 are honest; they were carried forward
this session without a check and now say so instead of hiding behind a fresh date.
`--fail-on-stale` exits 3 so a cron job or gate can act. **Deliberately not a CI
test on age**: a date-triggered failure breaks the build on a calendar day with
no code change, punishing whoever commits next rather than whoever owns the
blocker. The CI test is structural instead — every interim lane must record
*how* it was verified, which fails on the commit that introduces the omission.
```task
id: WARDEN-WP-0033-T06
status: done
priority: high
state_hub_task_id: "94f77f5a-f919-5328-832c-ba1d24c6431b"
```
**Correct first-time OpenBao administration routing.** `rapp-postgres` reported
on 2026-08-22 that `warden plan` mapped first-time
`database/config/platform-pg-2` administration to the generic
`openbao-api-key` template. It consequently proposed paste-once KV provisioning
and a workload OIDC role, neither of which can configure database connections,
policies, auth roles, or token roles. Their Desk session stopped without an
approval or secret action.
The authoritative platform runbook and rapp-postgres's live T04 evidence agree
on the missing distinction: this is one attended KeyCape-backed OpenBao identity
act at auth mount `netkingdom`, role `platform-admin`. It is not a credential
value handoff. Root stays offline break-glass authority and a workload role must
never be widened to make the operation pass.
Add an exact `openbao-platform-admin-login` lane, an operator playbook, and a
regression that makes the reported request resolve to `founder_required` with
`oidc_login` — never `paste_once_provision`. Verify the route, then return the
corrected non-secret command to rapp-postgres.
**Done 2026-08-22.** The new active lane resolves the exact reported request at
score 20, ahead of the generic KV template at 11, and returns one
`founder_required` act:
`bao login -no-print -method=oidc -path=netkingdom role=platform-admin`.
Planner output offers only `warden access openbao-platform-admin-login --fetch`
and the exact owner command; login lanes no longer inherit secret-value
transports (`--exec`, `--out`, `--wrap`). The lane is explicitly a high-risk,
non-workload human identity act, so the generated boundary artifact lists it as
having no KV address rather than inventing one.
Verification: 384 tests pass, Ruff passes, workload accounting resolves all 28
lanes (3 resolved, 17 unknown, 8 not-applicable), and the boundary invariant
reports 20 high-risk lanes, 14 concrete paths covered, 6 non-KV/pattern lanes,
0 uncovered. No login or credential action was performed.
## Related
- `secrets-engine` `SECRETS-WP-0006` — catalog admission, decision `ae676382`
- `RISK-F-0009` — closed by railiance-platform 2026-08-21; 0 uncovered
- `railiance-platform` `RAILIANCE-WP-0022` (boundary coverage), `RAILIANCE-WP-0017`
- `ADR-0002`, `ADR-0003`, `ADR-0004`, `ADR-0005`, `ADR-0007`
- `WARDEN-WP-0030` — the delegation register these five lanes retire from