Repository navigation
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@codex review |
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. |
|
Codex Review: Something went wrong. Try again later by commenting “@codex review”. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What changed
accept_packetnow stores append-only generation claims underaccepted_packet:<capture>:<generation>. Each claim records the packet digest, an owner token, and its claim time. A different digest gets 409 while the current generation is committed or younger than the five-minute recovery bound. The bound has no measurement behind it; it is an explicit crash-recovery limit.Claims are never deleted. A durable committed marker is written after packet metadata and the capture or amendment record persist. An identical retry can finish a failed request, while a different packet can claim the next generation only after an uncommitted claim is stale.
The hostile tests cover a failed owner with an identical writer still active, cancellation and crash-style interruption, stale takeover, identical retry, and committed-generation retention.
Why
PR #331 deletes an uncommitted claim when a request fails. That lets a paused identical writer race with a later different packet. The later packet can overwrite the stored packet and metadata. Retaining generations prevents the failed owner from erasing the decision record.
How it works
flowchart TD A[Read generation 0] --> B{Same digest?} B -->|yes| C[Replay or complete] B -->|no, fresh or committed| D[409] B -->|no, stale and uncommitted| E[Claim generation 1] E --> F[Persist packet and metadata] F --> G[Write committed marker]The generation claim is the durable decision record. Full write fencing is not included in this WIP and remains below.
UI changes
N/A. This changes the finalize API and its state records.
Verification
env -u NODE_ENV OMP_NUM_THREADS=1 uv run --frozen --extra api pytest server/api/tests/test_finalize_hostile.py -qpassed: 15 tests.env -u NODE_ENV OMP_NUM_THREADS=1 uv run --frozen --extra api pytest server/api/tests -q --ignore=server/api/tests/test_events_orchestrator_wake.pypassed: 223 tests.env -u NODE_ENV OMP_NUM_THREADS=1 uv run --frozen --extra api ruff check server/api/finalize.py server/api/tests/test_finalize_hostile.pypassed.ruff format --checkpasses after formatting the two changed files.uvicornforserver/api/tests/test_events_orchestrator_wake.py.13e0989cbecause that head deletes the claim or leaves no claim after interruption. They pass on this commit.Risk
Packet bytes and shared metadata are still written to un-fenced keys. A paused generation can write after a newer generation takes over. That fencing work is left for the lead because it needs a coordinated storage-key contract. The PR is a WIP until fencing is added.
Checklist
🤖 Generated with Claude Code