Repository navigation
fix(pipeline): route a Manager DISPATCH from its reply text (#539) - #545
Draft
nt-nerdtechnic wants to merge 1 commit into
Draft
nt-nerdtechnic wants to merge 1 commit into
nt-nerdtechnic wants to merge 1 commit into
Conversation
The stage router read DISPATCH only from the Manager's screen buffer. A block that did not parse there was dropped without a log line, the workers' REPORTs stayed queued for MANAGER-READY, and the stage sat idle as running. The Manager's turn_complete text now feeds the same routing, each block is routed once, and a DISPATCH before MANAGER-READY implies it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #539. This covers suggestions 1 and 2 (the DISPATCH reaches its worker, and a DISPATCH before READY counts as READY). Suggestions 3 and 4 are not in this PR, so the issue stays open.
Problem
A stage-2 Manager (Claude) printed a
DISPATCHfor 畫師 and ended its turn without---MANAGER-READY---. The issue reads this as "dropped by design", but the stage router does not holdDISPATCHfor READY:managerRouterScanroutes anyDISPATCHit parses. What happened is that no router parsed this one. Both the stage router and the global Manager router readDISPATCHonly from the Manager's screencleanBuffer, and the run log has neither a🎯 → 畫師line nor aslot not foundline. SoparseDispatchBlocksfound no block there. A Claude screen merges rows: its status bar and spinner land on the sentinel's row, which is whyfindSentineltolerates them. Ato:/message:pair that does not sit on separate lines parses as nothing, and nothing was logged. The router had no other source, as its own comment said ("the router has no turn-text fallback of any kind").Meanwhile
queueOrRouteWorkerMsgheld the workers' REPORTs for READY, so all three panes went idle, each waiting on another, and the stage and its nodes kept showingrunning.Fix
routeManagerTurnTextis called on everyturn_complete. It finds the router of the running stage whose Manager is this pane, ignores a replayed turn older than the router's arm (the same tolerancejudgeTurnTextuses), and reads the reply text:---MANAGER-READY---, which marks the Manager ready;DISPATCHblocks, which are routed.routeManagerDispatchis now the one routing path for both the screen scan and the reply text. It records each block (the target plus the message with whitespace dropped, so the TUI's wrapping and indentation do not count) and routes it once.DISPATCHbefore READY implies READY:markManagerReadylogsManager READY (implied by its DISPATCH)and releases the held messages. Before READY the Manager can only be coordinating, and holding its workers' REPORTs for a line it may never print is what deadlocked the stage.markManagerReady, and its floor-cursor logic is unchanged.Not in this PR
deriveGlobalManageralso makes it the global Manager. So the global router and the stage router both scan the same panes. The global router routes worker REPORTs to the Manager at once, bypassing the pre-READY queue: the run log's01:37:12 🎯 Global → Manager: [REPORT from 畫師]comes before READY. When the Manager's screen does parse, both routers inject the sameDISPATCH. That is a separate root cause, and a follow-up.STAGE-DONEis still read from the screen only. A Manager whose screen does not show it is caught by the stage watchdog.pipeline_status, and a stage-editor hint about DISPATCH/REPORT) are not done.Tests (red first, then green)
App.managerDispatchTurnText.test.ts(new) lifts the routing functions out and runs them against stubs:DISPATCHreaches its worker;DISPATCHbefore READY implies READY and releases the held REPORT;MANAGER-READYin the reply releases the queue;All 6 failed before the fix.
Also run locally:
App.managerStageWatchdog,App.pipelineScanWindow,App.pipelineLinearRegressionandApp.pipelineStagePrewarm(71 tests in total), andpnpm typecheck. All green.Protection check
DISPATCHrouting moved intomarkManagerReadyandrouteManagerDispatch, with the same log lines.markManagerReady,routeManagerDispatchandrouteManagerTurnTextfunctions, and theStageRouter.routedDispatchesfield.🤖 Generated with Claude Code