the-custodian/canon/standards/task-wait-qualifiers_v0.1.md
codex d9652d5ec0
Some checks are pending
CI Smoke / host-smoke (push) Waiting to run
CI Smoke / container-smoke (push) Waiting to run
Python Tests / pytest (push) Successful in 28s
Task Wait Qualifiers rule 6: owner-return waits use blocked_on: message-from:<agent>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-28 23:16:48 +02:00

5.6 KiB

id type title domain status version owner revision last_reviewed review_interval created updated scope related_workplans supersedes
canon-task-wait-qualifiers standard Task Wait Qualifiers v0.1 custodian accepted 0.1 the-custodian accepted-1 2026-09-28 6m 2026-09-28 2026-09-28 fleet
CUST-WP-0074
CUST-WP-0072
STATE-WP-0092
COORDINATION-WP-0005
RAIL-FAB-WP-0029
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:

# 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 another owner's reply, with no workplan id yet, is an external commitment qualified by blocked_on: message-from:<agent> on the task block — the vocabulary C-25 already watches for unread replies. The consistency check accepts it in place of depends_on; the hub read model reports such a task as unqualified until an id exists, so 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.