Skip to content

fix(compaction): let admission proceed when the breaker cancelled opportunistic compaction - #532

Closed
effortprogrammer wants to merge 2 commits into
code-yeongyu:mainfrom
effortprogrammer:fix/issue-531-compaction-cooldown-admission
Closed

fix(compaction): let admission proceed when the breaker cancelled opportunistic compaction#532
effortprogrammer wants to merge 2 commits into
code-yeongyu:mainfrom
effortprogrammer:fix/issue-531-compaction-cooldown-admission

Conversation

@effortprogrammer

@effortprogrammer effortprogrammer commented Jul 30, 2026

Copy link
Copy Markdown

What changed

When the compaction circuit breaker cancels an opportunistic (threshold / pre-prompt) compaction, admission now proceeds without compaction instead of throwing RequiredCompactionError:

  • _enforceCompactionBeforeProvider — pre-prompt threshold tail returns "not compacted" on cooldown instead of throwing
  • _enforceFinalProviderAdmission — proceeds on cooldown only when the final payload is not actually oversized
  • _revalidateScheduledContinuationAdmission — proceeds on cooldown
  • _handleRetryableError — retries the turn instead of returning "blocked" on cooldown

Overflow-triggered admission is untouched (fail-closed). If the context genuinely exceeds the window, the provider's overflow error drives the existing one-shot overflow recovery, so proceeding is safe.

Why

The breaker's job is to stop paying for doomed compaction during a provider outage. But core converted the breaker cancel (rejectionCause: "circuit-breaker") into a hard admission failure on every path, so a tripped breaker bricked any session over the soft threshold: every prompt rejected with Context remains above the compaction threshold because compaction did not complete, forever. Any autonomous continuation driver (extensions that re-prompt on agent_end) loops without bound.

Live forensics on a real stuck session (issue #531 has the full timeline): compaction spinner rendering ~13/s, summarization retries at the exact 60s breaker-cooldown cadence, and a final parked state burning >100% CPU with zero session writes.

Opportunistic compaction is an optimization; when the breaker declares compaction unavailable, the honest degradation is to let the turn try — the provider either accepts (soft threshold exceeded ≠ window exceeded) or returns a real overflow error.

Observed behavior (real CLI, mock provider, A/B)

Driver: .agents/skills/senpi-qa/scripts/scenarios/compaction-retry-cycle-repro.mjs (included; turn 1 pins usage over the threshold, then all provider requests fail transiently, and the driver re-prompts like an autonomous continuation extension).

unpatched patched
prompts rejected due to compaction (after breaker trip) 8/8 0/8
provider turn requests 4 (then nothing ever again) 13 (turns keep flowing)
agent_end after prompt 2+ 0 10
compaction_start without compaction_end 0 0

Full logs: local-ignore/qa-evidence/20260730-issue-531-cooldown-admission/{unpatched,patched}.log.

Tests

  • New test/suite/regressions/531-compaction-cooldown-admission.test.ts: red before the fix (RequiredCompactionError at the exact admission site), green after; a non-breaker cancel control verifies admission still fails closed for generic refusals.
  • npx vitest --run test/compaction/ test/compaction*.test.ts test/suite/ test/agent-session-auto-compaction-queue.test.ts test/interactive-mode-compaction*.test.ts: 364 files, 2466 passed, 1 skipped.
  • npx biome check clean; root npx tsgo --noEmit exit 0.

Residual risk

  • During an outage, sessions over the soft threshold now pay one real provider attempt per prompt instead of dying at admission; that is the intended degradation and produces a visible provider error rather than an invisible compaction loop.
  • The lifecycle-leak aspect of the incident (spinner left open after the cycle) did not reproduce in the sandbox (all start/end pairs matched in both runs); if it recurs it deserves its own fix.

closes #531


Summary by cubic

Let admission proceed without compaction when the circuit breaker cancels opportunistic compaction, so sessions over the soft threshold keep running during provider outages. Final oversized payloads and overflow-triggered paths still fail closed.

  • Bug Fixes
    • _enforceCompactionBeforeProvider, _revalidateScheduledContinuationAdmission: proceed on breaker cooldown instead of throwing.
    • _enforceFinalProviderAdmission: proceed on cooldown only if the final payload isn’t oversized.
    • _handleRetryableError: retry the turn instead of returning "blocked" when on cooldown.
    • Overflow-triggered admission remains unchanged (fail-closed).
    • Added regression test test/suite/regressions/531-compaction-cooldown-admission.test.ts and a CLI repro script compaction-retry-cycle-repro.mjs; the repro uses the repo-standard mock key sk-mock-qa-7f3a to avoid secret scanner noise.

Written for commit 3ff2c6f. Summary will update on new commits.

Review in cubic

…ortunistic compaction

When the compaction circuit breaker trips (provider outage, persistent
summarization failure), session_before_compact is cancelled with
rejectionCause "circuit-breaker". Core converted that cancel into a hard
RequiredCompactionError on every admission path, so any session over the
soft threshold was bricked: every prompt rejected, and autonomous
continuation drivers looped forever — observed live as a permanent
"Compacting..." spinner with summarization retries at the 60s cooldown
cadence.

Opportunistic compaction (threshold/pre_prompt) is an optimization, so a
breaker-cancelled compaction now degrades to proceeding without it:

- _enforceCompactionBeforeProvider and _enforceFinalProviderAdmission
  proceed when the last rejection was circuit-breaker (final admission
  still fails closed when the payload is actually oversized)
- _revalidateScheduledContinuationAdmission proceeds on cooldown
- _handleRetryableError retries instead of returning "blocked" on cooldown

Overflow-triggered admission is unchanged (fail-closed). If the context
genuinely exceeds the window, the provider overflow error drives the
existing one-shot overflow recovery.

Regression: test/suite/regressions/531-compaction-cooldown-admission.test.ts
(red before, green after; non-breaker cancel control stays fail-closed).
Live CLI A/B driver: .agents/skills/senpi-qa/scripts/scenarios/compaction-retry-cycle-repro.mjs
(unpatched: 8/8 prompts bricked; patched: 0/8, turns reach the provider).

QA evidence: local-ignore/qa-evidence/20260730-issue-531-cooldown-admission/

closes code-yeongyu#531
@gitguardian

gitguardian Bot commented Jul 30, 2026

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

Since your pull request originates from a forked repository, GitGuardian is not able to associate the secrets uncovered with secret incidents on your GitGuardian dashboard.
Skipping this check run and merging your pull request will create secret incidents on your GitGuardian dashboard.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
34049272 Triggered Generic High Entropy Secret 5e2781f .agents/skills/senpi-qa/scripts/scenarios/compaction-retry-cycle-repro.mjs View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

… driver

GitGuardian flagged sk-ant-mock-7f3a as a Generic High Entropy Secret;
replace it with the repo's existing committed mock credential
(sk-mock-qa-7f3a from mock-loop-support.mjs API_PRESETS).
@code-yeongyu

Copy link
Copy Markdown
Owner

[sisyphus-bot] Thank you for the thorough investigation, regression test, and CLI repro. This fix was carried onto current main in #556 with your implementation preserved and co-author attribution; #556 passed all required checks, merged as 264078608fa15caea32aa4c1c7814bee4d2a1faa, and closed #531. I am closing this now-superseded PR to avoid duplicate or conflicting delivery.

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.

Breaker-tripped compaction hard-blocks prompt admission forever — session stuck in infinite compaction rejection loop

2 participants