snapshot.sh: byte-offset cursor replaces fixed-line-count tail
Date: 2026-10-16
Queue item added: 2026-09-14, follow-on from sessions/2026-09-14-agent-log-lines-per-day-rate.md
The problem
snapshot.sh captured a fixed tail of agent.log at mutation time, sized by
a guessed constant. First guess was 500 lines (covered about 5 hours).
The 2026-09-14 session measured the real rate (about 2,416 lines/day) and
raised the constant to 3,000 lines (about 1.2 days). That fix only moved the
problem, it did not remove it. A fixed line count can only ever be correct
for one specific elapsed-time gap between snapshots. A shorter gap than
assumed wastes overlap (most of the tail duplicates the prior snapshot). A
longer gap silently drops the earliest lines with zero warning, which is
the actual failure mode that matters, because snapshot.sh exists specifically
to preserve forensic evidence around hysteresis-protocol phase boundaries
that can be days apart.
The fix
Replaced the fixed-line tail with a tracked byte-offset cursor
(log-snapshots/.cursor_offset). Each run:
- Reads the previous offset (defaults to 0 if the cursor file does not exist yet, i.e. first run).
- Compares it to the live file’s current size via
stat -c%s. - If current size is less than the stored offset, the log rotated out from
under the cursor (5MB/3-backup size-based rotation, confirmed
2026-09-09). The exact rotation boundary cannot be recovered from the
live file alone, so it falls back to a capped tail (default 20,000 lines,
about 8 days at the measured rate) and prints a loud multi-line warning
pointing at
agent.log.1for manual recovery if the lost window matters. - Otherwise it captures exactly
tail -c "+$((offset+1))"through end-of-file, writes that slice (empty-safe, bounded, never more or less than the true elapsed gap), and stamps the cursor file with the new offset regardless of which branch ran.
This makes coverage scale automatically to actual elapsed volume instead of trusting a guessed constant. A one-hour gap captures roughly an hour. A ten-day gap captures roughly ten days (unless rotation ate part of it, which is now a loud warning instead of a silent gap).
Verification (real invocations, not just code review)
Ran snapshot.sh four times for real against live agent.log
(4,729,286 bytes at the time) and committed each:
- No prior cursor (first run ever): fell through to offset 0, correctly captured the full live file (4,729,286 bytes) as the baseline, wrote the cursor.
- Normal incremental run, ~10 seconds later: captured exactly 340 new bytes since run 1, labeled “exact since-last-snapshot coverage.” This is the core behavior change working as designed. A fixed-3000-line tail would have recaptured most of the same 3,000 lines again regardless of the real 340-byte gap.
- Simulated rotation: manually set the cursor file to an offset larger than the current file size (999,999,999 vs. 4,729,966), ran with a 500-line fallback cap. Correctly detected the rotation condition, printed the full warning block, fell back to a capped tail, and restamped the cursor to the real current size.
- Second real incremental run after restoring the correct cursor: captured another exact 340-byte delta cleanly.
The one untested branch is the exact-zero-new-bytes case (current size
equals stored offset). Could not trigger it live because agent.log kept
growing from this very session’s own activity between invocations — there
was no real quiet window available to test against. Reviewed that branch by
inspection instead: it only prints a message and skips writing the (would be
empty) output file, no destructive path, low risk left unverified live.
Questions
None new. This closes the queued item cleanly: the mechanism behind the 09-14 fix (fixed-count guessing) is gone, replaced with something that measures the actual quantity it was always trying to approximate.