Context Window Data Source Investigation and Statusline Styling¶
Date: 2026-08-04
Branch: feature/statusline-polish
Session: Post-V1.0 statusline polish and context window trace
Part 1: Statusline Provider-Hue Styling (implementation)¶
What changed¶
A presentation layer was added to the statusline to apply per-provider color and usage-health coloring. The existing provider-aware logic (composeRoute, resolveProvider, truncateRoute) was not modified — color is applied at render time only, after the segment-content functions return plain text.
Architecture¶
- New file:
Statusline/lib/style.js— ANSI decoration layer, called only fromrender()instatusline.js. - Config:
Statusline/lib/config.jsgained aSTYLEblock (provider hue map, usage-health thresholds, segment weights) and a sharedSTALE_MARKERconstant. route.js: Changed one literal (" [stale]"→STALE_MARKER) — same string, no behavioral change.statusline.js:render()derives the provider fromresolveProvider(transcriptInfo.model, mapping)and passes the plain route string + provider tostyle.route().- Tests: 35 tests all pass; width-bound assertion updated to strip ANSI before measuring;7 style-layer unit tests added.
Design principle¶
The presentation layer is additive decoration. Every segment-content function (composeRoute, formatContext, truncateRoute) still returns plain text. This preserves byte-for-byte test assertions on the provider-aware logic while allowing styling to be tuned or disabled (NO_COLOR) without touching content.
Color scheme deployed¶
| Segment | Color |
|---|---|
| Provider prefix (known) | Dim + provider hue (opencode=blue, nvidia=cyan, gemini=magenta, local=green) |
| Provider prefix (unknown) | Dim |
| Model | Bold |
| Git branch | Green |
% used (context) |
Green <50%, yellow <80%, red ≥80% |
N ctx |
Dim |
| Token deltas (+in/−out) | Dim |
[stale] marker |
Yellow |
Test artifact¶
Commit: c0792f9 on feature/statusline-polish.
Part 2: Context Window Data Source Investigation (research)¶
Question investigated¶
Is the "200K ctx" shown by the statusline hardcoded, or is it pulled from an observed source (like the provider)? If not from an observed source, is such a source available in OmniRoute?
Finding 1: "200K ctx" comes from Claude Code's payload, not OmniRoute¶
Status: Verified fact
Confidence: High
Evidence: Statusline/lib/format.js:26 reads ctx.context_window_size from the stdin payload. The payload is generated by Claude Code (Phase 1B input contract). No hardcoded 200000 exists anywhere in the Statusline source. The input-contract finding confirms: "The script contains no fallback to read OmniRoute data, the transcript, or any external source. It renders only what Claude Code provides in the statusline payload."
Implication: The context window reflects what Claude Code believes the model's window is (based on the requested model, e.g. auto/cheap), not necessarily the true window of the model OmniRoute actually resolved. This is the same "requested vs resolved" divergence documented for model names.
Finding 2: call_logs does not record context window¶
Status: Verified fact
Confidence: High
Evidence: call_logs schema has model, provider, requested_model, token counts (tokens_in, tokens_out, tokens_cache_read, etc.), but no context_window, max_tokens, or window_size column. The table records usage, not the model's capacity.
Finding 3: OmniRoute's model_capabilities table is empty¶
Status: Verified fact
Confidence: High
Evidence: SELECT COUNT(*) FROM model_capabilities returns0 rows. The table exists (schema includes limit_context, limit_input, limit_output) but is unpopulated in this installation.
Finding 4: model_context_overrides has real context windows, with uneven coverage¶
Status: Verified fact
Confidence: High
Evidence: SELECT COUNT(*) FROM model_context_overrides returns 424 rows. Table schema:
CREATE TABLE model_context_overrides (
provider TEXT NOT NULL,
model_id TEXT NOT NULL,
real_context INTEGER NOT NULL, -- the corrected context window (tokens)
source TEXT NOT NULL DEFAULT 'manual', -- 'manual' | 'auto:discovery'
refreshed_at TEXT NOT NULL,
PRIMARY KEY (provider, model_id)
);
- All 424 entries have
source = 'auto:discovery'. - Providers with entries:
openrouter(362),gemini(47),groq(15). - Providers with no entries:
opencode,nvidia,local,anthropic,sambanova,deepseek, etc.
Finding 5: Only 62 resolved calls have a direct model_id match to the overrides¶
Status: Verified fact
Confidence: High
Evidence: SELECT COUNT(*) FROM call_logs c JOIN model_context_overrides o ON c.model = o.model_id WHERE c.status=200 AND c.model IS NOT NULL returns 62.
These are predominantly openrouter models (nvidia/nemotron, gemini, cohere, etc.). The internal proxy models (big-pickle, mimo-v2.5-free, deepseek-v4-flash-free — the ones most commonly seen in this setup) have no entries in model_context_overrides.
Finding 6: Provider key mismatch between call_logs and model_context_overrides¶
Status: Verified fact
Confidence: High
Evidence: call_logs records provider = "nvidia" for nvidia/nemotron-3-super-120b-a12b; model_context_overrides stores the same model under provider = "openrouter". A direct (provider, model_id) join fails; a model_id-only join works for the 62 matches but is fragile (4 models appear under multiple providers, though with identical real_context values in observed data).
Summary: where context-window data exists¶
| Source | Has real data? | Covers the common models? | Latency |
|---|---|---|---|
Payload context_window_size |
No (Claude Code's guess for the requested model) | Always present | Free (already in payload) |
call_logs |
No (records usage, not the window) | N/A | ~0.25–1.13s via Docker |
model_context_overrides.real_context |
Yes (424 models, auto-discovered) | Only for openrouter/gemini/groq models; no coverage for internal proxy models | Fast (SQLite read) |
model_capabilities |
Schema exists (limit_context) but unpopulated (0 rows) |
N/A | N/A |
Implication for V2¶
To show the resolved model's real context window (instead of Claude Code's guess), the statusline would need to:
- Extend the
update-model-provider-mapping.jsscript to also querymodel_context_overrides.real_contextfor matching model IDs. - Add
real_contextto the mapping file JSON. - Fall back to the payload's
context_window_sizewhen no match exists.
Coverage would be good for external models (nvidia/nemotron, gemini, claude-on-openrouter) but absent for the internal proxy models (big-pickle, mimo-v2.5-free). This is an honest limitation, not a bug — the data simply does not exist for those models in OmniRoute's current tables.
Part 3: Post-sync verification — Model Database sync from models.dev (same day)¶
After Part 2 was recorded, the OmniRoute admin UI's Model Database section ("Auto-sync pricing, capabilities & specs from models.dev") was manually synced. Re-verification found this populates the previously-empty model_capabilities table.
Finding 7: model_capabilities went from 0 to 7,278 rows, all with limit_context¶
- Status: Verified fact
- Confidence: High
- Evidence:
SELECT COUNT(*) FROM model_capabilities→ 7,278 (was 0 before the sync).SELECT COUNT(*) FROM model_capabilities WHERE limit_context IS NOT NULL→ 7,278 (100%). Schema unchanged (limit_context,limit_input,limit_output). - Provider distribution (top rows): nano-gpt (615), openrouter (368), kc/kilo-gateway/kilocode (344 each), vercel (315), llmgateway (189), merge-gateway (152), poe (137), zenmux (120), amazon-bedrock (116), novita-ai (107), nvidia (98), and many more aggregators.
Finding 8: The internal proxy models now have real context windows¶
- Status: Verified fact
- Confidence: High
- Evidence:
model_capabilitiesrows for the models most commonly resolved incall_logs: big-pickle→limit_context200,000 (providers:opencode,opencode-zen)mimo-v2.5-free→ 200,000 (opencode,opencode-zen)deepseek-v4-flash-free→ 200,000 (opencode,opencode-zen)deepseek-v4-flash→ 1,000,000 (opencode,opencode-zen)- This directly resolves the Part 2 gap: internal proxy models now have observed context-window data in OmniRoute.
Finding 9: Provider keys align between call_logs and model_capabilities for the common models¶
- Status: Verified fact
- Confidence: High
- Evidence: provider+model join returns 1,709 matched call rows (
JOIN ... ON l.model = c.model_id AND l.provider = c.provider WHERE l.status = 200).call_logsrecordsprovider = 'opencode'for big-pickle/mimo/deepseek-flash;model_capabilitiesalso stores them underopencode(plus a separateopencode-zenmirror with identical values). The provider-key mismatch that affectsmodel_context_overrides(nvidia vs openrouter) does not affect this table for the observed models. - Note: table-specific observation; the
model_context_overridesmismatch remains unresolved.
Finding 10: model_context_overrides is unchanged by the sync¶
- Status: Verified fact
- Confidence: High
- Evidence: still 424 rows after the sync. The Model Database sync writes to
model_capabilities, not tomodel_context_overrides.
Coverage summary after sync¶
- 384 distinct successfully-resolved model IDs map to a
model_capabilitiesrow. - 1,709 resolved calls match on
(provider, model). - For the common internal proxy models,
limit_context= 200,000 — matching what Claude Code already reports for the requestedauto/cheap(payloadcontext_window_size). The divergence is only visible for models likedeepseek-v4-flash(real 1,000,000) andnvidia/nemotron(real 1,000,000), where Claude Code's payload guess understates the real window.
Implication for V2 (updated)¶
model_capabilities.limit_context, joined on (provider, model_id), is now the preferred observed source for the resolved model's context window (superseding the model_context_overrides path). V2 design should:
- Extend
Scripts/update-model-provider-mapping.jsto also querymodel_capabilities.limit_context(and optionallylimit_input/limit_output). - Add a
contextWindow(or similar) field to the mapping file JSON. - Have the statusline fall back to the payload's
context_window_sizewhen no match exists. - Use
opencode(notopencode-zen) as the canonical provider key for the internal proxies, matchingcall_logs.
Open questions carried forward (updated)¶
Resolved by the sync:
- ~~Are there other OmniRoute tables that record model capacity for the internal proxy models?~~ → Yes: model_capabilities, populated by the models.dev sync.
- ~~Could the model_capabilities table be populated, and by what process?~~ → Yes: the admin "Model Database" sync populates it (7,278 rows).
Remaining:
1. Is the opencode vs opencode-zen duplication a stable convention (same model mirrored under multiple aggregator keys), and which key should the mapping script prefer?
2. Does the Model Database sync run on a schedule or only manually? (Relevant to mapping-file freshness.)
3. Does limit_context reflect the model's native window or a provider-capped window?
4. Is the model_context_overrides provider-key mismatch (nvidia in call_logs vs openrouter in overrides) a permanent naming convention, or will a future OmniRoute version reconcile them?
Part 4: V2 — real context window from model_capabilities (implementation, deployment, and the artifact defect)¶
Date: 2026-08-04 (same session)
Branch: feature/statusline-polish
Commits: e3c03c5 (V2 implementation), ca4a9ec (generation fix + regression tests)
Implementation summary¶
V2 makes the context-window segment show the resolved model's real window from
model_capabilities.limit_context instead of Claude Code's payload guess — the path
outlined in "Implication for V2 (updated)" above, with these decisions fixed at the
planning gate:
- Schema shape (a) — a sibling top-level block, never a change to the
modelsshape (seeStatusline/Design/03-provider-model-naming.md):
{
"version": 1,
"generated_at": "2026-08-04T00:00:00Z",
"models": { "big-pickle": "opencode" },
"contextWindows": { "big-pickle": 200000 }
}
- Join key:
model_idonly (not(provider, model_id)), matching the internal proxy models and sidestepping the nvidia/openrouter provider-key mismatch; mirror duplicates are collapsed withMAX(limit_context). - Scope:
limit_contextonly (limit_input/limit_outputdeferred — no consumer).
| File | Change |
|---|---|
Scripts/update-model-provider-mapping.js |
SQL gains LEFT JOIN model_capabilities c ON l.model = c.model_id and MAX(c.limit_context) AS ctx; aggregate() threads ctx into a contextWindows block |
Statusline/lib/mapping.js |
new resolveContextWindow(model, mapping) accessor; resolveProvider byte-for-byte unchanged |
Statusline/lib/format.js |
formatContext(ctx, overrideWindow) — a positive override wins over ctx.context_window_size |
Statusline/statusline.js |
render() resolves the window alongside the provider and passes it as the override |
Statusline/test/statusline.test.js |
11 V2 runtime tests (accessor + override/fallback) |
Fallback chain: mapping contextWindows match → payload context_window_size →
segment omitted (unchanged). 45/45 tests passed at commit e3c03c5.
Deployment outcome¶
- Deployed V2 to
~/.claude/statusline/viaScripts/deploy-statusline.js(V1 backed up as~/.claude/statusline.js.pre-phase4.*). - Regenerated the mapping via
Scripts/update-model-provider-mapping.js: 8 → 12 models, all 12 withcontextWindows; no existing provider mapping changed (the earliermistral-large-latestmodel-only observation was a stale-mapping miss — the model had been routed since the previous regeneration, which predates it). - Live smoke through the deployed binary (
NO_COLOR): mistral-large-latest(mapped) →mistral/mistral-large-latest 262K ctx— real window (262,144), not the payload's 200,000.some-unknown-model(unmapped) → model-only,200K ctx— payload fallback intact.big-pickle(mapped, pre-existing) →opencode/big-pickle 200K ctx— no provider-display regression.- Suite: 50/50 pass (45 + 5 pipeline regression tests).
Defect discovered during deployment verification¶
The first regeneration after deploy produced a mapping without contextWindows.
V2's runtime logic (resolveContextWindow, the formatContext override) was correct and
fully tested — but it always received null because the generated artifact never
contained the block, so every model silently fell back to the payload guess. Until the
mapping was correct, the feature was a silent no-op.
Root cause¶
aggregate() in the committed V2 script dropped the new column:
- The SQL selected MAX(c.limit_context) AS ctx (4th column), but aggregate() parsed
only [model, provider, nRaw] and the returned JSON had no contextWindows key.
- The consumer side was unit-tested (45/45) but the producer side (SQL output →
mapping JSON) had no coverage, so the defect passed the suite.
The fix (commit ca4a9ec)¶
aggregate()now parses the 4th field, builds awindowsmap (max positive ctx per model), and writescontextWindowswhen non-empty.- The block is omitted when nothing resolves, so old artifacts and empty outputs degrade to the payload fallback (schema stays backward-compatible).
main()is guarded byrequire.main === moduleandaggregate()is exported, so the generation pipeline is unit-testable without docker.
New regression tests¶
5 tests in Statusline/test/statusline.test.js pin the generated artifact, not just
the runtime accessor: contextWindows written from sqlite output; missing/non-numeric
ctx skipped; mirror duplicates keep the max ctx; block omitted when no model has ctx;
provider selection unchanged. Suite 45 → 50, all passing.
Engineering lesson learned¶
When introducing a generated artifact, test both the producer and the consumer. A passing consumer test does not prove that the producer generated the expected artifact. The V2 runtime was fully tested and correct; the mapping the producer wrote was not, and the feature silently degraded until the producer was fixed and covered.