Skip to content

Views and coverage

Two accounting systems keep a corpus honest about what it serves and what it is missing. Views decide which knowledge an agent sees. Coverage decides whether the corpus is telling the truth about its own completeness.

Views: one corpus, the right slice per consumer

Different agents need different knowledge, and one agent seeing another's knowledge is a bug. A V1-maintenance agent should draw on V1 docs without being nagged about a newer platform; a platform agent should never even see that a V1 existed. Views make this precise.

A view is a named set of sources plus a supersession-visibility rule, declared in the corpus manifest:

yaml
views:
  default:        { sources: [platform, sdks-nodejs], supersession: redirect }
  platform:       { sources: [platform], supersession: redirect }
  v1-maintenance: { sources: [sdks-nodejs, sdks-react], supersession: redirect }

A consuming repo commits one line - .alloy/corpus.lock holds { version, view } - and every query passes the view through. No agent ever infers which knowledge applies; the repo declares it. A supersession edge whose successor is inside the active view redirects to it; one whose successor is outside degrades to a one-line note, so an agent is never steered toward docs its view cannot use.

Within a view, each category carries a machine-maintained map (index.md). Unit routers declare judgment cells in their frontmatter (owns, load_when), and alloy finalize rolls them up into the category map between fence markers - LLM-free and byte-stable, with a --check mode wired into the gate so a map can never drift from the documented-unit set. You never hand-edit a map; you edit the router frontmatter and let finalize project it.

Coverage: every element in exactly one state

Coverage is the accounting that stops the silent-omission failure. For a source that opts in, every source element lands in exactly one of three states:

  • EXTRACTED - a rule pack reaches it. It is (or will be) documented.
  • EXCLUDED - a recorded decision, with a mandatory written rationale, that it is not a documentable unit.
  • UNKNOWN - a surfaced gap. Nobody has decided.

The accounting runs on two planes with separate denominators - declared slices and raw files - so a gap is caught whether it is a whole undocumented unit or a single unopened file.

UNKNOWN is the point

Extraction is a whitelist, and a whitelist's danger is that what it does not name is invisible. UNKNOWN is the complement that makes the invisible loud: a directory nobody decided about is reported, not skipped. This is not theoretical - real packages once went undocumented while a corpus reported itself complete, precisely because nothing forced a decision about them. UNKNOWN forces the decision.

Two rules follow:

  • A rationale-less exclusion is rejected. An exclusion with no reason is a silent ignore wearing a config hat. The rationale should let a reviewer disagree with you.
  • A STALE exclusion (one that matches nothing) is reported. It is a typo or a decision that has rotted as the code moved.

The strict flip

By default UNKNOWN surfaces without failing anything - alloy status reports it and still exits 0, so a daily detection job never reds your main branch. Once a source is fully triaged, a source can opt into coverage.strict: true, and an invocation can enforce it:

bash
alloy status --gate     # exit 1 iff a coverage.strict source has UNKNOWN > 0

That is the deliberate progression: keep UNKNOWN visible while you are still triaging, then flip strict on to hold the line once you have driven it to zero.

E11 Alloy - knowledge as a build artifact.