wait-discipline: an idle signal is not completion — name the tree-state check #44

Closed
opened 2026-08-14 13:01:50 +00:00 by jbr870 · 2 comments
Owner

Rank 8 of 13 in #37 · harness defect + suite-side hardening

Evidence

Across /develop and QA on #230, five agents went idle without sending their completion report:

Agent What the tree actually showed
WU-230-3-1 Implementer committed d80ff97, no report
WU-230-3-3 Test Writer six files written, none committed — the unit was genuinely unfinished
test-quality (QA Stage A) report delivered only after a ping
fixer (QA round 1) committed 3bf3eed, no report
fixer2 (QA round 2) idled twice; never reported
sweep-hunter2 (QA final) load-bearing report delivered only after a ping

The orchestrator's handling was correct every time — check the tree first, then ask, never assume —
and it named the pattern explicitly: "Fourth agent to idle without reporting — that's a consistent
harness behaviour this session, and pinging has recovered it every time."

Prior sighting: implementer report-delivery friction already recorded as a comment on #11.

Why this is worth an issue rather than a watchlist entry

The recovery is only safe because wait-discipline.md already says silence means ask, not assume.
But the cost is real (minutes per occurrence, six occurrences in one feature), and one case —
WU-230-3-3 — would have been recorded as complete by a lead that trusted the idle signal.

Proposed change

  • Upstream: report this as a Claude Code harness defect (idle notification delivered, final
    report dropped).
  • Suite side: make the tree-state check on an unreported idle a named step in
    wait-discipline.md rather than a principle, with the explicit rule that an idle signal is
    never evidence a unit finished
    — only committed work plus a verified gate run is.

Acceptance

  • wait-discipline.md carries the named step and the "idle is not completion" rule.
  • The upstream report is filed and linked here.
**Rank 8 of 13** in #37 · harness defect + suite-side hardening ## Evidence Across `/develop` and QA on #230, **five agents went idle without sending their completion report**: | Agent | What the tree actually showed | |---|---| | WU-230-3-1 Implementer | committed `d80ff97`, no report | | WU-230-3-3 Test Writer | six files written, **none committed** — the unit was genuinely unfinished | | `test-quality` (QA Stage A) | report delivered only after a ping | | `fixer` (QA round 1) | committed `3bf3eed`, no report | | `fixer2` (QA round 2) | idled twice; never reported | | `sweep-hunter2` (QA final) | load-bearing report delivered only after a ping | The orchestrator's handling was correct every time — check the tree first, then ask, never assume — and it named the pattern explicitly: *"Fourth agent to idle without reporting — that's a consistent harness behaviour this session, and pinging has recovered it every time."* Prior sighting: implementer report-delivery friction already recorded as a comment on #11. ## Why this is worth an issue rather than a watchlist entry The recovery is only safe because `wait-discipline.md` already says silence means ask, not assume. But the cost is real (minutes per occurrence, six occurrences in one feature), and one case — WU-230-3-3 — would have been recorded as complete by a lead that trusted the idle signal. ## Proposed change - **Upstream:** report this as a Claude Code harness defect (idle notification delivered, final report dropped). - **Suite side:** make the tree-state check on an unreported idle a *named step* in `wait-discipline.md` rather than a principle, with the explicit rule that **an idle signal is never evidence a unit finished** — only committed work plus a verified gate run is. ## Acceptance - `wait-discipline.md` carries the named step and the "idle is not completion" rule. - The upstream report is filed and linked here.
Author
Owner

/meta-amend outcome — suite-side half amended; issue stays OPEN for the upstream report

Commit 8440c90 on main. Acceptance criterion 1 is met; criterion 2 is not, and I have deliberately not done it — see below.

Verified at HEAD (7879495)

The gap held. wait-discipline.md §1 carried the liveness caveat — "an agent that has sent nothing is unobserved, not dead" — which covers silence. It said nothing about the different failure mode this issue records: the idle notification arrives and the final report is dropped. Nothing in the file connected an idle signal to what may be written into a completion record, and the recovery the orchestrator performed correctly six times was a principle to be re-derived each occurrence, not a step.

The amendment (AC1)

New §1a — "An idle signal is not a completion signal — check the tree, then ask", placed inside rule 1 so the existing rules 1, 3, 5 consumer references keep their numbering:

  1. Read the tree, not the signal — within the agent's declared file boundaries: git log for its commit marker, git status for uncommitted/untracked work, and the result of whatever gate that unit owes. "Committed work plus a verified gate run is the only evidence a unit finished."
  2. Then ask it directly — one round-trip, per the existing liveness caveat, and explicitly after the tree read, not instead of it: "the tree tells you what the answer should say."
  3. Reconcile, and say which happened — tree shows the work → the report is missing, not the work: write the outcome from the tree, name the commits, record that it was reconstructed. Tree shows partial/uncommitted/no work → the unit is unfinished whatever the idle signal implied; it goes back to the agent or to the stall path.

Closing rule: "Never write a completion record on the strength of an idle notification — not a work-unit outcome, not a domain report, not a Phase Outcome. If the record cannot name the commits, there is nothing to record yet."

Consumers updated to point at it (not restate it): develop/SKILL.md §3.2 Waiting on the team — "an idle teammate is not a finished work unit", naming 3.4's completion record as what must not be reached; qa-playbook.md §2 — the existing pair of spawn-prompt rules gains one rule for the driver, since §1a is the driver's job, not the spawned role's.

Gate

scripts/lint-conventions.sh — clean.

Desk-check against the originating scenario (verity #230)

Walking each of the five recorded occurrences against §1a:

Agent Tree state §1a outcome
WU-230-3-1 Implementer committed d80ff97, no report step 1 finds the commit → step 3 first branch: outcome written from the tree, commits named, reconstruction recorded
WU-230-3-3 Test Writer six files written, none committed step 1 finds no commit → step 3 second branch: unfinished, back to the agent. This is the case the issue says "would have been recorded as complete by a lead that trusted the idle signal" — §1a's tree-first ordering is what catches it
test-quality (QA Stage A) report only after a ping step 2 recovers it; the driver rule in qa-playbook §2 is what makes the ping the expected move rather than an improvisation
fixer (QA round 1) committed 3bf3eed, no report as row 1
fixer2 (QA round 2) idled twice, never reported step 1 governs; whatever the tree shows decides, and no completion record is written without commits
sweep-hunter2 (QA final) load-bearing report only after a ping step 2; and the sweep's Phase Outcome cannot claim coverage until §1a resolves

The orchestrator's improvised handling was already correct every time — what the amendment buys is that it no longer has to be re-derived, and that the one dangerous case (row 2) is caught by the ordering rather than by the lead's judgement.

AC2 — the upstream report is NOT filed

"The upstream report is filed and linked here" asks for a defect report against the Claude Code harness (idle notification delivered, final report dropped). I have not filed it: that is an outward-facing report to a third party, not a skill-text amendment, and it is the operator's to make and sign. It is also outside /meta-amend's lane by definition.

This issue therefore stays open for that criterion alone. What a filer needs is all here: six occurrences in one feature across two skills, both Task-spawned subagents and Agent-Team teammates, idle notification delivered in each case, final report absent, and a direct message to the agent recovering the report every time. Prior sighting recorded as a comment on #11.

What validates it next

The next multi-teammate /dev:develop run that hits an unreported idle. The signal to watch is whether the tree read happens before the ping — the ordering is the whole value, and it is the part most likely to be skipped when the ping feels faster.

## /meta-amend outcome — suite-side half amended; issue stays OPEN for the upstream report Commit `8440c90` on `main`. **Acceptance criterion 1 is met; criterion 2 is not, and I have deliberately not done it — see below.** ### Verified at HEAD (`7879495`) The gap held. `wait-discipline.md` §1 carried the *liveness caveat* — "an agent that has sent nothing is *unobserved*, not dead" — which covers **silence**. It said nothing about the different failure mode this issue records: the idle notification **arrives** and the final report is dropped. Nothing in the file connected an idle signal to what may be written into a completion record, and the recovery the orchestrator performed correctly six times was a principle to be re-derived each occurrence, not a step. ### The amendment (AC1) New **§1a — "An idle signal is not a completion signal — check the tree, then ask"**, placed inside rule 1 so the existing `rules 1, 3, 5` consumer references keep their numbering: 1. **Read the tree, not the signal** — within the agent's declared file boundaries: `git log` for its commit marker, `git status` for uncommitted/untracked work, and the result of whatever gate that unit owes. *"Committed work plus a verified gate run is the only evidence a unit finished."* 2. **Then ask it directly** — one round-trip, per the existing liveness caveat, and explicitly **after** the tree read, not instead of it: "the tree tells you what the answer should say." 3. **Reconcile, and say which happened** — tree shows the work → the *report* is missing, not the work: write the outcome from the tree, name the commits, record that it was reconstructed. Tree shows partial/uncommitted/no work → the unit is **unfinished** whatever the idle signal implied; it goes back to the agent or to the stall path. Closing rule: *"Never write a completion record on the strength of an idle notification — not a work-unit outcome, not a domain report, not a Phase Outcome. If the record cannot name the commits, there is nothing to record yet."* Consumers updated to point at it (not restate it): `develop/SKILL.md` §3.2 *Waiting on the team* — "an idle teammate is not a finished work unit", naming 3.4's completion record as what must not be reached; `qa-playbook.md` §2 — the existing pair of spawn-prompt rules gains one rule for the **driver**, since §1a is the driver's job, not the spawned role's. ### Gate `scripts/lint-conventions.sh` — clean. ### Desk-check against the originating scenario (verity #230) Walking each of the five recorded occurrences against §1a: | Agent | Tree state | §1a outcome | |---|---|---| | WU-230-3-1 Implementer | committed `d80ff97`, no report | step 1 finds the commit → step 3 first branch: outcome written from the tree, commits named, reconstruction recorded | | **WU-230-3-3 Test Writer** | **six files written, none committed** | step 1 finds no commit → step 3 second branch: **unfinished**, back to the agent. This is the case the issue says "would have been recorded as complete by a lead that trusted the idle signal" — §1a's tree-first ordering is what catches it | | test-quality (QA Stage A) | report only after a ping | step 2 recovers it; the driver rule in qa-playbook §2 is what makes the ping the expected move rather than an improvisation | | fixer (QA round 1) | committed `3bf3eed`, no report | as row 1 | | fixer2 (QA round 2) | idled twice, never reported | step 1 governs; whatever the tree shows decides, and no completion record is written without commits | | sweep-hunter2 (QA final) | load-bearing report only after a ping | step 2; and the sweep's Phase Outcome cannot claim coverage until §1a resolves | The orchestrator's improvised handling was already correct every time — what the amendment buys is that it no longer has to be re-derived, and that the one dangerous case (row 2) is caught by the ordering rather than by the lead's judgement. ### AC2 — the upstream report is NOT filed *"The upstream report is filed and linked here"* asks for a defect report against the Claude Code harness (idle notification delivered, final report dropped). I have not filed it: that is an outward-facing report to a third party, not a skill-text amendment, and it is the operator's to make and sign. It is also outside `/meta-amend`'s lane by definition. **This issue therefore stays open** for that criterion alone. What a filer needs is all here: six occurrences in one feature across two skills, both `Task`-spawned subagents and Agent-Team teammates, idle notification delivered in each case, final report absent, and a direct message to the agent recovering the report every time. Prior sighting recorded as a comment on #11. ### What validates it next The next multi-teammate `/dev:develop` run that hits an unreported idle. The signal to watch is whether the tree read happens **before** the ping — the ordering is the whole value, and it is the part most likely to be skipped when the ping feels faster.
Author
Owner

Upstream half resolved — issue closed

Acceptance criterion 2 is met in adapted form: the defect was already reported upstream, so we confirmed rather than filed.

The canonical upstream report is anthropics/claude-code#84527 (open, active) — identical fingerprint: report fully written, payload-less idle notification delivered, final message dropped. Cluster context: #80727, #86471, #85047; earlier mechanism investigation #78338 (closed).

Our confirmation was posted on #84527 (2026-08-25, operator-pasted): Linux / 2.1.245, 9/9 idle notices delivered with 0/9 report messages (the two-panel evidence from #43, comment 1327), and — additive to their thread — the SendMessage resend also failed to deliver on 2.1.245 where it had recovered 6/6 on an older build, corroborating their reported ping-recovery regression; transcript extraction (subagents/*.jsonl) recovered all 9 reports.

Suite side was already done: wait-discipline.md carries the "idle is not completion" rule (commit 8440c90, comment 1286). Both AC halves are now met.

## Upstream half resolved — issue closed **Acceptance criterion 2 is met in adapted form: the defect was already reported upstream, so we confirmed rather than filed.** The canonical upstream report is [anthropics/claude-code#84527](https://github.com/anthropics/claude-code/issues/84527) (open, active) — identical fingerprint: report fully written, payload-less idle notification delivered, final message dropped. Cluster context: [#80727](https://github.com/anthropics/claude-code/issues/80727), [#86471](https://github.com/anthropics/claude-code/issues/86471), [#85047](https://github.com/anthropics/claude-code/issues/85047); earlier mechanism investigation [#78338](https://github.com/anthropics/claude-code/issues/78338) (closed). Our confirmation was posted on #84527 (2026-08-25, operator-pasted): Linux / 2.1.245, 9/9 idle notices delivered with 0/9 report messages (the two-panel evidence from #43, comment 1327), and — additive to their thread — the SendMessage resend also failed to deliver on 2.1.245 where it had recovered 6/6 on an older build, corroborating their reported ping-recovery regression; transcript extraction (`subagents/*.jsonl`) recovered all 9 reports. Suite side was already done: `wait-discipline.md` carries the "idle is not completion" rule (commit `8440c90`, comment 1286). Both AC halves are now met.
Sign in to join this conversation.
No description provided.