Skip to content

🤖 fix: keep frozen system sections on an assistant-last retry - #7654

Merged
ThomasK33 merged 3 commits into
mainfrom
tk/f36-f37
Oct 27, 2026
Merged

ThomasK33 merged 3 commits into
mainfrom
tk/f36-f37

Conversation

@ThomasK33

Copy link
Copy Markdown
Member

Summary

A retry after a failed stream no longer rewrites the warm prompt cache when a frozen system section changed during the turn. Before, a request whose history ends with an assistant row (a retry after "stream closed unexpectedly", or a resume) re-froze every changed section at its live value: the skill index, AGENTS.md blocks, Tool: sections, the MCP list and the volatile tail. Now such a request keeps the frozen sections and records nothing. The next request after a user message sends the change as a row. The PR also adds two tests for #7652 and #7653.

Background

On 2026-10-26 the host logged three cache.prefix_break events in the tool block (agent_skill_read), on a build that already freezes the skill index (#7308). Each came 13 to 22 seconds after turn.failed ("Anthropic stream closed unexpectedly") and an automatic retry. In two workspaces, the retry's assistant row recorded a second system skill-index record inside the same segment (12,113 to 11,996 characters), because the skill list had changed globally during the turn. The only path to a mid-segment system record is the assistant-last branch of planSystemSection.

Implementation

planSystemSection (volatileSystemTail.ts): when the history does not end with a user message, it now returns the frozen section plus the rows already sent, with no new record. It no longer re-freezes at the live value. A re-freeze for a model, route or agent switch still runs first and is unchanged.

Validation

  • New: "a retry after an assistant row keeps the frozen skill index in the tool block" (the live case), and "an assistant-last request keeps the frozen tail and the next user turn sends the row". Both fail with the old branch. I rewrote two tests that pinned the old re-freeze.
  • Tests for 🤖 fix: move the MCP server list into the volatile system tail #7653: a route without tail rows (OpenAI) still sends the live <mcp> list in the system prompt, with no row and no record.
  • Tests for 🤖 fix: put post-compaction attachments before the newest request #7652: with a file-change notification as the newest user row, the post-compaction attachments keep their place across a retry, a mid-turn budget warning, a request without attachments, and the next turn. The test fails with the old splice, with append-at-end, and with synthetic rows skipped.
  • Nothing reads the synthetic attachment row's timestamp: convertToModelMessages drops the metadata.

Risks

Low. On an assistant-last request, the model reads the frozen sections until the next user turn. A flow that never adds a user row would never see a change. I know of no such flow. The rebuilds in turnRequestBuilder.ts (rebuildAfterSequencing, the thinking-level rebuild) still reuse the first payload's tools. With this fix both builds plan the same tools, but the code does not enforce that.


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $604.04

A request whose history ends with an assistant row (a retry after a
stream failure, or a resume) cannot carry a system row, so a changed
frozen section re-froze at the live value. On the live host that
rewrote the cached tool block three times on 2026-10-26: each time the
retry came 2 s after "Anthropic stream closed unexpectedly", and the
skill list had changed during the turn. The section now stays frozen,
the request records nothing, and the next request after a user message
sends the change as a row. The turn's earlier steps read the frozen
section anyway.

---
_Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_
<!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
…ile-change row

- aiService: an OpenAI route (no system rows) still sends the <mcp>
  server list in its system prompt after #7653, live, with no tail row
  or record.
- turnContextAssembler: with a durable <system-file-update> row as the
  newest user row, post-compaction attachments go between the user's
  message and the notification, and a retry after the committed
  assistant row, a budget warning appended mid-turn, the plain request
  and the next turn all keep the rows before the turn's request.

---
_Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_
<!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-26T23:50:46.338930Z 6e3d58b Manual request
🔒 Security Review ✅ Completed 2026-10-26T23:51:30.687395Z 6e3d58b Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: bc27080698

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bc27080698

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/utils/messages/volatileSystemTail.ts
@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

🟢 e2e stories (Haiku): 14 passed

22 agent steps · 7 replayed from cache · 15 model calls · 46.3k tokens (28% cached)
Spend: $0.09 of the $1.00 cap (proxy ledger)

All 14 tests in 9 files
Test Agent Time
🟢 chatRestart.e2e.ts · 1 passed 1 step · 1 call 5.6s
🟢 a chat survives a restart of the server 1 step · 1 call 5.6s
🟢 compaction.e2e.ts · 1 passed 1 step · 1 call 4.8s
🟢 /compact replaces the old chat with a summary 1 step · 1 call 4.8s
🟢 pluginTrustRestart.e2e.ts · 1 passed 4 steps · 2 calls 9.3s
🟢 a trusted plugin hook stays trusted after the server restarts 4 steps · 2 calls 9.3s
🟢 settingsRoundTrip.e2e.ts · 1 passed 2 steps · 1 call 9.1s
🟢 a chat survives trips through Settings 2 steps · 1 call 9.1s
🟢 sidebarPerWorkspace.e2e.ts · 1 passed 4 steps · 1 call 4.9s
🟢 a new workspace starts with its right sidebar collapsed while another keeps it open 4 steps · 1 call 4.9s
🟢 smoke.e2e.ts · 1 passed 2 steps · 1 call 2.6s
🟢 the agent opens the playground workspace 2 steps · 1 call 2.6s
🟢 streamErrors.e2e.ts · 1 passed 1 step · 1 call 7.1s
🟢 stream errors show in the chat, and the chat recovers 1 step · 1 call 7.1s
🟢 todoNudge.e2e.ts · 1 passed 1 step · 1 call 3.1s
🟢 the agent finishes open TODO items after the turn-end nudge 1 step · 1 call 3.1s
🟢 touchAlignment.e2e.ts · 6 passed 6 steps · 6 calls 22.3s
🟢 the Settings close button is level with the title on a touch screen 390px wide 1 step · 1 call 4.7s
🟢 the Settings close button is level with the title on a touch screen 768px wide 1 step · 1 call 4.0s
🟢 Backup settings checkboxes are small and level with their labels on a touch phone 1 step · 1 call 4.1s
🟢 the heartbeat checkbox is small and level with its label on a touch phone 1 step · 1 call 3.3s
🟢 a reply's model and time stay on one line on a touch phone 1 step · 1 call 3.0s
🟢 the workspace actions menu stays on the title row on a touch phone 1 step · 1 call 3.3s

e2e 0.20.0 · 1m 12s · web · run artifacts

🟢 e2e Electron stories (Haiku): 3 passed

3 agent steps · 3 model calls · 8.0k tokens (32% cached)
Spend: $0.01 of the $1.00 cap (proxy ledger)

All 3 tests in 3 files
Test Agent Time
🟢 electron/deepLink.e2e.ts · 1 passed 1 step · 1 call 6.4s
🟢 a deep link of a second launch starts a chat in the running app 1 step · 1 call 6.4s
🟢 electron/menuBar.e2e.ts · 1 passed 1 step · 1 call 6.0s
🟢 the workspace menu bar is the desktop title bar 1 step · 1 call 6.0s
🟢 electron/smoke.e2e.ts · 1 passed 1 step · 1 call 5.5s
🟢 Xum Electron opens the playground workspace 1 step · 1 call 5.5s

e2e 0.20.0 · 20.1s · electron · run artifacts

🟢 e2e agent repros (Haiku): no tests selected

Spend: $0.00 of the $1.00 cap (proxy ledger)

e2e 0.20.0 · 5.3s · 2 targets (web, phone) · run artifacts

An assistant-last request keeps the frozen sections (F36), but only the
custom-instructions channel took the model/agent switch re-freeze. A
partial turn resumed under another agent, model or route then kept the
old agent's frozen Tool: instructions, skill index and volatile tail
until a later user turn. planSystemPrompt now computes the switch once
and passes it to every channel's planner, so a switch re-freezes all
sections and records "system" for each, which replay reads back. A
same-agent retry still keeps the frozen sections.

Codex PRRT_kwDOPxxmWM6wf11x.

---
_Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_
<!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: 6e3d58b3b3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 6e3d58b3b3

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33
ThomasK33 added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit 9878324 Oct 27, 2026
34 checks passed
@ThomasK33
ThomasK33 deleted the tk/f36-f37 branch October 27, 2026 00:38
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