[Re-raise] 5 stale-closed issues re-verified against the bundle: 2 provider-parity items hold (corrected), 2 token items withdrawn/reframed, + 4 new findings
Note on format. Claude Code's bug template asks for one bug per issue. This is deliberately a consolidated re-raise: five issues the stale-bot closed without triage, grouped so the cluster is reviewable together, plus the findings my pre-posting re-check surfaced. Every item below carries its own mechanism + repro, and I'm glad to split any one into its own templated[BUG]/[FEATURE]report — just say which. Filed free-form (rather than the single-report template) only because no single template fits a multi-issue re-raise; happy to reformat to your preference.
Summary
On 2026-04-10 I filed five detailed issues (#46416, #46420, #46421, #46422, #46423). All five were auto-closed as not planned by the stale bot — none received maintainer triage, and several had substantive community engagement (technical corroboration, workarounds, design proposals) after they were filed.
Before re-raising I re-verified each claim against the shipped bundle (@anthropic-ai/claude-code v2.1.112, cli.js) and cross-checked the public CHANGELOG through 2.1.167, so you don't have to re-investigate what's already shipped — and so I'm not re-raising anything that's already fixed. That re-check changed my conclusions on two of the five: I'm withdrawing one to a confirm-only question (B1) and reframing another as a by-design confirmation (B2), because the bundle shows the original mechanism doesn't hold. The remaining two provider-parity items hold up, with corrected mechanisms (my original root-cause guesses were wrong on the cause even where the symptom was right). I've also included a short set of new, separately-reproduced findings surfaced during the re-check.
I'm happy to split this back into separate issues if that's easier to route — consolidating only to make triage cheaper.
All function names below (e.g.ff,vJ,sI,Jn,keY) are minified identifiers from the v2.1.112cli.js. They're included as grep anchors, not as source symbols.
---
Cluster A — third-party / custom-provider parity
A1 · Context-window detection caps third-party providers at 200K (was #46416) — still open
Corrected mechanism (my original root-cause was wrong on the cause). The context-window resolver (ff(q,K) in the bundle) does not gate on the base URL. It matches the model name against a hardcoded first-party allowlist and otherwise returns a hardcoded 200K default:
function ff(q,K){
if(S6(process.env.DISABLE_COMPACT)&&process.env.CLAUDE_CODE_MAX_CONTEXT_TOKENS){...return _}
if(DP(q))return 1e6; // model name matches /\[1m\]/i
if(K?.includes(Zo)&&vo(q))return 1e6; // vo(): claude-sonnet-4 / opus-4-6 / opus-4-7
if(XV8(q))return 1e6; // coral_reef sonnet
return DR1 // DR1 = 200000
}
So a gateway/3P model (MiniMax, OpenRouter, vLLM/Ollama routers, Bedrock/Vertex aliases) whose id is not on that name allowlist and does not contain the [1m] marker always resolves to 200K, regardless of base URL or the gateway's real window. (My original issue blamed a base-URL eligibility gate / getContextWindowForModel; those symbols aren't in the shipped bundle. The symptom is the same, but the cause is a model-name allowlist — flagging so triage looks in the right place.)
Correction to my own "no override env var" claim: there are two partial overrides, both unsatisfying — so the honest ask is for a clean one, not "add any override":
CLAUDE_CODE_MAX_CONTEXT_TOKENSexists inff()but only takes effect whenDISABLE_COMPACTis also set (CHANGELOG 2.1.98 confirms this coupling is intentional). So you can raise the window only by turning autocompact off — see the new finding N1 below, where this becomes a hard either/or.- The
[1m]model-name marker (a substring match anywhere in the id via/\[1m\]/i, not strictly a suffix) forces 1M, so a 3P user can sometimes piggyback by putting[1m]in the pinned model id — a hack, not a capability fix.
Current state — still open. CHANGELOG cross-check: the Opus-4.7 "200K → 1M" fix is first-party only (it extends the same name allowlist); the gateway /v1/models picker entries only affect the picker listing and output-token resolution, never ff()'s context window; ANTHROPIC_DEFAULT_{OPUS,SONNET,HAIKU}_MODEL_SUPPORTS/_NAME/_DESCRIPTION override effort/labels but explicitly not the context window. No entry resolves 3P context-window resolution.
Why it matters: the context bar, AutoCompact, and "Prompt is too long" guards all read this number, so 3P/local-router users get early/false compaction and a misleading bar. The practical workaround today is "ignore the bar and /compact by feel."
Ask: either consult the gateway's reported capabilities, or add a standalone per-model context-window override that does not require DISABLE_COMPACT (e.g. ANTHROPIC_CONTEXT_WINDOW_TOKENS).
Repro: configure a custom ANTHROPIC_BASE_URL gateway serving a real >200K model whose id isn't opus-4-7/4-6/sonnet-4 and doesn't contain [1m]; /context and AutoCompact behave as if max = 200K. Only escapes: DISABLE_COMPACT=1 + CLAUDE_CODE_MAX_CONTEXT_TOKENS=<real>, or put the [1m] marker in the model id.
A2 · No portable session-state continuity across a provider/model switch (was #46423 feature; #46420 bug reframed) — feature still open
Reframe (correcting the original bug claim). Re-checking the bundle, I need to retract the strong form of #46420 — "switching between two configured models drops conversation context". It doesn't:
- An in-session
/modelswitch preserves the conversation. The handler spreads the entire existing state object and changes only the model fields:T6(($w)=>({...$w, mainLoopModel:T8, mainLoopModelForSession:null, ...})). It does not touch the separate conversation-message state — the only history-wipe path is the distinct/clearcommand. CHANGELOG corroborates ("Resumed sessions now keep the model they were using…"). - The real discontinuity is env-var driven and restart-only:
ANTHROPIC_MODEL/ANTHROPIC_BASE_URLare read once at startup and are in the restart-required set, so changing provider means relaunchingclaude— a new process, a new session, no carry-over. That's startup-config semantics, not a runtime reset.
What remains genuinely open (the #46423 feature): there is no portable cross-switch continuity mechanism. Full-CHANGELOG scan for continuity/rehydrate/handoff/portable-state across a model or provider switch returns zero matches. (The adjacent "/model in one session silently changing the autocompact threshold in other concurrent sessions" fix is cross-session threshold leakage — not this.)
Why it matters: multi-provider / cost-routing workflows are increasingly common; switching provider today means relaunch + hand-writing critical state into memory files (fragile). A community commenter (wazionapps) proposed a clean boundary worth considering: on switch, rehydrate a portable operational-state snapshot (current goal, next action, hot files, pending approvals, loaded memory refs) — distinct from the raw transcript.
Ask: an opt-in portable operational-state packet that survives a provider relaunch / handoff.
---
Cluster B — token accounting (both down-graded after re-check; please confirm rather than treat as open bugs)
B1 · Local token estimation vs cached context (was #46422) — withdrawing the bug claim; confirm-only
My original claim was that the local estimator ignores cache_read_input_tokens / cache_creation_input_tokens versus the API usage. Against v2.1.112 this is not the case — every context-usage path already sums the cache fields and anchors on real API usage:
function ey6(q){return q.input_tokens+(q.cache_creation_input_tokens??0)+(q.cache_read_input_tokens??0)+q.output_tokens}
function vJ(q){ ... return ey6(z)+qT(q.slice(K+1)) } // last real API usage + char/4 estimate of only the un-acked tail
The same cache-inclusive sum drives the bar percentage and latestInputTokens, and it's present identically in the v2.1.89 baseline — so the "cache ignored" mechanism wasn't there even at filing time. I'm withdrawing B1 as a bug.
Two narrow things I'd only ask you to confirm, not treat as open:
- The statusline cumulative-vs-current fix ("Fixed statusline
context_windowtoken counts reflecting cumulative session totals instead of current context usage") is, I believe, the actual fix for the symptom I most likely saw (bar over-reading on a long cached session). Confirming that closes the user-visible side. - The only residual divergence I can find is the char/4 estimate of the current un-acked trailing turn (
qT(q.slice(K+1))) — inherently approximate, bounded to one turn, self-correcting on the next API response. Not cache-specific. (This connects to new finding N2 below.)
B2 · Parallel subagent cache_read accumulation (was #46421) — by design; confirmation + cost-doc note would close it
Re-checking: each subagent is an independent context window ("Implicit fork — inherits full conversation context", model:"inherit"), so it re-sends the parent prefix; with caching warm that returns as cache_read_input_tokens, aggregated with += (no cap, no cross-agent dedup). So parent-visible cache_read does scale with fan-out — but cache_read is the cheap, desired path, not a leak: the bundle's price table shows promptCacheReadTokens:0.3 vs inputTokens:3 (Sonnet) — ~10× cheaper than fresh input and ~12.5× cheaper than cache_creation. My original "no user-visible benefit" framing had it backwards.
The genuinely expensive adjacent path — cache_creation on sub-agent progress summaries — was already addressed: 2.1.128 "Fixed sub-agent progress summaries missing the prompt cache (~3× cache_creation reduction)" and "Fixed sub-agent summaries firing repeatedly while a sub-agent's transcript is static, capping worst-case token cost on idle sub-agents."
So B2 is effectively by design with the costly path already mitigated. The only open question: is a shared-prefix dedup or a per-dispatch cache_read cap on the roadmap, or should this be documented as expected fan-out cost? A one-line confirmation + a cost-docs note closes it.
---
Additional reproducible findings (surfaced during the re-check, separately reproduced)
These are new (not in the original five), each verified against v2.1.112 and confirmed un-fixed through CHANGELOG 2.1.167.
N1 · CLAUDE_CODE_AUTO_COMPACT_WINDOW is capped to the mis-detected 200K window for 3P models (P2)
Mechanism. The autocompact-window resolver returns window: Math.min(ff(model), override):
function Jn(q,K){let _=ff(q,eM());
if(process.env.CLAUDE_CODE_AUTO_COMPACT_WINDOW){...return{window:Math.min(_,A),configured:A,source:"env"}}
... }
For a 3P model ff() returns DR1=200000, so min(200000, 1000000)=200000. The override is parsed, clamped to [100K,1M], and echoed back as configured:1000000/source:"env" — yet the effective window stays 200K. (/autocompact does disclose the result as "capped by model", so it isn't entirely silent — but the override is accepted and surfaced as configured:1000000 before being clamped away, which reads as "it took my setting." Separately, for experiment-sourced compaction the UI prints a hint to override with CLAUDE_CODE_AUTO_COMPACT_WINDOW=1000000 that is itself then clamped — misleading for the narrow set of users who see it.) The autoCompactThreshold setting and CLAUDE_AUTOCOMPACT_PCT_OVERRIDE are capped the same way.
This is worse than A1's "no override": the documented escape hatch fails closed precisely for the 3P users who need it (accepted, echoed as configured, then clamped). Combined with A1's CLAUDE_CODE_MAX_CONTEXT_TOKENS requiring DISABLE_COMPACT, there is no supported configuration that gives a 3P large-context model both a correct window and autocompact — the two override paths are mutually exclusive.
CHANGELOG: not fixed. (The 1M-context-model false-block fix only applies to models already detected as 1M; AUTO_COMPACT_WINDOW/AUTOCOMPACT_PCT_OVERRIDE never appear as a 3P remedy.)
Repro: ANTHROPIC_BASE_URL=https://api.minimax.io/anthropic, ANTHROPIC_MODEL=MiniMax-M2.7 (real 1M window, no [1m] in id), CLAUDE_CODE_AUTO_COMPACT_WINDOW=1000000, autocompact on → /context still scales to 200K and autocompact fires near ~187K; the debug autocompact log shows effectiveWindow=200000.
N2 · Context bar and the AutoCompact gate count different totals — bar shows headroom while AutoCompact fires (P2)
Mechanism. The footer token-warning and several token surfaces read the last assistant turn's API usage (the sI-family; /context has its own related ce6/_l8 path, not identical to sI, but likewise anchored on last-response usage). The AutoCompact gate instead uses vJ(q) = that last-response usage plus a local char/4 estimate of every message after the last assistant turn:
function sI(q){ ... if(z)return ey6(z); ... return 0 } // bar
function vJ(q){ ... return ey6(z)+qT(q.slice(K+1)) } // autocompact gate
Same denominator, different numerator. After the last reply, a large paste or a big tool_result sits in q.slice(K+1) until the next assistant turn lands fresh usage. During that window the bar can read "32% until auto-compact" while AutoCompact, counting the just-injected large tool result, fires immediately — compaction "out of nowhere." It self-heals on the next assistant turn (both reconverge), which is why it reads as intermittent.
CHANGELOG: not fixed. Prior reconciliations (/context ↔ statusline header, cumulative→current) align the display surfaces with each other — all sI-family. None aligns the display with the AutoCompact decision input vJ.
Repro: in a session with an existing last-assistant usage, note the "% until auto-compact" bar, then paste a very large block / trigger a tool returning a large result → AutoCompact fires while the bar had just shown comfortable headroom. Verbose shows autocompact: tokens=… carrying a higher number than the bar implies.
N3 · Local estimator counts every image and every document/PDF block as a flat 2000 tokens (P3)
Mechanism. In the local estimator, if(q.type==="image"||q.type==="document")return 2000. Claude Code sends PDFs as {type:"document",source:{type:"base64",media_type:"application/pdf"}}; a real multi-page PDF is tens of thousands of tokens but is pinned at 2000. Since the AutoCompact pre-check (vJ) uses this estimate for the un-acked trailing slice, a freshly-attached large PDF under-accounts by tens of thousands of tokens until the next API turn returns true usage. (The bundle's own image config — pxPerToken:28, maxTargetTokens:1568, and a note about 2576px on newer models — shows the flat 2000 also mis-estimates high-res images.)
CHANGELOG: not fixed. Image-pipeline entries are about actual API cost / compression, not the local estimator constant; no entry touches document/PDF token estimation at all.
Repro: attach a large multi-page PDF mid-session and watch /context / AutoCompact — most visible as AutoCompact not firing when a huge PDF should have pushed it over. Estimate-only; corrects on the next API response and is bounded by the "Prompt is too long" guard.
N4 · Stop/SubagentStop prompt-hook transcript truncation uses [1m]-only 1M detection (P3)
Mechanism. Prompt-based Stop/SubagentStop hooks re-query the model with the session transcript, first truncated by keY(transcript, model) with budget _=DP(model)?1e6:DR1 then floor(_*0.7). DP matches the literal [1m] suffix only, while the real context-window resolver ff grants native 1M to additional models (opus-4-7, opus-4-6, sonnet-4, coral-reef) without the suffix. So a user on plain opus-4-7 — 1M everywhere else (picker, bar, autocompact) — has the Stop-hook transcript truncated to 140,000 tokens, dropping older evidence the stopping condition may depend on.
CHANGELOG: not fixed. Stop-hook entries change other fields; the Opus-4.7 200K→1M fix targets /context + autocompact, not the hook truncation budget in keY.
Repro: on opus-4-7 (no [1m]), build a >~140K-token session, then trigger a prompt Stop hook whose stopping condition depends on something early in the session → the hook evaluates against a transcript truncated to the most recent ~140K and can answer wrong. Debug shows Hooks: truncated Stop transcript … (budget 140000, model …opus-4-7).
---
Why re-raise
None of these were closed by a maintainer decision — they were closed by inactivity (stale). I've done the homework this time: re-verified each against the shipped bundle, withdrew B1 and reframed B2 where the code showed my original mechanism was wrong, corrected A1/A2's mechanisms so triage looks in the right place, and added four separately-reproduced findings. The surviving provider-parity items (A1, A2-feature, N1) appear genuinely unfixed and have a clear, small fix surface. Even a triage label or a "won't-fix, here's why" would be more useful than another stale timeout.
Original issues: #46416 · #46420 · #46421 · #46422 · #46423
Version note. Re-verified against the locally-installed @anthropic-ai/claude-code v2.1.112 bundle; CHANGELOG cross-checked through 2.1.167. The version I'm running is 2.1.165 — the CHANGELOG shows no explicit fix for any mechanism above, but N2/N3/N4 are the most exposed to silent implementation drift in the 2.1.112 → 2.1.165 gap, so a quick spot-check against the current build is worth it before treating those three as prod-current. A1/A2/N1 are structural and long-standing (present identically in the 2.1.89 baseline).This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗