Windows Desktop: duplicate ordinal hides persisted tail; native projection recovery succeeds but loaded history stays stale
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
What version of the Codex App are you using?
Windows installed package: 26.903.9818.0, read from the running executable's package path, not the About dialog. Active backend: codex-cli 0.153.4, verified with the running backend executable's --version.
What subscription do you have?
Not independently verified during recovery. The final persisted turn ended with usage_limit_exceeded.
What platform is your computer?
Windows, x64, OS build 26200; PowerShell. A local Desktop conversation associated with a WSL working directory.
What issue are you seeing?
After a normal reboot, a long-running conversation reopened at an older point. Recent user/assistant exchanges and tool activity were absent from Desktop, although they remained in the canonical rollout JSONL. The original thread has now been recovered without editing either rollout, and I confirmed that its missing tail is visible again.
This is related to #44432, #43124, and #42197. The additional evidence here is a successful isolated native replay, exact preservation checks, and the difference between repaired persisted history and an already-loaded Desktop session. Please consolidate with an existing issue if appropriate.
Read-only diagnosis
The thread uses paginated history with an older base rollout and a continuation segment. Both files parsed through EOF:
- Base rollout: 166,136,929 bytes, 30,371 records.
- Continuation: 41,417,003 bytes, 7,189 records; final ordinal 37551 at 2026-09-11T17:16:11.269Z.
- The continuation contains exactly one non-increasing ordinal boundary:
ordinal type timestamp (UTC)
34088 response_item/custom_tool_call_output 2026-08-29T19:23:08.258Z
34089 event_msg/token_count 2026-08-29T19:23:08.271Z
34089 event_msg/thread_settings_applied 2026-08-29T19:23:44.638Z
34090 event_msg/task_started 2026-08-29T19:23:44.660Z
34091 turn_context 2026-08-29T19:23:45.711Z
The continuation's thread_history_projection_state row had:
next_rollout_byte_offset = 17972950
next_rollout_ordinal = 34090
Byte 17972950 starts the second record numbered 34089. Codex repeatedly logged:
failed to project durable rollout for <original-thread-id>:
thread-store internal error: thread history projection for <continuation-id>
expected ordinal 34090, got 34089
The catalog pointed to the correct rollout and had its current timestamp. SQLite quick_check passed. The base segment's much larger offset was valid for its separate file, not a cursor to reset. Projection failures were logged before the reboot; the reboot exposed stale persisted history rather than being established as the original cause.
What steps can reproduce the bug?
Observed sequence, not a deterministic minimal reproducer:
- Continue a long-running, paginated local Desktop conversation across multiple sessions.
- A token-count record and a later settings-applied record receive the same ordinal. The cause of that reuse has not been established.
- Later turns continue to be written to the rollout, while projection repeatedly fails at the earlier collision.
- Reboot and reopen the same conversation: Desktop shows the older projected endpoint.
What is the expected behavior?
Durable messages should remain accessible in the original conversation. Ordinal allocation should avoid reuse, and projection failures should produce an actionable indication rather than silently hiding the tail. Please provide a supported, transcript-preserving recovery path for affected threads, including refreshing already-loaded history state.
Additional information: successful recovery evidence
This was a case-specific diagnostic recovery, not a general SQL workaround recommendation:
- Backed up databases, WAL/SHM files, indexes, and both rollouts; also made consistent SQLite snapshots.
- In an isolated copy, changed only the continuation's expected ordinal from 34090 to 34089, leaving byte offset 17972950 unchanged. This allowed processing the settings record rather than skipping it.
- The installed native Codex backend resumed the isolated copy and replayed to byte 41417003 / next ordinal 37552, exactly EOF. SHA-256 checks confirmed both copied rollouts were unchanged.
- Compared native-generated projection rows against live state: 1,157 missing items and 15 missing turns, with all 1,204 existing continuation items and 6 existing turns unchanged.
- Installed only the native-generated missing rows and the EOF cursor in one SQLite transaction. Other threads' rows were verified unchanged; integrity checks passed. Both original rollout hashes remained unchanged.
- The already-running Desktop backend then returned the restored turn IDs but empty item lists, and the visible UI remained stale. A fresh isolated backend returned all 69 items in the final turn and all 5 items in the preceding completed turn. After a full Desktop restart, I confirmed the missing tail was visible in the original conversation.
No canonical transcript was rewritten, renumbered, truncated, or deleted. No state database was deleted, no replacement conversation was created, and no new user turn was submitted during recovery. Private thread identifiers, transcript content, project paths, credentials, and full logs are intentionally omitted.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing the native thread history projection and ordinal handling described in the report, then compare the isolated backend replay with the already-running Desktop backend. Reproduce the duplicate-ordinal case if possible and determine how projection failures and loaded-history refresh are surfaced. Done means durable history remains accessible without altering the canonical rollout and recovery is supported rather than case-specific.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust, sqlite
- Domain
- backend, databases, desktop
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 28/100