Expand description
OT.3b — agenda scan results, remembered across restarts.
OT.3 priced the parse at 1–2 ms per file (benches/agenda_scan_input.rs).
An agenda is refreshed far more often than its files change — gr,
reopening the view, an autocmd, and every editor restart — and without a
cache each of those reparses the whole project and re-calls the guest for
every file.
§What is cached, and why not the tree
The rows, not the parse tree. Tree-sitter has no serialisation for a
Tree — there is no to_bytes / from_bytes in the crate — so a
persistent cache physically cannot hold snapshots. It has to hold what the
scan derived, which is also what org-roam’s database holds for the same
reason.
That turns out to be the better layer anyway: a hit skips the parse and the guest call, where a snapshot cache would only have skipped the parse.
§What it does NOT skip
The read. You cannot know a file is unchanged without looking at it, and the
host reads it upstream regardless (it needs the text to build the source
Document). A warm read is ~10–50 µs against a ~2 ms parse, so this is the
cheap end and not worth an mtime pre-filter’s correctness risk.
§The key
(generation, path, content-hash).
Content hash, not mtime. The text is already in hand, so hashing costs ~2–5 µs against the ~2 ms it protects, and it is exactly right: no one-second mtime granularity, no filesystem that lies, no length collision to paper over. A file that came back byte-identical genuinely produces the same rows.
Generation is the opaque u64 the guest returns from begin — for org,
derived from the day the scan is anchored to and the configured TODO
keywords. Cached rows embed presentation computed against that anchor
("tomorrow", "overdue by 2 day(s)"), so serving them under a different
anchor would render yesterday’s “tomorrow” as tomorrow — silently wrong at
midnight, which is the exact bug begin’s anchor exists to prevent. Keying
on the generation makes a cached value a pure function of its key, so that
cannot happen: the day rolls, the generation changes, the cache is discarded.
The host never learns what a date group or a TODO keyword is. It compares two integers.
§Failure behaviour
Every failure degrades to “no cache”, never to an error and never to a wrong answer: a missing file, a schema-version mismatch, corrupt bytes, an unreadable directory, a failed write. A cache that cannot be trusted is simply not used, and the scan runs as it did before OT.3b.
Structs§
- Scan
Cache - A persistent agenda-result cache for one source.