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
This commit is contained in:
parent
96dbb22aab
commit
c1330049d9
5 changed files with 290 additions and 24 deletions
71
workplans/WARDEN-WP-0038-plan-mutation-intent.md
Normal file
71
workplans/WARDEN-WP-0038-plan-mutation-intent.md
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
---
|
||||
id: WARDEN-WP-0038
|
||||
type: workplan
|
||||
title: "warden plan must distinguish reading a secret from mutating one"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: proposed
|
||||
owner: ops-warden
|
||||
topic_slug: netkingdom
|
||||
planning_priority: P1
|
||||
depends_on_workplans:
|
||||
- WARDEN-WP-0029
|
||||
created: "2026-09-08"
|
||||
updated: "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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue