Skip to content

feat(compaction): adaptive failure backoff and actionable context budget errors - #1122

Open
ChrAlpha wants to merge 2 commits into
felinics:mainfrom
ChrAlpha:fix/compaction-cooldown-backoff
Open

feat(compaction): adaptive failure backoff and actionable context budget errors#1122
ChrAlpha wants to merge 2 commits into
felinics:mainfrom
ChrAlpha:fix/compaction-cooldown-backoff

Conversation

@ChrAlpha

@ChrAlpha ChrAlpha commented Aug 31, 2026

Copy link
Copy Markdown
Member

What this is

Two halves of the same failure experience, landed as two commits: when compaction fails under pressure the retry cadence now adapts (commit 1), and when a turn is ultimately rejected for context budget the error tells the user what to do about it (commit 2). The second half was originally #1123, folded in here since both exist to make the context-budget failure path recoverable and legible.

How it works

Cooldown backoff (feat(compaction): retry on exponential backoff under hard context pressure)

The compaction failure cooldown was a flat five minutes regardless of pressure, so one transient summarizer failure at the blocking threshold left every turn degraded or failing for the full window.

  • Failures now track consecutive attempts per session. Automatic triggers fired at or above the hard threshold (75% of the context window) pass HardPressure — both the async trigger and the sync backstop compute it from the same pressure/budget pair — and re-attempt on an exponential schedule: 30s, 1m, 2m, 4m, capped at 4m30s.
  • The cap sits strictly below the 5m entry-expiry window, so a capped retry still finds the failure entry alive and attempts keep accumulating instead of resetting through expiry. Steady state under a permanently failing summarizer with sustained hard pressure is one attempt per 4m30s — effectively the old flat cadence, but a transient failure recovers after 30s instead of five minutes.
  • Soft-pressure triggers keep the flat cooldown; success still clears the state; manual runs still bypass; the in-flight-owner attach still precedes the cooldown check.

Actionable budget errors (feat(apperror): make context budget errors actionable)

A turn rejected for context budget surfaced only "Required context exceeds the model context budget." — accurate, but with nothing the user can do about it, in English, on every surface.

  • The Detail strings for context.protected_overflow and context.budget_unsatisfied now name the recovery paths: run /compact to summarize older history, shorten the request (window-too-small only), or switch to a model with a larger context window. Channel replies use the Detail directly; the web UI localizes by code.
  • All three web locales updated per the codesync(error-catalog) contract; pinned expectations updated in Go tests and the web vitest suite.
  • Reviewed: a repo-wide sweep found no other consumer of the old strings; /compact is registered on the shared channel command group and shipped as a web chat quick action; channel error rendering applies secret redaction only, no length caps. For a reserve-driven budget_unsatisfied (window smaller than the output reserve) only the model switch helps — the wording hedges all three remedies.

Verification

  • Unit tests pin the exact backoff timeline: early hard-pressure retry after the first step, doubling on repeat failure, cap-below-expiry with attempts persisting across a capped retry, reset after success, and a full RunCompactionSync gate test (normal pressure skips inside the cooldown, hard pressure past the backoff reaches the model)
  • go test -race ./internal/agent/context/compaction/; go test ./internal/apperror/ ./internal/agent/runtime/native/ ./internal/handlers/ -count=1; pnpm --filter @memohai/web exec vitest run src/utils/api-error.test.ts (51/51) — all re-run on the combined head
  • Full go test ./... + lint via pre-commit on each commit; two adversarial review rounds on the backoff (the original cap-equals-expiry sawtooth was found in review and is pinned by the rewritten cap test) and one on the error copy

⚠️ No human QA — this PR has not been verified by a human yet. Remove this line once a human confirms the happy path.

…ssure

The failure cooldown was a flat five minutes regardless of pressure, so
one transient summarizer failure at the blocking threshold left every
turn degraded or failing for the full window. Failures now track
consecutive attempts; triggers fired at or above the hard threshold pass
HardPressure and re-attempt on an exponential schedule (30s, 1m, 2m, 4m)
capped strictly below the flat cooldown, so a capped retry still finds
the failure entry alive and attempts accumulate instead of resetting
through entry expiry. Soft-pressure triggers keep the flat cooldown,
success clears the state, and manual runs still bypass.
@ChrAlpha
ChrAlpha requested a review from a team as a code owner August 31, 2026 11:24
A turn rejected for context budget surfaced only "Required context
exceeds the model context budget." — accurate, but with nothing the user
can do about it. Both context budget details now name the recovery
paths: run /compact to summarize older history, shorten the request
(window-too-small only), or switch to a model with a larger context
window. Localized copies updated in all three web locales per the
error-catalog codesync.
@ChrAlpha
ChrAlpha requested review from a team as code owners September 1, 2026 00:02
@ChrAlpha ChrAlpha changed the title feat(compaction): retry on exponential backoff under hard context pressure feat(compaction): adaptive failure backoff and actionable context budget errors Sep 1, 2026
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