fix(codex): resolve forks of turnless parents instead of retrying forever - #1578
Conversation
…ever Codex Desktop writes a rollout the moment a thread opens, so a fork taken before the first prompt names a parent that holds only session_meta and settings events. The fork gate treated a parent with no turn ids the same as a parent it could not find: the child was marked DataVersionNeedsRetry and re-parsed on every pass, and because a retry counts as a failure, one such fork on a reconciliation page aborted the page and every page behind it. A local archive carried six of these forks, all with readable parents, and logged the same abort every fifteen seconds for a day. A parent that was read but never opened a turn is resolved: the fork replayed no history, so the gate has nothing to drop and a retry could never learn more. Only a parent that cannot be read still defers the child.
roborev: Combined Review (
|
…nt blocks A readable parent with no turn ids does not always mean the fork replayed nothing: the parent may have written turns the fork copied before its own file flushed them. The child rollout tells the two apart, because a replay prefix always begins with the copied parent session_meta. Resolve the fork as current when that copied meta is absent, and keep deferring it until the parent advances when it is present, which the added test pins down.
roborev: Combined Review (
|
…ta gate The copied-meta rule from the previous commit assumed that a replayed parent prefix always starts with the parent's copied session_meta, so its absence proved the fork replayed nothing. Local Codex archives show otherwise: on Codex 0.147.0, the reporter's version, forks routinely replay parent turns with no copied parent session_meta at all. About half of the forks in one archive have no copied meta, and most of those still carry parent turn ids. The copied meta is not a replay signal. Without that signal the extra branch only guarded a window of a few milliseconds between Codex writing a turn to the parent rollout and a fork copying it, and with zero known parent turn ids the fork gate suppresses nothing on either branch. So the rule collapses to the first commit's intent: a parent that can be read is settled, a parent that cannot be read defers the child. The full-file scan for the copied meta and the test that pinned the disproven premise are removed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0158DH4fPMj7ogzQdPmyRqUZ
roborev: Combined Review (
|
|
The medium finding on From upstream
So the replayed prefix is a copy of what was already on disk, and rollout files are append-only. A parent with zero Two more points:
Caveat: the source read is current generated by a clanker |
Codex Desktop writes a rollout the moment a thread opens, so a fork taken before the first prompt names a parent that holds only
session_metaand settings events. The fork gate treated a parent with no turn ids the same way as a parent it could not find: the child was stampedDataVersionNeedsRetry, re-parsed on every pass, and never reached the current data version. Because a retry counts as a failure incollectAndBatch, one such fork on a reconciliation page aborted that page and every page behind it. A local archive carried six of these forks in one chain, every parent present and readable, and logged the identical abort every fifteen seconds for a day; the deferred-source work in #1490 stops the abort from spreading but leaves those forks permanently deferred.codexParentResolutionnow treats any parent that can be read as resolved, whether or not it holds turn ids. A turnless parent never opened a turn, so the fork replayed nothing and the gate has nothing to drop; with an empty parent turn set the gate suppresses nothing either way, so parsing the child as current is the only change. A parent that cannot be read still defers the child, exactly as before.An earlier revision of this PR kept a turnless parent blocking when the child carried a copied parent
session_meta, on the theory that a replay prefix always begins with that copied meta. A survey of a large local Codex archive disproved it: about half of the forks there, including many written by Codex 0.147.0, replay parent turns with no copied parent meta at all. That gate and its test are gone, which is why the net diff is small.Reviewers should look at
codexParentResolutionininternal/parser/codex.goandTestCodexProviderTurnlessParentResolvesWithoutRetry, which parses a fork of a meta-only parent and expects a current result with only the child's messages.Closes #1582
🤖 Generated with Claude Code
https://claude.ai/code/session_0158DH4fPMj7ogzQdPmyRqUZ