Repository navigation
fix(overleaf): resume sync steps a crash left unpublished - #624
Conversation
A crash before a step's bytes were staged let settlement close the step as skipped, and the applier then left its group half-applied. The applier now tries such a step again under a new record (step-N-1, ...) from plan.json. A crash between recording `publishing` and the native call left recovery unable to tell whether the call ran. The helper's lock outlives a dying server only until its call retires, so recovery now reads what stands: - exchange: staged copy still in its slot -> never ran; at the target -> ran - capture: nothing in `retained` -> never ran; something there -> ran - create: nothing at the target and its folder's change time unchanged since just before the call (new `parentChange`) -> never ran; otherwise review A step that never ran goes back to `prepared` and every check runs again. Adds a `called` test hook after each native call and real-crash tests for every unit shape at `checked` and `called`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
…ls in their group Codex round 1 on #624: - Recovery (a call without bytes) never makes a publication fenced by an expected mutation epoch: only its caller checks the epoch under the root lease. Such a record closes skipped with nothing published. This also closes the older case of a crash at `prepared`. - A folder removed before a file takes its place now carries the step's group checks, and the applier counts those removals when deciding whether a group was interrupted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex review, round 1 (gpt-6.1-sol, high reasoning)Verdict on
Each fix fails its tests without it (mutation-checked: 2, 1 and 1 failures). What held:
Now: 697 tests pass. Typecheck and lint are clean. Round 2 is reviewing the new head. 🤖 Generated with Claude Code |
…taging Codex round 2 on #624: - An admission indexed just before a crash, with no journal and nothing kept, is durably refused by settlement (nothing can have happened), so it no longer holds its file in attention; the applier retries such a step under a new record. - A staged copy whose identity was never recorded was still being written: it is private and unpublished, so it is discarded and staged again, or the step closes unpublished when recovery has no bytes. The crash-test child can now die inside a file rename or open, reaching windows between the native hooks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex review, round 2 (gpt-6.1-sol, high reasoning)Verdict on
The crash-test child can now also die inside a file rename or open. Test: What held:
Now: 701 tests pass. Typecheck and lint are clean. Round 3 is reviewing the new head. 🤖 Generated with Claude Code |
…ve layer decides Codex round 3 on #624 showed that settling an indexed admission without a journal as "nothing happened" was wrong: parent folders can be created before the first journal, settlement does not own the identity index it wrote to, and prune identities cannot be retried. That window is reverted to the native layer's design: the file stays in retained attention for explicit review, and nothing is lost. The applier's matching no-journal retry is removed with it. The crash test now asserts that outcome precisely, and still proves that a crash while staging finishes the group. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex review, round 3 (gpt-6.1-sol, high reasoning)Verdict on
Resolution: reverted, not patched further. The window between the file layer's intent index and a step's first journal can't be resolved from evidence. #353's native layer already handles it as retained attention: the file waits for explicit review, and nothing is lost. The applier's matching "no journal" retry is removed too. Test: Kept from round 2: discarding a staged copy whose identity was never recorded. Codex's live-writer probes showed the record-folder lease protects it. Test: Known limits of this PR, all ending in review with no data lost:
Now: 700 of 701 tests pass. The one failure is the intermittent 🤖 Generated with Claude Code |
Codex review, round 4 (gpt-6.1-sol, high reasoning)Verdict on What held:
Evidence: 230 committed tests and 26 extra probes passed on macOS. 🤖 Generated with Claude Code |
…able-steps-20261022
What this fixes
Follow-up to #620 (Codex's round 5 there). A crash at certain narrow points left a valid group of changes partly applied and handed it to review, even though recovery had what it needed to finish. This has to land before step 3 lets the applier write to the project folder.
step-N-1, …), using the bytes inplan.json, and reruns every check.displacedretaineddisplacedparentChange)When a call never ran, the step goes back to
preparedand every check runs again.Also fixed, found in review
prepared.Known limits
Both end in review with nothing lost.
Tests
checked(just before the call) and atcalled(just after it);vp test run src/scient/overleaf src/scient/workspace src/workspace: 701 tests. Typecheck and lint are clean. The intermittentplainPublicationlock-timing test recorded on #620 is unrelated. These tests need macOS native publication and are skipped on Linux CI.Review
Four Codex rounds (gpt-6.1-sol, high reasoning), recorded in the comments.
Plans: #535.
🤖 Generated with Claude Code