currentdate-normalize: mask CC's daily date injection so midnight stops busting the prefix - #342
Conversation
…ps busting CC stamps "Today's date is YYYY-MM-DD." into the claudeMd system-reminder block inside messages[0] — measured ~30k characters into content[3]. When the calendar day rolls over mid-session the value advances and everything from byte 0 through the first cache_control marker invalidates: a full cold write, once per midnight, for every session still running. ~386k tokens on the session that motivated it. It is a scheduled cache bust, and it scales with how long sessions live rather than with what they do. Writes a canonical 0000-00-00 placeholder instead. The model still sees the # currentDate header, so the signal is visibly abstracted rather than missing, and CC still delivers the real rollover through its own "The date has changed" reminder when it happens. Idempotent by construction (negative lookahead on the placeholder), because a proxy can see the same body more than once.
|
Reviewed at HEAD. Small (276+/0-, one extension + test file). Verdict: code is clean; one design question for @cnighswonger before I apply
|
The defect
CC stamps the date into the claudeMd system-reminder block:
It sits deep inside the first user message's injected claudeMd block —
measured ~30k characters into
messages[0].content[3]. When the calendar dayrolls over mid-session that value advances by one, and everything from byte 0
through the first
cache_controlmarker invalidates. A full cold write, onceper midnight, for every session still running. ~386k tokens on the session
that motivated it (2026-04-23 00:34:50).
It is the one cache bust you can predict to the minute, and it scales with how
long sessions live rather than with what they do.
Approach
Write a canonical
0000-00-00placeholder in place of the value.# currentDateheader, so the signal reads asabstracted rather than missing.
"The date has changed" system-reminder when it actually happens, so nothing
the model needs is lost — only the byte that changes on a timer.
YYYY-MM-DDshape so anything downstream thatparses that format keeps parsing.
Notes
the placeholder, so a second pass finds nothing and produces identical bytes.
A proxy can see the same body more than once (retries, replays), and a
non-idempotent mask could emit two different versions of one body.
# currentDate. CC emits the line both with and withoutthat header across claudeMd shapes; anchoring would miss half the cases. The
sentence is specific enough to match anywhere — the tests pin that
Todays date is …,Today's date is unknown.,2026-8-16and a bareThe release was on 2026-08-16.are all left alone.identity-normalization(300), which stabilizes thesame class of volatile per-turn field, and before the cache_control mutators.
systemblock, where it has been observedas well.
Verification
The headline test replays one session serialized either side of a rollover:
the two bodies differ before the mask (asserted, so the premise cannot rot) and
are byte-identical after.
node --test→ 13/13. Also ransession-key-invariants(4/4) andproxy-pipeline(15/15) locally;tools/absence-scan.mjsclean over both files. Your CI is the authoritativerun — it caught a real design bug in #340 that my local runs missed.
Load-bearing?
Yes — it rewrites bytes inside the cached prefix.
— Claude Opus 5, working with @deafsquad