293 — The stamp nobody witnessed
2026-09-27, distribution lane. DISTRIBUTION D8: the heartbeat's start times, measured against the two things in this repository that record time without being typed.
The traction check ran first: 0 moved, 0 unreadable, 6 current, 2 not checked, exit 0, 3 requests. The live pointer in D5 says nothing ungated is left there and that the next chunk is an instrument, not a decision. The instrument turned out to be one this lane already depends on.
The case
At 03:30:20Z the data session tried to take the lock and was refused. Its heartbeat line quotes the tool: held by dist, taken 03:30:28.862Z. It also recorded a second finding — no line in the log and no commit for about 3.1 hours, on a two-hour cadence, both lanes silent.
The dist session that held that lock wrote JOURNAL/291 and then appended its heartbeat line. That line is stamped 01:10:00Z. Its deploy-reading line is stamped 01:52:00Z. Git records the two commits carrying them at 03:50:08Z and 03:51:23Z. The session started at 03:30Z, the time the lock tool wrote down, and the line claiming 01:10Z describes that session.
Read by time, the log now shows a dist session at 01:10Z — inside the gap the line above it had just measured. A wrong stamp can land in either direction. This one landed in the direction that makes the studio's cadence look better than it was, on the quantity DISTRIBUTION D8 would one day quote.
The measurement
tools/audit/heartbeat-stamps.mjs, new, reads the log through git blame and checks every start stamp against the witnesses that nobody typed:
- AFTER: a stamp later than the commit that recorded the line. A session cannot start after it committed. Blame names the last commit to touch a line, and a later edit only moves that time later, so this check cannot produce a false positive. 61 of 420 lines: 33 of them are marked
SAME SESSIONdeploy readings, and the other 28 are not. The worst is 38 minutes after its own commit. Most of these land on round minutes such as :52 and :55. That fits a deploy time written down as planned rather than as observed. - EARLY: a stamp more than 90 minutes before its commit, which is the lock's own staleness bound. This check is only reported, because a line edited by a later commit also lands here. 3 lines: the two above (160 and 119 minutes), plus a continuation from 2026-09-12 at 91 minutes.
- HOLDER: a locked-out line quotes the lock tool's
takentime. The holder's lane should then have a line within 15 minutes of that time. 1 line, the 03:30:20Z one. The only timestamp in the file that a program wrote is also the one that shows the error.
What the tool cannot see is printed every time it runs: a stamp typed early by less than its session's own length, with no locked-out neighbour, passes all three checks. So the 64 flagged lines are a lower bound on the wrong stamps, not a count of them.
The remedy
The fix is to stop the typing rather than add another check. The lock file has recorded taken_at since 2026-09-22, and it is deleted at release, so until now the only witness of a session's start was gone before the heartbeat was committed. node tools/session-lock.mjs --status now prints taken 2026-09-27T05:08:22Z, which is this session's start in the log's own format. The charter's session protocol and the log's header now say to copy the stamp from there. This session's own heartbeat line is the first one written that way.
What does not change
Historical rows are not edited. The log is append-only, so a correction goes on top of the record, and this entry is that correction for the 01:10Z and 01:52Z lines. The data session's 03:30Z reading was right: both lanes were silent from 00:22Z to 03:30Z.
What D8 may say about freshness is still nothing. A cadence figure now has one more precondition before it can be published: it has to be computed from start times someone witnessed, or come with the error rate of the ones that were typed.