Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Discovery

Discovery decides which files count as documents, and it is deliberately narrow. Files with the exact lowercase suffix .md or .markdown are structured-markdown; .mdx files are structured-mdx. Six exact extensionless basenames, README, CONTRIBUTING, CHANGELOG, SECURITY, SUPPORT, and CODE_OF_CONDUCT, are extensionless-markdown and use the Markdown adapter. .cursorrules and llms.txt are plain-advisory: they are scanned by an adapter that extracts no references. .adoc and .asciidoc are structured-asciidoc, and .rst is structured-rst. .txt stays off both lists: the suffix says nothing about what is inside. Django can state its convention without admitting every file under docs by using one exact tree-and-suffix selector bound to rst; unrelated suffixes remain outside. .ipynb and .org are unparsed-markup: this engine has no parser for a notebook or for Org markup, so those files are discovered and counted as unsupported-document-format and their content is never read, the same honest count an unbound policy include reaches. Notebook Markdown has measured reference yield, but its decoded cell spans are not physical JSON spans and the current report cannot name a cell; the notebook measurement records why that format remains visible but unparsed. Quarto’s .qmd suffix remains outside the document set, while MyST’s .md files receive only the CommonMark/GFM semantics their suffix promises. The adjacent-format measurement records why MyST, Quarto, and Org need renderer-aware adapters rather than suffix aliases. An include may instead bind one of the five built-in adapters, which reads the named path or tree under that grammar without installing another parser. One grammar answers per path per evaluation: the candidate policy’s bindings, or the base’s when the candidate carries none, and dropping a binding while keeping the include is policy weakening under policy/include-binding-removed. Every other file is a possible reference target, not a built-in document. These rows come directly from the classifier.

Nine directory names are always skipped, wherever they appear in a path:

node_modules  vendor  third_party  dist  build  .next  target  test  tests

The names are fixed: no configuration adds one or takes one away. A repository policy can still readmit coverage underneath a skipped name, because policy adds coverage and never removes it: a document include admits its one exact path, a plain tree include admits the whole subtree, and a suffixed tree include admits only its exact tail. That is the monorepo lever. A package legitimately named build, dist, test, or tests keeps its prose scanned through one tree include in the repository policy, and there is no mechanism in the other direction: Amiss always reads the whole repository, so a monorepo cannot scope a run down to one package. Skipping is visible in both directions: skipped documents still show up in the report’s counts, as excluded. This repository relies on the rule itself: its vendored parser test corpus lives under corpus/third_party/ exactly so that fixture files full of deliberately broken links are never read as prose.

test and tests joined the list on measurement. Across fifteen public repositories, 391 of 3,934 discovered documents sat under one of those names and carried 400 references between them, about one apiece, while producing 45 of the missing rows, every one a deliberately broken fixture. Two were prose: the READMEs explaining pydantic’s own test suites. Prettier is the case that made it a defect rather than noise, since seven intentionally malformed MDX fixtures under tests/format/ refused its entire run; it scans now, and the first thing it reports is a real break in its contributing guide.

Nine paths through the classifier:

docs/guide.md               structured-markdown   scanned
site/page.mdx               structured-mdx        scanned
README                      extensionless-markdown scanned
llms.txt                    plain-advisory        scanned, nothing extracted
docs/guide.adoc             structured-asciidoc   scanned
docs/guide.rst              structured-rst        scanned
notes/plan.org              unparsed-markup       counted, never read
vendor/lib/README.md        excluded              the vendor component is in the closed set
src/parser.rs               not a document        a reference target only

Markdown and MDX recognize frontmatter only at byte zero, optionally after one UTF-8 BOM. The first complete line must be exactly --- or +++; the closing line repeats it, except that --- also permits .... A recognized region is opaque to the document grammar and may contain at most 65,536 bytes, excluding the BOM. An opener without a permitted closer, or a closer past that bound, remains ordinary document text. The published frontmatter vectors execute this boundary, including LF, CRLF, bare CR, BOM, and exact-limit cases, through the production recognizer in the frontmatter test.

A reference definition whose decoded label begins with exact lowercase amiss: is a reserved governed claim. Entity and escape decoding happens before that test; case is not folded. Every reserved definition node contributes its exact source digest, including a losing normalized duplicate, and only the first normalized definition controls whether a consumer becomes an ordinary reference. A governed definition spelling the closed value grammar is evaluated as a claim, described in Claims. Everything else in the namespace on the candidate side is an unsupported capability boundary: the run ends incomplete with exit 2. A base-only definition does neither. The governed-definition vectors drive extraction, source hashing, candidate-only grouping, and report construction in the governed test, including one refusal vector per clause of the value grammar.

Every count is reported: discovered, scanned, unsupported, excluded, unlinked. The last count is zero unless trusted complete site-build evidence supplies a source root, navigation manifest, rendered entrypoints, and the source documents reachable through the completed HTML link graph. unlinked-document then names a scanned structured document inside that root which is neither the manifest nor reachable. Outbound-reference counts never stand in for navigation evidence. The exact predicate is in the document finding evaluator.

Paths are treated as bytes. Amiss does not fold case and does not normalize Unicode, because Git addresses files by exact bytes, and a checker that guesses two names are equivalent will eventually insist that two different files are the same file. A name whose bytes are not valid UTF-8 is still a name: the entry is classified by the same suffix rules, scanned, and reported, with its path written as a bytes_hex object naming the raw bytes as lowercase hex, since JSON text cannot carry them directly. Only a name outside the path grammar itself, one containing a backslash or a NUL byte, or a bare . or .. segment, is refused. That refusal is never quiet: the run stops as incomplete, the error is recorded as UNREPRESENTABLE_PATH with the exact bytes in path_bytes_hex, and the exit is 2. Dropping such an entry silently would be the worst bug this tool could have: the report would come back green with a document missing from it, and a missing row is the one defect no reader can notice.

Both commit-tree and staged-index discovery emit document rows strictly increasing and unique by those raw path bytes. That ordering is load-bearing: exact document queries and policy-inventory checks use binary search over it, and two-sided report construction merge-joins the ordered sides. The discovery ordering test pins the Git directory-boundary ordering against both snapshot modes, the report test pins interleaved base and candidate rows, and the amiss-scan pipeline benchmark tracks lookup and merge cost as the row count grows.

Last change: , commit: 1c46feb4