429'd-ping → cache-TTL analyzer
Run from the project root:
node .skills/ttl-429/scripts/ttl_429.mjs [--ttl-sec N] <instance.ARM.ndjson> [more.ndjson ...]
The question
clawback's keep-alive ping re-reads the cached prefix, so a successful
ping (200, cache_read>0) demonstrably refreshes Anthropic's TTL. The open
question is the 429'd ping: Anthropic returns no usage body, so we cannot
see whether the request still touched the cache. The only observable is the
next success on the same SESSION KEY.
How it decides
For each 429'd ping it finds the next 200-with-usage on that session and asks:
did more than --ttl-sec elapse since the last known-warm event (so the cache
should have expired), with no intervening success to refresh it? If yes and
the probe still reads warm → REFRESH (the 429'd ping kept it alive). If the
probe reads cold → NO-REFRESH. If the boundary was never crossed, or a 200
landed first, → INCONCLUSIVE.
What you need for a clean answer
A paired run where the cache is allowed to go cold across the TTL boundary with only a 429'd ping spanning it. That means:
- a real inter-turn gap longer than the TTL (default 300s, or 3600s under
--inject-extended-cache-ttl); - no PTY 🔥 keep-alive (billable turns would refresh both arms and erase the isolation);
- keep-alive ON on the primary, OFF on the shadow;
- enough rate-limit pressure that the primary's gap-ping actually 429s.
Without 429'd pings the analyzer says so plainly — the stock cadence keeps the cache warm, so no ping is ever isolated across a boundary.
Phantom detection (bonus)
The per-session warmth table flags any session with ≥3 pings and zero warm
pings as ⚠ PHANTOM: an uncacheable aux context (sub-1024-token prefix) the
keep-alive armed and is pinging for pure cost. Cross-check against the
keepAliveMinPrefixBytes gate in src/keepalive.js.