Repository navigation
Description
Summary
Since #3884 (a2a0cb1, released in v1.0.0-beta.87), every Codex user prompt is stored as two session messages. lcm_load_session returns the prompt twice, and the session database search returns it twice. Legacy rollouts that pair an agent_message event with an assistant response_item also duplicate the reply.
Cause
Codex writes one message as two records in the same turn:
- a
response_itemwithpayload.type: "message"and roleuserorassistant, and - an
event_msgwith the same text:item_completed/UserMessagefor prompts in current rollouts, or the legacyuser_messageandagent_message.
9d1f430 kept the response_item user message out of projection because item_completed already records it. #3884 made every user and assistant response_item message a canonical Message so import counts match the raw file. Projection is per record, so both records now become turns. The test change in #3995 asserts that both turns exist.
Evidence (record kinds and counts only)
A read-only census of local Codex rollouts:
| Rollouts | User item_completed events |
Paired with an identical user response_item |
Pair order | Same turn_id |
|---|---|---|---|---|
| 97 since 2026-10-10 | 16 | 16 | response_item first, adjacent |
yes |
| 150 from September | 420 | 419 | response_item first |
yes (635 of 635 pairs in 250 files) |
The prompt pairs have different native ids. They share the turn id (payload.turn_id on the event, internal_chat_message_metadata_passthrough.turn_id on the response_item). Current rollouts write replies as item_completed / AgentMessage followed by an assistant response_item. Capture leaves AgentMessage unsupported, so current replies project once.
Most user response_item messages with no event are subagent prompts, which only exist in that form. Keeping them searchable was the goal of #3884.
Reproduced through the real import path:
- The runtime acceptance test that admits a current-shape rollout gets three session messages for one prompt and one reply: the prompt twice and the reply once.
- MCP
lcm_load_sessionover the same rollout returns the prompt twice.
Expected
Each prompt and reply is one logical turn in projection, lcm_load_session and search. Capture keeps both records and their provenance. Stores that already hold both rows converge without a reset.
Activity