Repository navigation
Resume accepted inside a delete's commit window waits the delete out instead of exiting - #12
Conversation
…te out instead of exiting A launcher can accept a resume by installing .resuming after a delete's checks and before its rename; the delete then finds the marker and rolls back. But an engine that started before the rollback finished found the run in the trash (no journal) or under the delete's lock (already being executed) and exited, so the accepted resume never ran. retention now marks its run lock op: 'delete'. A resume (the CLI's run --resume and resume paths, which the CLI, MCP and viewer launchers' children enter, and the engine's ownership step) waits up to 15s while a live delete holds the run, at its path or in a trash entry, then proceeds: the run is back if the delete rolled back, gone if it committed. Tests cover the engine starting under the delete's lock and while the run is in the trash (both failed before), and the post-rename test now expects the waiting resume to take the run after the rollback without ever recreating runs/<id>.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: eab6d90210
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
To use Codex here, create an environment for this repo. |
Follow-up to #12 from its Codex review. claimRun checked for a delete in progress only after a claim failed, so a delete that finished in between left the resume exiting with a stale error although the run was back. Once no delete is in progress, one more claim decides. Deterministic regression test in test/retention.test.js.
Fixes the production follow-up flagged in #10. A resume accepted while a delete of the same run was committing could fail quietly.
The problem
A launcher can accept a detached resume inside a delete's commit window. That is after the delete's checks and before its rename. The launcher installs
.resumingand spawns the engine, and the delete then finds the marker and rolls back (§7.3.3: delete loses). But the spawned engine is a separate process, and it can reach the run before that rollback finishes:run.lock, so the engine refuses withrun is already being executed by pid <delete's pid>.no journal.Either way the engine exits and does not retry. The accepted resume never runs, and its marker ages out after 30s. Safety held, since the run was never both resumed and deleted, but the resume was lost.
The fix
retentionmarks its run lockop: "delete"(src/run-lock.jsacquireRunLock(dir, { op })).deleteInProgress(dir, trashRoot, runId)checks for a lock markedop: "delete", held by a live process, written within the last minute. It looks at the run's directory and at the run's trash entries, since the lock travels into the trash with a committing delete.A resume waits up to 15s (
settleDelete, polling every 50ms) while a delete is in progress on its run, then proceeds:run --resumeandresumepaths, before the journal read (these are the paths the CLI, MCP and viewer launchers' children enter);claimRun), around the directory check and lock acquisition.If the delete rolled back, the run is back and the resume takes it. If it committed, the resume fails exactly as before.
Unchanged:
runs/<id>before it owns the run. The single linearization point (the delete's rename) holds.Tests (
test/retention.test.js)runs/<id>and that the rollback restored the run byte for byte. It then asserts that the waiting resume takes the run. This test fails on main.Docs: ARCHITECTURE.md (
run.lock), CHANGELOG (Unreleased → Fixed).