Skip to content

cache_ttl wording implies it controls the provider's cache lifetime — it controls MC's fold decision (doc/wording fix) #347

Description

@iceteaSA

Summary

cache_ttl decides when Magic Context assumes the provider's cached prefix is dead and re-materializes m[0]. It has no effect on the provider's actual cache lifetime.

Every user-facing string describing it currently suggests the opposite. This is a documentation/wording issue, not a code defect — the behavior is correct.

I introduced the worst of these strings in #245, so filing it against my own wording.

The three surfaces, and why they compose into a wrong model

1. CONFIGURATION.md:122

Magic Context defers all mutations until the cached prefix expires. The default cache_ttl of "5m" matches most providers.

"Matches most providers" reads as this value mirrors the provider's TTL — i.e. that the setting and the provider's cache are the same quantity. Nothing on the page says it is MC's own gate.

2. Schema .describe()

Cache TTL: string (e.g. "5m", "1h", "30s") ... Set to "never" for lanes kept warm by an [external cache-keep tool]

The label is "Cache TTL" unqualified, and "lanes kept warm" ties the setting to actual warmth rather than to MC's assumption about it.

3. execute-status.ts:147 (mine, from #245)

never expires (always-warm lane)

The most misleading of the three: rendered in /ctx-status, it states the cache never expires. What it means is that MC never treats it as expired.

Each is defensible alone; together they describe a coherent, wrong mental model — "this is how long the cache lives."

Why I think it's worth a fix rather than a shrug

The misread survived contact with people who had read the code. Tonight a fleet of agents on this box — including the ones that wrote and reviewed #245 — held the belief that cache_ttl: "never" protected those lanes from expiry. It was only corrected by reading parseCacheTtl and the scheduler predicates directly.

The failure is silent and asymmetric:

  • Operator sets "never" on lanes fronted by an external cache-keep tool, believing they are protected.
  • The provider's TTL is untouched — 5 minutes unless extended-TTL is explicitly requested in the request body (cache_control: { ttl: "1h" }); the beta header alone is inert.
  • MC correctly does not fold, and faithfully replays identical prefix bytes.
  • If the provider entry expired anyway, that request pays full price while MC's own status surface reports the lane as never-expiring.

Measured on this box today: 12 full prefix re-sends followed >5 minutes of idle on lanes configured "never", at 250K–435K tokens each. MC behaved exactly as designed. The config just doesn't mean what its own status line says.

Suggested fix — wording only, not a rename

I would not rename the key. cache_ttl predates #245, a rename is a breaking config change, and the ambiguity is carried by the prose rather than the identifier.

Three small edits:

  • CONFIGURATION.md — replace "matches most providers" with a statement of what the knob does, e.g. "How long MC assumes a provider's cached prefix stays valid. This is MC's own deferral gate — it does not change the provider's cache lifetime. The default 5m matches Anthropic's default TTL."
  • Schema .describe() — lead with the scope: "How long MC assumes the provider cache stays warm (MC-side only; does not extend the provider's TTL)."
  • execute-status.ts:147never expires (always-warm lane) → something like MC never folds on idle (assumes external cache-keep). Same information, no claim about the provider.

Optionally, one line under "never" noting that provider-side extended TTL is a separate request-level concern, so the two aren't confused again.

Happy to send the PR — it's three strings and a doc paragraph. Equally happy to be told the current wording is fine and the fleet should have read the code, which is a fair position; I'm filing because the misread was unanimous among people who had, and because the status line makes a claim about the provider that MC cannot actually guarantee.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions