fix(#5564): carry minted id onto eager-save checkpoint row in display merge

Codex/Opus gate finding: in eager session-save mode the current user turn is
checkpointed into s.messages before the agent runs (no id yet); after
_assign_stable_message_ids stamps the returned result row, the display merge
keeps the durable eager checkpoint and skips the stamped result — leaving the
display row id-less while its context twin carries the minted id, silently
defeating id-based fork/truncate alignment for eager-mode users. The merge now
copies the minted id onto the kept checkpoint when it lacks one (guarded so it
can't overwrite or duplicate). Opus verified cross-array id pairing holds across
the real 3-turn transform pipeline.
This commit is contained in:
nesquena-hermes 2026-07-04 23:06:21 +00:00
parent ee93425b26
commit a8568749a1

View file

@ -5264,6 +5264,18 @@ def _merge_display_messages_after_agent_result(previous_display, previous_contex
# before the agent runs. When the agent returns that same user turn
# in result_messages, keep the durable checkpoint and append only
# the assistant/tool delta.
# The eager checkpoint was written before _assign_stable_message_ids
# stamped the result rows, so it has no `id` while the context copy
# does — which would silently defeat id-based fork/truncate alignment
# for eager-mode users. Carry the minted id onto the kept checkpoint
# so display and context share it (#5564).
if (
isinstance(msg, dict)
and msg.get('id') is not None
and isinstance(merged[-1], dict)
and merged[-1].get('id') is None
):
merged[-1]['id'] = msg['id']
continue
if (
key is not None