Repository navigation
fix(core): hide instruction updates a revert left behind - #63667
Conversation
There was a problem hiding this comment.
The fix holds up. With the runner harness I reproduced the stale instruction notice after a committed revert on dev, using both the PR's scenarios and the steps from #62027, and it's gone with this change. The session-* core tests pass (794/0), as does tsc -b in packages/core.
Hiding updates whenever no state exists is sound, because the next step always starts a fresh state from a new event. After compaction the hidden updates are already in the baseline, since advancing the epoch copies the current values into it. Forks are unaffected because their epoch starts at 0.
Public API unchanged: the only addition is the internal InstructionState.epochStart. session.context returns fewer messages only in the post-revert case, which matches its documented meaning (the active context messages).
No blocking concerns.
Issue for this PR
Closes #62027
Related: #61550 is the same kind of contradiction in historical forks. This PR doesn't change forks, so that one stays open.
Type of change
What does this PR do?
After a revert, the model could see an instruction update that contradicts its own system prompt.
When a committed revert removes an instruction update, core throws away the instruction state, and the next step builds the system prompt again from current values. Updates that came before the revert point stay in history, though, and the model still sees them. So it gets the fresh system prompt plus an old update saying something else.
Reproduced on
devwith the runner test harness:This affects every instruction source: MCP guidance, Code Mode catalog, date, API entries. It would also affect a Plan-style "you are in Plan mode" source: after this revert the session is back on build, but the model is told it's in Plan.
The fix: the instruction state already records where its current system prompt starts (
epoch_start), and every update before that point is already included in it. History now hides instruction update messages older than that point. If there is no state, as right after the revert clears it, the next system prompt is built fresh, so every older update is hidden.The filter is in
messageEntries, so the runner,generate, compaction, the compaction precompute andsession.contextall see the same history.What else changes, and why it's safe:
session.context(documented as the active context messages) drop the stale update.How did you verify your code works?
hides an update a revert left behind once the source is removed, and the existingresyncs the instruction state when a committed revert removes an updatenow also checks the messages. Both fail without the fix and pass with it.bun typecheckinpackages/core.devon my machine.Screenshots / recordings
Not a UI change.
Checklist