61cd299c6e
Follow-up to #96634 (stall-fallback retry, #78981) addressing donovan-yohan's post-merge adversarial review. The stall path detaches a timed-out primary worker (fence cancel wins; future stays on the pool) and immediately runs the fallback against the SAME ContextCompressor, creating two verified races: 1. Late-primary snapshot restore: the detached primary's unwind called _restore_compressor_attempt_state with the PRIMARY's pre-attempt snapshot. Landing after the fallback's commit it rolled _previous_summary/cooldown/provenance/telemetry back to pre-primary values, silently discarding fallback-owned state. 2. Shared _compression_cancelled_check: the late primary's `finally` cleared the callback the fallback had just installed, so the fallback's F4 cancellation consult read None. Fix: a monotonic per-compressor attempt generation claimed under one module lock (_claim_compressor_attempt). Snapshot restores carry their claiming generation and no-op when stale; the cancelled-check set/clear moves into owner-stamped helpers (_install_compression_cancelled_check / _clear_compression_cancelled_check_if_owner) so only the installing attempt can clear it. The commit fence keeps owning COMMIT admission; the generation owns compressor-ATTRIBUTE writes — two boundaries. Legacy callers (attempt_generation=None) and slotted third-party compressors (generation 0) keep the historical unconditional behavior. Secondary review items: - Lean chunk digests during a stall-fallback retry now follow the summary onto the pinned healthy route: take_pinned_summary_route() echoes the consumed route into a context-local _SUMMARY_ROUTE_CONSUMED, and _build_chunk_digests passes attempt_summary_route_kwargs() (non-consuming) to call_llm. The pin's single-use contract for the SUMMARY call is unchanged — the main-model retry still never re-issues the pinned route. - Worker re-run repeating pre-compression callbacks: documented as an accepted limitation on _retry_compression_on_fallback_chain (built-ins idempotent; resuming mid-pipeline would couple the retry to host callback ordering). Tests (tests/agent/test_compression_attempt_ownership.py, 10 cases): deterministic interleavings for both races (late-primary restore no-ops + preserves fallback state; stale finally cannot clear the fallback's callback), legacy/slotted compatibility, digest route follow + context-locality of the consumed echo. Mutation-checked: reverting only the two prod files to origin/main fails the suite; restored stack green (21 passed incl. the original #78981 suite). The one red in the wider sweep (test_silence_cannot_approach_double_idle_timeout) is pre-existing on clean origin/main — verified independently.