Skip to content

fix(herdr): restore worker child groups after model switches - #5864

Open
ShayGus wants to merge 6 commits into
kunchenguid:mainfrom
ShayGus:fm/fm-herdr-projection-relaunch
Open

ShayGus wants to merge 6 commits into
kunchenguid:mainfrom
ShayGus:fm/fm-herdr-projection-relaunch

Conversation

@ShayGus

@ShayGus ShayGus commented Sep 27, 2026 •

Copy link
Copy Markdown

Intent

In Herdr's left pane, workers normally appear as separate child groups under Firstmate. After their model was switched, the replacements appeared as tabs in one group. This is not acceptable. Find and fix that bug. Keep each worker's existing project work safe. The three live replacement tabs must return to child groups as well: add a guarded live repair for them plus safe child-group creation for future relaunches after a missing pane.

What Changed

  • Add a guarded Herdr reproject command that moves a live worker tab into its own child workspace, preserves its process and worktree, and rebinds the task record and presentation journal.
  • Recreate a projected child workspace during relaunch when the recorded pane and child are proven gone; refuse ambiguous recovery states and retain safe flat fallback.
  • Update Herdr documentation and add coverage for live moves, missing-child relaunches, ordering, and recovery refusals.

Risk Assessment

🚨 High: The three live default-session tabs remain unmoved and unverified, and the two upstream checks (CI, Require no-mistakes) have NOT run — both stand action_required with zero jobs on this fork PR head, waiting for upstream maintainer workflow approval, not passed. All code findings closed through review fix rounds at the gate head; Test passed.

Testing

Portable Herdr and control checks passed after fixing a host-specific process fixture. Named Herdr labs passed live reproject, adversarial rename, relaunch, and concurrent recovery checks; the long presentation run timed out after its relaunch proof, and a focused lab completed the remaining recovery check. The timed-out lab was removed through guarded teardown. No TUI screenshot was available because the lab viewer drains its pty output; captured Herdr workspace and pane responses show the live layout.

  • Live validation: ✅ go - 6 of 6 scenarios driven live against the product
Scenario Result Live Evidence
A worker spawned in Herdr appears in its own child group while the active tab keeps focus ✅ pass live presentation-herdr-e2e.log
A model-switch relaunch after the old pane disappears recreates an ordered child with the same projection token and preserved project worktree ✅ pass live presentation-herdr-e2e.log
Concurrent primary and secondmate recovery replaces old panes in separate child groups without focus drift ✅ pass live concurrent-recovery-workspaces.json and the two recovered pane responses
A live flat worker is moved into an ordered child while its agent process, endpoint, project copy, and focus survive ✅ pass live control-herdr-smoke.log
A renamed old child blocks a live move without rebinding the worker ✅ pass live control-herdr-smoke.log
A renamed receipt-named child is rejected before workspace ordering ✅ pass live control-herdr-smoke.log
Evidence: Live Herdr control smoke test

Source: Live Herdr control smoke test

ok - real herdr: exit on a pane with no registered agent is idempotent success
ok - real herdr 0.9.1: a gone session reads recoverable while a live pane and a malformed target do not
warning: /tmp/fm-control-herdr.PXBFa1/home/data/hsmoke/launch-brief.md records no ship branch; defaulting to legacy branch fm/hsmoke
warning: /tmp/fm-control-herdr.PXBFa1/home/data/hsmoke/launch-brief.md records no delivery contract line (scaffolded before ship briefs recorded one); launching on the explicit --mode no-mistakes - confirm its definition of done matches
ok - real herdr: a drifted agent-free shell returns to its worktree and reuses the same endpoint
ok - real herdr: interrupt refuses when herdr's own agent registry reports no agent
ok - real herdr: interrupt delivers the harness's key and proves the agent survived it
ok - real herdr: no control verb removed the endpoint or the task's local copy
ok - real herdr 0.9.1: a registration Herdr keeps after its agent exits reads stale-agent and recovers as dead
ok - real herdr: exit on a pane with a stale registration is idempotent success
warning: /tmp/fm-control-herdr.PXBFa1/home/data/hsmoke/launch-brief.md records no ship branch; defaulting to legacy branch fm/hsmoke
warning: /tmp/fm-control-herdr.PXBFa1/home/data/hsmoke/launch-brief.md records no delivery contract line (scaffolded before ship briefs recorded one); launching on the explicit --mode no-mistakes - confirm its definition of done matches
ok - real herdr: a stale registration no longer blocks relaunch, and the endpoint and local copy survive
ok - real herdr: an agent behind an unproven composer fails closed instead of typing an exit command into it
ok - real herdr: a renamed old child blocks a live move without rebinding the worker
ok - real herdr 0.9.1: reproject moves a live flat tab to an ordered child with its agent, process, and focus intact
error: herdr task tab for hreproj is not inside its owning parent; refusing live move
ok - real herdr: a renamed receipt-named child is rejected before ordering
Evidence: Live model-switch relaunch evidence

Source: Live model-switch relaunch evidence

ok - real Herdr lab: an opted-out spawn retains the Stage 1 Herdr command sequence with zero ordering calls
ok - real Herdr lab: a home that configured nothing is projected by default on herdr 0.9.1
ok - real Herdr lab: every projected create, task-tab create, seeded prune, and move preserves active workspace and tab
ok - real Herdr lab: persisted-focused seeded prune proceeds when no live client is attached
ok - real Herdr lab: bounded lock contention warns and falls back flat without projection or focus drift
ok - real Herdr lab: concurrent primary workers form one stable contiguous block without active workspace/tab drift
ok - real Herdr lab: forced workspace.move failure leaves a successful worker in default order with a warning and no cleanup
ok - real Herdr lab: concurrent post-create abort cleanup stays serialized with exact focus restoration
ok - real Herdr lab: Treehouse commands and metadata shape are byte-identical except for endpoint IDs and spawn incarnation
ok - real Herdr lab: exact task-pane close removes the projected workspace with no unrestored wrong-focus interval
ok - real Herdr lab: concurrent projected cleanup is serialized and leaves active workspace/tab unchanged
ok - real Herdr lab: three repeated concurrent create/order/cleanup waves have zero active workspace or tab drift
ok - real Herdr lab: the primary presentation setting inherits into real secondmate homes
ok - real Herdr lab: primary and two secondmate homes each own a top-level contiguous child block
ok - real Herdr lab: concurrent primary/A/B spawns preserve parent order and exact focus
ok - real Herdr lab: session lock contention from a secondmate home falls back flat with no journal
ok - real Herdr lab: Hi Bit and Wheelhouse-style same-identity restarts reclaim one nested space with exact focus and idempotence
ok - real Herdr lab: secondmate restart binding and reclaim stay isolated to the exact child home and parent
ok - real Herdr lab: a prepublication abort restores the old binding and permits retry
ok - real Herdr lab: a model-switch relaunch recreates the ordered child with the same token and captain focus
Evidence: Herdr workspace layout after concurrent recovery

Source: Herdr workspace layout after concurrent recovery

{"id":"cli:workspace:list","result":{"type":"workspace_list","workspaces":[{"active_tab_id":"w1:t2","agent_status":"unknown","focused":true,"label":"firstmate","number":1,"pane_count":1,"tab_count":1,"workspace_id":"w1"},{"active_tab_id":"w3:t3","agent_status":"unknown","focused":false,"label":"└ resume-wave-primary · p:rgBFjV_OpYEpIcOK0K--8A","number":2,"pane_count":1,"tab_count":1,"workspace_id":"w3"},{"active_tab_id":"w2:t1","agent_status":"unknown","focused":false,"label":"2ndmate-bravo","number":3,"pane_count":1,"tab_count":1,"workspace_id":"w2"},{"active_tab_id":"w4:t3","agent_status":"unknown","focused":false,"label":"└ resume-wave-bravo · p:Z2XEKCbrXs8cq4rfUdQkgg","number":4,"pane_count":1,"tab_count":1,"workspace_id":"w4"}]}}
Evidence: Recovered primary pane

Source: Recovered primary pane

{"id":"cli:pane:get","result":{"pane":{"agent_status":"unknown","cwd":"/tmp/fm-herdr-presentation.hdOGkR/recovery-project","focused":false,"foreground_cwd":"~/.treehouse/recovery-project-621056/1/recovery-project","pane_id":"w3:p3","revision":10,"scroll":{"max_offset_from_bottom":0,"offset_from_bottom":0,"viewport_rows":40},"tab_id":"w3:t3","terminal_id":"term_65c6f54f1a4905","terminal_title":". ","terminal_title_stripped":".","workspace_id":"w3"},"type":"pane_info"}}
Evidence: Recovered secondmate pane

Source: Recovered secondmate pane

{"id":"cli:pane:get","result":{"pane":{"agent_status":"unknown","cwd":"/tmp/fm-herdr-presentation.hdOGkR/recovery-project","focused":false,"foreground_cwd":"~/.treehouse/recovery-project-621056/2/recovery-project","pane_id":"w4:p3","revision":10,"scroll":{"max_offset_from_bottom":0,"offset_from_bottom":0,"viewport_rows":40},"tab_id":"w4:t3","terminal_id":"term_65c6f55a5150a6","terminal_title":". ","terminal_title_stripped":".","workspace_id":"w4"},"type":"pane_info"}}
- Outcome: 🔧 2 issues found → no changes applied ✅ across 2 runs (59m35s)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

⚠️ **Review** - 1 warning
  • 🚨 bin/backends/herdr.sh:3119 - A missing-child relaunch advances the presentation journal before publishing the replacement task record. If record preparation or publication fails (bin/fm-spawn.sh:4896, 4958), abort cleanup closes the new pane (bin/fm-spawn.sh:1255), but the journal still names it. The next retry fails the old-record equality check (bin/backends/herdr.sh:2958) and creates a flat tab (bin/fm-spawn.sh:3538), reproducing the reported layout bug. Keep the journal and record recoverably consistent on prepublication abort.
  • 🚨 bin/backends/herdr.sh:3348 - Herdr can apply a pane move and then return a CLI error. This branch treats that result as proof nothing moved; fm-control.sh:1237 then removes the recovery receipt and prior copies. Even with a successful move response, postmove failures at bin/backends/herdr.sh:3356, 3361, 3369, 3373, 3377, 3382, 3387, or 3391 return before the new IDs are exposed, so fm-control.sh:1242 records a moved receipt with an empty endpoint. Preserve uncertainty after issuing the move, expose response-derived IDs immediately, and make recovery consume the retained receipt.
  • ⚠️ bin/backends/herdr.sh:3167 - The live repair also accepts and upgrades version 1 journals (bin/backends/herdr.sh:3209, 3386, 3423). The specified model-switch case uses stale version 2 bindings; no intent requirement needs this less-bound legacy path. Remove version 1 acceptance from this repair.
  • ⚠️ bin/backends/herdr.sh:3297 - The new move accepts stale-agent and no-agent shell panes, including on resume (bin/backends/herdr.sh:3416); fm-control.sh:1194 also admits a dead agent grade. The requested repair is for live replacement workers. Remove the idle-shell acceptance and require a live worker.
  • ⚠️ bin/backends/herdr.sh:3003 - The new recreation and live-move paths each copy the token workspace and pane scan (bin/backends/herdr.sh:3261), alongside the existing recovery scan. No intent requirement needs parallel copies of this safety rule. Remove the copies and use one read-only token-risk check.
  • ⚠️ The criterion says, “The three live replacement tabs must return to child groups as well.” This change adds the reproject command and demonstrates it in a lab, but provides no evidence that it was applied to the three live tabs. Their actual layout is external to this worktree; confirm and complete that operational repair.

🔧 Fix applied.
11 issues (4 errors, 7 warnings) still open:

  • 🚨 bin/backends/herdr.sh:3119 - A missing-child relaunch advances the presentation journal before publishing the replacement task record. If record preparation or publication fails (bin/fm-spawn.sh:4896, 4958), abort cleanup closes the new pane (bin/fm-spawn.sh:1255), but the journal still names it. The next retry fails the old-record equality check (bin/backends/herdr.sh:2958) and creates a flat tab (bin/fm-spawn.sh:3538), reproducing the reported layout bug. Keep the journal and record recoverably consistent on prepublication abort.
  • 🚨 bin/backends/herdr.sh:3348 - Herdr can apply a pane move and then return a CLI error. This branch treats that result as proof nothing moved; fm-control.sh:1237 then removes the recovery receipt and prior copies. Even with a successful move response, postmove failures at bin/backends/herdr.sh:3356, 3361, 3369, 3373, 3377, 3382, 3387, or 3391 return before the new IDs are exposed, so fm-control.sh:1242 records a moved receipt with an empty endpoint. Preserve uncertainty after issuing the move, expose response-derived IDs immediately, and make recovery consume the retained receipt.
  • ⚠️ bin/backends/herdr.sh:3167 - The live repair also accepts and upgrades version 1 journals (bin/backends/herdr.sh:3209, 3386, 3423). The specified model-switch case uses stale version 2 bindings; no intent requirement needs this less-bound legacy path. Remove version 1 acceptance from this repair.
  • ⚠️ bin/backends/herdr.sh:3297 - The new move accepts stale-agent and no-agent shell panes, including on resume (bin/backends/herdr.sh:3416); fm-control.sh:1194 also admits a dead agent grade. The requested repair is for live replacement workers. Remove the idle-shell acceptance and require a live worker.
  • ⚠️ bin/backends/herdr.sh:3003 - The new recreation and live-move paths each copy the token workspace and pane scan (bin/backends/herdr.sh:3261), alongside the existing recovery scan. No intent requirement needs parallel copies of this safety rule. Remove the copies and use one read-only token-risk check.
  • ⚠️ The criterion says, “The three live replacement tabs must return to child groups as well.” This change adds the reproject command and demonstrates it in a lab, but provides no evidence that it was applied to the three live tabs. Their actual layout is external to this worktree; confirm and complete that operational repair.
  • 🚨 bin/backends/herdr.sh:3058 - A Herdr tab-create error after workspace creation leaves the new token workspace and seeded pane behind, but the relaunch falls back flat. The 33bb3f6 fix round left this post-mutation path at bin/backends/herdr.sh:3058-3067; workspace-create uncertainty at 2586-2605 and seeded-tab prune failure at 2638-2644 have the same risk. A later retry sees the leftover token and again falls back flat. Refuse fallback unless cleanup proves the entire new workspace is gone.
  • 🚨 bin/fm-spawn.sh:1283 - The 33bb3f6 rollback fix restores the old journal only in the EXIT trap and ignores a failed restore write here. A process crash before the trap, or a failed restore, leaves the journal naming the new endpoint while the old task record remains; the next retry fails the equality gate at bin/backends/herdr.sh:2958-2966 and creates a flat tab. Recover this same-identity, journal-ahead state at the shared recreation gate after proving the replacement cannot contain a live worker.
  • ⚠️ bin/backends/herdr.sh:3217 - If pane move returns an error before moving and supplies no IDs, the 33bb3f6 fix round retains an empty moved receipt (bin/fm-control.sh:1272-1280). On every rerun, pane get confirms the original live flat endpoint, but this branch refuses another move indefinitely. Resolve a retained uncertain receipt when the original endpoint and absence of a token child prove no move occurred.
  • ⚠️ bin/fm-control.sh:1085 - The change adds prior metadata and journal copies (bin/fm-control.sh:1161-1162, 1225-1228), receipt journal_bound and meta_bound fields (1085-1086), and control_reproject_tx in task metadata (1133-1141). No recovery path reads any of them, and the stated repair needs only the receipt phase and endpoint. Remove this unused transaction bookkeeping.
  • ⚠️ docs/herdr-backend.md:404 - This sentence says a live endpoint refuses reproject, contradicting the live-worker requirement and the allowed live path at bin/backends/herdr.sh:3233-3244. Change the refusal to the actual dead or unverified states.

🔧 Fix applied.
13 issues (4 errors, 9 warnings) still open:

  • 🚨 bin/backends/herdr.sh:3119 - A missing-child relaunch advances the presentation journal before publishing the replacement task record. If record preparation or publication fails (bin/fm-spawn.sh:4896, 4958), abort cleanup closes the new pane (bin/fm-spawn.sh:1255), but the journal still names it. The next retry fails the old-record equality check (bin/backends/herdr.sh:2958) and creates a flat tab (bin/fm-spawn.sh:3538), reproducing the reported layout bug. Keep the journal and record recoverably consistent on prepublication abort.
  • 🚨 bin/backends/herdr.sh:3348 - Herdr can apply a pane move and then return a CLI error. This branch treats that result as proof nothing moved; fm-control.sh:1237 then removes the recovery receipt and prior copies. Even with a successful move response, postmove failures at bin/backends/herdr.sh:3356, 3361, 3369, 3373, 3377, 3382, 3387, or 3391 return before the new IDs are exposed, so fm-control.sh:1242 records a moved receipt with an empty endpoint. Preserve uncertainty after issuing the move, expose response-derived IDs immediately, and make recovery consume the retained receipt.
  • ⚠️ bin/backends/herdr.sh:3167 - The live repair also accepts and upgrades version 1 journals (bin/backends/herdr.sh:3209, 3386, 3423). The specified model-switch case uses stale version 2 bindings; no intent requirement needs this less-bound legacy path. Remove version 1 acceptance from this repair.
  • ⚠️ bin/backends/herdr.sh:3297 - The new move accepts stale-agent and no-agent shell panes, including on resume (bin/backends/herdr.sh:3416); fm-control.sh:1194 also admits a dead agent grade. The requested repair is for live replacement workers. Remove the idle-shell acceptance and require a live worker.
  • ⚠️ bin/backends/herdr.sh:3003 - The new recreation and live-move paths each copy the token workspace and pane scan (bin/backends/herdr.sh:3261), alongside the existing recovery scan. No intent requirement needs parallel copies of this safety rule. Remove the copies and use one read-only token-risk check.
  • ⚠️ The criterion says, “The three live replacement tabs must return to child groups as well.” This change adds the reproject command and demonstrates it in a lab, but provides no evidence that it was applied to the three live tabs. Their actual layout is external to this worktree; confirm and complete that operational repair.
  • 🚨 bin/backends/herdr.sh:3058 - A Herdr tab-create error after workspace creation leaves the new token workspace and seeded pane behind, but the relaunch falls back flat. The 33bb3f6 fix round left this post-mutation path at bin/backends/herdr.sh:3058-3067; workspace-create uncertainty at 2586-2605 and seeded-tab prune failure at 2638-2644 have the same risk. A later retry sees the leftover token and again falls back flat. Refuse fallback unless cleanup proves the entire new workspace is gone.
  • ⚠️ bin/backends/herdr.sh:3217 - If pane move returns an error before moving and supplies no IDs, the 33bb3f6 fix round retains an empty moved receipt (bin/fm-control.sh:1272-1280). On every rerun, pane get confirms the original live flat endpoint, but this branch refuses another move indefinitely. Resolve a retained uncertain receipt when the original endpoint and absence of a token child prove no move occurred.
  • ⚠️ bin/fm-control.sh:1085 - The change adds prior metadata and journal copies (bin/fm-control.sh:1161-1162, 1225-1228), receipt journal_bound and meta_bound fields (1085-1086), and control_reproject_tx in task metadata (1133-1141). No recovery path reads any of them, and the stated repair needs only the receipt phase and endpoint. Remove this unused transaction bookkeeping.
  • 🚨 bin/backends/herdr.sh:3157 - Round 2 added a workspace-absence check but left the journal unchecked. If the journal rename takes effect and then reports an error, this branch closes the new workspace and returns 2 (bin/backends/herdr.sh:3159-3164). fm-spawn.sh:3547-3548 then launches flat while the journal names the removed child; the next relaunch refuses the mismatch. Permit flat fallback only after confirming the journal still matches the old task record, or restore that binding.
  • ⚠️ bin/backends/herdr.sh:3369 - With the parent followed by another workspace and ordering unavailable or failing, pane move succeeds but best-effort ordering leaves the child outside the parent block. The binding check then returns 2, leaving the live worker moved while its task record still names the old pane. Every retry has the same dependency. Preflight required ordering before the live move, and keep the endpoint record recoverable if ordering fails afterward. The same dependency affects recreation at bin/backends/herdr.sh:3134-3142; Round 2's resume path retains it at bin/backends/herdr.sh:3395-3397.
  • ⚠️ bin/fm-control.sh:1292 - The completed receipt phase is unnecessary once the task record and journal are bound: no recovery path reads phase=complete. Remove the completed receipt write and retain the receipt only for unresolved moves. Its write can currently fail after REPROJECT_PHASE becomes complete, causing the exit handler at bin/fm-control.sh:1093-1094 to skip releasing the session and metadata locks.
  • ⚠️ bin/fm-control.sh:1129 - This branch strips control_reproject_tx, but the final change never writes or reads that field. No live-repair or recovery requirement needs this legacy branch from an intermediate fix round; remove it.

🔧 Fix applied.
12 issues (4 errors, 8 warnings) still open:

  • 🚨 bin/backends/herdr.sh:3119 - A missing-child relaunch advances the presentation journal before publishing the replacement task record. If record preparation or publication fails (bin/fm-spawn.sh:4896, 4958), abort cleanup closes the new pane (bin/fm-spawn.sh:1255), but the journal still names it. The next retry fails the old-record equality check (bin/backends/herdr.sh:2958) and creates a flat tab (bin/fm-spawn.sh:3538), reproducing the reported layout bug. Keep the journal and record recoverably consistent on prepublication abort.
  • 🚨 bin/backends/herdr.sh:3348 - Herdr can apply a pane move and then return a CLI error. This branch treats that result as proof nothing moved; fm-control.sh:1237 then removes the recovery receipt and prior copies. Even with a successful move response, postmove failures at bin/backends/herdr.sh:3356, 3361, 3369, 3373, 3377, 3382, 3387, or 3391 return before the new IDs are exposed, so fm-control.sh:1242 records a moved receipt with an empty endpoint. Preserve uncertainty after issuing the move, expose response-derived IDs immediately, and make recovery consume the retained receipt.
  • ⚠️ bin/backends/herdr.sh:3167 - The live repair also accepts and upgrades version 1 journals (bin/backends/herdr.sh:3209, 3386, 3423). The specified model-switch case uses stale version 2 bindings; no intent requirement needs this less-bound legacy path. Remove version 1 acceptance from this repair.
  • ⚠️ bin/backends/herdr.sh:3297 - The new move accepts stale-agent and no-agent shell panes, including on resume (bin/backends/herdr.sh:3416); fm-control.sh:1194 also admits a dead agent grade. The requested repair is for live replacement workers. Remove the idle-shell acceptance and require a live worker.
  • ⚠️ bin/backends/herdr.sh:3003 - The new recreation and live-move paths each copy the token workspace and pane scan (bin/backends/herdr.sh:3261), alongside the existing recovery scan. No intent requirement needs parallel copies of this safety rule. Remove the copies and use one read-only token-risk check.
  • ⚠️ The criterion says, “The three live replacement tabs must return to child groups as well.” This change adds the reproject command and demonstrates it in a lab, but provides no evidence that it was applied to the three live tabs. Their actual layout is external to this worktree; confirm and complete that operational repair.
  • 🚨 bin/backends/herdr.sh:3058 - A Herdr tab-create error after workspace creation leaves the new token workspace and seeded pane behind, but the relaunch falls back flat. The 33bb3f6 fix round left this post-mutation path at bin/backends/herdr.sh:3058-3067; workspace-create uncertainty at 2586-2605 and seeded-tab prune failure at 2638-2644 have the same risk. A later retry sees the leftover token and again falls back flat. Refuse fallback unless cleanup proves the entire new workspace is gone.
  • ⚠️ bin/backends/herdr.sh:3217 - If pane move returns an error before moving and supplies no IDs, the 33bb3f6 fix round retains an empty moved receipt (bin/fm-control.sh:1272-1280). On every rerun, pane get confirms the original live flat endpoint, but this branch refuses another move indefinitely. Resolve a retained uncertain receipt when the original endpoint and absence of a token child prove no move occurred.
  • 🚨 bin/backends/herdr.sh:3157 - Round 2 added a workspace-absence check but left the journal unchecked. If the journal rename takes effect and then reports an error, this branch closes the new workspace and returns 2 (bin/backends/herdr.sh:3159-3164). fm-spawn.sh:3547-3548 then launches flat while the journal names the removed child; the next relaunch refuses the mismatch. Permit flat fallback only after confirming the journal still matches the old task record, or restore that binding.
  • ⚠️ bin/backends/herdr.sh:3369 - With the parent followed by another workspace and ordering unavailable or failing, pane move succeeds but best-effort ordering leaves the child outside the parent block. The binding check then returns 2, leaving the live worker moved while its task record still names the old pane. Every retry has the same dependency. Preflight required ordering before the live move, and keep the endpoint record recoverable if ordering fails afterward. The same dependency affects recreation at bin/backends/herdr.sh:3134-3142; Round 2's resume path retains it at bin/backends/herdr.sh:3395-3397.
  • ⚠️ bin/backends/herdr.sh:3342 - The live repair assumes the journal’s old child is gone, but the token scan matches labels only. If that exact workspace survives under a renamed label, reproject moves the flat worker at bin/backends/herdr.sh:3396 and overwrites the old binding at :3442; resume can overwrite it at :3477. Round 3’s token-scan extraction left this ID check absent. Prove the journal workspace ID is absent before moving or rebinding.
  • ⚠️ bin/backends/herdr.sh:3463 - Round 4 left ordering before verification in the Round 3 resume path. After a move succeeds but rebind stops, a user can rename the new child; retry reorders that receipt-named workspace at :3463, then rejects its changed label at :3464. The callers at :3305, :3332, and :3500 reach this path. Verify the exact unordered binding before changing workspace order.

🔧 Fix applied.
1 warning still open:

  • ⚠️ The criterion says, “The three live replacement tabs must return to child groups as well.” This change adds the reproject command and demonstrates it in a lab, but provides no evidence that it was applied to the three live tabs. Their actual layout is external to this worktree; confirm and complete that operational repair.
🔧 **Test** - 2 issues found → no changes applied ✅
  • ⚠️ The Test agent did not finish within its invocation budget. Reported: agent run tests timed out after 30m0s: agent last produced output 32s ago (98 observed); agent reported: codex exited: signal: terminated: 2026-09-27T03:22:23.916863Z ERROR rmcp::transport::worker: worker quit with fatal: Transport channel closed, when AuthRequired(AuthRequiredError { www_authenticate_header: "Bearer resource_metadata=&fix(watcher): make check wakes lossless via watcher-side suppression #34;https://mcp.posthog.com/.well-known/oauth-protected-resource/mcp\"" }) 2026-09-27T03:22:25.182368Z ERROR rmcp::transport::worker: worker quit with fatal: Transport ch.... This is a budget or provider-slowness cut, not a code failure. Re-running the same request costs another full budget, so no further attempt is made automatically. If this repository's targeted tests or evidence gathering routinely approach the default 30m0s, raise test_agent_timeout in global config. Respond with fix to spend another budget: a repair turn runs only for selected findings other than this budget cut, then validation re-runs. Or abort and retry after raising the budget.
  • 🚨 Approval is refused: the run worktree at ~/.no-mistakes/worktrees/f4bb769f35f8/01M3G8M8YGQPZF8RA5EE5Z86N8 holds work no Test turn validated, and the steps after Test would commit and publish it. It holds uncommitted changes to tests/fm-backend-herdr-presentation-e2e.test.sh, tests/fm-control-herdr-smoke.test.sh (inspect with git -C ~/.no-mistakes/worktrees/f4bb769f35f8/01M3G8M8YGQPZF8RA5EE5Z86N8 status and git -C ~/.no-mistakes/worktrees/f4bb769f35f8/01M3G8M8YGQPZF8RA5EE5Z86N8 diff). Respond with fix to validate it, or abort.

🔧 No changes applied.
✅ Re-checked - no issues remain.

  • Live validation: ✅ go - 6 of 6 scenarios driven live against the product
Scenario Result Live Evidence
A worker spawned in Herdr appears in its own child group while the active tab keeps focus ✅ pass live presentation-herdr-e2e.log
A model-switch relaunch after the old pane disappears recreates an ordered child with the same projection token and preserved project worktree ✅ pass live presentation-herdr-e2e.log
Concurrent primary and secondmate recovery replaces old panes in separate child groups without focus drift ✅ pass live concurrent-recovery-workspaces.json and the two recovered pane responses
A live flat worker is moved into an ordered child while its agent process, endpoint, project copy, and focus survive ✅ pass live control-herdr-smoke.log
A renamed old child blocks a live move without rebinding the worker ✅ pass live control-herdr-smoke.log
A renamed receipt-named child is rejected before workspace ordering ✅ pass live control-herdr-smoke.log
  • tests/fm-backend-herdr.test.sh: initial fixture failure reproduced; fixture fixed and rerun passed
  • tests/fm-control.test.sh: passed
  • timeout 420s tests/fm-control-herdr-smoke.test.sh: passed
  • timeout 900s tests/fm-backend-herdr-presentation-e2e.test.sh: passed through model-switch relaunch, then reached the time limit
  • Two focused named-lab runs of the concurrent recovery test body: passed; the second saved live workspace and pane responses
  • bin/fm-herdr-lab.sh teardown fm-lab-fm-herdr-present-2709868-20381: removed the stopped lab left by the timed-out run
  • Read-only Herdr session inventory confirmed no remaining fm-lab-* sessions; working tree contains only the three validated test edits
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

Upstream Checks

CI and Require no-mistakes both report action_required with zero jobs and no logs on this fork PR head, so no CI code ran. Both wait for upstream maintainer workflow approval. This PR is NOT ready to merge on checks, and the three live tabs stay unchanged until after merge and update.

…hildren on relaunch

fm-control.sh gains a herdr-only reproject verb that moves a live flat
task tab into an ordered projected child under its exact parent and
rebinds the task record plus the presentation journal. The pane keeps
its process, agent registration, and cwd. A crash-recovery receipt
makes reruns resume the rebind instead of moving again, and the new
child is never closed as rollback.

fm-spawn.sh relaunch rebind first attempts the same-token recreation
when the recorded pane and its whole workspace are positively gone,
keeping flat as the fallback for every ambiguous case.

Covers the model-switch incident shape both live and on future
relaunches.
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