Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e0a754b
test(docs): check the evidence anchors against source
jeremi Aug 22, 2026
503ef3b
docs: correct the secret-file and problem-code claims
jeremi Aug 22, 2026
6388243
fix(docs): close four gaps in the evidence anchor check
jeremi Aug 22, 2026
25f4b0a
docs: cite where the wire keys the prose quotes are spelled
jeremi Aug 22, 2026
45674f0
fix(docs): close six more gaps in the evidence anchor check
jeremi Aug 22, 2026
6b6bc47
fix(docs): refuse an anchor citation that a symlink leads out of
jeremi Aug 22, 2026
ea8b12b
feat(docs): check the wire values an anchor spells in capitals
jeremi Aug 22, 2026
149ea5e
docs: state which symbol shapes the anchor check reads
jeremi Aug 22, 2026
63b1627
feat(docs): read a brace-list citation as the files it names
jeremi Aug 22, 2026
05676c6
feat(docs): check the leaf of a dotted key path an anchor cites
jeremi Aug 22, 2026
59d3756
feat(docs): read a bare filename that opens an anchor
jeremi Aug 22, 2026
7f1491b
feat(docs): read a bare child directory an anchor cites
jeremi Aug 22, 2026
632a466
feat(docs): read a name that runs an initialism into its capitals
jeremi Aug 22, 2026
0c27764
docs: name the shape a citation carries
jeremi Aug 22, 2026
58fa8da
ci: run the documentation anchor check on every pull request
jeremi Aug 22, 2026
8017dfd
docs: spell a one-word type or variant qualified in an anchor
jeremi Aug 22, 2026
ff622f3
feat(docs): require a bare sibling that names a Rust source file
jeremi Aug 22, 2026
96ac335
fix(docs): refuse the repository-root file a symlink leads out of
jeremi Aug 22, 2026
b56f0e2
feat(docs): open a citation on every top-level directory
jeremi Aug 22, 2026
5cbeaaf
feat(docs): report an anchor that resolves no path
jeremi Aug 22, 2026
50b377d
fix(docs): report a line reference the anchor spelled wrong
jeremi Aug 22, 2026
b70ecfa
fix(docs): read a bare child against the kind its parent resolves to
jeremi Aug 22, 2026
73f6c95
docs: state what the anchor check now guarantees
jeremi Aug 22, 2026
0003231
fix(docs): read a bare child against the directory the anchor resolved
jeremi Aug 22, 2026
f20ace4
fix(docs): close three more gaps in the evidence anchor check
jeremi Aug 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,30 @@ jobs:
rust:1.95-trixie@sha256:f49565f188ee00bc2a18dd418183f2c5f23ef7d6e691890517ed341a598f67c3 \
bash /work/docs/site/scripts/check-evidence-tutorials.sh

evidence-anchors:
# The documentation anchors cite source across the whole workspace, so this check
# runs on every pull request rather than behind the changed-path classifier: a
# rename outside the docs job's allow-list is exactly the drift it exists to catch.
# The checker imports only node:fs, node:path, and node:url, so a checkout and a
# Node runtime are all it needs; the docs job runs it again inside check:source.
name: Evidence anchors
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
persist-credentials: false
submodules: false

- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
with:
node-version: 22.12.0

- name: Check documentation anchors against the source tree
run: node docs/site/scripts/check-evidence-anchors.mjs

docs:
name: Docs checks
needs: changes
Expand Down Expand Up @@ -1186,6 +1210,7 @@ jobs:
- release-tool
- release-source-proof
- evidence-tutorials
- evidence-anchors
- docs
- editor-extensions
- client-bindings
Expand Down
71 changes: 71 additions & 0 deletions docs/site/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,77 @@ fixtures, OpenAPI, or an upstream standard. When evidence is missing, mark the
claim inline with a `TODO[evidence]` MDX comment and propose a weaker claim
level, rather than deleting the claim or asserting it.

`npm run check` resolves those anchors and fails when one does not. A cited
path must exist, a cited line reference must fall inside its file, and a cited
symbol must occur in at least one path the same anchor cites. Every anchor has
to cite at least one path this repository holds, since one that resolves none
has nothing to read its symbols against; pair an upstream standard with the
file that implements it rather than citing the standard alone. A citation may
start at any top-level directory the repository keeps, and `schemas/` is read
against the crate or product cited before it first and against the repository
root last, because both keep one. A path a symlink leads out of the checkout is
refused rather than read. A line reference is spelled `:12` or `:12-14` and
nothing else, so `:abc`, `:1foo`, and `:1.5` are reported rather than thrown
away; the full stop that ends a sentence on a path is punctuation and is left
alone. A citation that has drifted is a merge blocker, not a wart, so check an
anchor when you move the code it points at. Run `npm run check:evidence-anchors` alone
for the fast version. Root CI runs it twice: once inside the docs job, and once
in a job of its own that runs on every pull request, because the anchors cite
source all over the workspace and the docs job only runs for a changed path it
recognizes. A bare filename beside a cited path is read as prose when nothing
resolves, so naming a file the repo does not own, an adopter's `origins.yaml`
or a path a generated package writes, is still fine wherever the anchor
resolves some other path. A bare `.rs` sibling is the exception: only this
repository writes Rust into the stack, so a Rust filename has to resolve, and
deleting the file one names fails the check. Several files in one directory may
be cited in the compact brace form,
`crates/registry-relay-v2/src/{api,startup}.rs`, which is read as one citation
per entry, so each file it names has to exist on its own. A bare name ending in
a slash continues the directory cited before it, `deployment-projects/ then
protected-read-evidence/`, and has to exist under it. It continues that path
only where the repo holds it as a directory, so beside a file the name stays
prose: `governed/` after `package.rs`, and `output/` after the extensionless
`release/scripts/registry-release`, name directories the program writes, not
ones the repo holds.

The check reads a symbol by its shape: `snake_case`, `SCREAMING_SNAKE_CASE`,
`UpperCamelCase`, `lowerCamelCase`, a name spelled with empty parentheses such as
`router()`, and an all-capital wire value carrying a digit such as `ES256`.
`UpperCamelCase` covers a name with an initialism run into it, `OAuthErrorCode`,
once that name carries two lower-case runs and one capital run of two or more. A
qualified name is read segment by segment: the last segment is read whatever its
shape, and each segment that qualifies it is read once it carries a shape of its
own. A dotted configuration or wire key path is read the same way, segment by
segment, once one of its segments carries a shape:
`evidence_data_request.transport_absences.credentials` is checked down to its
leaf, and a `*` standing for any key is skipped rather than looked up.

Anything outside those shapes is prose, which leaves three gaps worth knowing. A
one-word name is not checked, because `UpperCamelCase` asks for two capitalized
chunks: the only shape that would reach `Visibility` also reaches every
sentence-initial word an anchor writes, `Evidence`, `Relay`, and `The` among
them. Spell a one-word type or variant qualified when you want it checked,
`AccessRule::Public` or `contract::Visibility`, since the last segment of a
qualified name is read whatever its shape. A qualifier is still read by shape, so
`Command::Check` puts `Check` under the check and leaves `Command` outside it. A
name nothing separates from an acronym the prose spells is not checked either: an
all-capital wire value with no digit, `EdDSA`, and a capitalized name carrying
one lower-case run, `SDMXProfile`. The only shape that reaches either also pulls
in `OpenAPI`, `SQLite`, `OpenCRVS`, and every other acronym the prose spells,
which would fire on correct anchors. A key path no segment of which carries a
shape, `sources.*.authentication.kind`, is not read at all: its segments are
among the commonest words in the tree, so a check on them would pass on any file
that happens to mention them. All three gaps are deliberate. Spell such a value
or key beside a symbol the check can see.

Two things the check deliberately allows. Bare `path:start-end` citations still
pass: `--strict-line-refs` rejects them, but it stays off while a backlog of
them remains, and the check prints how many are left. Prefer citing a symbol
over a line range in new writing, because a symbol survives the next edit above
it. Prescriptive guidance that tells an operator to set a value is also
untouched, since the check reasons about claims describing what code does, not
about advice.

A procedure carries more than its commands: the reason for a step whose reason is
not visible in the command, what an irreversible step forecloses, what failure
looks like and the next move, and a `caution` or `danger` at every action that
Expand Down
3 changes: 2 additions & 1 deletion docs/site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"check:docset": "node scripts/check-docset.mjs",
"check:release-manifests": "python3 ../../release/scripts/registry-release validate-docsets",
"check:evidence-links": "node scripts/check-evidence-links.mjs",
"check:evidence-anchors": "node scripts/check-evidence-anchors.mjs",
"check:content": "node scripts/check-doc-frontmatter.mjs",
"check:cli-reference": "node scripts/generate-cli-reference.mjs --check",
"check:cutover": "node scripts/check-current-doc-cutover.mjs",
Expand All @@ -46,7 +47,7 @@
"check:tutorial:evidence:dry-run": "bash scripts/check-evidence-tutorials.sh --dry-run",
"check:links": "npm run build && npm run check:links:built",
"check": "npm run check:source && npm run build && npm run check:built:current",
"check:source": "npm run check:cli-reference && npm run generate && npm run check:evidence-links && npm run check:docset && npm run check:release-manifests && npm run check:archive-lock && npm run check:content && npm run check:cutover && npm run check:notary-surface && npm run check:markdown && npm run check:style && npm run check:style:fixtures && npm run check:openapi && npm run check:config-vocabulary && npm run check:tutorial:dry-run && npm run check:tutorial:evidence:dry-run && npm run check:tutorial:discovery:dry-run && npm run check:svg",
"check:source": "npm run check:cli-reference && npm run generate && npm run check:evidence-links && npm run check:evidence-anchors && npm run check:docset && npm run check:release-manifests && npm run check:archive-lock && npm run check:content && npm run check:cutover && npm run check:notary-surface && npm run check:markdown && npm run check:style && npm run check:style:fixtures && npm run check:openapi && npm run check:config-vocabulary && npm run check:tutorial:dry-run && npm run check:tutorial:evidence:dry-run && npm run check:tutorial:discovery:dry-run && npm run check:svg",
Comment thread
jeremi marked this conversation as resolved.
"check:built:current": "npm run check:accessibility:built && npm run check:llms:built && npm run check:seo:current && npm run check:links:current",
"check:production": "npm run check:source && npm run build:dev && npm run check:production:built",
"check:production:built": "DOCS_DIST_DIR=$PWD/dist/dev DOCS_PUBLIC_BASE=/dev/ npm run check:accessibility:built && DOCS_DIST_DIR=$PWD/dist/dev DOCS_PUBLIC_BASE=/dev/ npm run check:llms:built && DOCS_DIST_DIR=$PWD/dist/dev DOCS_PUBLIC_BASE=/dev/ npm run check:seo:current && DOCS_DIST_DIR=$PWD/dist/dev DOCS_PUBLIC_BASE=/dev/ npm run check:links:current",
Expand Down
Loading