Propose Task Wait Qualifiers v0.1 and extend the task-block convention (CUST-WP-0074-T01)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
codex 2026-09-28 22:14:38 +02:00
parent 42a262bf83
commit 11e6202287
2 changed files with 153 additions and 2 deletions

View file

@ -20,8 +20,9 @@ depends_on:
``` ```
Unset `flavor` is not residual. Do not implement `flavor: residual` unless Unset `flavor` is not residual. Do not implement `flavor: residual` unless
demand or risk has promoted it to another flavor. `depends_on` lists demand or risk has promoted it to another flavor. Frontmatter `depends_on`
blocker **workplan** ids; that is the field C-20 indexes. 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 Closed workplans may be moved to `workplans/archived/` with a completion-date
prefix: `YYMMDD-CUST-WP-NNNN-<slug>.md`. The frontmatter id remains prefix: `YYMMDD-CUST-WP-NNNN-<slug>.md`. The frontmatter id remains
@ -44,12 +45,24 @@ Task blocks use this shape:
id: CUST-WP-NNNN-T01 id: CUST-WP-NNNN-T01
status: wait | todo | progress | done | cancel status: wait | todo | progress | done | cancel
priority: high | medium | low priority: high | medium | low
depends_on: [OTHER-WP-0001, OTHER-WP-0002-T03] # wait: external commitment
needs_human: true # wait: human gate
blocking_reason: "<why, one line>" # required whenever status is wait
decision_id: CCR-2026-0004 # optional, tracked decision behind a human gate
state_hub_task_id: "<uuid>" # written by fix-consistency — do not edit state_hub_task_id: "<uuid>" # written by fix-consistency — do not edit
``` ```
Status progression is `todo` → `progress` → `done`; use `wait` for waiting or Status progression is `todo` → `progress` → `done`; use `wait` for waiting or
blocked work and `cancel` for stopped work. 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 Workplan frontmatter carries `state_hub_workstream_id` — a legacy field name
kept for compatibility; it holds the hub workplan UUID and is written by kept for compatibility; it holds the hub workplan UUID and is written by
fix-consistency. Do not edit or rename it. fix-consistency. Do not edit or rename it.

View file

@ -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`.