Repository navigation
fix(goal-loop): a loop follows its pane when the agent is replaced (#1279) - #1287
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1279) Loops are keyed by session id, and every replacement path gives the pane a new one. The loop stayed under the dead id, so the pane, Resume/Stop and the new process's goal_loop_complete all missed it. The renderer, which commits the old -> new swap, now tells main (goal-loop:carry). Main moves the loop, paused as interrupted (the restart rule: never blind-continue into a process that has not proved its hooks), and never overwrites a successor's own loop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Juliusolsson05
added a commit
that referenced
this pull request
Sep 25, 2026
…ation with Goal Loop tools - A picker swap (newConversation) carried the old conversation's loop into an unrelated one, whose Resume then injected the wrong goal. - A reload that resolved the successor's domains without goal_loop still carried the loop into a process that can never call goal_loop_complete. Both now leave the loop where it was (paused under the old id, the pre-#1279 state). Tests cover both, the reload-all path and a user-paused loop (surviving mutants in review A). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…; pin reload-all and the carry's own persist - A2: a loop skipped by the carry (a different conversation, or a successor without goal_loop) stayed paused under an id no pane has; it is now stopped after the commit, like AgentMcpServersModal's own reload. - A1/B1: a mixed-capability Reload Agents test pins that only the successor keeping goal_loop gets the loop (deleting the reload-all carry or its filter now fails). - B2: the persistence check runs right after the carry, before complete() could rewrite the file, so a missing persist in carry fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…it and says what happens now The JSDoc sat above stopGoalLoops and still said a loop left behind stays paused; since review A2 such loops are stopped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
Author
|
Final disposition (pre-merge), head cef5365. Three independent reviewers:
Findings and dispositions: Round 1
Round 2
Round 1, reviewer C (final head; all minor, none fixed)
Residuals:
Merges through batch PR #1318 once every member passes its gate. 🤖 Generated with Claude Code |
This was referenced Sep 26, 2026
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.
Fixes #1279.
Found by the Stage 3 C2 hunt. Plan:
docs/plans/2026-09-25-goal-loop-follows-replace.md(first commit).Why
GoalLoopService keys loops by session id. Reload, provider switch, resume, rewind, the MCP toggle and Reload Agents all give the pane a new id. The loop stayed filed under the dead id, so it vanished from the pane: Resume and Stop couldn't reach it, and
goal_loop_completefrom the new process failed.What merges
GoalLoopService.carry(from, to)moves a loop to the successor.interrupt()a removal would. That drops the dead id's trackers, so an active loop arrives paused/interrupted. This is the restart rule: the new process hasn't proved its hooks. The user resumes the loop from the pane, which now finds it.goal-loop:carry, has the same trust gate asgoal-loop:control.replaceSessionand Reload Agents), after the commit, using the same old→new map it applies to pins, lanes and relationships. For each replaced pane:newConversation, e.g. the Conversations picker) and its resolved MCP domains includegoal_loop.controlGoalLoop({ action: 'stop' }), because no pane could ever reach it again, and a successor without Goal Loop tools could not complete it. This is the rule AgentMcpServersModal already applies to its own toggle.Tests
GoalLoopService.test.ts, 4 new tests):carrynever overwrites and ignores an unknown source;replacementOwnership.renderer.test.tsx, 5 new tests):npx tsc -bis clean.Residual
🤖 Generated with Claude Code