Skip to content

fix(codex): read the human turns Codex writes now, not only the ones it used to - #371

Open
fstubner wants to merge 1 commit into
mainfrom
fix/codex-user-turns
Open

fix(codex): read the human turns Codex writes now, not only the ones it used to#371
fstubner wants to merge 1 commit into
mainfrom
fix/codex-user-turns

Conversation

@fstubner

@fstubner fstubner commented Sep 9, 2026

Copy link
Copy Markdown
Owner

Codex renamed the shape a user turn arrives in. The reader kept looking for the old one, so every human turn in a current transcript was dropped.

shape text location
old payload.type === "user_message" payload.message
current payload.type === "item_completed", payload.item.type === "UserMessage" item.content[].text

Nothing caught it, and nothing could have

event_msg is a known event type and payload.type was present, so the drift guard had nothing to report. The turns just stopped arriving.

Measured across the real store on this machine — 825 session files:

shape turns
old (read) 41
current (dropped) 15,169

Going back to 2025-12.

Why this is worse than a gap

Search still returned the assistant side of every Codex conversation, so a session looked present and complete while carrying almost none of what the person asked for. The question a handoff answers is usually "what was I trying to do" — which lives entirely in the half that was missing.

Verification

Against the newest real transcript on this machine:

human turns in the file 32
emitted before 0
emitted after 32, text intact

First recovered turn: "Can you audit this project?"

mutation result
revert to the old shape only 2 of 4 tests fail

710 tests pass, typecheck and lint clean.

Deliberately unchanged

response_item records with role user are still skipped: they're system-injected context (AGENTS.md, permissions, environment) and outnumber the real turns in a file carrying both, which is why they were never the answer.

Found by an audit agent reading real Codex files rather than the code.

…it used to

Codex renamed the shape a user turn arrives in and the reader kept looking for
the old one, so every human turn in a current transcript was dropped.

The original shape is `event_msg` with `payload.type === "user_message"` and
the text on `payload.message`. The current one wraps it: `payload.type ===
"item_completed"`, `payload.item.type === "UserMessage"`, and the text inside a
`content` parts array — the same parts shape the assistant side uses.

Nothing caught the change, and nothing could have. `event_msg` is a known event
type and `payload.type` was present, so the drift guard had nothing to report;
the turns just stopped arriving. Measured across the real store on this
machine, 825 session files: 41 turns still in the old shape, 15,169 in the new
one, going back to 2025-12.

What that produced is worse than a gap. Search still returned the assistant
side of every Codex conversation, so a session looked present and complete
while carrying almost none of what the person actually asked for — and the
question a handoff answers is usually "what was I trying to do", which lives
entirely in the half that was missing.

Both shapes are read now. `response_item` records with role "user" are still
skipped deliberately: they are system-injected context (AGENTS.md,
permissions, environment) and they outnumber the real turns in a file carrying
both, which is why they were never the answer.

Verified against the newest real transcript on this machine: 32 human turns in
the file, 0 emitted before, 32 after, text intact. Reverting to the old shape
alone turns two of the four tests red.

Found by an audit agent reading real Codex files rather than the code.
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