Skip to content

fix(codex): fence overlapping compaction attempts - #94

Open
mulfyx wants to merge 1 commit into
raine:mainfrom
mulfyx:fix/codex-compaction-generation-fencing
Open

fix(codex): fence overlapping compaction attempts#94
mulfyx wants to merge 1 commit into
raine:mainfrom
mulfyx:fix/codex-compaction-generation-fencing

Conversation

@mulfyx

@mulfyx mulfyx commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Summary

Codex compaction kept one registry entry per Claude session, while asynchronous compaction producers and terminal handlers identified that entry only by session and model.

On base 529e1d6, a compaction request awaits upstream work before storing its result (request path). Meanwhile, store_compaction replaces the session slot unconditionally, and activation/abort do not identify the originating attempt (registry and store, activation and abort).

With overlapping compactions A and B for the same session, a late A completion could therefore:

  • overwrite B's newer native history;
  • anchor B's native history with A's portable summary;
  • clear B's state after a late A failure.

This change:

  • allocates a monotonic CompactionAttempt before awaiting upstream compaction;
  • publishes a Preparing generation immediately;
  • permits store, activation, and abort only for the current generation;
  • carries the generation through replay and all buffered/live completion and cleanup paths.

The scope is same-session stale-completion/lost-update protection, not a cross-session isolation issue.

Consistency precedents

These are consistency precedents, not claims that the Responses compaction API mandates generation IDs:

  • This repository's continuation state already allocates a turn ID before asynchronous work and rejects stale publish/abort operations (allocation, guards).
  • OpenAI documents compacted encrypted_content as an opaque item that must be carried into subsequent Responses requests (compaction guide). Keeping it paired with the portable summary from the same attempt is therefore an application-level consistency requirement.
  • OpenAI Codex uses expectedTurnId as an optimistic concurrency precondition (schema) and validates it atomically under the active-turn lock (implementation).
  • RFC 9110 describes conditional writes as protection against parallel lost updates (If-Match section 13.1.1).

Validation

  • The stale-activation regression test fails on the unfenced implementation and passes with this change.
  • Deterministic tests cover stale store, activation, abort, replay abort, invalid stale summary, and replay checks while a newer generation is still preparing.
  • cargo test --all-targets: 828 tests passed.
  • cargo clippy --all-targets -- -D warnings: passed.
  • A controlled runtime A/B race delayed A until B completed; the next turn replayed the newer native-B history.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant