[feedback] Model: timestamps get invented from elapsed work; compaction summaries carry them forward as facts
Context. Solo-operator project using Claude Code (desktop app, Windows 11) with a lead session on Claude Fable 5.1 orchestrating Opus 5.5 / Sonnet subagents (in-process, worktree-isolated), a JSON task store (~1,100 records), PreToolUse/SubagentStop hooks and a harvest-train commit flow. Everything below was measured on 2026-09-28 in one session of ~20 dispatches, two blind judge pairs and nine commits. Numbers are from tool output, not recollection; no secrets or private paths included.
Finding. The lead model (Fable 5.1) labelled rulings and log lines with times estimated from elapsed work instead of reading a clock, twice in one day and after a written lesson; a compaction summary then repeated the invented times with full confidence and the next context re-used them.
Evidence (measured). Labels ran 20-40 minutes ahead of date -u at 05:2x-06:1xZ; pre-compaction labels ran hours ahead (a '13:0x local' label for a 04:40Z run). The only true record was the timestamp field a hook wrote on each board write.
Reproduction. Ask the model to log a timestamped decision after ~20 minutes of work without telling it to read a clock; compare with the wall clock. Compact; ask for that decision's time.
Ask. (1) A model that writes a time reads a clock in the same step (or the harness injects the time). (2) A compaction summary grades each fact MEASURED or RECALLED and carries the source for measured ones. (3) After compaction, the model re-measures any clock or count before re-using it.
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
Independent confirmation from a different setup (macOS, not Windows), with transcript-derived numbers. Adds a day-level case where a compaction summary carried a wrong date forward, not only wrong times.
Setup. Claude Code on macOS (Darwin 25.6), versions 2.1.247 to 2.1.283, single user, long research sessions that write dated log lines, status headings and commit messages. Models seen in the affected turns:
claude-fable-5-1,claude-opus-5,claude-opus-5-5. The machine clock is fine (about 8 s off NTP); git author/committer times are all consistent with the transcript timestamps. The problem is only in times the model types into files and commit messages.Method. For every assistant
tool_use(Bash command, Write content, Edit new_string) in the session JSONL files, extract eachYYYY-MM-DD HH:MMstamp and compare it with that record's owntimestampfield converted to local time (UTC+8). A stamp more than 3 minutes after the moment it was written cannot be a record of a past event. Stamps that are genuinely about the future (appointments, deadlines, scheduled jobs, quota reset times) were excluded by keyword and by hand; stamps suffixedZwere counted separately.Minute-level result (2026-08-30 to 2026-09-28, 12 main sessions, subagents not included).
09-06 09:30written at09-05 09:29).dateoutput in context was from about 2.5 h earlier....Z), i.e. 16 h off.date", written after the day-level incident below; minute-level leads still appear up to today.Day-level result (one afternoon/evening, 2026-09-14 local).
datecall, and wrote an erratum; the files were left unrenamed so existing path citations stay valid, so the wrong dates are now permanent in the history.Why this matters. These stamps are written in the same form as measured facts ("owner 2026-09-18 20:05", "checked 2026-09-27 23:55"), so later sessions, compaction summaries and other agents read them as provenance. The day-level case shows the compaction summary turning a guessed date into the date the next context works from.
Ask (agreeing with the above, plus one point).
Related: #92732 (same class, macOS, Opus 5), #75281 (per-turn time injection).
Update, 8 days later, same project, same effect, now with a mechanism that catches it.
After the original report we wrote the rule "read the clock before typing a time" into memory and a lesson file. It kept recurring. Counts come from the typed text compared with the git commit timestamps of the same work (Windows 11, Claude Code 2.1.290 at the time of this comment):
New vs the issue: a written rule did not hold, even when it was in context. The model fills the time from its sense of elapsed work, and that drifts ahead. What does work for us now is a mechanical check: before every commit, a small script reads the added lines, and any time on today's date that lies after the system clock is refused (a time written down can never be later than the commit that records it). It caught the next slip at once. It cannot catch a guessed time in the past.
This agrees with the macOS data above (136 of 560 stamps ahead): the error is directional (ahead), which fits "estimated from elapsed work" rather than random noise.
Ask unchanged: when the model writes a time, it should read a clock in that same step; or the harness should inject the local time with offset every turn (#75281), so the estimate is never needed.
Thank you for the careful numbers; they are stronger than ours, and the macOS data answers the "Windows only?" question. Your point that it recurs after a written rule matches ours exactly: 6 incidents in 2 days, 4 of them after we had written the lesson that same evening (details in the comment above). Our errors are also all ahead of the clock, like your 136 of 560. We agree with all three asks, in particular per-turn local time with offset (#75281). What finally holds for us is mechanical, not a rule: a pre-commit check that refuses any time on today's date that lies after the system clock.