Review findings B1, B2, S2, S3, B3 (store sites), decision I, J and L.
- B1: the clock-marker flush is now the `Store::flush` impl, so
`Node::flush` writes the marker and fsyncs. The inherent
`LogStore::flush` is gone (calls resolve to the trait method).
- B2 / decision I: `open` (after the tick fold) and `set_wall_clock`
(after the wall fold) rewrite the log as a snapshot: header, Boot,
every live Obs at its current age with stored_at = now, a Release
for every released id still held, and a closing Clock marker (no
wall at open, wall_now after the fold). Temp file beside the log,
fsync, rename, fsync dir. Every stored_at on disk is then in the
current boot's ticks, so lineage survives any number of reboots, and
an expiry or floor from the fold survives a later reboot. A leftover
temp file from an interrupted snapshot is removed on open.
- Lock across the rename: the snapshot's temp file is created 0600 and
locked before it is renamed over the log, so the file at the path is
always locked by the live store. An opener that locked a file a
snapshot just replaced detects it (dev/inode check) and retries.
- S2: the known-downtime fold adds downtime minus the ticks the open
fold counted minus (now - open_tick), once, not per-entry
now - stored_at, so a flush before trust no longer double-counts.
- S3: flush and set_wall_clock clamp `now` to the time anchor (the
latest tick the store has seen); stored_at never moves backwards.
- B3: the derived marker wall and the expiry `lifetime + 1` saturate.
- Decision J: peer_time_estimate returns the latest estimate among
non-quarantined observations with observed_at; rustdoc says peer
time is unauthenticated.
- Decision L: trim rustdoc states quarantined entries are exempt from
every rule; tested.
- A header torn while the log was first created (shorter than the
header, starting with the magic) opens as a new log; any other short
file is still refused and left alone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>