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
|
|
@ -10,11 +10,11 @@
|
||||||
# declares it, and is null where the field set has not been established --
|
# declares it, and is null where the field set has not been established --
|
||||||
# null means unknown, never 'one field'.
|
# null means unknown, never 'one field'.
|
||||||
|
|
||||||
generated_at: "2026-09-04T23:20:26Z"
|
generated_at: "2026-09-08T12:52:59Z"
|
||||||
source: ops-warden/registry/routing/catalog.yaml
|
source: ops-warden/registry/routing/catalog.yaml
|
||||||
catalog_revision: "00145d705e88eeb9a880a85a3cc15a5205dde2d6"
|
catalog_revision: "00145d705e88eeb9a880a85a3cc15a5205dde2d6"
|
||||||
catalog_revision_date: "2026-09-05T01:19:48+02:00"
|
catalog_revision_date: "2026-09-05T01:19:48+02:00"
|
||||||
catalog_dirty: false
|
catalog_dirty: true
|
||||||
high_risk_lane_count: 24
|
high_risk_lane_count: 24
|
||||||
concrete_path_count: 15
|
concrete_path_count: 15
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -335,9 +335,9 @@ entries:
|
||||||
delegation:
|
delegation:
|
||||||
mode: interim
|
mode: interim
|
||||||
intended_owner: key-cape
|
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. Asked of key-cape 2026-08-28; KEY-WP-0009 accepting issuance ownership for machine identities is the precedent that makes it answerable."
|
blocked_on: "ACCEPTED by key-cape 2026-09-08 (msg 12f1bdfa): key-cape owns interactive login, OIDC identity-token issuance and MFA for this lane, confirming the 2026-08-28 correction of intended_owner from secrets-engine (whose 2026-08-21 refusal was right). Lane stays interim because the accepted ownership covers only the identity half: the fetch_command yields an OPENBAO token, and the netkingdom auth mount, the role=<domain> mapping, the token store and its enforcement are OpenBao's, with role/policy definition railiance-platform's. keycape login is not a drop-in — it yields a key-cape issuer JWT written to a private file, a different credential type with a different verifier (KEY-WP-0014-T04). Retires when a key-cape-native front door yields the credential this route's consumers expect, or when the route is deliberately re-contracted to a JWT. Verified against key-cape docs/native-authentication.md, docs/openbao-service-auth-contract.md, config/service-clients.example.yaml, src/internal/server/oidc/discovery.go."
|
||||||
reviewed: "2026-08-28"
|
reviewed: "2026-09-08"
|
||||||
verified: asked-and-waiting
|
verified: owner-confirmed
|
||||||
# Login lane (WP-0014 T4) — interactive auth bootstrap, not a secret read. No
|
# 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
|
# secret-read gate (you have no identity yet) and no caller-auth precheck (the
|
||||||
# point is to obtain one). warden runs it interactively as the caller and never
|
# point is to obtain one). warden runs it interactively as the caller and never
|
||||||
|
|
@ -764,9 +764,9 @@ entries:
|
||||||
delegation:
|
delegation:
|
||||||
mode: interim
|
mode: interim
|
||||||
intended_owner: key-cape
|
intended_owner: key-cape
|
||||||
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."
|
blocked_on: "Narrowed 2026-09-08 to rotation steps 1-2 only: successor generation and the CAS write to both custodians (platform/workloads/rapp-qonto/keycape-client field client_secret, and sso/keycape-rapp-qonto-client key client-secret) remain custody/deployment acts with no admitted execution and rollback contract, and no admitted ops-warden lane authorizes them. The key-cape-native exchange now exists (keycape service-token, 2026-09-05, KEY-WP-0014-T03) and step 3 verification exists as one command (keycape verify-client, 2026-09-08, including predecessor rejection and identical-secret detection); both are documented in key-cape/docs/native-authentication.md. The prior blocker recorded both as absent, which was accurate on 2026-08-28 and is not accurate now — corrected by key-cape (msg 08d42f47). Re-checked against key-cape source 2026-09-08."
|
||||||
reviewed: "2026-08-28"
|
reviewed: "2026-09-08"
|
||||||
verified: source-read
|
verified: owner-confirmed
|
||||||
risk: high
|
risk: high
|
||||||
workload_ref:
|
workload_ref:
|
||||||
applicability: applicable
|
applicability: applicable
|
||||||
|
|
@ -781,11 +781,15 @@ entries:
|
||||||
rotation:
|
rotation:
|
||||||
method: rotate
|
method: rotate
|
||||||
owner: key-cape
|
owner: key-cape
|
||||||
automatable: true
|
# Not drivable end to end: steps 1-2 are custody/deployment acts with no
|
||||||
|
# admitted execution transport, so an executable driver (WARDEN-WP-0027
|
||||||
|
# Strand B) must not treat this lane as automatable. Step 3 alone is one
|
||||||
|
# owner command today — the precision lives in the steps, not the flag.
|
||||||
|
automatable: false
|
||||||
steps:
|
steps:
|
||||||
- "Generate a fresh newline-free secret through an approved execution transport; never print it."
|
- "Generate a fresh newline-free secret through an approved execution transport; never print it. NOT automatable — no admitted execution and rollback contract (see delegation.blocked_on)."
|
||||||
- "Write the same value to OpenBao and sso/keycape-rapp-qonto-client, then restart KeyCape."
|
- "CAS-write the same value to platform/workloads/rapp-qonto/keycape-client and sso/keycape-rapp-qonto-client preserving siblings, then restart KeyCape in the agreed window. NOT automatable — same blocker; on failure reconcile both custodians to the same version before declaring rollback complete."
|
||||||
- "Verify positive qonto:read exchange plus wrong-secret and excessive-scope denial without printing tokens."
|
- "Verify positive qonto:read exchange plus predecessor-secret and excessive-scope denial without printing tokens: run the owner command keycape verify-client (key-cape/docs/native-authentication.md)."
|
||||||
|
|
||||||
- id: net-kingdom-lldap-bind-credential
|
- id: net-kingdom-lldap-bind-credential
|
||||||
title: NetKingdom LLDAP bind credential for identity and privacyIDEA resolver
|
title: NetKingdom LLDAP bind credential for identity and privacyIDEA resolver
|
||||||
|
|
|
||||||
|
|
@ -994,12 +994,31 @@ def test_asked_and_waiting_is_not_verification():
|
||||||
|
|
||||||
|
|
||||||
def test_stale_gaps_flags_unverified_even_when_the_date_is_today():
|
def test_stale_gaps_flags_unverified_even_when_the_date_is_today():
|
||||||
|
"""Property, not a named lane.
|
||||||
|
|
||||||
|
Originally pinned to `key-cape-oidc-login` sitting `asked-and-waiting`;
|
||||||
|
key-cape answered on 2026-09-08, so the fixture lane moved and the test
|
||||||
|
failed on someone else's good news rather than on a defect. The claim being
|
||||||
|
made is about the verification method, so assert that instead: any lane
|
||||||
|
whose blocker was never re-established is stale on the day it was reviewed.
|
||||||
|
"""
|
||||||
catalog = load_catalog(_repo_catalog())
|
catalog = load_catalog(_repo_catalog())
|
||||||
stale = {e.id for e in catalog.stale_gaps(include_draft=True, today=date(2026, 8, 21))}
|
today = date(2026, 9, 8)
|
||||||
# Asked of key-cape on 2026-08-21 and unanswered -- zero days old, still stale.
|
stale = {e.id for e in catalog.stale_gaps(include_draft=True, today=today)}
|
||||||
assert "key-cape-oidc-login" in stale
|
unverified = [
|
||||||
# Confirmed by the owner the same day -- fresh.
|
e for e in catalog.gaps(include_draft=True)
|
||||||
assert "issue-core-ingestion-api-key" not in stale
|
if not e.effective_delegation.is_verified
|
||||||
|
]
|
||||||
|
for entry in unverified:
|
||||||
|
assert entry.id in stale, f"{entry.id} is unverified but not stale"
|
||||||
|
# A lane the owner confirmed today is fresh, so staleness is not vacuous.
|
||||||
|
fresh = [
|
||||||
|
e.id for e in catalog.gaps(include_draft=True)
|
||||||
|
if e.effective_delegation.is_verified
|
||||||
|
and e.effective_delegation.reviewed == today.isoformat()
|
||||||
|
]
|
||||||
|
assert fresh, "expected at least one owner-confirmed-today lane"
|
||||||
|
assert not (set(fresh) & stale)
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_verification_method_rejected(tmp_path):
|
def test_invalid_verification_method_rejected(tmp_path):
|
||||||
|
|
@ -1027,10 +1046,10 @@ def test_cli_route_gaps_fail_on_stale_exits_3(repo_catalog_env):
|
||||||
assert result.exit_code == 3
|
assert result.exit_code == 3
|
||||||
rows = json.loads(result.stdout)
|
rows = json.loads(result.stdout)
|
||||||
assert any(r["stale"] for r in rows)
|
assert any(r["stale"] for r in rows)
|
||||||
# An asked-and-waiting lane stays stale until it is verified, regardless of
|
# A lane whose blocker was never re-established stays stale regardless of
|
||||||
# how many calendar days have elapsed since the request.
|
# how many calendar days have elapsed since it was reviewed. Asserted over
|
||||||
assert any(
|
# the verification method rather than one named lane -- see
|
||||||
r["stale"]
|
# test_stale_gaps_flags_unverified_even_when_the_date_is_today.
|
||||||
and r["verified"] == "asked-and-waiting"
|
for row in rows:
|
||||||
for r in rows
|
if row["verified"] in ("asked-and-waiting", "unverified"):
|
||||||
)
|
assert row["stale"], f"{row['id']} is unverified but not stale"
|
||||||
|
|
|
||||||
172
workplans/ADHOC-2026-09-08.md
Normal file
172
workplans/ADHOC-2026-09-08.md
Normal file
|
|
@ -0,0 +1,172 @@
|
||||||
|
---
|
||||||
|
id: WARDEN-WP-ADHOC-2026-09-08
|
||||||
|
type: workplan
|
||||||
|
title: "Ad Hoc Tasks — 2026-09-08"
|
||||||
|
domain: infotech
|
||||||
|
repo: ops-warden
|
||||||
|
status: finished
|
||||||
|
owner: claude
|
||||||
|
topic_slug: netkingdom
|
||||||
|
created: "2026-09-08"
|
||||||
|
updated: "2026-09-08"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Ad Hoc Tasks — 2026-09-08
|
||||||
|
|
||||||
|
Four key-cape messages, all follow-on from `WARDEN-WP-0033`. Two carry answers
|
||||||
|
ops-warden's catalog was waiting for; both make a recorded blocker less true than
|
||||||
|
it reads. This is the T05 mechanism paying out — and this time the owner ran it
|
||||||
|
against us rather than us running it against them.
|
||||||
|
|
||||||
|
### T01 — Narrow the `rapp-qonto-keycape-client` blocker (msg `08d42f47`)
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: WARDEN-WP-ADHOC-2026-09-08-T01
|
||||||
|
status: done
|
||||||
|
priority: high
|
||||||
|
```
|
||||||
|
|
||||||
|
The blocker recorded "still no key-cape-native exchange/rotation command",
|
||||||
|
`verified: source-read` against key-cape source on 2026-08-28. Accurate then;
|
||||||
|
two things landed after that read:
|
||||||
|
|
||||||
|
- `keycape service-token` (2026-09-05, KEY-WP-0014-T03) — the client_secret_basic
|
||||||
|
exchange the blocker records as absent.
|
||||||
|
- `keycape verify-client` (2026-09-08) — rotation step 3 as one command,
|
||||||
|
including predecessor rejection and identical-secret detection.
|
||||||
|
|
||||||
|
**Narrowed, not cleared**, as key-cape asked. What remains genuinely blocked is
|
||||||
|
steps 1-2: successor generation and the CAS write to both custodians. Those are
|
||||||
|
custody and deployment acts, key-cape deliberately ships no command for them, and
|
||||||
|
no admitted ops-warden lane authorizes them either (T03).
|
||||||
|
|
||||||
|
`verified` moved to `owner-confirmed` — the correction came from the owner.
|
||||||
|
|
||||||
|
`rotation.automatable` flipped `true` → `false`, which key-cape explicitly asked
|
||||||
|
us not to do "either way" without precision. Done with the precision they wanted,
|
||||||
|
in the only place the schema has room for it: the flag is a single hint consumed
|
||||||
|
by a future executable driver (`WARDEN-WP-0027` Strand B), and a driver told
|
||||||
|
`true` would attempt custody acts with no admitted transport — the dangerous
|
||||||
|
direction. So the flag fails safe and the *steps* now carry the per-step truth,
|
||||||
|
each naming whether it is automatable and why. Offered them a schema change if a
|
||||||
|
per-step field would serve better; not built on speculation.
|
||||||
|
|
||||||
|
### T02 — Record key-cape's acceptance of `key-cape-oidc-login` (msg `12f1bdfa`)
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: WARDEN-WP-ADHOC-2026-09-08-T02
|
||||||
|
status: done
|
||||||
|
priority: high
|
||||||
|
```
|
||||||
|
|
||||||
|
key-cape **accepted** ownership: interactive login, OIDC identity-token issuance
|
||||||
|
and MFA. This confirms the 2026-08-28 correction of `intended_owner` from
|
||||||
|
secrets-engine to key-cape, and confirms secrets-engine's 2026-08-21 refusal was
|
||||||
|
right. `verified: asked-and-waiting` → `owner-confirmed`.
|
||||||
|
|
||||||
|
**The lane stays `interim`.** Acceptance covers the identity half only. The
|
||||||
|
`fetch_command` yields an *OpenBao* token — the `netkingdom` mount, the
|
||||||
|
`role=<domain>` mapping, the token store and its enforcement are OpenBao's, with
|
||||||
|
role and policy definition railiance-platform's. `keycape login` yields a
|
||||||
|
key-cape issuer JWT to a private file: different credential type, different
|
||||||
|
verifier, different enforcement owner. Accepting an owner is not the same as the
|
||||||
|
owner fronting the lane, and `ADR-0003` says the interim cover is retired when
|
||||||
|
the front door exists, not when ownership is agreed. Retirement condition is now
|
||||||
|
recorded on the entry.
|
||||||
|
|
||||||
|
Their reading of the risk is right and we confirmed it: `warden_executes: false`
|
||||||
|
with a `wiki_ref` pointer, so per `ADR-0001` this is a pointer layer, not a code
|
||||||
|
path with programmatic consumers. `risk: standard` and
|
||||||
|
`workload_ref: not-applicable` are correct — a human identity act with no KV
|
||||||
|
path, consistent with how `ADR-0008` treats the other non-KV lanes.
|
||||||
|
|
||||||
|
### T03 — Answer "who executes Qonto rotation steps 1-2" (msg `0a6c9d88`)
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: WARDEN-WP-ADHOC-2026-09-08-T03
|
||||||
|
status: done
|
||||||
|
priority: high
|
||||||
|
```
|
||||||
|
|
||||||
|
Answer: **nobody, admittedly, today** — and ops-warden must not invent one.
|
||||||
|
|
||||||
|
Steps 1-2 mutate custody on `platform/workloads/rapp-qonto/keycape-client` and
|
||||||
|
`sso/keycape-rapp-qonto-client`. Custody of platform workload paths is
|
||||||
|
railiance-platform's; the admitted execution front door for provisioned
|
||||||
|
secret-exec is `secrets-engine exec`. ops-warden owns neither and absorbing it
|
||||||
|
would be `ADR-0002` and `ADR-0005` violated in one act. Routed to
|
||||||
|
railiance-platform, with secrets-engine named as the transport owner — and
|
||||||
|
secrets-engine independently confirmed the same boundary three days earlier
|
||||||
|
(msg `15f0c0ca`): they will not rewrite a production lane's custody state from a
|
||||||
|
coordination message without owner confirmation.
|
||||||
|
|
||||||
|
key-cape was right not to treat a generic `warden route` match as authorization.
|
||||||
|
See T04 for what our own tool did when asked.
|
||||||
|
|
||||||
|
### T04 — `warden plan` returned `autonomous` for a custody *write* (defect)
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: WARDEN-WP-ADHOC-2026-09-08-T04
|
||||||
|
status: done
|
||||||
|
priority: high
|
||||||
|
```
|
||||||
|
|
||||||
|
Verifying T03 against our own front door:
|
||||||
|
|
||||||
|
```
|
||||||
|
warden plan "generate a successor client secret ... and CAS-write it to
|
||||||
|
OpenBao platform/workloads/... and sso/..." --json
|
||||||
|
verdict: autonomous
|
||||||
|
lane_id: rapp-qonto-keycape-client
|
||||||
|
commands: warden access ... --exec / --out / --wrap
|
||||||
|
```
|
||||||
|
|
||||||
|
A need that says *generate* and *CAS-write* resolved to `autonomous` and was
|
||||||
|
answered with three **read** transports. This is the `WARDEN-WP-0033-T06` shape
|
||||||
|
recurring — a generic keyword match producing a confident wrong act — except T06
|
||||||
|
fixed one route by adding an exact lane, and the defect is in the classifier.
|
||||||
|
`warden plan` has no notion of read versus mutate intent, so every write need
|
||||||
|
matches the lane that *reads* the same path and comes back `autonomous`.
|
||||||
|
|
||||||
|
Not fixed here: a classifier is design work with an approval-semantics blast
|
||||||
|
radius, which the convention says is a workplan, not an adhoc.
|
||||||
|
Promoted to **`WARDEN-WP-0038`** (`proposed`).
|
||||||
|
|
||||||
|
Worth stating plainly: key-cape distrusted this output on principle and was right
|
||||||
|
to. Had they trusted it, our tool would have told them to proceed autonomously on
|
||||||
|
an unadmitted custody mutation.
|
||||||
|
|
||||||
|
### T05 — Acknowledge the KEY-WP-0009 handoff (msg `5bc58847`)
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: WARDEN-WP-ADHOC-2026-09-08-T05
|
||||||
|
status: done
|
||||||
|
priority: low
|
||||||
|
```
|
||||||
|
|
||||||
|
Informational; no route retired or changed. Their routing note matches ours:
|
||||||
|
"login / OIDC / MFA" → key-cape means **issuance only**, and secret *values*
|
||||||
|
route to OpenBao custody. Nothing to change in `wiki/CredentialRouting.md`.
|
||||||
|
|
||||||
|
Also records that the KEY-WP-0009 reply ops-warden reported never arriving indeed
|
||||||
|
never existed (KEY-WP-0014-T02, audited 2026-09-05). Our 2026-08-28 finding was
|
||||||
|
right, and the correction is theirs, recorded.
|
||||||
|
|
||||||
|
### T06 — Unpin two tests from a transient catalog state
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: WARDEN-WP-ADHOC-2026-09-08-T06
|
||||||
|
status: done
|
||||||
|
priority: medium
|
||||||
|
```
|
||||||
|
|
||||||
|
`test_stale_gaps_flags_unverified_even_when_the_date_is_today` and
|
||||||
|
`test_cli_route_gaps_fail_on_stale_exits_3` both asserted that
|
||||||
|
`key-cape-oidc-login` specifically sat `asked-and-waiting`. T02 answering that
|
||||||
|
question broke them — **the tests failed on good news**, not on a defect, and a
|
||||||
|
test that fails when a counterparty replies will get suppressed rather than read.
|
||||||
|
|
||||||
|
Both now assert the property they were always about: any lane whose blocker was
|
||||||
|
never re-established is stale regardless of its date, over whatever lanes are in
|
||||||
|
that state. The named-lane version of the claim already exists as a unit test on
|
||||||
|
`Delegation.is_verified`, which is where a fixture belongs.
|
||||||
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