Skip to content

fix(orchestration): record durable worker handles + correct in-session SendMessage revival - #2

Merged
DumoeDss merged 1 commit into
mainfrom
worktree-fix-worker-resume-handles
Jul 13, 2026
Merged

fix(orchestration): record durable worker handles + correct in-session SendMessage revival#2
DumoeDss merged 1 commit into
mainfrom
worktree-fix-worker-resume-handles

Conversation

@DumoeDss

Copy link
Copy Markdown
Owner

Why

A real autopilot run failed to resume its workers because of two coupled defects in the orchestration-worker-lifecycle area.

  1. The LEAD recorded each stage worker with a fabricated name field instead of the durable agentId + transcript the Agent tool actually returned, so collectStageWorkers silently dropped the record — the worker became invisible to rasen pipeline resume, forcing a cold reconstruction and losing the warm-seed path.
  2. The generated playbook asserts that SendMessage-ing a completed worker within a live session revives it (by name) — but the transcript proves a completed Agent-tool subagent is NOT reliably name-addressable even ~27 messages later in the same un-compacted session (the harness replied "No agent named 'implementer' is currently addressable … use the agent ID"). The playbook's revival claim is wrong, and the run-state gap that made the failure silent had no validation to catch it.

What Changes

  • Durable handles in run-state. The generated playbook's Step B dispatch instructions now tell the LEAD to capture agentId + transcript from the Agent (Task) tool's spawn RESULT and write them into the stage's worker record (Claude), or threadId + transcript/turnId (Codex) — never a made-up name. The Worker schema fields stay optional and .passthrough() so archived auto-run.json still parses.
  • Validation, not silence. rasen pipeline resume surfaces a non-fatal warning (json + text) for every stage whose worker record lacks any durable handle (agentId / transcript / threadId) — i.e. a name-only or role-only record — naming the offending stage and the non-durable keys present. A new duplicate-key detector likewise warns (non-fatal) when auto-run.json carries duplicate JSON keys, which JSON.parse silently collapses.
  • Correct the revival claim. Rewrote the playbook's Step A, Step F.1 (incl. the "two are the SAME mechanism" note), and Step H.4a(b)/H.4b revival paths to prescribe agentId-first re-engagement: name is a non-durable dispatch label, NOT a resume handle; a completed Agent-tool subagent may be unreachable even within the same session; fall back to the transcript warm-seed (Tier-B) when agentId is absent or does not resolve. Code comments in run-state.ts (~L34–43) and pipeline.ts (~L423–425) aligned with this reality.
  • Hidden bugs (in-scope). collectStageWorkers silent drop → caught by the resume warning; the unknown name field → flagged by name in the warning (passthrough preserved); Tier-A honesty → Step A text and the claude-settings.ts header comment stop overclaiming re-addressability.
  • Tests. Extended run-state.test.ts (worker-handle validation helper, duplicate-key detector, collectStageWorkers behavior unchanged for durable handles) and pipeline.test.ts (resume warns on a name-only worker and on duplicate keys, in json + text; a durable-handle worker warns nothing).

No breaking CLI changes. No new required schema fields. Archived run-state continues to parse.

Impact

  • Generated playbook (src/core/templates/workflows/_orchestration.ts): Step A (tier honesty), Step B (capture agentId+transcript from the spawn result), Step F.1 (agentId-first revival + the "same mechanism" note), Step H.4a(b)/H.4b (agentId-first revival). Embeds via ORCHESTRATION_PLAYBOOK into auto.ts, review-cycle.ts, goal-command.ts — their parity hashes in test/core/templates/skill-templates-parity.test.ts move.
  • src/core/templates/workflows/auto.ts: the Resume-section comment that restated the (wrong) within-session revival claim is aligned.
  • src/core/pipeline-registry/run-state.ts: doc comment (~L34–43) aligned; new non-fatal helpers — a duplicate-key detector over the raw JSON text and a worker-handle-validation helper. RunStateWorkerSchema stays optional + .passthrough().
  • src/commands/pipeline.ts: resume surfaces workerHandleWarnings + duplicate-key warnings (json + text); the "dead SendMessage handles" comment (~L423–425) is aligned.
  • src/core/claude-settings.ts: header doc comment (~L1–9) stops overclaiming Tier-A re-review guarantees.
  • Tests: test/core/pipeline-registry/run-state.test.ts, test/commands/pipeline.test.ts, and the parity hash list in test/core/templates/skill-templates-parity.test.ts.

No runtime tier detection is added (tier is LEAD-self-reported from the playbook); adding a runtime env-probe is explicitly out of scope. No auto-run.json is written or edited by this change.

Test plan

  • npx tsc --noEmit exit 0
  • pnpm lint 0 errors
  • pnpm test 2526 passed / 0 failed
  • pnpm run build ok
  • affected test/commands/pipeline.test.ts 46 passed / 0 failed (re-review)
  • rasen validate clean; isComplete: true

🤖 Generated with Claude Code

…n SendMessage revival

Two coupled defects broke autopilot worker resume: the LEAD recorded a
fabricated `name` instead of the durable `agentId`+`transcript` the Agent
tool returns (so collectStageWorkers silently dropped the worker, forcing a
cold reconstruction), and the generated playbook wrongly claimed a completed
Agent-tool subagent is name-addressable within the same session. Capture
durable handles on dispatch, surface non-fatal resume warnings for name-only
worker records and duplicate JSON keys, and rewrite the revival paths to be
agentId-first with transcript warm-seed fallback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@DumoeDss
DumoeDss merged commit efbf313 into main Jul 13, 2026
10 checks passed
@DumoeDss
DumoeDss deleted the worktree-fix-worker-resume-handles branch July 20, 2026 09:22
DumoeDss added a commit that referenced this pull request Jul 28, 2026
…oject identity, ENOENT-discriminate reads (PR#88 B5/B6/M3/M4)

B5: commitStoreRegistration serialized via a per-root owner-aware lock; cleanup re-verifies metadata id+uid before delete (defense-in-depth; v1 undefined-uid handled). B6: clearProjectOwnership + migrate-membership acquire the per-record membership lock and re-read+merge roles so a concurrent add-project survives; per-record locking, no deadlock. M3: normalizeProjectIdentity (sameProjectIdentity helper) at all audited project-ID comparison sites in context.ts + execution-binding.ts. M4: readRecordFile + listStoreProjectRecords ENOENT-discriminate (StoreError on EACCES/EIO/EBUSY, not silent absent).

Tests: 102 pass / 1 POSIX-skip; B5/B6/M3/M4 deterministically red on pre-fix. tsc+lint clean. en/ja locales carry child #2's deferred mutationDegraded + #4's new error codes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
DumoeDss added a commit that referenced this pull request Jul 28, 2026
… wrapping, test fixes

Resolves the 6 remaining CI failures on PR #88 head (e3532d0):
- #2 audits-api socket hang: rejectImport uses socket.end() (FIN) + destroy fallback, not req.destroy() (RST)
- #4 B3 race loser: snapshot fs.existsSync before probe; absent-at-start + later-refused = obtain-failed (lost race)
- #5 token-audit: read() wraps all errors as AuditServiceError (was ELOOP on Linux symlinks)
- #1 pin RASEN_AGENT_RUNTIME per-test (dispatchMode assertion)
- #3 bootstrap-obtain registry cleanup via updateStoreRegistryState (was regex corrupting the entry)
- #6 board-page waitForState polling helper (fresh act() per poll)
M1: lost-race diagnostic split (retry, not relocate). T2: theoretical TOCTOU accepted-known.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
DumoeDss added a commit that referenced this pull request Jul 28, 2026
…robe + merge reconciliation

3 remaining CI failures on d49205b fixed:
- #1 pipeline-store-root-selection (persistent, failed 3x): validatePipelineByName
  passed no probeCodex to validatePipelineForExecution, so it probed the REAL
  codex binary. CI has no codex installed -> any pipeline with a codex role
  reported pipeline_runtime_unavailable. The prior host-runtime pin was
  insufficient because exec-bridge (claude host) ALSO probes codex. Fix:
  probeCodex: () => true -- validate is structural integrity; codex binary
  presence is a pre-execution concern (pipeline run preflight). Unsupported
  dispatch routes still fail.
- #2 command-registry (merge-introduced): the merged `update` command exposes
  --force/--all-projects/--only-this but COMMAND_REGISTRY only listed --force.
  Added the two dropped flags to the completion registry.
- #3 identity-boundaries (merge-introduced): project-home.ts AI_TOOLS.find
  (t => t.value === toolId) reads a TOOL id, not a store pointer alias; the
  guard scanned it because the file imports STORE_POINTER vocab. Added to
  INNOCENT_VALUE_RECEIVERS (matches init.ts::t precedent).

Verified locally (fresh build): the 3 files + doctor/project-registry/validate/update
regression all green; tsc + lint clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
DumoeDss added a commit that referenced this pull request Aug 9, 2026
…p+archive

Captures the ECP-7 close-out state at LEAD context ~95%: 5 children
terminal (foundation/prepare-unavailability/cutover/closure/host);
executor verified-CLEAN (round-1 + LEAD 7.1 additivity/Record-no-mutation
checks + projection clean) at 35/39, 4 ECP-8-deferred tasks gating archive.
Resume: ledger-reconcile + ship+archive executor -> policy-parity ->
operator items (self-hosting toy-change, ECP-8 macOS).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant