From a85e0c8be0bdc205f38116aa07efaf07b861be36 Mon Sep 17 00:00:00 2001 From: thisisjun786 <259586770+thisisjun786@users.noreply.github.com> Date: Tue, 15 Sep 2026 04:53:45 +0900 Subject: [PATCH 1/7] [agent] docs(plan): define evidence-based subagent retirement --- .../260915_subagent_retirement/000_plan.md | 84 +++++++++++++++++++ .../260915_subagent_retirement/010_policy.md | 63 ++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 devlog/_plan/260915_subagent_retirement/000_plan.md create mode 100644 devlog/_plan/260915_subagent_retirement/010_policy.md diff --git a/devlog/_plan/260915_subagent_retirement/000_plan.md b/devlog/_plan/260915_subagent_retirement/000_plan.md new file mode 100644 index 00000000..c976b888 --- /dev/null +++ b/devlog/_plan/260915_subagent_retirement/000_plan.md @@ -0,0 +1,84 @@ +# Require evidence before retiring a subagent + +An executor can still be investigating while its working tree is clean. Issue +[#178](https://github.com/lidge-jun/codexclaw/issues/178) records a worker stopped +seconds after a successful read. This unit replaces the wait-count heuristic with +an activity-based decision procedure in the existing waiting reference. It also +keeps repeated busywork, explicit limits and safe handoff in view. + +## Scope and completion + +- Class C2; one satisfy-spec PABCD work-phase, `wp1`. +- Trigger: implement #178 and open a linked pull request. +- Goal: a coordinator can distinguish slow progress, suspected stagnation, + confirmed failure and unavailable observations before deciding to retire. +- Out: runtime watchdogs, provider retries, new configuration/schema fields, + installed-payload changes, merge, release and deployment. +- Tools: local Git/source reads, native V1 subagents, existing checks and GitHub + branch/PR publication. Writes stay in this task's linked worktree and native + session evidence. No user token/cost/wall-clock budget was specified; preserve + explicit limits when present and do not invent a universal timeout. +- Verifier: the baseline commands below plus independent semantic review of + [the scenario matrix](010_policy.md#acceptance-scenarios). +- Stop: close the cycle with verified text and publish an ordinary PR to `dev`. + DONE requires a linked PR and accurate check results; unmet evidence stays + incomplete. Host limits or cancellation are reported as such, never success. +- Memory artifact: this unit, then its `_fin/` archive; raw consultation/dispatch + handles and receipts remain in untracked native session evidence. +- Escalation: main resolves scope/judgment gaps. A new worker handoff requires a + plan amendment. Retirement and replacement follow managed dispatch results; + `reconcile`/`stop` never authorize direct work or another spawn. + +## Existing owners and baseline + +`plugins/codexclaw/skills/loop/references/waiting.md:31-35` retires after about +three waits. `structure/20_pabcd_dispatch_doctrine.md:181-195` includes bare +timeout among failure reasons. The V1 table in +`plugins/codexclaw/skills/pabcd/references/delegation.md:133` calls a wait timeout +a normal outcome. The waiting reference already owns the shared decision rule; +the other files should point to it rather than copy a second classifier. + +Verified on upstream `dev` at `03541398` before edits: + +| Command | Result | What it observes | +| --- | --- | --- | +| `npm run gate` | exit 0 | `gate.mjs` scans skill references and `structure/*.md` for claim hygiene and checks inventory; not retirement semantics | +| `node plugins/codexclaw/scripts/test.mjs plugins/codexclaw/test/manifest-policy.test.mjs` | 7 pass, 0 fail | existing owner-route resolution includes `waiting.md`; not model behavior | + +No phrase-presence test or unused decision helper will be added. They would test +the wording or a second implementation that the coordinator never executes +(`dev-testing` TEST-PROMPT-SEAM-01). The source is agent-followed E7 guidance; +execution surface: main's judgment; bypass: ignore/misread it; residual: model +variance and missing observations; final enforcement layer: none. + +## Architect consultation and main decisions + +The native V1 architect proposed D1-D5 from the owner files. Its initial proposal +included phrase tests; its revised proposal withdrew them after the existing +testing rule was supplied. Actual handle, proposal and reflection are retained +with this session's dispatch evidence, outside published project documents. + +| Decision | Main disposition | +| --- | --- | +| D1 trigger taxonomy | Accept with amendment: a confirmed stop/cancel is not automatically a provider failure. Separate wait timeout, terminal error and evidenced stagnation. | +| D2 activity evidence | Accept with amendment: new reads or command events are candidate evidence only when they advance the packet. Repeated reads/messages prompt investigation, not an automatic new count threshold. | +| D3 checkpoint | Accept: use supported non-interrupting delivery, explain queued-input limits, request findings/remaining work/next artifact. Reviewers report next review result, not a forced first edit. | +| D4 retirement evidence | Amend: record decision before stop; verify terminal state and owned processes after stop. A returned *previous* `running` status does not prove termination. Preserve managed fallback gates. | +| D5 observation and proof | Accept revised semantic review. No assumed access to child rollouts. Do not link installed skills to repository-only devlogs. | + +No-code alternatives: doing nothing retains the contradiction; merely lengthening +three waits still mistakes elapsed observations for failure; a runtime helper has +no existing consumer and expands this change. Reuse the current protocol owners. + +Reflection of this concrete plan: ALIGNED on D1-D5, with the named main +amendments accepted. Independent A audit: PASS, no blockers. S3 now explicitly +permits retirement only after stagnation is evidenced; the canonical recovery +rule must also govern shorthand references such as `plan-output.md:18`. + +## Change ownership + +The executor owns the four bounded source-document edits listed in +[010_policy.md](010_policy.md). Main owns this plan, semantic acceptance decisions, +consultation records, final review/integration, checks and publication. One commit +may carry the coherent document fix; follow repository `[agent] fix(...)` style. +No branch stacking is needed. Preserve unrelated local integration work. diff --git a/devlog/_plan/260915_subagent_retirement/010_policy.md b/devlog/_plan/260915_subagent_retirement/010_policy.md new file mode 100644 index 00000000..7b796ffd --- /dev/null +++ b/devlog/_plan/260915_subagent_retirement/010_policy.md @@ -0,0 +1,63 @@ +# wp1: Change the retirement decision at its existing owners + +Depends on `000_plan.md` D1-D5. One C2 work-phase; no production code or new types. + +## Exact edit map + +| File | Before | After | Owner | +| --- | --- | --- | --- | +| `plugins/codexclaw/skills/loop/references/waiting.md` | final bullet retires after about three waits | Replace that bullet with compact progress/checkpoint/retirement sections. Keep existing peer boundary and V1/V2 wait visibility. | executor | +| `structure/20_pabcd_dispatch_doctrine.md` | DISPATCH-RETIRE-01 treats bare timeout as failure and implies unconditional replacement/reclaim | Refer to waiting's evidence rule; qualify timeout as actual terminal error only; keep bounded recovery but defer managed replacement/reclaim to protocol result. | executor | +| `plugins/codexclaw/skills/pabcd/references/delegation.md` | wait route and normal-timeout table; generic failure recovery | Clarify non-interrupting checkpoint delivery and timeout observation. Preserve transport schemas and existing first-fallback gates. | executor | +| `CHANGELOG.md` | empty Unreleased | One concise Fixed entry for #178, explicitly agent-followed guidance. | executor | + +The waiting rule must distinguish substantive progress, suspected stagnation, +confirmed failure and unavailable observation. Refresh task-scoped observations +just before retiring. Liveness alone and file timestamps alone do not prove +semantic progress; no edits alone do not prove a stall. A healthy long command +may have sparse output and must be inspected before cancellation. + +For suspected stagnation, request one non-interrupting checkpoint where supported, +then compare new evidence with the prior observation at a stated, task-appropriate +next review point. Repeated/no-op work must not reset that review point forever. +That review point is not a new cancellation budget. An unread queued message and +silence with missing visibility do not confirm a stall. If an opaque task cannot +be assessed within authorized limits, report the observation gap and seek direction +without claiming failure or silently replacing it. + +Explicit cancellation, actual terminal failures and stated user/host resource +limits take precedence over progress. Keep cancellations/exhausted limits separate +from provider errors. Record pre-stop reason and last meaningful activity, then +post-stop terminal state, owned processes/partial edits, retained results and +remaining work. If termination is unknown, no overlapping writer may be started. +Managed `ready` requires a new claim; `main-direct` permits reclaim; +`reconcile`/`stop` permit neither. Never manufacture an OCX error code for a stall. + +## Acceptance scenarios + +These are semantic review cases, not executable runtime tests. A fresh C reviewer +must derive actions from the final policy and name ambiguities before acceptance. + +| ID | Activation | Expected observable decision | +| --- | --- | --- | +| S1 | Four waits, no edits, nine meaningful reads; last read seconds ago | keep active; no retirement from polls/clean Git | +| S2 | A long build is running with sparse output and no expired limit | inspect command state; sparse output alone cannot retire | +| S3 | Same unchanged reads/status repeatedly; delivered checkpoint and later comparable observations show no advancement | eligible to retire once stagnation is evidenced at the stated review point; repeats alone only prompt investigation | +| S4 | No child log access; clean Git; checkpoint may still be queued | observation unavailable; no invented failure or unanswered-message deadline | +| S5 | Native V2 wait reports updates without final text | obtain the separately delivered answer before judging | +| S6 | Actual terminal error | preserve original error and use managed failure/reconciliation path | +| S7 | User cancels or an explicit resource bound expires despite progress | stop within authority; report cancellation/bound, not provider failure | +| S8 | Stop call returns previous status `running` | verify current terminal state and owned jobs before handoff | +| S9 | Failure report returns `reconcile` or `stop` | neither direct implementation nor replacement spawn | +| S10 | New irrelevant reads or identical heartbeats keep arriving | liveness only; do not postpone reassessment forever | +| S11 | Reviewer produces no files while making new findings | treat review artifacts as progress; never require an edit | +| S12 | Finished child still has a queued checkpoint response/turn | reconcile actual current status; a checkpoint request is not permission to duplicate work | + +## Verification and delivery + +Run `npm run gate`, the existing manifest-policy test command in `000_plan.md`, +and `git diff --check`. Review links and all active retirement-rule references. +The first two checks already ran successfully at baseline; whitespace check is +mechanical only. No typecheck/build is claimed for prose. Record per-scenario +review and limitations in `011_verification.md`, archive this unit at completion, +and publish an ordinary fork PR to upstream `dev` with `Closes #178`. From 3767ae8826866ad1186639763b25de8d03bf06fc Mon Sep 17 00:00:00 2001 From: thisisjun786 <259586770+thisisjun786@users.noreply.github.com> Date: Tue, 15 Sep 2026 05:13:44 +0900 Subject: [PATCH 2/7] [agent] fix(delegation): require evidence before retiring subagents --- CHANGELOG.md | 10 ++++ .../260915_subagent_retirement/000_plan.md | 17 ++++++ .../260915_subagent_retirement/010_policy.md | 0 .../011_verification.md | 59 +++++++++++++++++++ .../skills/loop/references/waiting.md | 58 ++++++++++++++++-- .../skills/pabcd/references/delegation.md | 12 +++- structure/20_pabcd_dispatch_doctrine.md | 17 ++++-- 7 files changed, 162 insertions(+), 11 deletions(-) rename devlog/{_plan => _fin}/260915_subagent_retirement/000_plan.md (86%) rename devlog/{_plan => _fin}/260915_subagent_retirement/010_policy.md (100%) create mode 100644 devlog/_fin/260915_subagent_retirement/011_verification.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 96dee162..12b653bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,16 @@ All notable changes to codexclaw are documented here. The format follows ## [Unreleased] +### Fixed + +- Subagent waiting guidance instructed coordinators to retire workers after + about three empty waits, even when analysis could still be progressing. + `waiting.md` now requires evidence of progress or stagnation, preserves + unavailable observations, and uses non-interrupting checkpoints. Delegation + and DISPATCH-RETIRE-01 clarify actual shutdown checks and managed recovery; + cancellation or exhausted limits grant no retry or replacement. This changes + agent-followed guidance, not runtime enforcement (#178). + ## [0.2.28] - 2026-09-14 ### Fixed diff --git a/devlog/_plan/260915_subagent_retirement/000_plan.md b/devlog/_fin/260915_subagent_retirement/000_plan.md similarity index 86% rename from devlog/_plan/260915_subagent_retirement/000_plan.md rename to devlog/_fin/260915_subagent_retirement/000_plan.md index c976b888..5fa48a15 100644 --- a/devlog/_plan/260915_subagent_retirement/000_plan.md +++ b/devlog/_fin/260915_subagent_retirement/000_plan.md @@ -82,3 +82,20 @@ The executor owns the four bounded source-document edits listed in consultation records, final review/integration, checks and publication. One commit may carry the coherent document fix; follow repository `[agent] fix(...)` style. No branch stacking is needed. Preserve unrelated local integration work. + +## Delivery conclusion + +The four document edits are implemented. The final independent reviewer derived +all twelve intended actions from the policy without seeing expected answers; +its initial and focused follow-up verdicts were PASS. The existing gate, seven +owner-route tests and whitespace check passed. See +[011_verification.md](011_verification.md) for scope and limits. + +The chosen hypothesis was that clearer evidence requirements can prevent the +observed premature retirement. This unit does not measure model compliance; +there is no basis for claiming faster execution or a runtime guarantee. A +watchdog and phrase-presence tests were rejected because neither would verify +the coordinator behavior without a real runtime consumer. + +Delivery stops at a reviewed contribution to upstream `dev`, linked to #178. +No merge, release, deployment or installed-payload update is part of this unit. diff --git a/devlog/_plan/260915_subagent_retirement/010_policy.md b/devlog/_fin/260915_subagent_retirement/010_policy.md similarity index 100% rename from devlog/_plan/260915_subagent_retirement/010_policy.md rename to devlog/_fin/260915_subagent_retirement/010_policy.md diff --git a/devlog/_fin/260915_subagent_retirement/011_verification.md b/devlog/_fin/260915_subagent_retirement/011_verification.md new file mode 100644 index 00000000..619baf36 --- /dev/null +++ b/devlog/_fin/260915_subagent_retirement/011_verification.md @@ -0,0 +1,59 @@ +# Verification of the retirement guidance + +The changed artifact is coordinator guidance. Structural checks and semantic +review are separate evidence; neither is a guarantee of future model compliance. + +## Independent review + +A fresh C reviewer received the four changed source documents and twelve +observation-only scenarios, without the plan or its expected-answer matrix. +It independently derived the following actions and returned PASS, no blockers. +Main compared the results with the pre-written acceptance rows. + +| Scenario | Derived action | Result | +| --- | --- | --- | +| S1 meaningful reads, no edits | continue bounded waiting | matches | +| S2 healthy long command | inspect state; sparse output alone is not failure | matches | +| S3 evidenced stagnation | retire only after evidence, then verify shutdown and permitted recovery | matches | +| S4 unavailable observations | report the gap; queued input/timeouts do not prove failure | matches | +| S5 V2 mailbox | obtain separately delivered answer | matches | +| S6 terminal error | preserve error and follow managed reconciliation | matches | +| S7 cancellation/explicit limit | stop; do not automatically continue | matches | +| S8 previous status running | withhold overlapping work until current state and owned jobs are checked | matches | +| S9 reconcile/stop result | no replacement or direct implementation | matches | +| S10 irrelevant activity | keep reassessment point; noise is not progress | matches | +| S11 reviewer findings | continue without requiring edits | matches | +| S12 queued checkpoint after completion | reconcile current state before handoff | matches | + +The reviewer briefly stumbled over the Unobservable bullet's comma list and +the changelog's verb "retired". Main clarified insufficient observations as +the condition and changed the historical mechanism to "instructed coordinators +to retire". These are readability fixes, not new runtime behavior. The same +reviewer checked those two edits and returned PASS with no remaining notes; +all twelve independently derived actions were unchanged. + +## Checks observed by the independent reviewer + +- `npm run gate`: exit 0; no status/claim/count/inventory drift. +- `node plugins/codexclaw/scripts/test.mjs plugins/codexclaw/test/manifest-policy.test.mjs`: + exit 0, 7 pass, 0 fail. +- `git diff --check`: exit 0. +- Source hashes were stable during the initial four-file review. + +The existing route test reads the waiting reference's routing path. The gate +walks skill references and structure documents for claim hygiene. These checks +do not execute a model's retirement decisions. The scenario matrix is a semantic +review, not a deterministic unit test or an instrumented lifecycle replay. + +## Limits and retained evidence + +No runtime code, model routing, installed plugin bytes, configuration or tests +were changed. No phrase-presence test or unused helper was introduced. Source +tests cannot establish cross-model compliance or delivery timing on every host. +A future coordinator ignoring substantive progress despite reading this policy +would falsify the assumption that clearer guidance alone is sufficient. + +Raw native dispatch handles, reviewer responses and check receipts remain in +untracked session evidence. Public evidence is summarized here; no private +session transcript or host-specific path is published. The contribution is +tracked by [issue #178](https://github.com/lidge-jun/codexclaw/issues/178). diff --git a/plugins/codexclaw/skills/loop/references/waiting.md b/plugins/codexclaw/skills/loop/references/waiting.md index 534827cb..8aedaf53 100644 --- a/plugins/codexclaw/skills/loop/references/waiting.md +++ b/plugins/codexclaw/skills/loop/references/waiting.md @@ -28,8 +28,56 @@ external processes inside a loop: See `cxc-pabcd` `references/delegation.md`. - Never end the turn just because a wait timed out — re-wait or poll, and keep the user informed each cycle. -- If a reviewer/worker has produced nothing after ~3 wait cycles, treat it as - a failed dispatch (DISPATCH-RETIRE-01) rather than waiting silently forever. - That retirement CONSUMES the DISPATCH-RETIRE-01 same-agent retry: go straight - to a fresh spawn with the failure folded into the new packet — the silent - agent does not get a second retry. + +## Progress, stagnation, failure, unobservable (LOOP-WAIT-EVIDENCE-01, DEFAULT) + +Wait count and elapsed time are not the retirement signal; evidence is. Before +retiring a dispatched agent, refresh task-scoped observations (VCS diff, owned +processes, recent output) and classify what you actually see: + +- **Progress** — new evidence advancing the packet: edits, findings, reads, + command events, delivered artifacts. A read-only reviewer produces findings, + not edits; never require a file change from one. Liveness alone — identical + heartbeats, repeated no-op reads or messages — is not semantic progress and + does not postpone reassessment forever. On V2, a wait reporting updates is + not the answer: obtain the separately delivered final message first. +- **Suspected stagnation** — comparable observations show no advancement. + Where supported, send one non-interrupting checkpoint asking for findings, + remaining work and the next artifact; a queued-but-unread checkpoint is not + proof of a stall. Compare new evidence with the prior observation at one + stated, task-appropriate next review point. That point fixes when you look + again; it is not a new cancellation budget, and repeated no-op activity does + not reset it. +- **Confirmed failure** — an actual terminal error, or stagnation evidenced at + the stated review point. A wait timeout alone is a normal outcome, and a + healthy long command may emit sparse output — inspect command state before + treating silence as failure. Missing edits alone do not prove a stall. +- **Unobservable** — available observations cannot establish progress or + failure; for example, child state is inaccessible and the only signals are + a clean tree and a checkpoint that may still be queued. Report the observation + gap and seek direction within authorized limits; never manufacture a failure + or an OCX error code for a stall. + +Explicit cancellation, actual terminal failures and stated user/host resource +limits outrank progress evidence; report cancellations and exhausted bounds as +what they are, separate from provider errors, and preserve the original error. + +## Retirement and handoff + +Retire on confirmed failure or an explicit cancellation/bound, not on a wait +count. Record the pre-stop reason and last meaningful activity; after the stop +call, verify the actual terminal state, owned processes and partial edits — a +returned *previous* status of `running` is not proof of termination. If +termination is unknown, start no overlapping writer. A finished child may still +hold a queued checkpoint response; reconcile its real status, and never treat a +checkpoint request as permission to duplicate its work. + +Recovery from confirmed failure follows the bounded lifecycle +(DISPATCH-RETIRE-01): at most one retry on the same handle, then a fresh spawn +with the failure folded into the new packet. When the configured +first-fallback protocol manages the dispatch its result owns the next step +instead — `ready` means claim the next attempt, `main-direct` means main +reclaims the work, and `reconcile`/`stop` authorize neither a replacement +spawn nor direct execution. Cancellation or an exhausted bound grants no +continuation: stop within authority and report the cancellation or bound, +never as a provider failure. diff --git a/plugins/codexclaw/skills/pabcd/references/delegation.md b/plugins/codexclaw/skills/pabcd/references/delegation.md index 2d4e76cc..aa2878ce 100644 --- a/plugins/codexclaw/skills/pabcd/references/delegation.md +++ b/plugins/codexclaw/skills/pabcd/references/delegation.md @@ -97,6 +97,12 @@ reuse the same reviewer throughout the A loop. Before waiting on dispatched work, read the mode-neutral [Waiting on work](../../loop/references/waiting.md) rules in either HITL or HOTL. This route does not authorize an otherwise forbidden dispatch, wait, or mode transition. +A wait timeout is an observation outcome, not a verdict: classify progress, +suspected stagnation, confirmed failure and unavailable observation per that +reference before any retirement. A suspected-stall checkpoint uses +non-interrupting delivery where the family supports it — V1 `send_input` +without `interrupt`, V2 `send_message` — and a queued message is context the +child may not have read yet, never proof of a stall. ### Detect the family first (DISPATCH-SCHEMA-DETECT-01, STRICT) @@ -130,7 +136,7 @@ thread surface: a separate Codex task is not a bigger subagent. See |---|---| | spawn | `spawn_agent({ message \| items, model?, reasoning_effort?, fork_context? })` | | handle | returns `{ agent_id, nickname }`; address by `agent_id` | -| wait | `wait_agent({ targets[], timeout_ms })` returns final status that **may carry the final message**; a timeout is a normal outcome | +| wait | `wait_agent({ targets[], timeout_ms })` returns final status that **may carry the final message**; a timeout is a normal outcome, not failure evidence | | follow-up | `send_input({ target, message \| items, interrupt? })` | | stop | `close_agent({ target })`, returning the previous status | | restore | `resume_agent({ id })` | @@ -275,7 +281,9 @@ protocol. A PreToolUse reminder after a direct call cannot retroactively manage `not_created`, `stopped`, `unknown`, or `running`. Known no-child failures need concrete `reconciliation` evidence. A stopped child requires its recorded `agentId` and evidence that work/processes stopped and changes were inspected; - pass only remaining work to the replacement. Unknown outcomes never authorize + a stop call returning previous status `running` is not that evidence — verify + the current terminal state and owned processes first. Pass only remaining work + to the replacement. Unknown outcomes never authorize another child. If native spawn is absent, report `outcome:unavailable` with confirmed `not_created` and capability evidence, never a policy denial. 5. `ready` means claim the next attempt. `main-direct` means main reclaims the diff --git a/structure/20_pabcd_dispatch_doctrine.md b/structure/20_pabcd_dispatch_doctrine.md index ef76fcbb..efbfe7f0 100644 --- a/structure/20_pabcd_dispatch_doctrine.md +++ b/structure/20_pabcd_dispatch_doctrine.md @@ -179,17 +179,26 @@ codexclaw translation: `agents.max_threads` (default 6) and V2 `max_concurrent_threads_per_session` (default 4, including the root). - **DISPATCH-RETIRE-01 (fresh-spawn fallback).** This is the exception to the reuse - default above: an agent id that failed (error, timeout, unresponsive, nonsense - output) is retired, not nursed. At most ONE retry against the same task_name; then + default above: an agent id that failed is retired, not nursed — where failure + means an actual terminal error, nonsense output, or stagnation evidenced per + the waiting reference's evidence rule + (`plugins/codexclaw/skills/loop/references/waiting.md`). A bare wait timeout is + a normal outcome, not a failure. Explicit cancellation or an exhausted + user/host bound stops within authority and is reported as such; it is not a + failure and grants no retry, replacement, or reclaim. At most ONE retry against the + same task_name; then abandon it (V2 has only `interrupt_agent`; V1 has `close_agent` and `resume_agent`) and fresh-spawn with the failure summary folded into the new TASK packet. Repeated `followup_task`/`send_message` against a broken agent is a broken-resume loop — the dispatch analogue of LOOP-REPAIR-01's doom loop. When the fresh spawn — a SECOND distinct agent — also fails the SAME task packet, stop blaming agents: two independent failures on one packet are evidence the packet - itself failed the DISPATCH-ECONOMY-01 specifiability bar. The main session + itself failed the DISPATCH-ECONOMY-01 specifiability bar. Absent a managed + dispatch, the main session reclaims that slice and does the work directly instead of dispatching a third - copy (packet-failure reclaim, 260711 fork-debate verdict #4). Lineage: + copy (packet-failure reclaim, 260711 fork-debate verdict #4); under configured + first fallback the protocol result owns that decision — `main-direct` permits + reclaim, `reconcile`/`stop` permit neither reclaim nor a replacement spawn. Lineage: `../jawcode/devlog/_plan/260616_actor_fresh_fallback/_fin/00_moc.md` (implementation-verified). Both rules are E7 doctrine (agent-followed); no hook observes agent lifecycles. From 4a829dfe9567254119b1c756370e5388ca1129c3 Mon Sep 17 00:00:00 2001 From: thisisjun786 <259586770+thisisjun786@users.noreply.github.com> Date: Tue, 15 Sep 2026 16:05:40 +0900 Subject: [PATCH 3/7] [agent] fix(pabcd): preserve managed recovery in plan template --- .../011_verification.md | 18 ++++++++++++++++++ .../skills/pabcd/references/plan-output.md | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/devlog/_fin/260915_subagent_retirement/011_verification.md b/devlog/_fin/260915_subagent_retirement/011_verification.md index 619baf36..e2bd2a59 100644 --- a/devlog/_fin/260915_subagent_retirement/011_verification.md +++ b/devlog/_fin/260915_subagent_retirement/011_verification.md @@ -57,3 +57,21 @@ Raw native dispatch handles, reviewer responses and check receipts remain in untracked session evidence. Public evidence is summarized here; no private session transcript or host-specific path is published. The contribution is tracked by [issue #178](https://github.com/lidge-jun/codexclaw/issues/178). + +## PR review follow-up: plan template recovery + +[Review comment](https://github.com/lidge-jun/codexclaw/pull/179#discussion_r4009201474) +identified an unconditional two-failure reclaim instruction still present in +`pabcd/references/plan-output.md`. The earlier review treated it as shorthand; +that was insufficient because coordinators use the template to write plans. + +The escalation row now distinguishes unmanaged recovery from configured first +fallback and links to the existing recovery owner. Main reclaims only on +`main-direct` under managed dispatch; `reconcile` and `stop` authorize neither +reclaim nor replacement, even after two failures. Unmanaged reclaim requires +prior work to have stopped. The P-phase amendment requirement is retained. + +Manual comparison with `delegation.md` and DISPATCH-RETIRE-01 confirmed the +`main-direct`, `reconcile`, `stop`, and unmanaged-recovery cases. Fresh checks: +`npm run gate` passed; manifest-policy tests passed 7/7; `git diff --check` +was clean. These remain document checks and semantic review, not runtime proof. diff --git a/plugins/codexclaw/skills/pabcd/references/plan-output.md b/plugins/codexclaw/skills/pabcd/references/plan-output.md index d856c0ab..8fa25f4b 100644 --- a/plugins/codexclaw/skills/pabcd/references/plan-output.md +++ b/plugins/codexclaw/skills/pabcd/references/plan-output.md @@ -15,7 +15,7 @@ not silently remove a field. | Stop condition | When the authorized work ends; plan-only stops after returning the requested plan. | | Memory artifact | Where the plan/evidence is recorded. For a no-file request, name this returned plan rather than creating a file. Authorized persistent execution still follows the implementation-unit record rules. | | Expected terminal outcomes | What success, unresolved requirements or blocked execution would mean for this scope. Report outcomes are not new FSM phases or host goal statuses. | -| Escalation condition | What requires main/user direction. If delegation is planned, state both directions: main reclaims a slice after two distinct agents fail its packet (DISPATCH-RETIRE-01); pushing a slice to a worker requires a P-phase amendment, never a mid-B improvisation. | +| Escalation condition | What requires main/user direction. Delegation plans follow DISPATCH-RETIRE-01: without managed dispatch, main reclaims after two distinct agents fail the same packet, once prior work is stopped. With [configured first fallback](delegation.md#configured-first-fallback), the returned action governs recovery: only `main-direct` permits reclaim; `reconcile`/`stop` permit neither reclaim nor replacement. Pushing a slice to a worker requires a P-phase amendment, never a mid-B improvisation. | HOTL goal plans also state the cxc-loop resource bounds. Follow the live host goal-tool contract; do not invent a token or time budget that the user did not set. From 3c0bcc6f71eeef41b4c6f0e31b3c965e3077bbad Mon Sep 17 00:00:00 2001 From: thisisjun786 <259586770+thisisjun786@users.noreply.github.com> Date: Tue, 15 Sep 2026 16:10:18 +0900 Subject: [PATCH 4/7] [agent] fix(delegation): defer architect recovery to managed dispatch --- .../011_verification.md | 16 ++++++++++++++ .../skills/pabcd/references/delegation.md | 22 +++++++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/devlog/_fin/260915_subagent_retirement/011_verification.md b/devlog/_fin/260915_subagent_retirement/011_verification.md index e2bd2a59..7f83ee0d 100644 --- a/devlog/_fin/260915_subagent_retirement/011_verification.md +++ b/devlog/_fin/260915_subagent_retirement/011_verification.md @@ -75,3 +75,19 @@ Manual comparison with `delegation.md` and DISPATCH-RETIRE-01 confirmed the `main-direct`, `reconcile`, `stop`, and unmanaged-recovery cases. Fresh checks: `npm run gate` passed; manifest-policy tests passed 7/7; `git diff --check` was clean. These remain document checks and semantic review, not runtime proof. + +## PR review follow-up: architect recovery + +[Review comment](https://github.com/lidge-jun/codexclaw/pull/179#discussion_r4012925635) +found the same incomplete propagation in the architect-specific recovery clause. +Accepted: a role-specific instruction must not bypass the common recovery owner. +The clause now defers managed retries and reclaim to the returned action, and +limits the same-handle/two-context rule to unmanaged dispatch. Prior work must +be stopped and inspected before unmanaged recovery. Missing architect consultation +still blocks dependent completion, including when main reclaims planning. + +Reviewed recovery references in the active skills and structure doctrine. Manual +comparison covered managed `ready`, `main-direct`, `reconcile`, `stop`, unmanaged +recovery, and the unmet-consultation constraint. Fresh `npm run gate`, all 7 +manifest-policy tests, and `git diff --check` passed. These are document checks +and main's semantic review; the initial independent scenario review is unchanged. diff --git a/plugins/codexclaw/skills/pabcd/references/delegation.md b/plugins/codexclaw/skills/pabcd/references/delegation.md index aa2878ce..fff7deb4 100644 --- a/plugins/codexclaw/skills/pabcd/references/delegation.md +++ b/plugins/codexclaw/skills/pabcd/references/delegation.md @@ -245,13 +245,21 @@ named decision revisions within ONE plan; a separate new plan starts a fresh con Do not promise cost savings from reuse. Use the host's supported follow-up and wait operations; an empty timed wait alone is not evidence of a failed call. -On an actual failed call, preserve the failure evidence and apply the existing -retirement rule: at most one retry on the same handle, then a fresh context carrying -the failure and plan. If a second distinct context also fails, main reclaims the -planning work under the existing lifecycle rule, but the missing architect consultation -remains unmet. Report the gap and stop dependent completion; main self-check does not -replace it. Do not silently switch models, register roles, or bypass host restrictions. -Explicit user limits still govern dispatch and completion scope. +On an actual failed call, preserve the failure evidence. With +[configured first fallback](#configured-first-fallback), the returned action governs +recovery: `ready` requires a new claim, only `main-direct` permits reclaim, and +`reconcile`/`stop` permit neither reclaim nor replacement. The unmanaged retry rule +below does not authorize extra calls on this path. + +Without managed dispatch, apply the existing retirement rule: at most one retry +on the same handle, then a fresh context carrying the failure and plan. If a second +distinct context also fails, main reclaims the planning work. Confirm prior work +has stopped and inspect partial results before retry, replacement or reclaim. + +In either path, a missing architect consultation remains unmet. Report the gap +and stop dependent completion; main self-check does not replace it. Do not silently +switch models, register roles, or bypass host restrictions. Explicit user limits +still govern dispatch and completion scope. ## Speculative dispatch (DISPATCH-SPECULATE-01, HEURISTIC) From 20e50485f994bed509f44e071e7119b536b1d520 Mon Sep 17 00:00:00 2001 From: thisisjun786 <259586770+thisisjun786@users.noreply.github.com> Date: Tue, 15 Sep 2026 16:15:52 +0900 Subject: [PATCH 5/7] [agent] fix(loop): classify unusable final output as failure --- .../260915_subagent_retirement/011_verification.md | 13 +++++++++++++ plugins/codexclaw/skills/loop/references/waiting.md | 11 +++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/devlog/_fin/260915_subagent_retirement/011_verification.md b/devlog/_fin/260915_subagent_retirement/011_verification.md index 7f83ee0d..a1e485b7 100644 --- a/devlog/_fin/260915_subagent_retirement/011_verification.md +++ b/devlog/_fin/260915_subagent_retirement/011_verification.md @@ -91,3 +91,16 @@ comparison covered managed `ready`, `main-direct`, `reconcile`, `stop`, unmanage recovery, and the unmet-consultation constraint. Fresh `npm run gate`, all 7 manifest-policy tests, and `git diff --check` passed. These are document checks and main's semantic review; the initial independent scenario review is unchanged. + +## PR review follow-up: unusable final output + +[Review comment](https://github.com/lidge-jun/codexclaw/pull/179#discussion_r4012960563) +identified another owner mismatch: the doctrine includes nonsense output as a +failure, but the waiting classification only named terminal errors and stagnation. +Accepted: a transport-successful final response can still fail the task packet. +The waiting reference now includes demonstrably nonsensical or unusable final +output and requires concrete evidence. Interim updates and supported disagreement +alone do not count as failure. Existing shutdown and managed recovery rules apply. + +Fresh `npm run gate`, all 7 manifest-policy tests, and `git diff --check` passed. +These checks cover document hygiene and routes, not the output-quality judgment. diff --git a/plugins/codexclaw/skills/loop/references/waiting.md b/plugins/codexclaw/skills/loop/references/waiting.md index 8aedaf53..ba4fdc45 100644 --- a/plugins/codexclaw/skills/loop/references/waiting.md +++ b/plugins/codexclaw/skills/loop/references/waiting.md @@ -48,10 +48,13 @@ processes, recent output) and classify what you actually see: stated, task-appropriate next review point. That point fixes when you look again; it is not a new cancellation budget, and repeated no-op activity does not reset it. -- **Confirmed failure** — an actual terminal error, or stagnation evidenced at - the stated review point. A wait timeout alone is a normal outcome, and a - healthy long command may emit sparse output — inspect command state before - treating silence as failure. Missing edits alone do not prove a stall. +- **Confirmed failure** — an actual terminal error, final output demonstrably + nonsensical or unusable for the task packet, or stagnation evidenced at the + stated review point. Record concrete output evidence for an output-failure + judgment; interim updates and supported disagreement alone are not failures. + A wait timeout alone is a normal outcome, and a healthy long command may emit + sparse output — inspect command state before treating silence as failure. + Missing edits alone do not prove a stall. - **Unobservable** — available observations cannot establish progress or failure; for example, child state is inaccessible and the only signals are a clean tree and a checkpoint that may still be queued. Report the observation From 997cdf7ab203f650999eef1b110d147f622a97da Mon Sep 17 00:00:00 2001 From: thisisjun786 <259586770+thisisjun786@users.noreply.github.com> Date: Tue, 15 Sep 2026 16:33:58 +0900 Subject: [PATCH 6/7] [agent] docs(plan): specify reconciled task failure recovery --- .../260915_task_failure_recovery/000_plan.md | 48 ++++++++ .../010_recovery.md | 105 ++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 devlog/_plan/260915_task_failure_recovery/000_plan.md create mode 100644 devlog/_plan/260915_task_failure_recovery/010_recovery.md diff --git a/devlog/_plan/260915_task_failure_recovery/000_plan.md b/devlog/_plan/260915_task_failure_recovery/000_plan.md new file mode 100644 index 00000000..ef3ced7a --- /dev/null +++ b/devlog/_plan/260915_task_failure_recovery/000_plan.md @@ -0,0 +1,48 @@ +# Managed task failure recovery + +PR #179 follow-up to [review](https://github.com/lidge-jun/codexclaw/pull/179#discussion_r4013017929). +The prior documentation cycle preserved managed recovery authority. A later review +showed that confirmed task failures have no executable recovery path through it. +This cycle changes that conclusion with direct runtime evidence, not another prose exception. + +## Requirements and scope + +- Represent confirmed stagnation and unusable final output separately from provider errors. +- Require a recorded child, confirmed termination, partial-work inspection and concrete + task-failure evidence before handing off remaining work. +- Preserve provider decoding, cancellation/policy stops, identity, claim/spawn deduplication, + the two-candidate bound and independent-review obligations. +- Retain old dispatch-state compatibility and consistent installed caller guidance. +- Finish with relevant runtime/CLI regression evidence, current CI and no medium-or-higher + unresolved source or GitHub review findings. + +One bounded PABCD cycle follows this specification. The affected report contract receives +C4 review and negative-case coverage. Main owns decisions, integration, records and PR; +the configured executor will own the audited implementation bundle. The configured +architect proposes the contract and reflects on the executable plan before independent audit. + +Use the existing subagent-config module, tests, waiting/delegation owners and structure +index. No new dependency, retry framework, watchdog, provider call or installed configuration. +No merge, release or deployment. No user token, cost or wall-clock budget was specified; +the work remains bounded by this PR and its review findings. Preserve other checkouts. + +## Reproduction and trust boundary + +At `20e50485`, an isolated real `runDispatch` fixture creates and claims an executor, +records its child, then reports unusable final output with `executionState: stopped`, +the recorded identity and reconciliation evidence. First and repeated reports both +return `reconcile`, retain one attempt and request structured OCX evidence that does not +exist for this failure. Existing dispatch/CLI tests pass 23/23; they omit this recovery case. + +The assets are exclusive work ownership and bounded model invocation. The boundary is +main-supplied CLI JSON into persisted dispatch state. Malformed or conflicting reports, +quoted child output and stale identities must not create recovery permission. Main can +misreport observations already; these are caller assertions, not authenticated native +receipts. Tests must prove validation and state transitions without claiming to observe +real child termination or judge model output automatically. + +The executable file map, decision IDs, acceptance cases and consultation record belong +in `010_recovery.md`. Existing code-only checks and the normal build are available: +dispatch/CLI tests exit 0 (23 tests), `npm run build` exits 0 (181 files), and the gate +exits 0 on the baseline. Tests invoke the actual state machine and separate CLI processes; +the build compiles component source; the gate covers document hygiene only. diff --git a/devlog/_plan/260915_task_failure_recovery/010_recovery.md b/devlog/_plan/260915_task_failure_recovery/010_recovery.md new file mode 100644 index 00000000..59d556a6 --- /dev/null +++ b/devlog/_plan/260915_task_failure_recovery/010_recovery.md @@ -0,0 +1,105 @@ +# Task failure report: executable plan + +| Field | Contract | +|---|---| +| Goal | Safely recover confirmed task failures and close PR #179's substantive reviews. | +| Mode / class | Scoped HOTL; report contract receives C4 care. One recovery cycle. | +| Scope / resources | This checkout and PR only; no explicit token or time budget; no installation, live provider probe, merge or release. | +| Completion | Runtime/CLI positive and negative cases, affected suites/build, independent review and current CI pass; no medium-or-higher findings remain. | +| Escalation | Managed results govern all child recovery. `reconcile`/`stop` grant no reclaim or replacement; broader unrelated changes require a new decision. | + +## Decisions and consultation + +Architect proposal accepted as D1-D8 below. Main reproduced the stranded state and +accepts rotation to the existing next candidate, not a new same-model retry mode. +Generated repository payload is in scope; rebuilding it does not install the plugin. +Use `task_failed` consistently. Stagnation's review-point evidence stays in bounded +evidence text; no additional scheduler or observation database is needed. + +- D1: Add `outcome: task_failed`; keep `failed` provider decoding unchanged. +- D2: Require `taskFailure: {kind: stagnation|unusable_output, evidence: string}`. + Reject unknown keys/kinds, empty evidence, non-string values and text over 2000 characters. +- D3: Require the recorded child identity, `executionState: stopped`, and existing + bounded reconciliation evidence. Running/unknown state returns `reconcile`; no-child + task failure is rejected. Check state before any candidate or direct-work grant. +- D4: If `error` is supplied with `task_failed`, provider restrictions win: decoded + stop records the code and stops; unknown returns `reconcile`; next-eligible errors + are rejected as mixed reports and must use `outcome: failed`. No error means task path. +- D5: Reuse the existing failed-attempt tail: next configured candidate is `ready`, + then requires claim; after the last candidate return `main-direct`. No third attempt. +- D6: Persist nullable `Attempt.taskFailure`; preserve `code` for provider codes. + Old version-1 records missing the field normalize to null. Invalid stored values + fail closed. New records initialize null. Expose metadata through existing `attempts`. +- D7: Keep `DispatchResult` actions, role constraints, locks and native issuance unchanged. + Optional reason text may explain task recovery; it is not the authority signal. +- D8: Document the same payload in SessionStart guidance, delegation, waiting and + the public subagents guide. Update CHANGELOG and the structure index owner pointer. + +Alternative rejected: adding a fake OCX code or treating arbitrary `failed.error` +prose as next-eligible. That weakens the provider boundary and confuses observation +with provider error. A new `task_failed` report is an explicit main judgment with +separate evidence. It is not inferred from model output or a wait count. + +Architect proposal and reflection completed: ALIGNED for D1-D8, no material gaps. +Main accepts both implementation clarifications: decoded stop precedes the child-state +gate; ordinary `failed` reports retain their existing behavior even with stray task metadata. +Actual handles and raw consultation outputs stay in local task evidence. + +## File and field chain + +Paths below are repository-relative. The configured executor owns this implementation +bundle after A; main owns planning records, generated build output, measured README +test badges, verification records, source review and PR publication. + +| File | Change | +|---|---| +| `plugins/codexclaw/components/subagent-config/src/fallback-dispatch.ts` | MODIFY input outcome validation, task payload parser, attempt metadata factory/read validation, report transition; share bounded handoff tail. | +| `plugins/codexclaw/components/subagent-config/src/fallback-dispatch-cli.ts` | MODIFY `DISPATCH_GUIDANCE` with concrete task report. CLI already passes parsed JSON to `runDispatch`; no new command or flags. | +| `plugins/codexclaw/components/subagent-config/test/fallback-dispatch.test.ts` | MODIFY existing real fixture tests for state transitions and negatives; no deleted assertions. | +| `plugins/codexclaw/components/subagent-config/test/fallback-dispatch-cli.test.ts` | MODIFY real separate-process round trip covering task failure and persisted metadata. | +| `plugins/codexclaw/skills/pabcd/references/delegation.md` | MODIFY report instructions and evidence/limit precedence. | +| `plugins/codexclaw/skills/loop/references/waiting.md` | MODIFY recovery route for confirmed task failures; keep wait classification evidence-based. | +| `docs-site/src/content/docs/guides/subagents.md` | MODIFY public protocol example and limits. | +| `CHANGELOG.md`, `structure/INDEX.md` | MODIFY change record and owner description to include runtime recovery. | +| `plugins/codexclaw/components/subagent-config/dist/fallback-dispatch{,-cli}.js` | REGENERATE from source with the standard build; never hand-edit. | +| `README.md`, `README.ko.md` | MODIFY test count only if new tests change measured inventory; use normal inventory tool. | + +Creation is explicit CLI JSON → `runDispatch`/`report`; validation is the task parser +and stopped-child gate; serialization is `saveState`; deserialization is `readState`; +consumption is the existing `result().attempts` plus main guidance. `managedSpawn` and +`issueManagedSpawn` consume unchanged candidate/claim/state fields. The decoder remains +provider-only. No SDK, GUI input form or alternative report parser owns this field. + +## Acceptance and verification + +| Reachable trigger | Required observation | +|---|---| +| Created, stopped child; each task kind with valid evidence | First failure → ready; claim selects configured fallback; metadata round-trips with null provider code. | +| Same valid failure on last candidate, all roles | main-direct, exactly two attempts; reviewer still requires independent review. | +| State persisted without the new key | status works and later task failure recovers; malformed new metadata is rejected. | +| Running/unknown child state | reconcile, unchanged candidate count, no spawn/direct permission. | +| not_created, missing/wrong child, missing reconciliation | Rejected; no recovery grant or hidden state advancement. | +| Invalid kind/shape/unknown key, blank/oversized evidence | Rejected; existing state remains readable and unchanged. | +| Permission/policy/cancellation error plus task label | stop wins and persists; a later label cannot reopen it. | +| Unknown error plus task label | reconcile; no extra attempt. | +| Next-eligible provider error plus task label | Rejected as mixed; ordinary failed path retains old behavior. | +| Plain failed report with task metadata and no provider error | Existing unknown-error reconcile behavior, never implicit task recovery. | +| Before claim, stale ID, duplicate claim/issuance | Existing rejection/reconciliation and one-spawn invariant remain. | +| Already complete/stopped dispatch | No reopening by task report. | +| Separate CLI processes, valid task failures through both candidates | ready → claim → main-direct, metadata survives status/restart. | + +Record a failing task-recovery assertion before source changes, then the same test +passing. Focused baseline command (exit 0, 23 tests) directly loads the two target suites: +`node plugins/codexclaw/scripts/test.mjs plugins/codexclaw/components/subagent-config/test/fallback-dispatch.test.ts plugins/codexclaw/components/subagent-config/test/fallback-dispatch-cli.test.ts`. +After implementation run the complete subagent-config suite, `npm run build`, +`npm run gate`, full root tests for the measured badge count, inventory check and +`git diff --check`. Normal hosted CI covers OS and packed-payload compatibility. +Semantic review checks the caller docs against the live report contract. A fresh C +reviewer re-derives recovery reachability; merely preserving unknown-error rejection +does not prove task recovery works, which was the earlier review's blind spot. + +Enforcement scope: CLI validation and persisted transitions execute in code for managed +callers; direct native calls bypass this protocol. Evidence truth and actual child +termination remain main observations. No universal lifecycle-enforcement claim is made. +Keep this repair in PR #179 because its new failure classification otherwise strands +managed callers; the larger aggregate diff includes the original planning/evidence records. From cb25e3b11904b486c38990603374a80bdda2b19b Mon Sep 17 00:00:00 2001 From: thisisjun786 <259586770+thisisjun786@users.noreply.github.com> Date: Tue, 15 Sep 2026 17:42:45 +0900 Subject: [PATCH 7/7] [agent] fix(dispatch): recover confirmed task failures after reconciliation --- CHANGELOG.md | 9 +- README.ko.md | 2 +- README.md | 2 +- README.zh.md | 2 +- .../011_verification.md | 19 +- .../260915_task_failure_recovery/000_plan.md | 0 .../010_recovery.md | 11 +- .../011_verification.md | 61 ++++++ .../src/content/docs/guides/subagents.md | 9 + .../dist/fallback-dispatch-cli.js | 2 +- .../subagent-config/dist/fallback-dispatch.js | 45 ++++- .../src/fallback-dispatch-cli.ts | 2 +- .../subagent-config/src/fallback-dispatch.ts | 45 ++++- .../test/fallback-dispatch-cli.test.ts | 32 +++- .../test/fallback-dispatch.test.ts | 176 +++++++++++++++++- .../skills/loop/references/waiting.md | 8 + .../skills/pabcd/references/delegation.md | 25 ++- structure/INDEX.md | 1 + 18 files changed, 430 insertions(+), 21 deletions(-) rename devlog/{_plan => _fin}/260915_task_failure_recovery/000_plan.md (100%) rename devlog/{_plan => _fin}/260915_task_failure_recovery/010_recovery.md (93%) create mode 100644 devlog/_fin/260915_task_failure_recovery/011_verification.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 12b653bf..1f81accb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,8 +13,13 @@ All notable changes to codexclaw are documented here. The format follows `waiting.md` now requires evidence of progress or stagnation, preserves unavailable observations, and uses non-interrupting checkpoints. Delegation and DISPATCH-RETIRE-01 clarify actual shutdown checks and managed recovery; - cancellation or exhausted limits grant no retry or replacement. This changes - agent-followed guidance, not runtime enforcement (#178). + cancellation or exhausted limits grant no retry or replacement. Progress + assessment remains agent-followed (#178). +- Managed dispatch now accepts explicit `task_failed` reports for confirmed + stagnation or unusable final output. A recorded stopped child, task evidence + and reconciliation are required before the existing bounded handoff can run. + Provider errors keep their existing classification; cancellation and permission + denials cannot be overridden by a task-failure label (#178). ## [0.2.28] - 2026-09-14 diff --git a/README.ko.md b/README.ko.md index 35736a36..e6b0c524 100644 --- a/README.ko.md +++ b/README.ko.md @@ -13,7 +13,7 @@
-
+
diff --git a/README.md b/README.md
index 2dcee674..e3fd4f04 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@
-
+
diff --git a/README.zh.md b/README.zh.md
index f0a07a0b..0bab5bb6 100644
--- a/README.zh.md
+++ b/README.zh.md
@@ -13,7 +13,7 @@
-
+
diff --git a/devlog/_fin/260915_subagent_retirement/011_verification.md b/devlog/_fin/260915_subagent_retirement/011_verification.md
index a1e485b7..a6c9a6e3 100644
--- a/devlog/_fin/260915_subagent_retirement/011_verification.md
+++ b/devlog/_fin/260915_subagent_retirement/011_verification.md
@@ -45,10 +45,10 @@ walks skill references and structure documents for claim hygiene. These checks
do not execute a model's retirement decisions. The scenario matrix is a semantic
review, not a deterministic unit test or an instrumented lifecycle replay.
-## Limits and retained evidence
+## Initial policy revision: limits and retained evidence
-No runtime code, model routing, installed plugin bytes, configuration or tests
-were changed. No phrase-presence test or unused helper was introduced. Source
+At the initial policy revision, no runtime code, model routing, installed plugin
+bytes, configuration or tests were changed. No phrase-presence test or unused helper was introduced. Source
tests cannot establish cross-model compliance or delivery timing on every host.
A future coordinator ignoring substantive progress despite reading this policy
would falsify the assumption that clearer guidance alone is sufficient.
@@ -104,3 +104,16 @@ alone do not count as failure. Existing shutdown and managed recovery rules appl
Fresh `npm run gate`, all 7 manifest-policy tests, and `git diff --check` passed.
These checks cover document hygiene and routes, not the output-quality judgment.
+
+## Later review: managed recovery reachability
+
+[Review comment](https://github.com/lidge-jun/codexclaw/pull/179#discussion_r4013017929)
+found that recognizing task failures did not make managed recovery executable:
+descriptive stagnation or unusable-output reports remained `reconcile` even after
+termination was confirmed. A source review at `20e50485` correctly verified that
+unknown error prose cannot rotate providers, but missed the need for a separate
+task-failure path. Main reproduced that gap with the real state machine.
+
+The follow-up cycle is recorded in `devlog/_fin/260915_task_failure_recovery/`.
+Its runtime/CLI evidence supersedes the initial policy-only scope above; it must
+not be inferred from the earlier semantic scenario review.
diff --git a/devlog/_plan/260915_task_failure_recovery/000_plan.md b/devlog/_fin/260915_task_failure_recovery/000_plan.md
similarity index 100%
rename from devlog/_plan/260915_task_failure_recovery/000_plan.md
rename to devlog/_fin/260915_task_failure_recovery/000_plan.md
diff --git a/devlog/_plan/260915_task_failure_recovery/010_recovery.md b/devlog/_fin/260915_task_failure_recovery/010_recovery.md
similarity index 93%
rename from devlog/_plan/260915_task_failure_recovery/010_recovery.md
rename to devlog/_fin/260915_task_failure_recovery/010_recovery.md
index 59d556a6..fe72e7d6 100644
--- a/devlog/_plan/260915_task_failure_recovery/010_recovery.md
+++ b/devlog/_fin/260915_task_failure_recovery/010_recovery.md
@@ -47,9 +47,12 @@ Actual handles and raw consultation outputs stay in local task evidence.
## File and field chain
-Paths below are repository-relative. The configured executor owns this implementation
-bundle after A; main owns planning records, generated build output, measured README
-test badges, verification records, source review and PR publication.
+Paths below are repository-relative. After A, the executor owns the state-machine
+implementation and two test files. During B it explicitly released the untouched
+guidance/documentation files to main; the sequential handoff was delaying integration.
+Main owns that wording, planning records, generated build output, measured README
+test badges, verification records, source review and PR publication. D1-D8 and the
+acceptance criteria are unchanged; this is a successful scope split, not failure recovery.
| File | Change |
|---|---|
@@ -62,7 +65,7 @@ test badges, verification records, source review and PR publication.
| `docs-site/src/content/docs/guides/subagents.md` | MODIFY public protocol example and limits. |
| `CHANGELOG.md`, `structure/INDEX.md` | MODIFY change record and owner description to include runtime recovery. |
| `plugins/codexclaw/components/subagent-config/dist/fallback-dispatch{,-cli}.js` | REGENERATE from source with the standard build; never hand-edit. |
-| `README.md`, `README.ko.md` | MODIFY test count only if new tests change measured inventory; use normal inventory tool. |
+| `README.md`, `README.ko.md`, `README.zh.md` | MODIFY test count only if new tests change measured inventory; use normal inventory tool. |
Creation is explicit CLI JSON → `runDispatch`/`report`; validation is the task parser
and stopped-child gate; serialization is `saveState`; deserialization is `readState`;
diff --git a/devlog/_fin/260915_task_failure_recovery/011_verification.md b/devlog/_fin/260915_task_failure_recovery/011_verification.md
new file mode 100644
index 00000000..fe6d2eae
--- /dev/null
+++ b/devlog/_fin/260915_task_failure_recovery/011_verification.md
@@ -0,0 +1,61 @@
+# Task failure recovery verification
+
+The implemented `task_failed` path closes the runtime gap reported in
+[PR review](https://github.com/lidge-jun/codexclaw/pull/179#discussion_r4013017929).
+Both confirmed task kinds now reach the existing bounded handoff after a recorded
+child is stopped and evidence is supplied. Unknown provider prose still reconciles;
+no provider error code was invented or added to the decoder.
+
+## Observed checks
+
+- RED: `confirmed task failure recovers through the next candidate, then main-direct`
+ failed with `invalid report outcome` against the prior source.
+- GREEN: the same test passed after implementation; the initial focused run passed
+ 24 tests. Later coverage added malformed metadata, legacy records, identities,
+ provider precedence, terminal guards and separate CLI persistence.
+- Main reproduced and corrected stale provider-code metadata after a prior
+ reconciled report; accepted task failures now clear that code.
+- Standard build passed: 181 source files compiled, manifest layout validated.
+- Compiled root CLI QA passed 35 separate invocations with captured stdin,
+ stdout, stderr and exit codes. Cases covered failure recovery through both
+ candidates, status/resume, duplicate claim, live/unknown child, malformed input,
+ 2000/2001-character bounds and terminal cancellation/permission precedence.
+ No native agents or providers were invoked by the fixtures; temporary QA
+ state was removed and its absence confirmed.
+- Full root suite: 3165 total, 3091 pass, 74 skip, 0 fail. The source diff hash
+ was unchanged throughout the run. Inventory badges were then regenerated from
+ that measured total; inventory check, document gate and diff check passed.
+
+The initial full run failed five unrelated environment checks: this checkout had
+no installed React dependency, and an existing `/tmp/.git` made four temporary-root
+fixtures resolve their ancestor. Installing the lockfile's existing dependencies
+and setting an isolated temporary directory fixed the environment. The ten tests
+in those two files passed, then the whole suite passed. No product code or test
+assertion was changed to suppress these failures; package manifests and lockfile
+are unchanged.
+
+## Independent review
+
+The architect proposed D1-D8 and reflected ALIGNED on the concrete plan. Independent
+A audit found no blockers and reran the 23-test baseline. A fresh C reviewer reviewed
+all changed source, tests, generated bytes, caller guidance and records; it independently
+derived positive recovery and negative cases before returning PASS with no substantive
+findings. Source-to-dist compilation matched, 19 reviewed file hashes stayed stable,
+and a later pass accounted for the three generated README badge updates.
+
+Reviewer VM probes covered eight scenario groups. Its first documentation-example
+probe selected the wrong example and failed; correcting that extractor proved the
+actual task-report example reaches `ready`. Removing the new task branch in memory
+restored `invalid report outcome`, confirming the new recovery test is not vacuous.
+
+## Evidence limits
+
+Runtime tests and CLI fixtures prove report validation and state transitions. They
+do not authenticate main's observations, measure live model compliance or establish
+that a real child/process stopped. The output-quality judgment remains main-owned.
+No plugin was installed, and no merge or release occurred. The fixtures made no
+provider calls.
+The earlier policy-only review missed recovery reachability; broader runtime evidence
+was necessary to close this issue. Raw receipts and native handles remain local.
+
+Hosted CI and GitHub re-review are verified on the published commit separately.
diff --git a/docs-site/src/content/docs/guides/subagents.md b/docs-site/src/content/docs/guides/subagents.md
index 482f1c2f..8bde1a62 100644
--- a/docs-site/src/content/docs/guides/subagents.md
+++ b/docs-site/src/content/docs/guides/subagents.md
@@ -106,6 +106,15 @@ authentication and cancellation failures stop. Ambiguous creation or ongoing wor
must be reconciled before replacement; stopped executors require a change review
and cleanup evidence. Unknown error prose does not trigger blind rotation.
+Confirmed stagnation or unusable final output uses a separate `outcome:task_failed`
+report with `taskFailure: {kind: "stagnation" | "unusable_output", evidence: "..."}`.
+Include the recorded child ID, `executionState:stopped`, and `reconciliation`
+describing termination and partial-work inspection. Both evidence strings must be
+non-empty and at most 2000 characters. This report has no provider `error`; it uses
+the same bounded handoff and returned actions as provider recovery. Cancellation,
+exhausted limits and a wait timeout alone are not task failures. Validate final
+work before reporting `outcome:complete`, which cannot be reopened for recovery.
+
OCX retains its own retries and global/per-model fallback. The two-attempt limit
applies to CXC-issued native attempts, not every downstream provider request.
Requested and observed models are recorded separately; an unobserved actual model
diff --git a/plugins/codexclaw/components/subagent-config/dist/fallback-dispatch-cli.js b/plugins/codexclaw/components/subagent-config/dist/fallback-dispatch-cli.js
index 76d2fbda..4a224ce2 100644
--- a/plugins/codexclaw/components/subagent-config/dist/fallback-dispatch-cli.js
+++ b/plugins/codexclaw/components/subagent-config/dist/fallback-dispatch-cli.js
@@ -4,7 +4,7 @@ import { fileURLToPath } from "node:url";
import { runDispatch } from "./fallback-dispatch.js";
import { readConfig, ROLES } from "./store.js";
-export const DISPATCH_GUIDANCE = `Roles with a first fallback use the main-owned dispatch protocol before native spawn. Run cxc subagents dispatch with one JSON object on stdin: {action:"start",sessionId: