From 49f505615a05168ec341ccb9848fb8acf64e2ada Mon Sep 17 00:00:00 2001 From: codex Date: Mon, 28 Sep 2026 20:52:02 +0200 Subject: [PATCH] Draft CUST-WP-0074: qualify task wait states (external vs human gate) Derived-state shape chosen over new stored statuses; reuses task-block depends_on, needs_human and blocking_reason. Blocked-workplan graph snapshot recorded under history/. Co-Authored-By: Claude Fable 5.1 --- history/20260928-blocked-workplan-graph.md | 93 +++++++ .../CUST-WP-0074-qualified-wait-states.md | 229 ++++++++++++++++++ 2 files changed, 322 insertions(+) create mode 100644 history/20260928-blocked-workplan-graph.md create mode 100644 workplans/CUST-WP-0074-qualified-wait-states.md diff --git a/history/20260928-blocked-workplan-graph.md b/history/20260928-blocked-workplan-graph.md new file mode 100644 index 0000000..1f12690 --- /dev/null +++ b/history/20260928-blocked-workplan-graph.md @@ -0,0 +1,93 @@ +# Blocked workplan graph — 2026-09-28 + +Snapshot taken from the State Hub primary on 2026-09-28 for `CUST-WP-0074`. +Edges were extracted from the text of `wait` tasks (workplan-id references +by regex; repo-only references read by hand), because only 7 formal +dependency edges existed among open workplans. Treat the fan-out counts as +prioritisation evidence, not verified edges. + +## Numbers + +- 1465 workplans in the hub: 1297 finished, 53 archived, 108 blocked + (105 after excluding `@retired` slugs), 3 proposed, 2 backlog, 2 active. +- 220 `wait` tasks in the blocked set; 29 set `blocking_reason`, 5 set + `needs_human`. +- 48 blocked workplans have exactly one wait task (single gate). +- 6 blocked workplans have no wait task at all. +- Only 2 blocked workplans untouched since 2026-09-01 — this is not rot, + it is stranded waits. + +## Existing modelling found + +| Layer | What exists | +|---|---| +| State Hub | `workplan_dependencies` table, `/workplans/{id}/dependencies/`, C-20 indexes frontmatter `depends_on`; task columns `needs_human`, `intervention_note`, `blocking_reason`; workplan frontmatter `blocked_on:` watched by C-25 | +| railiance-fabric | `coordination_graph.py`, `export --format coordination`, `/ui/graph-explorer?mode=coordination` (`RAIL-FAB-WP-0029`, blocked on hosting under `RAIL-FAB-WP-0028`) | +| coordination-engine | `spec/coordination-model-v0.2.md` (`depends_on` as commitment), `spec/cross-owner-wait-mode-v0.1.md` (specified, not live) | + +Decision: improve these; do not create a `helix-fabric` sibling. + +## Gate roots (fan-out on the right) + +``` +R1 FLEX-WP-0020 (rename → access-engine) + ├─ NK-WP-0039 ├─ RAIL-FAB-WP-0031 ├─ REUSE-WP-0023 ├─ USER-WP-0034 + └─ RCLK-WP-0002 (needs an access-engine contract) + +R2 Operator credential provisioning (OpenBao; CCR-2026-0004; scoped attended applies) + ├─ RPF-WP-0035 → SECRETS-WP-0008 + ├─ SECRETS-WP-0006 / 0007 / 0009 ; MASON-WP-0004 / 0005 + ├─ SAND-WP-0015 → SAND-WP-0014 → GLAS-WP-0012 → GLAS-WP-0015 + ├─ IR-WP-0005 + IR-WP-0006 → IR-WP-0007 + ├─ RPF-WP-0015 / 0027 / 0038 ; RAIL-HO-WP-0012 + └─ WARDEN-WP-0027 / 0034 / 0039 / 0040 + +R3 audit-core owner returns (intake replies) + ├─ FLEX-WP-0031 ├─ NK-WP-0031 ├─ NK-WP-0040 ├─ APPROVAL-WP-0002 + └─ INFO-WP-0029 ; TEN-WP-0012 ; NK-WP-0035 (needs info-tech-canon) + +R4 Two real users on Vergabe (VERGABE-WP-0019, human acceptance) + ├─ RAPPS-WP-0014 ├─ VERGABE-WP-0018 (also HFACT-WP-0001-T05, active) + └─ CUST-WP-0071 ← measurements ← RAPP-QONTO-WP-0002, FIN-WP-0004 + +R5 ArgoCD lane (sequential) + RPF-WP-0044 → RPF-WP-0043 → RAPP-POLICY-NEXUS-WP-0002 → MASON-WP-0006 (dated 2026-12-21) + RPF-WP-0048 (+24h soak) → ACTIVITY-WP-0041 → ACTIVITY-WP-0040 ; ACTIVITY-WP-0032 + +R6 State Hub retirement / Fabric authority + RAIL-FAB-WP-0028 → RAIL-FAB-WP-0029 ; STATE-WP-0079 → HUB-WP-0006 / 0011 / 0012 + RAPPCOREHUB-WP-0003 → RAPPCOREHUB-WP-0002 → CORE-WP-0010 ; ORGREF-WP-0001 + +R7 Clock: RCLK-WP-0002 (four engines' contracts) + RCLK-WP-0005 → RCLK-WP-0004 ; RAIL-HO-WP-0013 + +R8 Identity: KEY-WP-0035, NK-WP-0033 custody, privacyidea token non-resolvable + → USER-WP-0026 / 0027 / 0028 / 0037, HUB-WP-0012, NK-WP-0042, KEY-WP-0013 +``` + +Most-referenced targets by extracted in-degree: SECRETS-WP-0007 (6), +HFACT-WP-0001 (6, active), SECRETS-WP-0010 (5, finished — a stale wait +signal), SECRETS-WP-0006 (4), STATE-WP-0079 (4), SAND-WP-0015 (4), +VERGABE-WP-0019 (4). + +## Unblock order (fan-out per unit of effort) + +1. Execute `FLEX-WP-0020` — one owner, scripted preflight, 5 dependents. +2. One attended OpenBao provisioning session — clears R2 and the HIGH + open item on CNPG backups (`RAILIANCE-WP-0015`). +3. Ask audit-core for its intake replies (R3) via the cross-owner-wait + pattern; do not reassign their tasks. +4. Get two real users into Vergabe (R4); `CUST-WP-0071` waits on it too. +5. Run the ArgoCD lane in order (R5); the soak is time-gated. +6. Finish `RAIL-FAB-WP-0028` — unblocks the graph view and the retirement + chain. +7. Park the time-gated ones: `MASON-WP-0006` (2026-12-21), the + `NK-WP-0022` / `RMASTER-WP-0020` retention windows, + `WHITEHAT-WP-0006` / `0008` (need a named target owner). + +## Hygiene (not really blocked) + +No wait task: `fluid-wp-0008`, `fluid-wp-0009`, `ft-wp-0001`, +`glas-wp-0015`, `key-wp-0013`, `three-phoenix-ha-cluster`. Self-ordering +chain: `FEP-WP-0002 → 0003 → 0004`, plus `0006`, `0008`. Trivial gate: +`testdrive-jsui-publication`. Roughly 15 workplans; the real blocked set +is 85–90. diff --git a/workplans/CUST-WP-0074-qualified-wait-states.md b/workplans/CUST-WP-0074-qualified-wait-states.md new file mode 100644 index 0000000..4b739ca --- /dev/null +++ b/workplans/CUST-WP-0074-qualified-wait-states.md @@ -0,0 +1,229 @@ +--- +id: CUST-WP-0074 +type: workplan +title: "Qualify task wait states: external commitment versus human gate" +domain: infotech +repo: the-custodian +status: ready +owner: the-custodian +topic_slug: custodian +flavor: planning +created: "2026-09-28" +updated: "2026-09-28" +related: + - CUST-WP-0072 + - STATE-WP-0092 + - COORDINATION-WP-0005 + - RAIL-FAB-WP-0029 + - CUST-WP-0071 +origin: analysis +origin_ref: the-custodian/history/20260928-blocked-workplan-graph.md +--- + +# Qualify task wait states: external commitment versus human gate + +## Why + +On 2026-09-28 the hub held 105 blocked workplans (retired slugs excluded) +with 220 `wait` tasks between them. The blocker was recorded as prose in +the task text. Only 7 dependency edges existed in `workplan_dependencies` +across all open workplans, and only 5 of the 220 wait tasks set +`needs_human`. Nothing could answer "which of these only Bernd can +unblock" or "which clear on their own when `FLEX-WP-0020` finishes" +without reading every task. + +Reading them shows two different kinds of wait: + +- **Case A — external commitment.** The task waits for another repo's + workplan or task to reach a terminal state. It clears by itself; the + waiting side only needs to observe. Example: five workplans wait on + the `flex-auth` → `access-engine` rename (`FLEX-WP-0020`). +- **Case B — human gate.** The task waits for a decision, an approval, an + attended privileged action, or a credential provisioned by an operator. + Nothing in the fleet clears it; a person does. Example: about 25 + workplans sit behind one attended OpenBao provisioning session + (`CCR-2026-0004` and the per-lane scoped applies). + +Both are `wait` today. Founder decision 2026-09-28: keep `wait` as the +stored status and qualify it, deriving two visible states from the +qualifier. This follows the existing convention that `stalled` and +`needs_review` are derived labels, not stored statuses +(`.claude/rules/workplan-convention.md`). Two new stored statuses were +rejected: every consumer (hub enum, fix-consistency rank logic, Fabric +`OPEN_TASK`, ralph-workplan, dashboards) would have to change at once +across 1465 workplans, whereas a qualifier is additive and a WARN drives +migration one workplan at a time. + +Analysis, gate roots and the extracted graph: +`history/20260928-blocked-workplan-graph.md`. + +## The shape + +No new keys. Three keys that task blocks already carry become meaningful +together: + +```yaml +# Case A — external commitment → derived state: waiting-external +status: wait +depends_on: [FLEX-WP-0020] # workplan id or task id (KEY-WP-0035-T02) +blocking_reason: "access-engine rename must land first" + +# Case B — human gate → derived state: needs-human +status: wait +needs_human: true +blocking_reason: "operator must provision NC_WEBDAV/AGE creds to OpenBao" +decision_id: CCR-2026-0004 # optional, when a tracked decision exists +``` + +Rules: + +1. A `wait` task carries `depends_on` (Case A), `needs_human: true` + (Case B), or both. Neither → consistency WARN. +2. `blocking_reason` stays required for `wait` (the hub API already + refuses `wait` without it). +3. Case A is satisfied when every `depends_on` target is `done`, + `finished` or `archived` — the coordination-model v0.2 commitment + rule. A task still `wait` past satisfaction → consistency WARN. +4. Case B is satisfied by a resolved decision or by the human's recorded + action in the task text; when `decision_id` is set, resolution of that + decision triggers the same WARN. +5. Workplan `blocked` stays stored. The hub derives `blocked-external` + when all its wait tasks are Case A, `blocked-human` when any is Case + B, so "everything waiting on a person" is one query. +6. A wait on a repo that has no workplan id yet stays Case A with the + repo named in `blocking_reason` and the workplan-level `blocked_on:` + field (C-25). Upgrade to a `depends_on` id as soon as the owner + returns one. + +The workplan-level `depends_on` (C-20) is unchanged. Task-level +`depends_on` is the new commitment surface; `related:` stays context. + +## Write the standard and update the convention + +```task +id: CUST-WP-0074-T01 +status: todo +priority: high +``` + +Owner: the-custodian. + +- `canon/standards/task-wait-qualifiers_v0.1.md`: the shape above, the + six rules, the derived-state names, and the satisfaction rule cross- + referenced to `coordination-engine/spec/coordination-model-v0.2.md` §5. +- `.claude/rules/workplan-convention.md`: extend the task-block template + and the status-progression paragraph; state that `wait` without a + qualifier is a WARN once T02 ships. +- `~/ralph-workplan/workplan-spec.md`: same template extension, so the + loop's "all tasks done" check is unaffected and it never picks up a + `needs_human` task. +- Human-gated: canon goes through proposal-then-review. Commit the + proposal, then record the founder's acceptance here. + +## Hand off enforcement and indexing to state-hub + +```task +id: CUST-WP-0074-T02 +status: todo +priority: high +``` + +Owner: state-hub. This task is the handoff and its acceptance; the +implementation lives in a `STATE-WP` workplan whose id gets recorded in +`depends_on` here once it exists. + +Requested, by hub message to `state-hub`: + +- C-20 reads task-block `depends_on` (workplan and task ids) and writes + `workplan_dependencies` rows with the waiting task as the from side — + the table has `to_task_id`; check whether a `from_task_id` column is + needed or whether `from_workplan_id` plus description suffices. +- New check (next free C-id): `wait` task with neither task-block + `depends_on` nor `needs_human: true` → WARN, not fixable. +- New check: `wait` task whose every `depends_on` target is terminal, or + whose `decision_id` is resolved → WARN "blocker satisfied", not fixable. +- `needs_human`, `blocking_reason` and `decision_id` written from file to + hub on sync (columns exist; `decision_id` may need one). +- `GET /tasks/` and `GET /workplans/` expose a derived `wait_kind` / + `blocked_kind` field per rule 5. Read model only — no new write route. + +Acceptance: the four checks run green against this repo, and the derived +fields answer for `CUST-WP-0074-T05` below. + +## Hand off the ontology addendum to coordination-engine + +```task +id: CUST-WP-0074-T03 +status: todo +priority: medium +``` + +Owner: coordination-engine. + +- `spec/coordination-model-v0.2.md` §5 gains commitment `kind: decision` + for Case B, obligor = the named human or decision id, satisfaction = + decision resolved. Case A is the existing `kind: completion`. +- `spec/cross-owner-wait-mode-v0.1.md` entry condition 1 changes from + "names another repo, owner, or workplan id" in prose to task-block + `depends_on`; the prose form remains a fallback until the T05 backfill + is complete. +- Human-gate cases must never be leased to a worker; make that explicit + in the Act section. + +## Hand off the view to railiance-fabric + +```task +id: CUST-WP-0074-T04 +status: todo +priority: medium +``` + +Owner: railiance-fabric, under `RAIL-FAB-WP-0029`. + +- `coordination_graph.py` reads task-block `depends_on` for edges and the + derived `wait_kind` for colour: external commitment versus human gate. +- Chokepoint sizing already uses in-degree; add a filter for + `needs-human` only, so the operator's queue is one view. +- Fabric remains a read of State Hub. No authoring. + +## Backfill the open wait tasks + +```task +id: CUST-WP-0074-T05 +status: wait +priority: high +needs_human: false +depends_on: [CUST-WP-0074-T01, CUST-WP-0074-T02] +blocking_reason: "Standard must be accepted (T01) and the unqualified-wait WARN must exist (T02) before touching foreign workplan files." +``` + +Owner: the-custodian, following the `CUST-WP-0072` backfill pattern: +edit files in each repo, commit, run fix-consistency, never patch the hub +directly. + +- Start with the gate roots in the history record (R1–R8): qualifying + those roughly 60 tasks turns the largest fan-outs into real edges. +- Case B tasks: set `needs_human: true`; attach `decision_id` where a + CCR or hub decision exists (`CCR-2026-0004` covers the offsite-backup + lane). +- Case A tasks: convert the referenced id in the prose to `depends_on`. +- Leave `flavor: residual` workplans alone. +- Done when the unqualified-wait WARN count for open workplans is zero. + +## Correct the mis-blocked workplans + +```task +id: CUST-WP-0074-T06 +status: todo +priority: low +``` + +Owner: the-custodian coordinates; each repo owner edits. + +Six blocked workplans have no `wait` task at all (`fluid-wp-0008`, +`fluid-wp-0009`, `ft-wp-0001`, `glas-wp-0015`, `key-wp-0013`, +`three-phoenix-ha-cluster`); the `FEP-WP-0002/0003/0004/0006/0008` chain +is self-ordering inside one repo; `testdrive-jsui-publication` waits on +a submodule init. Message each owner with the finding and the +qualifier rule. Do not edit their files or reassign their tasks. Record +the outcome per workplan here.