Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changes/context-guard/fix-context-guard-1m-band-2f868982.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
bump: minor
---

### Changed

- **The 1M-window token band reads `dumb` past 500000 tokens, not 250000 ([#6644](https://github.com/melodic-software/claude-code-plugins/issues/6644)).** At 26% of a 1M window the shipped bands read `dumb (3 of 3)` and sessions stopped work on it. The `smart` edge stays at 128000. The reader contract records the new basis: Google's GraphWalks BFS figures for Opus 5.5 and Fable 5.1, and Context Arena's 8-needle MRCR, where both Claude rows first score under one half at 512K. The 200k row and the percentage bands are unchanged; `zones.json` still overrides.

### Fixed

- **Band provenance figures.** The reader contract gave Claude Sonnet 5's 8-needle MRCR as at least 0.957 through 256K; the live table reads 0.529 at 128K and 0.522 at 256K. It also said no per-length data exists for Opus 5.5, but Google publishes its GraphWalks BFS scores (90.6% up to 128K, 66.8% from 256K to 1M).
7 changes: 7 additions & 0 deletions .changes/plugin-quality/fix-context-guard-1m-band-a79971d9.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
bump: patch
---

### Changed

- **The bundled zone resolver's 1M-window token band reads `dumb` past 500000 tokens, not 250000 ([#6644](https://github.com/melodic-software/claude-code-plugins/issues/6644)),** synced from context-guard's reader contract.
5 changes: 3 additions & 2 deletions lib/context-zone.fixtures.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ export default [
{"name":"tokens 200000+1 in 200000","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":200000,"total_output_tokens":1,"context_window_size":200000},"cli_version":"2.1.200"},"zones":null,"word":"unknown","notices":[]},
{"name":"tokens 118000+10000 in 1000000","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":118000,"total_output_tokens":10000,"context_window_size":1000000},"cli_version":"2.1.200"},"zones":null,"word":"smart","notices":[]},
{"name":"tokens 128000+1 in 1000000","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":128000,"total_output_tokens":1,"context_window_size":1000000},"cli_version":"2.1.200"},"zones":null,"word":"acceptable","notices":[]},
{"name":"tokens 249000+1000 in 1000000","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":249000,"total_output_tokens":1000,"context_window_size":1000000},"cli_version":"2.1.200"},"zones":null,"word":"acceptable","notices":[]},
{"name":"tokens 250000+1 in 1000000","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":250000,"total_output_tokens":1,"context_window_size":1000000},"cli_version":"2.1.200"},"zones":null,"word":"dumb","notices":[]},
{"name":"tokens 260000 in 1000000 (26% used, #6644) is not dumb","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":26,"remaining_percentage":74,"current_usage":{"input_tokens":100},"total_input_tokens":260000,"total_output_tokens":0,"context_window_size":1000000},"cli_version":"2.1.200"},"zones":null,"word":"acceptable","notices":[]},
{"name":"tokens 499000+1000 in 1000000","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":499000,"total_output_tokens":1000,"context_window_size":1000000},"cli_version":"2.1.200"},"zones":null,"word":"acceptable","notices":[]},
{"name":"tokens 500000+1 in 1000000","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":500000,"total_output_tokens":1,"context_window_size":1000000},"cli_version":"2.1.200"},"zones":null,"word":"dumb","notices":[]},
{"name":"tokens 999000+1000 in 1000000","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":999000,"total_output_tokens":1000,"context_window_size":1000000},"cli_version":"2.1.200"},"zones":null,"word":"dumb","notices":[]},
{"name":"tokens 1000000+1 in 1000000","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":1000000,"total_output_tokens":1,"context_window_size":1000000},"cli_version":"2.1.200"},"zones":null,"word":"unknown","notices":[]},
{"name":"window 500000 takes the 200000 class","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":110000,"total_output_tokens":0,"context_window_size":500000},"cli_version":"2.1.200"},"zones":null,"word":"acceptable","notices":[]},
Expand Down
8 changes: 4 additions & 4 deletions lib/context-zone.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
# window-class token bands over occupancy:
#
# window class 200000: smart ≤ 100000 < acceptable ≤ 150000 < dumb
# window class 1000000: smart ≤ 128000 < acceptable ≤ 250000 < dumb
# window class 1000000: smart ≤ 128000 < acceptable ≤ 500000 < dumb
#
# All are declared judgment defaults, NOT doc- or benchmark-derived
# constants (anchors and provenance are recorded in the reader contract).
Expand All @@ -64,7 +64,7 @@
# "acceptable_max_used_percentage": 75,
# "token_bands": {
# "200000": { "smart_max_tokens": 100000, "acceptable_max_tokens": 150000 },
# "1000000": { "smart_max_tokens": 128000, "acceptable_max_tokens": 250000 }
# "1000000": { "smart_max_tokens": 128000, "acceptable_max_tokens": 500000 }
# }
# }
#
Expand Down Expand Up @@ -92,7 +92,7 @@ DEFAULT_ACCEPTABLE_MAX=75
# [class, smart_max, acceptable_max] rows, ascending class order. JSON rather
# than whitespace rows because the bands are handed to the snapshot pass as
# data, so the comparison happens there instead of in a separate awk process.
DEFAULT_TOKEN_BANDS='[[200000,100000,150000],[1000000,128000,250000]]'
DEFAULT_TOKEN_BANDS='[[200000,100000,150000],[1000000,128000,500000]]'

unknown() {
printf 'unknown\n'
Expand Down Expand Up @@ -197,7 +197,7 @@ if [[ -e "$zones" ]]; then
acceptable_max=${zpct#* }
fi
if [[ "$ztb" == "invalid" ]]; then
printf 'context-guard: zones.json token_bands malformed — using shipped default token bands (200000:100000/150000, 1000000:128000/250000)\n' >&2
printf 'context-guard: zones.json token_bands malformed — using shipped default token bands (200000:100000/150000, 1000000:128000/500000)\n' >&2
elif [[ "$ztb" != "absent" ]]; then
token_bands=$ztb
fi
Expand Down
2 changes: 1 addition & 1 deletion plugins/context-guard/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ degraded context **before** quality slips, instead of guessing. Four parts:
worse computable zone wins): percentage bands over `used_percentage` (shipped defaults
smart ≤ 50 < acceptable ≤ 75 < dumb) and window-class token bands over occupancy
(`total_input_tokens + total_output_tokens`; shipped defaults 100k/150k on a 200k window,
128k/250k on a 1M window). Bands come from the machine-scope
128k/500k on a 1M window). Bands come from the machine-scope
`~/.claude/context-guard/zones.json` when present and valid, else from the shipped defaults.
Zones say *where you are*; consumers decide *what to do*.
- **PostCompact marker hook** (`hooks/post-compact-mark.sh`), a settings hook, so it runs where
Expand Down
7 changes: 7 additions & 0 deletions plugins/context-guard/hooks/context-guard.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,13 @@ test('zones.json: an extra threshold gets its approach line and its line once pe
])
})

// On a 1000000-token window with the shipped bands, 26% used (260000 tokens) reads acceptable:
// the reader contract's 1M row puts the dumb edge past 500000 tokens.
test('shipped bands, 1000000 window: 26% used announces acceptable, never dumb; 51% announces dumb', async ($, on) => {
const { w } = world(on, { window: 1_000_000 })
expect(await walk($, w, [5, 26, 51])).toEqual([[], [crossing('acceptable')], [crossing('dumb')]])
})

// The token edges of a 1000000-token window at 210000 and 410000; the percentage edges there
// (50% and 75%) sit at 500000 and 750000 tokens, so the token shape decides both crossings.
const TOKEN_EDGES = { token_bands: { '1000000': { smart_max_tokens: 210_000, acceptable_max_tokens: 410_000 } } }
Expand Down
2 changes: 1 addition & 1 deletion plugins/context-guard/hooks/zone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const DEFAULT_BANDS: Bands = {
acceptable: 75,
tokens: [
[200_000, 100_000, 150_000],
[1_000_000, 128_000, 250_000],
[1_000_000, 128_000, 500_000],
],
}
export const RANK: Record<Zone, number> = { smart: 0, acceptable: 1, dumb: 2 }
Expand Down
37 changes: 22 additions & 15 deletions plugins/context-guard/reference/reader-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ same triggers. These stamps are probe results with a date, not standing facts.
- **Default token bands (over occupancy = `total_input_tokens` + `total_output_tokens`, uppers
inclusive, selected by window class as described under "Occupancy and combination rule"):**
window class **200000**: `smart` ≤ **100000** < `acceptable` ≤ **150000** < `dumb`;
window class **1000000**: `smart` ≤ **128000** < `acceptable` ≤ **250000** < `dumb`.
window class **1000000**: `smart` ≤ **128000** < `acceptable` ≤ **500000** < `dumb`.
- **Token-shape version floor (fixed):** the token shape is computable only when the snapshot's
`cli_version` is present, purely numeric dotted, and **≥ 2.1.132**, the release from which the
token fields mean current occupancy rather than cumulative session totals.
Expand Down Expand Up @@ -226,28 +226,35 @@ a version field cannot (there is no writer authentication, so `cli_version` is u
every other snapshot value). The bundled resolver implements both gates.

**Band provenance:** the shipped token bands are **declared judgment**, not benchmark-derived
constants. No per-length long-context data is published for Claude Opus 5.5, Sonnet 5.5 or Fable
5.1; their system cards report only an aggregate ProgramBench score. The 1M row's edges, 128000
and 250000, are anchored on the nearest published data: on Context Arena's 8-needle MRCR (max
effort, Google tokenizer) Claude Opus 5 scores 0.913 at 128K, 0.656 at 256K and 0.425 at 512K, and
Claude Sonnet 5 a median of at least 0.957 through 256K and 0.041 at 512K; on GraphWalks BFS, run
by Google at max reasoning and published with Gemini 4 Argon on 2026-09-30, Fable 5.1 scores 91.4%
up to 128K and 65.0% from 256K to 1M. The 200k row's `acceptable` edge, 150000, sits at
constants. Anthropic publishes no per-length long-context scores for Claude Opus 5.5, Sonnet 5.5
or Fable 5.1: their system cards report one aggregate ProgramBench score each, an agentic task
whose episodes run up to the full 1M window. The published per-length data is retrieval and graph
traversal, not agentic work, and no study we found links those scores to agentic task quality. On
GraphWalks BFS, run by Google at max reasoning and published with Gemini 4 Argon, Opus 5.5 scores
90.6% up to 128K and 66.8% from 256K to 1M, and Fable 5.1 91.4% and 65.0%. On Context Arena's
8-needle MRCR (max effort), Claude Opus 5 scores 0.913 at 128K, 0.656 at 256K and 0.425 at 512K,
and Claude Sonnet 5 0.529, 0.522 and 0.320. The 1M row's `smart` edge, 128000, is the last length
at which those current-model scores are still near their best. Its `acceptable` edge, 500000,
sits below 512K, the first MRCR length at which both Claude rows score under one half. Between
the two, scores sag without a measured cliff, so a reading there is `acceptable`, not `dumb`: an
`acceptable` edge of 250000 read `dumb` at 26% of a 1M window on no evidence for current models
or agentic work (#6644). The 200k row's `acceptable` edge, 150000, sits at
the top of the practitioner consensus of about 125-150K. `zones.json` is the correction path, and
the numeric agreement of the 200k row's percentage translation with the shipped 50/75 percentage
defaults is coincidence, not validation.

- **Pointer**: when re-deriving a 1M band edge, fetch live:
[Context Arena, 8 needles](https://contextarena.ai/api/needle-summary?needles=8), the Claude
Opus 5 and Claude Sonnet 5 rows; [Gemini models](https://deepmind.google/models/gemini), the
Gemini 4 Argon table's GraphWalks BFS rows; the absence of per-length data, the
Gemini 4 Argon table's Opus 5.5 and Fable 5.1 GraphWalks BFS rows; the absence of per-length data, the
[Opus 5.5 system card](https://www-cdn.anthropic.com/fc1b44717c85dc068bc6ba5024219938094694bd/Claude%20Opus%205.5%20System%20Card.pdf)
section 8.10 and the [Fable 5.1 system card](https://www-cdn.anthropic.com/0339e6a7c5c7b87f5c07798616dc32c215d14235/Claude%20Fable%205.1%20&%20Claude%20Mythos%205.1%20System%20Card.pdf)
section 8.11. For the 200k row, correlate with [AI Hero, "Smart Zone"](https://www.aihero.dev/ai-coding-dictionary/smart-zone)
and [Geoffrey Huntley, "Ralph"](https://ghuntley.com/ralph/); no docs page covers where quality
degrades on a 200K window as of 2026-10-04.
- **As of**: 2026-10-07
- **Recheck trigger**: Opus 5.5, Fable 5.1 or Sonnet 5.5 appear on Context Arena; a new or revised
- **As of**: 2026-10-09
- **Recheck trigger**: Opus 5.5, Fable 5.1 or Sonnet 5.5 appear on Context Arena; Google's table
splits the 256K-1M GraphWalks bin; a new or revised
Anthropic system card publishes per-length scores; or a docs page starts covering where quality degrades on a 200K window, at which point the
200k row's pointer moves there.

Expand Down Expand Up @@ -382,7 +389,7 @@ session itself can know.
compaction fires at or near the model's context limit; the cases that fire earlier depend on the
model, the window it runs with, and the environment. For the current thresholds, see
[Claude Code model config, "Default auto-compact thresholds"](https://code.claude.com/docs/en/model-config#default-auto-compact-thresholds).
**As of:** 2026-09-30, the one number that section publishes, for native 1M windows, sits above
**As of:** 2026-10-09, the one number that section publishes for native 1M windows, about 967K tokens, sits above
the shipped `dumb` band, so it does not disturb the margin that the bands-below-the-trigger rule
protects, the way a lowered window does. **Recheck trigger:** that section is renamed or removed,
or publishes a default at or below the `dumb` band's lower edge. `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE`
Expand Down Expand Up @@ -451,8 +458,8 @@ hook, so a firing is best read diagnostically: **it means the boundary was misse
window was managed. Lowering the window moves the trigger, so the bands in `zones.json` must move
with it, normalized into the percentage shape. A 400000-token window on a 1M-class model puts the
trigger at **40% of the full window**, which is *inside* the shipped percentage `smart` band
(≤ 50), so the percentage shape still reads smart when auto-compact fires (the token shape decides
the zone there). Keeping the percentage bands below that trigger means pulling them under 40, not
(≤ 50), so the percentage shape still reads smart when auto-compact fires, and the token shape,
which decides the zone there, reads `acceptable`: neither shipped shape reaches `dumb` first. Keeping the percentage bands below that trigger means pulling them under 40, not
comparing 400000 against the token bands' occupancy edges, which measure a different quantity.

That diagnostic reading is adopted; the prescription that usually travels with it is not. **Leave
Expand Down Expand Up @@ -500,7 +507,7 @@ what the human sees and what consumers decide on. Zones say *where you are*; con
"acceptable_max_used_percentage": 75,
"token_bands": {
"200000": { "smart_max_tokens": 100000, "acceptable_max_tokens": 150000 },
"1000000": { "smart_max_tokens": 128000, "acceptable_max_tokens": 250000 }
"1000000": { "smart_max_tokens": 128000, "acceptable_max_tokens": 500000 }
}
}
```
Expand Down
5 changes: 3 additions & 2 deletions plugins/context-guard/scripts/context-zone.fixtures.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ export default [
{"name":"tokens 200000+1 in 200000","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":200000,"total_output_tokens":1,"context_window_size":200000},"cli_version":"2.1.200"},"zones":null,"word":"unknown","notices":[]},
{"name":"tokens 118000+10000 in 1000000","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":118000,"total_output_tokens":10000,"context_window_size":1000000},"cli_version":"2.1.200"},"zones":null,"word":"smart","notices":[]},
{"name":"tokens 128000+1 in 1000000","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":128000,"total_output_tokens":1,"context_window_size":1000000},"cli_version":"2.1.200"},"zones":null,"word":"acceptable","notices":[]},
{"name":"tokens 249000+1000 in 1000000","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":249000,"total_output_tokens":1000,"context_window_size":1000000},"cli_version":"2.1.200"},"zones":null,"word":"acceptable","notices":[]},
{"name":"tokens 250000+1 in 1000000","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":250000,"total_output_tokens":1,"context_window_size":1000000},"cli_version":"2.1.200"},"zones":null,"word":"dumb","notices":[]},
{"name":"tokens 260000 in 1000000 (26% used, #6644) is not dumb","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":26,"remaining_percentage":74,"current_usage":{"input_tokens":100},"total_input_tokens":260000,"total_output_tokens":0,"context_window_size":1000000},"cli_version":"2.1.200"},"zones":null,"word":"acceptable","notices":[]},
{"name":"tokens 499000+1000 in 1000000","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":499000,"total_output_tokens":1000,"context_window_size":1000000},"cli_version":"2.1.200"},"zones":null,"word":"acceptable","notices":[]},
{"name":"tokens 500000+1 in 1000000","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":500000,"total_output_tokens":1,"context_window_size":1000000},"cli_version":"2.1.200"},"zones":null,"word":"dumb","notices":[]},
{"name":"tokens 999000+1000 in 1000000","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":999000,"total_output_tokens":1000,"context_window_size":1000000},"cli_version":"2.1.200"},"zones":null,"word":"dumb","notices":[]},
{"name":"tokens 1000000+1 in 1000000","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":1000000,"total_output_tokens":1,"context_window_size":1000000},"cli_version":"2.1.200"},"zones":null,"word":"unknown","notices":[]},
{"name":"window 500000 takes the 200000 class","sid":"s1","snapshot":{"captured_at":"@now-30","session_id":"s1","context_window":{"used_percentage":null,"remaining_percentage":80,"current_usage":{"input_tokens":100},"total_input_tokens":110000,"total_output_tokens":0,"context_window_size":500000},"cli_version":"2.1.200"},"zones":null,"word":"acceptable","notices":[]},
Expand Down
Loading
Loading