wiki-lint’s semantic checks judge page bodies, and nothing tied a finding to the bodies it was judged from: the procedure named the pages to visit, not how to read them, at which snapshot, or within what cost. So enchiridion read-pages is the one body reader for the judgment pass. It reads page bodies — not frontmatter — from a single committed HEAD, in bounded batches with a cursor (--limit, --max-bytes, --after), and it records every body the run read in a per-run ledger under .wiki-knowledge/, keyed by HEAD. A later check serves a body from that ledger (cached: true) instead of reading it again, and a per-run budget (--budget, default 60) bounds what the run newly reads; --reset opens the run. Implicit concepts is the check that sweeps: it reads the eligible set — the page refs at HEAD minus the refs the mechanical pass already flagged (--exclude) — and every proposal carries {head, term, supporting: [{page_ref, blob_oid}]} naming at least three supporting bodies the run read, which anyone can re-check by re-running read-pages on those refs.
search snippet all mention the term cheaply, and none of them is the body. Making the read a named, batched command with HEAD and blob object IDs in its output turns “the bodies were read” into a fact a reader, a test or an eval can verify by re-running it, rather than a step the agent asserts it performed.read-pages resolves the eligible set itself — the page predicate at HEAD, minus the flagged refs — so no caller re-derives the rule, and the batch caps plus the run budget make the cost explicit. A sweep that ran out of budget or out of vault reports remaining and says so; missing a term costs nothing, claiming coverage the run did not have is the failure the old procedure allowed.HEAD and each page’s blob object ID is checkable, and it invalidates itself the moment a page or a commit moves.HEAD, not the working tree, because that is what the check scored. The mechanical pass and the fragmentation clusters read committed history (ADR-0015), so the bodies a judgment is pinned to must come from the same snapshot. An uncommitted draft is not a page until it is committed, and a body read from the working tree could silently disagree with the snapshot the finding is about.--limit, --max-bytes or the budget — and merely counted against the run, while the sweep stops at the cap and says exhausted: true. One counter keeps the trade visible without a second budget to reason about.search nominate terms and read only their hits. Cheaper per finding, but it makes recurrence a property of the index’s tokenizer and puts a snippet between the agent and the body, which is the inference the check must not make. The sweep keeps nomination and evidence separate: a snippet may suggest a term, only a read body supports one.HEAD and dropped on a schema bump, and it owns page rows rather than a run’s read history — a run-scoped cache with a spent counter is a different lifetime.HEAD plus --reset already delimits a run, and a moved HEAD is the one event that must invalidate it anyway.read-page does. It would let the sweep see uncommitted drafts, putting bodies into a report that the mechanical checks cannot corroborate and diverging from the snapshot every other lint read uses.enchiridion read-pages, with a row in the wiki-conventions script catalogue; it emits one JSON document, the dialect read-page and assess already use. read-page stays the working-tree single-page read, and assess stays the cluster reader that pins a Consolidation..wiki-knowledge/lint-bodies.json holds the run: {head, spent, pages: {ref: {blob_oid, title, bytes, body}}}. It is disposable state (ADR-0010), never vault history, and a ledger that is malformed, absent, or from another HEAD reads as empty rather than failing a read.--reset it. The cache is validated by the page’s blob object ID against the current HEAD, so a stale entry is dropped rather than served.HEAD (isPageRef), not readability: a committed page whose frontmatter a check refuses still has a body, and dropping it would hide it from eligible and from what the run reports as unread.wiki-lint step 4 owns the run contract — open with --reset, read bodies with read-pages, state what went unread — while reference/implicit-concepts.md owns the eligible set, the batch and budget mechanics, and the evidence block. wiki-linter’s brief names both.wiki-linter already does on its cheap tier.assess, which pins a cluster’s full text for a Consolidation; the two readers share a snapshot and an evidence shape, not a cache.