ops-warden/workplans/WARDEN-WP-0038-plan-mutation-intent.md
tegwick c1330049d9 docs: narrow qonto blocker, record key-cape lane ownership
key-cape corrected two blockers that had stopped being true after our
2026-08-28 source-read:

- rapp-qonto-keycape-client: `keycape service-token` (2026-09-05) is the
  native exchange the blocker recorded as absent, and `keycape verify-client`
  (2026-09-08) is rotation step 3 as one command. Narrowed to steps 1-2 --
  successor generation and the CAS write -- rather than cleared, as they
  asked. rotation.automatable -> false so a future executable driver is not
  told a lane with no admitted custody transport is drivable; the per-step
  truth moves into the steps.
- key-cape-oidc-login: ownership ACCEPTED by key-cape, so verified moves from
  asked-and-waiting to owner-confirmed. Lane stays interim -- acceptance
  covers the identity half, while the fetch_command yields an OpenBao token
  whose mount, role mapping and enforcement are not key-cape's.

Two tests pinned `key-cape-oidc-login` to sitting `asked-and-waiting`, so
answering the question broke them -- they failed on good news. Both now
assert the property instead: an unverified blocker is stale regardless of
date, over whatever lanes are in that state.

Verifying the routing answer against our own front door turned up a defect:
`warden plan` returns `autonomous` for a custody *write* and answers it with
read transports, because it has no read-versus-mutate intent. Recorded as
WARDEN-WP-0038 (proposed) -- the WP-0033-T06 shape, as a class this time.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1276224@bnt-lap001
Assistant-Session: 426ec497-e1c4-4dd3-b417-dfce1ca1dbc3
2026-09-08 14:55:02 +02:00

2.9 KiB

id type title domain repo status owner topic_slug planning_priority depends_on_workplans created updated
WARDEN-WP-0038 workplan warden plan must distinguish reading a secret from mutating one infotech ops-warden proposed ops-warden netkingdom P1
WARDEN-WP-0029
2026-09-08 2026-09-08

WARDEN-WP-0038 — Read versus mutate intent in the policy front door

The defect

warden plan scores a need against catalog lanes by keyword overlap and returns a verdict. It has no notion of what the caller wants to do. So a need that says generate a successor secret and CAS-write it to two custodians matches the lane that reads that path, scores well on the shared nouns, and returns:

verdict: autonomous
commands: warden access <lane> --exec / --out / --wrap

Three read transports offered as the answer to a write, under the verdict that means "proceed without the founder". Reproduced 2026-09-08 against rapp-qonto-keycape-client (ADHOC-2026-09-08-T04).

Why this is worse than a bad suggestion

warden plan is the documented first step before drafting any founder credential step (.claude/rules/credential-routing.md), and autonomous is consumed as an authorization signal by agents that have no other check. WARDEN-WP-0029 shipped the verdict because instinct was not auditable; a verdict that is confidently wrong in the permissive direction is worse than no verdict.

key-cape hit this and refused to rely on it — "we are not treating a generic match as authorization" — which is the only reason it surfaced as a design question rather than as an unadmitted custody mutation. The control that caught it was a counterparty's caution. That is not a control.

WARDEN-WP-0033-T06 is the same shape (rapp-postgres, generic openbao-api-key match → paste_once_provision for an act that could not work) and was fixed by adding one exact lane plus one regression. That fixed the instance. This is the class.

Shape of the fix (to be designed, not assumed)

  • Classify need intent — read / mutate / establish — before scoring, and never answer a mutate need with a read lane's transports.
  • A mutate need against a lane ops-warden does not own is unroutable with a CCR stub naming the custody owner, not autonomous. ADR-0003: cover gaps, never silently own them; a permissive verdict on someone else's custody act is a silent claim of ownership.
  • Consider whether rotation.steps should be reachable from plan at all, given they are advisory prose and several are explicitly not automatable.
  • Regression from the reproduced case, in the manner of T06.

Open question for design

Whether intent belongs in the matcher or in the lane. A lane could declare which acts it admits (read, rotate, provision) and plan could refuse any act a lane does not declare — stricter, and it fails closed on lanes that say nothing, which is the majority today. That is a catalog schema change and needs its own argument.