The context tab always showed less than the official chat context
indicator because the two sides used different rulers: the plugin
displayed its fixed-density heuristic total (4 chars/token, which
systematically undercounts CJK text and JSON schemas by ~10-15%),
while the official ring shows provider-reported billed tokens. The
running host also predated the occupancy feature entirely, so the
client fell back to the raw heuristic headline.
Core change: totals are anchored to the provider sample, heuristics
only supply the composition ratios (the official ContextMeter's own
trick):
- host: fold a contextPressure-equivalent occupancy projection
(pressureTokens / sampledSurfaceTokens / occupancyWindow) and serve
it on the snapshot; usage is sampled BEFORE the message joins the
surface, and streamed assistant/chunk usage samples count too, so
steps that fail mid-stream no longer fall back to pure heuristics.
- client: headline = occupancy.projectedTokens, with a last-request
fallback deriving the same figure against older hosts (a page
refresh fixes the live view before any server restart).
- composition bar, legend and trend bars are re-proportioned to the
anchored total (ratios stay heuristic, values marked ≈); the
conflicting 'estimate ≈ n (~p%)' second percentage is gone.
Verified by tests/diff-fold.mjs (kept as a differential regression
tool): the plugin's occupancy equals the official
contextPressure.projectedTokens to the token on all 33 real session
logs, incl. a 17k-event log with 9 compactions and a chunk-only-usage
session.