Finding: cache-read vs rate-limit burn on subscription (OAuth) seats
- Issue: #2183 (epic #1844 C6).
- Date: 2026-07-04.
- Verdict: negative-by-missing-witness — the measurement the issue asks for cannot be produced from existing fak telemetry, because the limit-burn side and the cache-read side of the required join are not co-persisted. The passive-on-OAuth AUTO rule therefore stays in place, but its provenance is upgraded from silently assumed on an axis it never looked at to explicitly unmeasured on the rate-limit axis, with a named witness gap.
The question
--managed-cache AUTO stays passive on subscription (OAuth) seats because “on a
Pro/Max subscription the marginal token price is flat”
(cmd/fak/guard_managed_cache.go:21-23).
That reasoning is denominated in dollars. Subscription seats do not die on
dollars — they die on rate limits (the whole reason fak resume scan
exists; the live-vs-post-mortem cap taxonomy is
cmd/fak/resume_scan.go:237 →
resume.ClassifyLimitText). #2183 asks the axis the dollar argument never looked
at: if the provider’s rate-limit accounting discounts cache reads the way its
billing does (the 0.1x provider cache-read multiplier is real and pinned at
internal/cachevaluereport/track2.go:46
providerCacheReadMultiplier = 0.1), then keeping an OAuth session cache-hot
would extend its runway before a limit crash — real managed-cache value on a
flat-rate seat, denominated in rate-limit headroom instead of dollars.
What was checked
The issue asserts “fak already has both sides of the join in the gateway.” That is true at the live observation seam and false at the durable-ledger seam — and the correlation the acceptance criteria want is a post-hoc join over real sessions, which needs the durable seam.
- Limit-burn side (account usage).
internal/accountobsfolds the provider’santhropic-ratelimit-unified-*(subscription 5h/7d window utilization / status / reset) andanthropic-ratelimit-<family>-*/x-ratelimit-*headers off every upstream response (internal/gateway/upstream_observe.go→internal/accountobs/accountobs.go). But the gap is one step earlier than “observed-but-not-persisted”: in the shipped tree the sessionTrackeris not wired into any production session at all.gateway.Config.UpstreamResponseObserver— the seam that would feed aTracker— is assigned only in a test (internal/gateway/upstream_observe_test.go); nocmd/fakfile importsinternal/accountobs; andSnapshot.Report(the guard-exit banner its own doc comment names) andSnapshot.PrometheusText(thefak_account_ratelimit_*gauges) have zero production callers — the guard’s/metricsPrometheusTextatcmd/fak/guard.go:1008renders the harness resource sampler, not the account view. The only live use of the header taxonomy is the transient per-429 reset resolver, which builds a throwawayaccountobs.New(), reads one response’sUnified()windows, and discards it (internal/agent/retry_limit.go:117-120;internal/resume/limit.go). So a running OAuth session neither accumulates a utilization curve nor writes one to any append-only ledger. - Cache-read side. The durable per-session record is the cache-savings ledger
docs/nightrun/cache-savings.jsonl(schemafak-cache-savings-ledger/1,internal/cachevaluereportSavingsRow). It carriescache_read_tokens,input_tokens,cache_creation_tokens— but no rate-limit / window / utilization / limit-remaining field. - The join. There is no durable row, and no shared session key, that pairs a
session’s cache_read-vs-uncached-input ratio with that same session’s observed
unified-window utilization delta or limit-crash timing.
SavingsRowand theaccountobssnapshot are never co-recorded. So the correlation the issue requests has no data source to run over.
Result
- Acceptance box 1 (“a written finding with measured limit-burn vs cache-read data from real subscription sessions”) is blocked on a missing witness — the co-persisted join does not exist. This is not “we measured and found no discount”; it is “the measurement cannot yet be taken.” Recording the difference honestly is the point: the AUTO rule is no longer resting on an unstated assumption.
- Acceptance box 2 is satisfied by its second branch — a documented result cited
from
guard_managed_cache.go: the passive-on-OAuth default is retained, and its banner reason (“subscription OAuth (flat-rate) — pass--managed-cache onto force”,resolveGuardManagedCache) remains honest, because fak still cannot see the wire economics on that axis. The rule is not flipped speculatively — the never-speculate honesty inguard_managed_cache.go:17-23and the banner-reason contract inbannerLineboth forbid activating on evidence fak does not have.
Untested hypothesis (must not be read as measured)
A plausible prior — explicitly not a finding — is that the subscription
unified window meters usage, not dollars, so a cache read may count toward the
5h/7d window at (or near) the same weight as uncached input even though it is
billed at 0.1x. If that holds, cache reads would not discount limit burn on
the token axis, and the passivity would be correct on the rate-limit axis too. The
opposite prior — that the provider applies the same 0.1x weighting to unified
usage as to billing — is equally unproven. Both are hypotheses the missing witness
would decide. Nothing here should be cited as evidence for either.
Generation classification
Per docs/generation.md, the issue was unclassified. On the
evidence above it classifies as gen/future (research / long-horizon option):
it studies whether a standing assumption holds on an axis with no current-product
witness, and its promotion depends on a witness that does not exist yet. It is not
gen/now (no current-product readout to move today), and not gen/next (no
near-term gate or dogfood — the enabling schema change has to land first).
- Promotion evidence (what would move it toward
now): a schema field that co-persists the per-sessionaccountobsunified-window utilization delta (and 429/crash timing) next tocache_read_tokens/input_tokenson thecache-savings(or a sibling) ledger, then N real OAuth sessions correlating limit-burn against cache-read ratio. That correlation is the promotion witness. - Demotion / retirement evidence: if the provider documents (or a measured session shows) that unified-window usage weights cache reads the same as uncached input, the lever has no runway value on OAuth — retire the “activate AUTO on OAuth” bet and keep passivity as measured, not assumed.
- Invalidating assumption: this finding assumes the join must be reconstructed
from fak-side telemetry. If the provider ever relays a per-response cache-read
usage attribution in the unified-window headers, the correlation could be read
directly off
accountobswithout a new ledger schema, and the “missing witness” framing here would be wrong.
Smallest next step
Because the account view is not accumulated per session at all (above), the witness lands in three ordered steps, not one:
- Wire it. Install a session-scope
accountobs.Trackerontogateway.Config.UpstreamResponseObserverin the guard/serve command (the seam and parser already exist and are tested) so a running OAuth session accumulates its unified-window utilization curve and 429 count. - Persist it. Append the folded snapshot (per-window utilization at exit, 429
count, resets) to the durable session ledger, keyed so it joins the
cache-savingsrow for the same session. - Measure it. Run a matched cache-hot vs cache-cold A/B on two equivalent Pro/Max seats and compare the unified-window utilization slope.
Until step 3, --managed-cache AUTO passivity on OAuth is evidence-tracked as
unmeasured, not silently assumed — which is the state #2183 asked for.