[coding-agents][Codex] Switching transcript_path within one session replaces earlier retained history
Summary
When a Codex task continues in a different rollout JSONL file while keeping the same session ID, the coding-agents integration can replace the previously retained conversation with only the continuation file's contents. Earlier facts associated with that document are then removed.
I observed multiple rollout files carrying the same session_meta.id in a Codex Desktop task. The retained conversation eventually matched the last segment rather than the accumulated history. A synthetic reproduction isolates this from transcript size: both files are under 1 KB.
Environment and verification scope
- Codex Desktop on Windows.
- Installed
@vectorize-io/hindsight-coding-agents: 0.6.1. - Local Hindsight API: 0.10.0, with append support advertised.
- Reader/planner/writer reproduction: executed against the installed 0.6.1 implementation, with an in-memory transport.
- Retain-to-server reproduction: separately executed against the original 0.6.1 writer and an isolated API bank; operations completed and document/fact contents were read back.
- Current
maininspected:bcca388b3a1125896d3f0b78578b798968e1f29c. The relevant replacement path remains in the source. I have not run the full integration against a build of this commit.
Steps to reproduce
- Create
rollout-a.jsonlwithsession_meta.payload.id = "synthetic-same-session", a user message sayingThe fictional Atlas connector is amber., and an assistant acknowledgement. Retain these two normalized turns under that session ID. - Append a user message saying
The Atlas review is Friday.and an acknowledgement to the same file. Retain again. This correctly appends the two new turns. - Create
rollout-b.jsonlwith the same session metadata ID, but only the next user message,The fictional Birch connector is violet., and an acknowledgement. The earlier messages remain in file A. - Supply the same hook
session_idwithtranscript_pathpointing to file B. The Codex reader supplies only B's two turns to the existing session cursor/writer. - Inspect the chosen update mode and the resulting
conversation:synthetic-same-sessiondocument.
The synthetic reader/planner/writer test produced:
| Input | Normalized turns | Update mode | Document identity |
|---|---|---|---|
| Initial file A | 2 | replace (initial creation) |
conversation:synthetic-same-session |
| File A after append | 4 | append |
same |
| Continuation file B | 2 | replace |
same |
File A was 623 bytes after its append; file B was 352 bytes. The final document contained violet and no longer contained amber or Friday.
The separate real-server test, using the same three-stage normalized-turn pattern and synthetic facts, confirmed the downstream effect:
| Completed stage | Document characters | Associated extracted facts | Earlier amber fact present |
|---|---|---|---|
| Initial retain | 283 | 1 | yes |
| Normal append | 429 | 2 | yes |
| Continuation, same session ID | 285 | 1 | no |
Those fact counts are observations from the test run, not an expectation about deterministic LLM extraction. The document replacement and missing earlier source text are directly observable. The temporary test bank was removed after verification.
Current source path
- The Codex hook declaration passes
ev.session_idand the singleev.transcript_pathto the reader. buildRetainreads that path; it does not reconstruct earlier files from the same session.planRetainchoosesreplacewhen the new turn count is smaller than the cursor or the prefix fingerprint differs.- The writer still uses
conversation:${sessionId}. Its replacement branch submits the currently available turns as the replacement document.
Expected behavior
A continuation file should preserve previously retained segments of the same task. Reconstructing a complete ordered session or retaining separate stable segment documents would both preserve that history. A partial continuation should not be treated as an authoritative replacement of the entire conversation.
Regression coverage should include a path change with a shorter continuation, a path change with an equal-or-larger but different prefix, and retrying the same continuation without duplicating content.
Related work
- #4380 / #4388 address the sliding 32 MiB tail window. Streaming a file in full fixes that cause, but does not recover earlier turns that live in a different file. The tiny-file reproduction above isolates this remaining case.
- #1222 / #2355 discuss preserving segments in the older Claude Code integration. They appear relevant as prior design work, but this report concerns the current shared coding-agents Codex path.
Source: vectorize-io/hindsight