From 11e6202287d97ca80a855e654969a9631b253da7 Mon Sep 17 00:00:00 2001 From: codex Date: Mon, 28 Sep 2026 22:14:38 +0200 Subject: [PATCH] Propose Task Wait Qualifiers v0.1 and extend the task-block convention (CUST-WP-0074-T01) Co-Authored-By: Claude Fable 5.1 --- .claude/rules/workplan-convention.md | 17 ++- canon/standards/task-wait-qualifiers_v0.1.md | 138 +++++++++++++++++++ 2 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 canon/standards/task-wait-qualifiers_v0.1.md diff --git a/.claude/rules/workplan-convention.md b/.claude/rules/workplan-convention.md index 3f7995f..8b3d28c 100644 --- a/.claude/rules/workplan-convention.md +++ b/.claude/rules/workplan-convention.md @@ -20,8 +20,9 @@ depends_on: ``` Unset `flavor` is not residual. Do not implement `flavor: residual` unless -demand or risk has promoted it to another flavor. `depends_on` lists -blocker **workplan** ids; that is the field C-20 indexes. +demand or risk has promoted it to another flavor. Frontmatter `depends_on` +lists blocker **workplan** ids (C-20). Task-block `depends_on` (below) lists +what one task waits for and is indexed the same way. Closed workplans may be moved to `workplans/archived/` with a completion-date prefix: `YYMMDD-CUST-WP-NNNN-.md`. The frontmatter id remains @@ -44,12 +45,24 @@ Task blocks use this shape: id: CUST-WP-NNNN-T01 status: wait | todo | progress | done | cancel priority: high | medium | low +depends_on: [OTHER-WP-0001, OTHER-WP-0002-T03] # wait: external commitment +needs_human: true # wait: human gate +blocking_reason: "" # required whenever status is wait +decision_id: CCR-2026-0004 # optional, tracked decision behind a human gate state_hub_task_id: "" # written by fix-consistency — do not edit ``` Status progression is `todo` → `progress` → `done`; use `wait` for waiting or blocked work and `cancel` for stopped work. +A `wait` task must be qualified: `depends_on` (clears by itself when every +target is terminal — derived state `waiting-external`), `needs_human: true` +(a person clears it — derived state `needs-human`), or both. Neither is a +fix-consistency WARN. The kind is derived, not a stored status; see +`canon/standards/task-wait-qualifiers_v0.1.md`. A `blocked` workplan is +derived as `blocked-human` when any wait task is a human gate, else +`blocked-external`. + Workplan frontmatter carries `state_hub_workstream_id` — a legacy field name kept for compatibility; it holds the hub workplan UUID and is written by fix-consistency. Do not edit or rename it. diff --git a/canon/standards/task-wait-qualifiers_v0.1.md b/canon/standards/task-wait-qualifiers_v0.1.md new file mode 100644 index 0000000..7eea015 --- /dev/null +++ b/canon/standards/task-wait-qualifiers_v0.1.md @@ -0,0 +1,138 @@ +--- +id: canon-task-wait-qualifiers +type: standard +title: "Task Wait Qualifiers v0.1" +domain: custodian +status: proposed +version: "0.1" +owner: the-custodian +revision: "proposed-1" +last_reviewed: "2026-09-28" +review_interval: 6m +created: "2026-09-28" +updated: "2026-09-28" +scope: fleet +related_workplans: + - CUST-WP-0074 + - CUST-WP-0072 + - STATE-WP-0092 + - COORDINATION-WP-0005 + - RAIL-FAB-WP-0029 +supersedes: none +--- + +# Task Wait Qualifiers v0.1 + +## Purpose + +A task in `status: wait` must say what it waits for in a form the fleet can +read without a person. Two kinds of wait exist and need different handling: + +- **External commitment** — the task waits for another workplan or task to + reach a terminal state. It clears on its own; the waiting side observes. +- **Human gate** — the task waits for a decision, approval, attended + privileged action or operator-provisioned credential. Nothing in the fleet + clears it; a person does. + +`wait` stays the only stored status for both. The kind is a **derived state** +computed from qualifier keys, in the same way `stalled` and `needs_review` +are derived labels rather than stored statuses (ADR-001 workplan convention). + +Founder decision 2026-09-28 (`CUST-WP-0074`): derived states, not two new +stored statuses. Reason: a qualifier is additive — existing files stay valid +and a consistency warning migrates them one workplan at a time — whereas new +statuses force every consumer (hub enum, fix-consistency rank logic, Fabric +open-task set, ralph-workplan, dashboards) to change at once. + +## Shape + +No new task-block keys. Three keys that task blocks already carry become +meaningful together: + +```yaml +# 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" + +# 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 +``` + +A task may carry both (derived state: both). `decision_id` is the id of a +hub decision or a change request; it is optional and never a substitute for +`needs_human: true`. + +## Rules + +1. A `wait` task carries a `depends_on` list, `needs_human: true`, or both. + Neither → consistency WARN (unqualified wait), not auto-fixable. +2. `blocking_reason` stays required for `wait`. The hub API already refuses + `wait` without it; the file must carry it so the hub can be rebuilt from + files. +3. An external commitment is satisfied when every `depends_on` target is + terminal: task targets `done` or `cancel`, workplan targets `finished` or + `archived` (coordination-model v0.2 §5 commitment rule). A task still + `wait` after satisfaction → consistency WARN (blocker satisfied). Targets + the hub cannot resolve produce no warning. +4. A human gate is satisfied by the person's recorded action in the task text, + or — when `decision_id` is set — by that decision resolving, which raises + the same WARN. +5. Workplan `blocked` stays stored. The hub derives `blocked-human` when any + wait task is a human gate, else `blocked-external` when any is an external + commitment, else `none`. "Everything waiting on a person" is therefore one + query, not a reading exercise. +6. A wait on a repo that has no workplan id yet is an external commitment + with the repo named in `blocking_reason` and in the workplan-level + `blocked_on:` field (watched by C-25). Upgrade to a `depends_on` id as + soon as the owner returns one. +7. A human-gate task is never leased to a worker. Coordination tooling treats + `needs_human: true` as a stop, not a wake condition. + +## Scope of `depends_on` + +- Workplan-frontmatter `depends_on` (C-20) is unchanged: it declares + workplan-level blockers. +- Task-block `depends_on` is the commitment surface this standard adds. It is + indexed into the same hub dependency table with the waiting task as the + from side. +- `related:` is context, never a commitment. + +## Derived state names + +| Stored | Qualifier | Derived task state | Hub field | +|---|---|---|---| +| `wait` | `depends_on` only | `waiting-external` | `wait_kind: external` | +| `wait` | `needs_human: true` only | `needs-human` | `wait_kind: human` | +| `wait` | both | both | `wait_kind: both` | +| `wait` | neither | unqualified (WARN) | `wait_kind: unqualified` | + +Workplan: `blocked_kind` ∈ `human` \| `external` \| `none`, null unless +`status: blocked`. + +## Consumers + +- **state-hub** — fix-consistency indexes task-block `depends_on`, emits the + two warnings, syncs `needs_human` / `blocking_reason` / `decision_id` from + file to hub, exposes `wait_kind` and `blocked_kind` on the read model. +- **coordination-engine** — `cross-owner-wait-mode` enters from task-block + `depends_on`; the ontology gains commitment `kind: decision` for human + gates. +- **railiance-fabric** — the coordination graph colours commitment edges and + human-gate nodes distinctly and offers a needs-human-only view. +- **ralph-workplan** — the loop never picks up a `needs_human` task and its + "all tasks done" retirement rule is unaffected. + +## Migration + +Existing `wait` tasks without a qualifier remain valid files. The unqualified +WARN drives the backfill (`CUST-WP-0074-T05`), gate roots first. Do not +touch `flavor: residual` workplans. + +## Review + +Proposal-then-review. Acceptance is recorded in `CUST-WP-0074-T01`; on +acceptance set `status: accepted`, `revision: accepted-1`.