# kcode-context-cache-policy
`kcode-context-cache-policy` owns the deterministic policy used to distinguish
append-only model context from cache-invalidating rewrites and to decide when
sparse model-visible stale-box and context-size markers are due. It has no
persistence, provider, logging, or Chatend dependency.
## Constants
- `CONTEXT_SIZE_MARKER_INTERVAL_TOKENS` is the minimum increase after one
context-size marker before another marker may be emitted. It is 10,000.
## Cache classification
### `CacheExpectation`
- `ColdStart`: no prior submitted cacheable projection exists.
- `ExpectedWarm`: the provider material is unchanged and the current cacheable
projection starts with the complete prior cacheable projection.
- `PlannedInvalidation { reason }`: provider material changed or the prior
cacheable projection is not an exact prefix of the current projection.
`label()` returns the stable log label. `planned_reason()` returns the reason
only for a planned invalidation. `expects_cache_hit()` is true only for
`ExpectedWarm`.
### `classify`
`classify(previous, current_text, current_material_fingerprint,
rewrite_reason)` compares one candidate with the previous submitted cacheable
projection.
`previous` is an optional `PreviousProjection` containing exact prior text and
the fingerprint of non-text provider material. Absence produces `ColdStart`.
Different material fingerprints produce a planned `provider_material_changed`
invalidation. Otherwise an exact byte-prefix match produces `ExpectedWarm`.
A non-prefix result uses the caller's nonblank `rewrite_reason`, or
`other_projection_rewrite` when the supplied reason is blank.
The function deliberately does not normalize whitespace or interpret text.
## Sparse markers
### `MarkerState`
The caller-reconstructed state for the current cache epoch:
- `reported_stale_boxes`: sorted box IDs already reported during the epoch.
- `last_context_size_tokens`: token estimate printed by the most recent size
marker in the epoch.
### `MarkerObservation`
The current sorted stale-box IDs, estimated current context tokens, active
failure-avoidance limit, and cache expectation.
### `MarkerDecision`
- `reset_epoch`: historical marker output must be suppressed.
- `stale`: optional `StaleMarker` to append.
- `context_size_tokens`: optional size value to append.
- `next_state`: complete marker state after applying the decision.
### `StaleMarker`
- `New(Vec<u64>)` renders `[new stale boxes: ...]`.
- `Consolidated(Vec<u64>)` renders `[stale boxes: ...]`.
### `decide_markers`
For `ExpectedWarm`, only newly stale IDs are emitted, and existing marker state
is retained. For `ColdStart` or `PlannedInvalidation`, a new epoch begins and
the complete current stale set is emitted once when nonempty.
A size marker is absent at or below 30% of the active limit. Above 30%, the
first marker in an epoch is emitted; later markers require at least 10,000
additional estimated tokens. A zero context limit never emits a size marker.
Inputs are caller-owned observations. The function has no side effects; the
Chatend owner is responsible for durably applying the returned outcome as one
operation.
## Cache outcomes
### `CacheOutcome`
- `Hit`: the provider reported at least one cached input token.
- `UnplannedMiss`: an expected-warm call reported input tokens but zero cached
input tokens.
- `Excluded`: a cold start or planned invalidation reported zero cached tokens.
- `UsageUnavailable`: complete input-token usage was unavailable or zero.
### `observe_cache`
`observe_cache(expectation, input_tokens)` classifies the provider's final
usage without inventing unreported cache-write data. `InputTokens` retains
total and cached input counts and computes uncached tokens with saturating
subtraction plus an optional cached/total ratio.