CUST-WP-0075: security gate assessment; route CUST-WP-0073-T05 to decision packet D3

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
codex 2026-10-03 03:12:09 +02:00
parent 504386ca70
commit 5fe38bc6d1
2 changed files with 141 additions and 1 deletions

View file

@ -0,0 +1,139 @@
---
id: 20261003-security-gate-packets
type: assessment
title: "What the dependency graph says about how security work gets blocked, and what to change"
date: "2026-10-03"
assessor: the-custodian (Claude)
audience: founder
status: recorded
related_workplans:
- CUST-WP-0075
- CUST-WP-0074
- CUST-WP-0072
- RPF-WP-0035
- WARDEN-WP-0027
origin: "Founder request 2026-10-03: use the dependency facility to shrink the blocked set and learn how to make the security infrastructure easier to maintain and extend."
---
# What the dependency graph says about security work
Snapshot 2026-10-03 from the workplan files of 145 registered repos
(`docs/evidence/2026-10-03-dependency-graph-triage/`). This is an
assessment with proposals. It changes no canon and authorizes nothing.
## 1. The shape of the blockage
| Measure | Value |
| --- | ---: |
| Open workplans | 108 (100 blocked) |
| Wait tasks inside them | 232 |
| Human gates (`needs_human: true`) | 69 |
| Human gates that named a hub decision | 0 |
| Owner-return waits (`blocked_on: message-from:`) | 20 |
| Wait tasks whose blockers were already terminal | 8 |
| Cycles | 0 |
Three facts matter more than the counts.
**The graph has no cycles and few true roots.** Removing the already-
satisfied and mis-statused cases, the open set hangs off roughly a dozen
root nodes. The two largest, `SAND-WP-0015-T04` (7 workplans behind it)
and `SECRETS-WP-0009-T03` (5), are themselves owner-return waits on
railiance-platform and glas-harness, which in turn wait on one attended
OpenBao session. So the single largest lever is not a repo and not a
workplan; it is one kind of act by one person.
**Human gates were invisible to the hub.** The wait-qualifier standard
(`canon/standards/task-wait-qualifiers_v0.1.md`) and C-40 rule 4 already
let a resolved decision clear a task. Nobody used it: all 69 gates were
prose. Bernd therefore had 69 places to read and no list to resolve.
`CUST-WP-0075-T03` routed 68 of them to eleven hub decisions (one has no
stated gate at all, `WARDEN-WP-0037-T03`, and goes back to its owner).
**Security work is where this concentrates.** Of the 69 gates, 19 are
attended OpenBao provisioning acts (packet D1), 14 are the ArgoCD
production-ownership sequence (D2), 3 are trust-root and custody design
(D3), 3 are destructive cleanups behind retention windows (D4), 7 are
production risk acceptances (D5). That is 46 of 69 in the credential,
identity, delivery and custody space. Product and research gates are the
minority.
## 2. Why credential work blocks the way it does
Reading the lane documents in railiance-platform
(`docs/credential-lane-designs/`, `docs/openbao-approved-automation-delegation.md`,
`docs/credential-lane-lifecycle-runbook.md`) and the ops-warden catalog
(38 routing entries) gives a consistent picture:
1. **Metadata is delegated, values are not.** The delegated applier may
write policies and auth roles from an approved CCR; secret *values*
stay an attended operator act "unless a later workplan approves a
stronger dual-control flow". Almost every D1 task is blocked at
exactly that value step: the policy is designed, reviewed, often
dry-run, and then waits for a session.
2. **Each lane negotiates its own session.** Nineteen tasks in twelve
repos describe the same act in their own words, with their own
evidence expectations. Nothing aggregates them, so no session is ever
"worth" scheduling and each lane waits for its own.
3. **Owner-return waits chain across repos.** sand-boxer waits on
railiance-platform, which waits on secrets-engine, which waits on the
session. Each hop is a hub message that may or may not be answered;
the C-25 unread-reply check exists but nothing sweeps it.
4. **The read model lags the files.** The hub carried 201 dependency
edges where the files carry more; task-level edges from the September
backfill were "parked" behind a deploy. Anyone querying the hub for
the graph got a thinner picture than the files hold.
None of this is a design flaw in OpenBao, KeyCape or ops-warden. It is
the absence of a *batching* and *routing* layer between well-designed
lanes and one scarce person.
## 3. Proposals (ease of maintenance and extension)
**P1 — Gates are born routed.** Extend C-39: a `needs_human: true` wait
in an open, non-residual workplan without `decision_id` is a WARN. Owner
repos then attach a decision at the moment they create the gate, and the
hub's open-decision list *is* Bernd's queue. (state-hub, small.)
**P2 — The attended provisioning window is a standing event.** Instead
of per-lane sessions, one dated window (fortnightly is enough at current
volume). Its checklist is generated, not written: every task carrying
the window's `decision_id`, joined to its CCR and lane doc, rendered by
`credential-change.py` as a numbered attended sequence with the receipt
each owner needs. Owners prepare to that checklist; the session runs it
top to bottom; resolving the decision raises C-40 on every task.
(railiance-platform owns the renderer; the-custodian owns the cadence.)
**P3 — Decide the dual-control value path once.** The delegation doc
leaves "stronger dual-control" open. The honest options are (a) keep
values attended but batched (P2 alone), (b) response-wrapped delivery
where the issuing system writes the value into OpenBao under a
one-time wrapping token the operator only *unwraps*, or (c) a scoped
operator-write role under MFA used by a wrapped command that never
prints. Pick one in packet D3 alongside the trust-root ruling; it removes
the value step from most future lanes. (railiance-platform workplan.)
**P4 — Catalog lane as the unit of extension.** A new consumer today
costs a design workplan, a CCR, an attended apply and bespoke evidence.
Make the ops-warden catalog entry the template: entry + CCR skeleton +
policy/role rendering + ExternalSecret manifest + evidence script
scaffolded from one command. Then a new lane is a reviewed PR, not a
workplan, and only its value step needs the window. (ops-warden +
railiance-platform.)
**P5 — Owner-return sweep.** A weekly the-custodian task lists every
`blocked_on: message-from:<agent>` task whose awaited agent has an
unread or unanswered message older than seven days and nudges the owner
in one message per agent. It uses C-25 output, not a new mechanism.
**P6 — Keep the hub graph current.** Run `statehub fix-consistency --all
--remote` on railiance01 nightly so C-20 keeps the edge table equal to
the files, and finish the deploy that carries task-level edges. The
graph scripts in this triage can then run against the hub alone.
## 4. What this does not change
The hub stays a read model. Decisions were recorded through the
sanctioned route and every `decision_id` lives in the owner file, synced
by fix-consistency. No workplan or task was registered by hand. No
credential was requested, printed or moved.

View file

@ -9,7 +9,7 @@ owner: the-custodian
topic_slug: custodian
flavor: implementation
created: "2026-09-24"
updated: "2026-09-28"
updated: "2026-10-03"
related:
- KEY-WP-0033
- RPF-WP-0044
@ -183,6 +183,7 @@ id: CUST-WP-0073-T05
status: wait
priority: low
needs_human: true
decision_id: 1591daa1-6e85-4dfd-aadd-5a9fe1ef47fa
blocking_reason: "Deferred by founder decision 2026-09-24; reopened only by the founder on one of the three triggers below, in one attended rotation window."
state_hub_task_id: "1b41b532-38a2-5f39-b387-28737934811a"
```