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.