The legacy cursor contains three fields:
{"mtimeMs": 0.0, "size": 0, "offset": 0}LAKE_DATA/cursors.json maps absolute source paths to records. offset is a complete-line boundary. Current records also contain source: sha256 is a 32-byte JSON array for the consumed prefix; device, inode, changedSeconds, and changedNanos identify the opened source generation. Unchanged detection requires these fields, matching size/mtime, and a fully consumed file.
For a modified file, the reader hashes the consumed prefix once before resuming. A changed or shorter prefix, or a legacy cursor with no proof, replays that source from the beginning. Existing masked canonical occurrences are counted rather than appended again, missing Oko rows are restored, and historical rows are never removed. Legacy records migrate lazily without a second Lake or raw-source copy.
A checkpoint follows canonical partition fsync and successful Oko projection writes. Recovery retains its old cursor until the whole source succeeds, so a failed later batch cannot turn its unfinished replay into an append. Retrying compares against all already retained occurrences. Cursor publication uses a lock, temporary file, fsync, rename, and data-directory fsync. Corrupt cursor JSON or canonical evidence is refused with its path and cause, not silently reset.
LAKE_DATA/stream.lock/owner.json grants one state writer at a time. The atomic lease records host, pid, process start, and token. A live incumbent is a refusal; a provably dead one can be recovered. Labels do not share this lease.
A cursor is resume metadata, not a copy of the vendor transcript and not an event index.