Remote/bridge-attached sessions silently disable threshold auto-compaction and ignore CLAUDE_AUTOCOMPACT_PCT_OVERRIDE unless an explicit window is configured
Summary
In a remote/bridge-attached session (i.e. one driven through the cloud/remote-control bridge), synchronous threshold auto-compaction never runs, and CLAUDE_AUTOCOMPACT_PCT_OVERRIDE is silently ignored entirely, unless an explicit window source is configured (CLAUDE_CODE_AUTO_COMPACT_WINDOW or a settings.autoCompactWindow). The context window grows unbounded (observed to ~238k tokens on a model whose auto-compact window was configured far lower) with zero auto-compaction; only manual /compact reduces it.
The trigger predicate WKp returns early — before it ever computes the token level or applies the percentage override — whenever the session is remote and the auto-compact-window source is the default "auto"/"experiment".
Environment
- Claude Code 2.1.186 (native install), model
claude-opus-4-8 - Session driven via the remote/bridge worker (CCR v2 worker session)
settings.jsonenv in effect:"CLAUDE_AUTOCOMPACT_PCT_OVERRIDE": "80"- No
CLAUDE_CODE_AUTO_COMPACT_WINDOWand noautoCompactWindowsetting (the natural config: "auto-compact at 80%").
Observed behavior
- Auto-compaction is enabled (the background precompute fired —
precomputed compact: started/ready/consumed— which requires auto-compact to be on). - Despite
CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=80, the conversation grew to ~238k tokens with no auto-compaction applied (it should have tripped far earlier). - The session was run with verbose+debug logging on, yet the debug log contains zero
autocompact: tokens=… level=…lines — the orchestrator's own log statement never executed. - Manual
/compactworked every time; it was the only thing that actually reduced context.
Root cause
The orchestrator XSo (exposed as p.autocompact) is called unconditionally every turn from the main REPL loop (the bridge injects inbound messages into that same loop), so it is invoked. The suppression is in its predicate WKp, which bails at its 4th guard — before the level computation, the percentage override, and the autocompact: log:
async function WKp(e, t, n, r, o = 0) {
if (r === "compact") return false;
if (hke(r)) return false;
if (!ZR()) return false;
if (Yz() && !v4() && !gke(t, n)) return false; // <-- bails here, before everything below
let s = SA(e, IR(t)) - o, i = _ke(s, t, n); // _ke -> Gkn applies CLAUDE_AUTOCOMPACT_PCT_OVERRIDE
return (C(`autocompact: tokens=${s} level=${i.level} effectiveWindow=${ree(t, n)}`),
i.level === "compact" || i.level === "blocked");
}
In a remote/bridge session, all three conjuncts of the 4th guard are true:
Yz()— true in remote mode.!v4()— true (kill-switch off).!gke(t, n)— true, becausegke()returns true only when the auto-compact-window source isenv/settings/clientdata/model-default:
``js`
function gke(e, t) {
let { source: n } = p$(e, t);
return n === "env" || n === "settings" || n === "clientdata" || n === "model-default";
}
p$()
With no explicit window configured, falls through to source: "auto" (or "experiment"), so gke() is **false** → !gke is true → the guard fires and WKp returns false. No level is computed, nothing is applied, and the autocompact:` log never runs.
Why CLAUDE_AUTOCOMPACT_PCT_OVERRIDE is completely ignored
The percentage override is read separately (into testPctOverride) and only applied downstream, inside _ke → Gkn, which runs after the guard above:
// EKr(): testPctOverride = parseFloat(CLAUDE_AUTOCOMPACT_PCT_OVERRIDE)
function Gkn(e, t) { // e = effective (ree) window
let n = e - 13000, r = t.testPctOverride;
if (r !== undefined && !isNaN(r) && r > 0 && r <= 100)
return Math.min(Math.floor(e * (r / 100)), n);
return n;
}
Two compounding facts make the override a complete no-op in this scenario:
CLAUDE_AUTOCOMPACT_PCT_OVERRIDEdoes not change the window source — it flows throughEKr.testPctOverride, never throughp$(). So it cannot, by itself, makegke()true.- Because
gke()therefore stays false,WKpbails at the 4th guard before_ke/Gknare ever called — so the override value is never read on the trigger path.
Net: a user who sets only CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=80 (the obvious way to say "auto-compact at 80%") in a bridge session gets no effect at all — it neither lowers the threshold nor unlocks the orchestrator. It is silently ignored.
Workaround
Set an explicit window, which forces source: "env" → gke() true → the 4th guard is disarmed → WKp proceeds, computes the level, applies the pct, and applies compaction:
"CLAUDE_CODE_AUTO_COMPACT_WINDOW": "150000"
With this set, CLAUDE_AUTOCOMPACT_PCT_OVERRIDE does take effect and composes with the window (threshold ≈ floor((window − reserve) × pct/100), e.g. ~104k for window 150000 + pct 80). Confirm it's working by checking the debug log for autocompact: tokens=… level=… lines, which should now appear.
(Note: once engaged, a custom window routes apply through the reactive path L8n/hSo, which can itself silently skip on a compaction abort or when the precompute isn't ready — so the window is necessary and near-sufficient, not bulletproof.)
Suggested fix
The 4th guard conflates "remote mode" with "no explicit window source" to suppress synchronous auto-apply, leaving threshold compaction unhandled for the default-config remote case. Options:
- Don't suppress synchronous auto-apply solely because
source ∈ {auto, experiment}in remote mode — fall through to the level check regardless of source (and let the reactive routing branch handle the apply if that's intended). - If the intent is to always route remote threshold compaction through the reactive path, ensure that path is actually reached for
source: "auto"/"experiment"(todayXSo's reactive branch requiresp !== "auto", so the default source also misses that path — nothing applies). - Make
CLAUDE_AUTOCOMPACT_PCT_OVERRIDEset the window source (or otherwise be honored) so that "auto-compact at N%" works without also requiring an explicit window — at minimum, it should not be silently ignored.
Reproduction / detection
- Remote/bridge-attached session,
claude-opus-4-8, auto-compact enabled, noCLAUDE_CODE_AUTO_COMPACT_WINDOW/autoCompactWindowset; optionallyCLAUDE_AUTOCOMPACT_PCT_OVERRIDE=80. - Let the conversation grow past the expected threshold.
- Symptom: context climbs well past the configured percentage with no auto-compaction;
~/.claude/debug/<session>.txtcontainsprecomputed compact:lines but noautocompact: tokens=… level=…lines. - Setting
CLAUDE_CODE_AUTO_COMPACT_WINDOW=<value>makes theautocompact:lines appear and compaction apply — confirming the source-gated suppression.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗