From fd65fd95f2be7bb6ba677e0aa486dac7a4eadd1d Mon Sep 17 00:00:00 2001 From: Serina Mcfall Date: Wed, 26 Aug 2026 17:26:19 +1200 Subject: [PATCH 1/6] docs(corpus): plan the code-references standard (#1308) Plan for issue #1308, capped at 5 steps by the #605 standards-batch brief rather than by a Size line the issue does not carry. Records what was verified before drafting: HEAD, the corpus tree's contents, the schema's required fields, and the validator's measured verdicts for the citation shapes the standard will rule on. Two findings from a self-run review-plan pass are already applied: - Medium: STEP 4 ran its three verification suites before the negative control's mutate-and-revert, so an imperfect revert satisfied the literal command sequence while shipping a file nothing re-checked. The negative control now runs first, and the suites run against the reverted file. - Low: the scope-boundary section claimed four of CONTRACT.md's six shapes name code. CONTRACT.md's own table marks three of six openable. Corrected, and the fourth code-naming form -- the commit reference -- is now named as a revision pin rather than counted as openable. That review was not independent: it reviewed a plan written in the same session by the same agent. Signed-off-by: Serina Mcfall --- ...ue-1308-corpus-standard-code-references.md | 232 ++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 launchpad/plans/2026-08-26-issue-1308-corpus-standard-code-references.md diff --git a/launchpad/plans/2026-08-26-issue-1308-corpus-standard-code-references.md b/launchpad/plans/2026-08-26-issue-1308-corpus-standard-code-references.md new file mode 100644 index 00000000000..bb520dbbdfa --- /dev/null +++ b/launchpad/plans/2026-08-26-issue-1308-corpus-standard-code-references.md @@ -0,0 +1,232 @@ +Issue #1308 — task: document corpus standard for code references +Stated size: no Size line; cap set by the #605 batch brief -> cap: 5 steps + +The issues in this batch carry no `Size` line. The dispatching brief settles it rather +than leaving it to be guessed: 5 steps. #636 was given 8 because it was the first node +and every convention was unsettled; these are single documents written against +conventions #636 already established, so the smaller cap is the right one. + +Target file: `launchpad/docs/corpus/standards/code-references.md` +Node id: `corpus-standard-code-references` (assigned by dispatch; permanent) +Branch: `task/1308-corpus-standard-code-references`, based on `origin/task/636-corpus-agents-md` + +--- + +ALREADY TRUE (verified against git and the running validator, not against notes) + +- `git rev-parse HEAD` -> `60d4947b7145a6ef25f185b9c25d43e43d99de3c`; `git status --short` + is empty. The branch is `task/636-corpus-agents-md` plus nothing. +- `launchpad/docs/corpus/` contains exactly one authored node: `AGENTS.md` + (`id: corpus-agents`). Everything else beneath it is `schema/`, which `validate.py`'s + `EXCLUDED_TOP_LEVEL_DIRS` skips. There is no `standards/` directory yet, and no + sibling node to point a relationship at. +- `node.schema.json` requires `id, type, status, origin, audiences, evidence`, permits + `relationships`, and sets `additionalProperties: false` — there is no `provenance` + field. +- `python3 launchpad/project-intelligence/corpus/validate.py` exits 0 today and prints + `PASS corpus validation found no errors; 1 item(s) reported unverified`. That one + item is `corpus-agents`' commit citation. +- `launchpad/project-intelligence/CONTRACT.md` section 3 enumerates six citation + shapes; `validate.py`'s `_classify_citation` is the only code that acts on them. +- CI runs the validator on `pull_request` and on pushes to `launchpad` for any change + under `launchpad/docs/corpus/**` + (`.github/workflows/launchpad-corpus-validate.yml`), so a local failure is a CI + failure. +- The validator's behaviour has already been measured directly during planning, so + STEP 1 is confirmation rather than discovery: `Justfile:999999` -> `ok` against a + 1005-line file (#1459); a GitHub `blob` link pinned to a full SHA naming a file that + never existed -> `ok`; `blob/main` -> error; a bare directory -> error; + `path:line:col` -> error; an uppercase 40-character SHA -> error. + +--- + +FRONT-MATTER CHOICES (decided here, not during drafting) + +- `type: governance`. It is the only enum member that describes a policy node. This + document rules on how other nodes cite code; it documents no architecture, + capability, interface or platform. `agent` — #636's choice — would be wrong, because + #636 *is* the file an agent harness resolves as instructions and this one is not. +- `audiences: [agent, developer, reviewer]`. `agent` and `reviewer` follow #636. + `developer` is added because #605's Outcome line names a developer authoring a node + ("A developer or agent can create one atomic corpus node..."), and this standard + governs that act. That source is an issue, not a file, so the body claim resting on + it is classified `TEAM_KNOWLEDGE` with `provided_by` naming #605 — not `INFERENCE`, + which is the exact misclassification caught on #636. `operator` is excluded: nothing + here is operational. +- `status: active`. `origin: launchpad`. Per the batch convention. +- No `relationships`. Every sibling standard is unmerged and `corpus-agents` is the + only loaded node; a `relationships[].target` naming an id no node carries is a hard + error in `find_unresolved_relationship_targets`. The absence and its reason are + stated in the body, as #636 does. +- Provenance goes in the `evidence` ledger as `commit 60d4947b...`, the one permitted + commit-only FACT. A second commit-only FACT would be a defect. + +--- + +SCOPE BOUNDARY AGAINST #1314 (evidence) — the live tension + +`AGENTS.md` states its citation-shape table "belongs in the evidence standard once that +lands (#1314)". #1308 is nevertheless the node for code references, and CONTRACT.md's +own §3 table marks three of its six shapes openable — file range, file line, bare path +— while a fourth, the commit form, pins a repository revision. Those four are the forms +that point at this repository's code; the remaining two, graph edge and tool result, +name tool output rather than code. The split adopted here, stated in the body rather +than resolved silently: + +- This node owns how a corpus node points at code: which reference forms are permitted, + what each one proves, pinning, positions, repo-relative resolution, and how a + reference stays honest as code moves underneath it. +- #1314 owns the ledger itself — `FACT`/`INFERENCE`/`TEAM_KNOWLEDGE`, precedence, and + the non-code evidence forms (tool results, graph edges, external URLs). +- The overlap is named in the body's scope section. The `AGENTS.md` forward-pointer + that will need updating is reported as a finding, not fixed here: the brief forbids + touching that file. + +A second discrepancy, found while establishing the above and confirmed by counting both +tables: **a URL is not one of CONTRACT.md §3's six shapes.** CONTRACT.md §3's table +lists File range, File line, Bare path, Graph edge, Tool result and Commit — no URL row, +and the section contains no occurrence of "url", "http" or "github". `validate.py` +nevertheless implements a whole `_classify_url` branch that accepts a commit-pinned +GitHub `blob`/`raw` link as `ok` and reports every other URL `unverified`, and +`AGENTS.md` presents a **seven**-row table introduced by the sentence "CONTRACT.md §3 +defines the six shapes", two of whose rows are URL forms CONTRACT.md does not contain. +This node therefore describes the forms `validate.py` actually accepts, names CONTRACT.md +§3 as the vocabulary for the six it does enumerate, and states plainly that the URL form +is validator behaviour not covered by that enumeration. The inconsistency itself is +filed as its own issue and named in the PR's Escalations; it is not fixed on this branch, +which may not touch `AGENTS.md` and does not own `CONTRACT.md`. + +--- + +STEP 1 Confirm the validator's verdict for every shape the standard will rule on [independent] + Re-run the classification probe against `validate._classify_citation` at this + HEAD and save the output, covering at minimum: bare file path, bare directory, + non-existent path, `path:line`, `path:start-end`, out-of-range line, inverted + range, line `0`, `path:line:col`, `path#fragment`, absolute path, path escaping + the repository, path not relative to the repository root, markdown-wrapped + path, GitHub `blob` at a full lowercase SHA, the same at an uppercase SHA, at a + short SHA, at `main`, with no trailing path, the `tree`/`blame`/`commits`/`edit` + verbs, `raw.githubusercontent`, the `http://` scheme, GitHub issue and PR URLs, + `commit `, a graph edge, a tool result, an external URL, and free text. + Every MUST and SHOULD the document later states must trace to a row in this + output. No claim about validator behaviour enters the node from memory. + done when: the probe has been run from the worktree and its stdout is saved to + the scratchpad, and every citation form the document will name appears there + with a recorded `ok` / `error` / `unverified` verdict. + +STEP 2 Create the node with schema-valid front matter and its evidence ledger [needs 1] ← RUNS HERE + Create `launchpad/docs/corpus/standards/code-references.md` with the front + matter decided above and one `evidence` entry per claim the body will make, + each classified against what STEP 1 measured and each citing a form STEP 1 + showed the validator accepts. The body may be a stub at this step. + done when: `python3 launchpad/project-intelligence/corpus/validate.py` run from + the worktree exits 0, names this node in no `FAIL` line, and reports exactly + two `UNVERIFIED` items — `corpus-agents`' commit citation and this node's — + proving the ledger rests on openable citations everywhere else. + +STEP 3 Write the body [needs 2] + Sections in this order, each answering a definition-of-done clause: + (1) Scope and authority — what this node governs, what it is not, that its + authority is `node.schema.json` plus `validate.py` with CONTRACT.md section 3 + as the shape vocabulary, and the #1314 boundary above. + (2) The reference forms and what each proves — the measured table from STEP 1; + the verdict column is what the validator returns, the next column is what a + passing verdict establishes, which for several forms is nothing. + (3) MUST requirements, separated from SHOULD guidance, each traceable to a + STEP 1 row. + (4) Enforcement — the local command, the CI workflow, and plainly stated, the + things a green run does not establish. + (5) Exceptions and escalation — when a non-checkable form is legitimate, and + what to do when a rule cannot be met. + (6) Links, not copies — schema, ADRs, CONTRACT.md, `AGENTS.md`, #1459. + (7) Scope and omissions — what is not covered, why no relationships, and what + was expected but could not be verified. + Enum member lists and the schema's field-combination matrix are linked, never + restated: the validator never reads body prose, so a copy stays green while + stale. + done when: every one of the issue's eleven definition-of-done checkboxes maps + to a named section or a front-matter field, written out clause by clause in the + commit message body; and the forms table carries a row for each form STEP 1 + measured. + +STEP 4 Verify [needs 3] + The negative control runs FIRST, so that every later command runs against the + file as it will ship. Running the suites before a mutate-and-revert step, as an + earlier draft of this plan did, means an imperfect revert — stray whitespace, an + incompletely removed citation — satisfies the literal command sequence while + shipping a node nothing re-checked. `review-plan` found that ordering defect in + this plan; this is the corrected order. + (a) Negative control: temporarily add to the node one citation the standard + forbids — an unpinned `blob/main` link is the cheapest case — run + `python3 launchpad/project-intelligence/corpus/validate.py`, observe it exit 1 + naming this node, then revert the edit and confirm with `git diff` that the file + is byte-identical to its pre-control state. This shows the document's MUSTs are + enforced rather than merely asserted. + (b) Then, against that final file, run from the worktree, each as the last + segment of its own command: + `python3 launchpad/project-intelligence/corpus/validate.py` -> exit 0; + `python3 -m unittest discover -s launchpad/project-intelligence/corpus/tests -p "test_*.py"` + -> OK, which also lands the verify-gate stamp; + `python3 -m unittest discover -s launchpad/docs/corpus/schema/tests -p "test_*.py"` + -> OK. + done when: the negative control was observed to exit 1 naming this node and the + revert was confirmed byte-identical by `git diff`; all three commands in (b) then + exit 0 against that reverted file; and `git status --short` shows only the + intended two files: the node and this plan. + +STEP 5 Commit [needs 4] + One commit for the node, signed off, message written to a file and applied with + `git commit -s -F ` — never `-m`, because a backtick or a `$(...)` inside + a double-quoted `-m` string is expanded by the shell and silently eats the + message. + done when: `git log --format='%s%n%b' -1` shows the clause-by-clause + definition-of-done list and a `Signed-off-by:` trailer, and `git status --short` + is empty. + +--- + +PARALLEL None. STEP 1 produces the evidence every later step consumes, and STEPs 2, 3 +and 4 all touch the same single file, so they are sequential by the same-file rule +however separable they look. One agent executes this plan start to finish. + +GATES `review-plan` on this plan before STEP 1 — self-review, not independent, and the +report must say so. `review-code` after STEP 4. `review-tests` does not apply: the diff +adds one Markdown node plus this plan and touches no test file; if STEP 4's negative +control ever becomes a committed fixture that changes and `review-tests` applies. +`review-adjudicate` over every finding those reviewers report. Then a mandatory Codex +cross-model final pass, which must verify the document's claims by running the validator +rather than by reading prose, and must specifically hunt for holes opened by earlier +fixes. `qa` explore mode does not apply: the change adds no runtime interface, the only +executable surface is `validate.py` which this branch does not modify, and STEP 4's +negative control is the exercise of it. + +BUDGET STEP 3. Writing MUST/SHOULD rules that are each traceable to a measured verdict, +without restating the schema and without straying into #1314's territory, is where the +time goes. The second-largest risk is STEP 4's negative control, which needs a citation +forbidden by the standard yet still reachable by the validator — an unpinned +`blob/main` link is the cheapest such case. + +OPEN The issue did not decide these. They are named, not resolved. +1. Whether the citation-shape table belongs here or in #1314. `AGENTS.md` pre-assigned + it to #1314 before #1308 existed as a drafted node. This plan puts the code-naming + shapes here, leaves the ledger to #1314, states that split in the body, and reports + the `AGENTS.md` pointer as a finding. If #1314 disagrees when it lands, one of the + two nodes is edited then — a `supersedes`/`references` decision, not this issue's. +2. Whether `developer` belongs in `audiences`. #636 chose `agent, reviewer`, and the + brief calls the question deliberately unsettled. This plan adds `developer` on + #605's Outcome wording and says so; a later batch-wide decision may normalise it. +3. Whether ADR-0003's markdown-link wrapper is required on corpus citations. + `_classify_url`'s docstring says the check is deliberately not enforced and that + #605 owns the decision. This node describes the current state and does not decide it. + +LEFT OUT Deliberately excluded. +- Fixing #1459. It is a defect in already-merged code with its own issue. This node + documents the behaviour that exists and prefers the form that is actually checked. +- Editing `launchpad/docs/corpus/AGENTS.md`. The brief forbids it; disagreements are + reported instead. +- Declaring any relationship. Nothing resolvable exists to target. +- A second corpus node of any kind. The issue's out-of-scope list forbids it, and any + second concept found while drafting is filed as its own issue. +- Any `generated/` artifact. `find_ownership_violations` fails closed on every non-`.md` + file under the corpus root, including inside `generated/`, until #1316 defines the + provenance contract. From ae6967663d5e93aa4c61fa1df1689f56c1996308 Mon Sep 17 00:00:00 2001 From: Serina Mcfall Date: Wed, 26 Aug 2026 17:26:26 +1200 Subject: [PATCH 2/6] docs(corpus): the code-references standard (#1308) Adds launchpad/docs/corpus/standards/code-references.md, node id corpus-standard-code-references, as the canonical policy for how a corpus node cites code. Every verdict in the document was measured by running validate._classify_citation at the recorded revision, not read off prose. The measurements the standard turns on: - A bare repository path is opened; it must resolve to a real file inside the repository, from the repository root. A directory, a missing path, an absolute path and an escaping path all fail. - In path:line and path:start-end the path is checked and the line is not. Justfile:999999 returns ok against a 1005-line file. That is #1459, and it is why a bare path is preferred. - A GitHub file link is syntax only. Pinned to a full lowercase 40-character SHA with a non-empty trailing path, a link naming a file that has never existed passes. The validator never contacts GitHub. - blob/main, an abbreviated SHA, an uppercase SHA, a pinned link naming no file, and the tree, blame, commits and edit verbs are all rejected. - Commit references, graph edges, tool results and non-GitHub URLs land on the non-fatal UNVERIFIED channel. Anything matching no known form is a hard error. Definition of done, clause by clause: 1. Exactly one hand-authored corpus document. Only code-references.md is added beneath the corpus root; the plan lives outside it. No generated artifact is added -- find_ownership_violations fails closed on every non-md file there until #1316 lands. 2. Schema-valid front matter with a stable id, type, status, origin, audiences, provenance and relationships appropriate to the node. type is governance -- the only enum member describing a policy node. audiences adds developer to #636's agent and reviewer, sourced to #605's outcome line and classified TEAM_KNOWLEDGE for that reason. Provenance is a commit citation in the evidence ledger, the schema's only legal home for it. No relationships: section 8 gives the reason, which is merge order rather than an empty corpus. 3. One independently maintainable node. Section 1 draws the boundary against the evidence standard, #1314. A second concept found while drafting -- a three-way divergence between CONTRACT.md, AGENTS.md and validate.py over whether a URL is a citation form -- is reported and filed rather than folded in. 4. Every substantive claim traceable, and the three classes not conflated. The ledger carries 20 entries: 17 FACT, each citing a file that was opened; 1 INFERENCE with a confidence, for the merge-order reasoning behind declaring no relationships; 2 TEAM_KNOWLEDGE, each naming the issue that is the source, because an issue is not a file that discusses the point. 5. Links implementation, verification, specification and decision without duplicating them. Section 7, plus an explicit note that enum lists and the schema's field rules are deliberately not copied, because the validator never reads body prose and a stale copy would stay green. 6. Checked against the recorded revision and against git, PRs and issues. Revision 60d4947b7145a6ef25f185b9c25d43e43d99de3c, confirmed present with git cat-file -e. #1459, #605, #1314 and #1316 were read. 7. Corpus validation passes locally: PASS, 0 errors, 2 unverified items, both of them the two nodes' revision citations. 8. States scope and authority. Section 1, which also states that the validator outranks this document where they disagree. 9. Separates MUST from SHOULD. Sections 3 and 4, as separate lists. 10. Defines enforcement and the exception and escalation process. Sections 5 and 6. Section 5 also names the four things a green run does not establish, and which rules only a reviewer can hold. 11. Links decisions rather than duplicating them. Section 7. Verified: the negative control was run first, injecting a blob/main link, a line:column suffix and an owner/repo#N reference into the ledger. The validator exited 1 naming this node on all three. The revert was confirmed byte-identical with diff, and the three suites then ran against that file: corpus validation exit 0; 79 corpus validator tests OK; 27 schema tests OK. Signed-off-by: Serina Mcfall --- .../docs/corpus/standards/code-references.md | 338 ++++++++++++++++++ 1 file changed, 338 insertions(+) create mode 100644 launchpad/docs/corpus/standards/code-references.md diff --git a/launchpad/docs/corpus/standards/code-references.md b/launchpad/docs/corpus/standards/code-references.md new file mode 100644 index 00000000000..93ffce67b58 --- /dev/null +++ b/launchpad/docs/corpus/standards/code-references.md @@ -0,0 +1,338 @@ +--- +id: corpus-standard-code-references +type: governance +status: active +origin: launchpad +audiences: + - agent + - developer + - reviewer +evidence: + - statement: "This node was authored and checked against repository revision 60d4947b7145a6ef25f185b9c25d43e43d99de3c." + entry_class: FACT + evidence: + - "commit 60d4947b7145a6ef25f185b9c25d43e43d99de3c" + - statement: "A code reference lives in a node's frontmatter evidence array, because the schema requires that array, defines no other field for citations, and rejects any field beyond the seven it names." + entry_class: FACT + evidence: + - "launchpad/docs/corpus/schema/node.schema.json" + - statement: "A bare repository path is opened on disk and must resolve to a real file: a directory, a path that does not exist, and a path naming no file all fail." + entry_class: FACT + evidence: + - "launchpad/project-intelligence/corpus/validate.py" + - statement: "A bare path is resolved against the repository root rather than the citing document, and after resolution it must still lie inside the repository, so an absolute path and a path that escapes the tree are both rejected." + entry_class: FACT + evidence: + - "launchpad/project-intelligence/corpus/validate.py" + - statement: "In a path:line or path:start-end citation the path is checked exactly as a bare path is, while the line number is compared only against itself -- start at least 1, end not before start -- and never against the length of the file." + entry_class: FACT + evidence: + - "launchpad/project-intelligence/corpus/validate.py" + - statement: "A GitHub repository file link is judged on syntax alone: the validator requires a full forty-character lowercase commit SHA and a non-empty path after it, and never contacts GitHub to establish that the named file exists." + entry_class: FACT + evidence: + - "launchpad/project-intelligence/corpus/validate.py" + - statement: "A repository link is rejected when it is pinned to a mutable ref, when it names no file after the ref, and when its verb is tree, blame, commits or edit rather than blob or raw." + entry_class: FACT + evidence: + - "launchpad/project-intelligence/corpus/validate.py" + - statement: "The requirement to pin a repository link to the full SHA and never to blob/main originates in ADR-0003's reference format." + entry_class: FACT + evidence: + - "launchpad/decisions/ADR-0003-handbook-page-provenance-contract.md" + - statement: "Commit references, graph edges, tool results and non-GitHub URLs are routed to a non-fatal UNVERIFIED channel that always prints and never changes the exit status." + entry_class: FACT + evidence: + - "launchpad/project-intelligence/corpus/validate.py" + - statement: "A citation matching no recognised form is a hard error rather than an UNVERIFIED notice." + entry_class: FACT + evidence: + - "launchpad/project-intelligence/corpus/validate.py" + - statement: "A citation that contains no whitespace and matches no other form falls through to the repository-path rule, so it is reported as a path that does not resolve rather than as an unrecognised form." + entry_class: FACT + evidence: + - "launchpad/project-intelligence/corpus/validate.py" + - statement: "Citation checking is structural: a citation that resolves to a real file is never opened, so nothing compares that file against the statement the citation sits under." + entry_class: FACT + evidence: + - "launchpad/project-intelligence/corpus/validate.py" + - statement: "The validator resolves a relationship target only against the ids carried by the Markdown files it discovers beneath the corpus root outside schema/, and an unmatched target is a hard error." + entry_class: FACT + evidence: + - "launchpad/project-intelligence/corpus/validate.py" + - statement: "CONTRACT.md section 3 enumerates six citation shapes -- file range, file line, bare path, graph edge, tool result and commit -- and none of them is a URL." + entry_class: FACT + evidence: + - "launchpad/project-intelligence/CONTRACT.md" + - statement: "AGENTS.md introduces its citation table as CONTRACT.md section 3's six shapes and then lists seven rows, two of which are URL forms CONTRACT.md does not enumerate." + entry_class: FACT + evidence: + - "launchpad/docs/corpus/AGENTS.md" + - "launchpad/project-intelligence/CONTRACT.md" + - statement: "AGENTS.md states that its citation-shape table is provisional and belongs in the evidence standard once that standard lands." + entry_class: FACT + evidence: + - "launchpad/docs/corpus/AGENTS.md" + - statement: "The same validator command that runs locally runs in CI on every pull request and on every push to launchpad that touches the corpus, and the just recipe wrapping it needs the Hermit environment activated first while the direct interpreter form does not." + entry_class: FACT + evidence: + - ".github/workflows/launchpad-corpus-validate.yml" + - "Justfile" + - "launchpad/docs/corpus/AGENTS.md" + - statement: "Declaring an edge to corpus-agents would validate on this branch and become a hard error if this node merged ahead of the branch that introduces corpus-agents, so this node declares no relationships." + entry_class: INFERENCE + evidence: + - "launchpad/project-intelligence/corpus/validate.py" + - "launchpad/docs/corpus/AGENTS.md" + confidence: 0.9 + - statement: "A line number that is not checked against the length of the cited file is a known defect rather than intended behaviour." + entry_class: TEAM_KNOWLEDGE + provided_by: "launchpad-26/buzz#1459 'bug: corpus validator accepts path:line citations whose line does not exist'" + - statement: "This standard addresses developers as well as agents and reviewers, because a developer is one of the two authors the parent feature names." + entry_class: TEAM_KNOWLEDGE + provided_by: "launchpad-26/buzz#605 outcome: 'A developer or agent can create one atomic corpus node and deterministic validation accepts or rejects it against one documented contract.'" +--- + +# Standard: code references + +How a corpus node points at code, what each reference form actually proves, and how a +reference stays honest once the code moves underneath it. Look up the rule you need; +this is reference material, not a tutorial. + +## 1. Scope and authority + +**This node governs** every citation, in any node's `evidence` ledger, that names code +in a repository: which forms are permitted, which are forbidden, how they are pinned and +positioned, and what a passing validation run does and does not establish about them. + +**Its authority is executable.** The rules below are not house style — each one is the +behaviour of `launchpad/project-intelligence/corpus/validate.py`, measured by running it, +and each MUST corresponds to a verdict that command returns today. Where this document +and that program disagree, **the program wins and this document has drifted.** +`launchpad/project-intelligence/CONTRACT.md` §3 supplies the vocabulary of shapes; +`launchpad/docs/corpus/schema/node.schema.json` supplies the field the citations live in. + +**This node does not govern the ledger itself.** Which class a claim carries, how +conflicting evidence is ranked, and the forms that name tool output rather than code — +graph edges and tool results — belong to the evidence standard (#1314). `AGENTS.md` says +its own citation table is provisional and belongs there once it lands; this node claims +only the code-naming half of that table, and the two will need reconciling when #1314 +arrives. That overlap is named here rather than silently resolved. + +**Nothing here is a decision about ADR-0003's markdown-link format.** `_classify_url` +accepts a bare pinned URL and documents in its own docstring that requiring the markdown +wrapper on corpus evidence is #605's call, not the validator's. This node describes that +state and leaves it open. + +## 2. The forms, and what a pass proves + +Six shapes are enumerated in `CONTRACT.md` §3. Four of them can name code in this +repository; the validator additionally accepts a seventh form — a URL — that §3 does not +enumerate at all. Every verdict below was measured against `_classify_citation` at the +revision this node records. + +| Form | Example | Verdict | What the verdict establishes | +|---|---|---|---| +| Bare repository path | `Justfile` | `ok` | **The file exists.** The path was resolved and opened. | +| Bare path, directory | `launchpad` | `error` | — a directory is not a file | +| Bare path, absolute | `/etc/passwd` | `error` | — must be repo-relative | +| Bare path, escaping | `../buzz/Justfile` | `error` | — resolves outside the repository | +| Path with a line | `Justfile:1` | `ok` | **The file exists.** The line does not. | +| Path with a line, out of range | `Justfile:999999` | `ok` | **The file exists.** Nothing else — the file is 1005 lines long. | +| Path with a range | `Justfile:1-99999999` | `ok` | Same: path checked, bounds not. | +| Path with a malformed position | `Justfile:0`, `Justfile:5-1` | `error` | — the position is inconsistent with itself | +| Path with a column or fragment | `…kind.rs:219:5`, `…kind.rs#symbol=Kind` | `error` | — not a supported form; see §5 for the misleading message | +| GitHub file link, pinned | `…/blob/<40-hex>/Justfile` | `ok` | **Nothing about the target.** Syntax only. | +| GitHub file link, pinned, target never existed | `…/blob/<40-hex>/does-not-exist.md` | `ok` | **Nothing.** The validator never contacts GitHub. | +| GitHub file link, mutable ref | `…/blob/main/Justfile` | `error` | — not pinned to a full SHA | +| GitHub file link, abbreviated or uppercase SHA | `…/blob/60d4947/…`, `…/blob/<40-HEX>/…` | `error` | — the SHA must be forty lowercase hex characters | +| GitHub link, no file after the ref | `…/blob/<40-hex>` | `error` | — names a repository at a commit, not a file | +| GitHub link, non-file verb | `…/tree/…`, `…/blame/…`, `…/commits/…`, `…/edit/…` | `error` | — a view of a file is not a citation of it | +| `raw.githubusercontent.com`, pinned | `…/<40-hex>/Justfile` | `ok` | Syntax only, as above. | +| GitHub issue or pull-request URL | `…/issues/1459` | `unverified` | Nothing. Recognised, unopenable. | +| Other external URL | `https://example.com/spec` | `unverified` | Nothing. | +| Commit reference | `commit <7-40 hex>` | `unverified` | Nothing on disk. See §6. | +| Graph edge, tool result | `a -> b (1 hop)` | `unverified` | Nothing. Owned by #1314. | +| Anything else | `#1459`, `issue #1459`, free text | `error` | — hard error, never a notice | + +A markdown wrapper — `[label](target)` — is unwrapped before any of this, so it is +accepted wherever its bare target would be, and rejected wherever its target would be. + +**Read the right-hand column, not the middle one.** Three of the four code-naming forms +return `ok` while establishing less than an author would assume: a line number is not +checked, and a GitHub link is not checked at all. + +## 3. MUST + +1. **A code reference MUST be a citation in the node's frontmatter `evidence` array.** + The schema defines no other field for one, and rejects any field beyond the seven it + names. +2. **A reference to a file in this repository MUST be a bare repository-relative path, + resolved from the repository root, naming a file that exists.** Not a path relative to + the citing document — `validate.py` is a real file, but the citation `validate.py` + fails from anywhere except the root. +3. **A reference MUST NOT be an absolute path and MUST NOT resolve outside the + repository**, before or after `..` segments and symlinks are followed. +4. **A file in this repository MUST NOT be cited as a GitHub link when a repository path + would name the same file.** The path form is checked against the filesystem; the link + form is checked against a regular expression. Choosing the link discards the only + guarantee available. +5. **A GitHub repository link MUST be pinned to the full forty-character lowercase commit + SHA, MUST use the `blob` or `raw` view, and MUST name a file after the ref.** ADR-0003 + is the source of the pinning rule; the other two are the validator's. +6. **A citation MUST NOT carry a column, a symbol fragment, or any suffix beyond `:line` + or `:start-end`.** Editor and compiler output (`file:219:5`) and index fragments + (`file#symbol=Name`) are hard errors, reported confusingly — see §5. +7. **An issue or pull request MUST NOT be cited as `#1459` or `owner/repo#1459`.** Both + are hard errors. Cite the full URL, which is recorded `unverified`, or attribute the + claim through `provided_by` — see §6. +8. **A claim classified `FACT` MUST rest on at least one citation the validator can + open**, with exactly one exception, in §6. A `FACT` supported only by `unverified` + citations has been checked by nothing. +9. **A node MUST carry at most one commit-only `FACT`** — the entry recording the + revision the node was checked against. Nothing enforces this; a second one produces + another non-fatal notice and still exits 0. It is a rule a reviewer holds. + +## 4. SHOULD + +1. **Prefer a bare path to `path:line`.** The line is not verified against the file, so a + position that has silently drifted is worse than no position: it looks precise. This + preference is provisional and lapses when #1459 is fixed. +2. **When a position genuinely earns its place, cite a range that brackets a named + symbol, and name that symbol in the `statement`.** A range that has drifted is still + wrong, but a reader comparing the statement's symbol name against the file can detect + it. A bare line number gives them nothing to compare. +3. **Cite the narrowest source that actually supports the claim, and only that.** A + second citation added "for context" is a second thing that can rot, and the checker + will not tell you which one did. +4. **Use the markdown-link form when a human will read the citation.** It is accepted for + both repository paths and URLs, and it costs nothing. +5. **For code in another repository, use a pinned `blob` link** — and record, in the + `statement` itself, what you actually opened, because nothing downstream will. + +## 5. Enforcement + +Run it locally, from the repository root: + +```bash +python3 launchpad/project-intelligence/corpus/validate.py +``` + +Exit 0 passes; 1 means at least one error, each naming the node it came from. +`just corpus-validate` is the same command but needs Hermit activated first. CI runs it +on every pull request and every push to `launchpad` that touches +`launchpad/docs/corpus/**`, so a local failure is a CI failure. + +**Four things a green run does not establish.** The first three are stated in +`AGENTS.md`; the fourth is not stated anywhere else. + +1. **That a citation supports its claim.** Checking is structural. A `FACT` citing a real + file that says nothing on the subject passes cleanly. Only a person reading the source + makes it a `FACT`. +2. **That an `UNVERIFIED` item is fine.** Those notices mean the form was recognised and + could not be opened. They print on passing runs precisely so a PASS does not claim + them. +3. **That a line number is real.** `Justfile:999999` passes against a 1005-line file + (#1459). +4. **That a rejection means what its message says.** A citation containing no whitespace + that matches no other form falls through to the repository-path rule, so `#1459` and + `launchpad-26/buzz#1459` are reported as paths that "do not resolve to a real file in + the repository". They are not paths and were never intended as paths. An author + debugging that message will look for a missing file that was never meant to exist. + +**What a reviewer has to hold, because no check will.** MUST 4 (path over link), +MUST 8 (a `FACT` rests on something openable), MUST 9 (one commit-only `FACT`), and every +SHOULD. All four pass validation whether honoured or not. + +## 6. Exceptions and escalation + +**The one permitted commit-only `FACT`** is the entry recording the revision the node's +claims were checked against. It is exempt from MUST 8 because the citation *is* the +claim, and it is checkable, just not by this checker: + +```bash +git cat-file -e # exit 0 means that revision exists in this repository +``` + +Run that and the entry is a `FACT`. A commit citation attached to any claim *about +repository content* is not covered by this exception — that claim needs the file, at that +revision. + +**When the only available source is unopenable** — an issue, a pull request, an upstream +specification, a tool's output — do not promote it. Cite the URL and accept the +`unverified` notice, or, where a person or an issue is the source rather than a document, +classify the claim `TEAM_KNOWLEDGE` and name that source in `provided_by`. A policy choice +attributed to a file that does not discuss it is not an `INFERENCE`; it is a +misclassification. + +**When a rule here cannot be met**, do not relax it locally. A standard one node +quietly widens has stopped being a standard, and the validator will not notice. Raise an +issue against #605 describing the reference you needed and could not write. The `flagged` +status is not the escape hatch: it names an unresolved conflict between two authoritative +sources, not an inconvenient rule. + +**When this document and the validator disagree**, the validator is right and this +document is the defect. Fix it here, with a new measured verdict, rather than working +around it in a node. + +## 7. Read these instead of trusting a copy here + +| For | Read | +|---|---| +| The frontmatter contract, and which field a citation lives in | `launchpad/docs/corpus/schema/node.schema.json` | +| Prose explanation of those fields | `launchpad/docs/corpus/schema/README.md` | +| The six citation shapes as vocabulary | `launchpad/project-intelligence/CONTRACT.md` §3 | +| What the checker actually does — the authority for every verdict above | `launchpad/project-intelligence/corpus/validate.py` | +| Creating, updating and retiring a node | `launchpad/docs/corpus/AGENTS.md` | +| Why a link must be pinned to the full SHA | `launchpad/decisions/ADR-0003-handbook-page-provenance-contract.md` | +| Why Markdown with frontmatter is canonical | `launchpad/decisions/ADR-0028-corpus-canonical-representation.md` | +| How to rank conflicting evidence | `launchpad/decisions/ADR-0029-corpus-evidence-precedence.md` | + +Enum member lists and the schema's field-combination rules are **not** repeated in this +document. The validator never reads body prose, so a copy of them here would stay green +forever after going stale. + +## 8. Scope and omissions + +**Not covered here, and these are gaps rather than silence:** + +| Not covered | Owned by | +|---|---| +| Classifying a claim, evidence precedence, and the graph-edge and tool-result forms | #1314 | +| Line numbers not being checked against file length | #1459 | +| Provenance for generated artifacts | #1316 | +| Naming, identifiers, taxonomy, status, diagrams, and the per-type templates | #1307 and #1309–#1351 | +| Whether ADR-0003's markdown-link wrapper is required on corpus evidence | #605 | + +**A divergence found while writing this node, reported rather than fixed.** `CONTRACT.md` +§3 enumerates six shapes and none of them is a URL — the section contains no occurrence of +"url", "http" or "github". `validate.py` nevertheless implements a whole URL branch, and +`AGENTS.md` presents a seven-row table introduced as "CONTRACT.md §3 defines the six +shapes", two of whose rows are URL forms §3 does not contain. This node describes the +forms the validator accepts and says plainly which of them §3 enumerates. Reconciling the +three documents is not this node's to do: it may not edit `AGENTS.md`, and it does not own +`CONTRACT.md`. + +**No `relationships` in this node's frontmatter.** The reason is merge order, not an empty +corpus. At the recorded revision `corpus-agents` is loadable, so an edge to it would +validate here — and would become a hard error the moment this node reached `launchpad` +ahead of the branch that introduces `corpus-agents`, because an unmatched target fails. +Every sibling standard is likewise unmerged. Edges get declared once the set has landed, +which is a follow-up, not an oversight. + +**What the recorded revision means.** It is the revision this node's claims were *checked +against*, not a record of when the file was last edited. Editing prose without re-checking +a source leaves it where it is; re-checking the sources moves it whether or not the body +changed. + +**Expected but not verified when this node was written:** + +- **No pinned GitHub link in this node's ledger was fetched from GitHub**, because there + are none — every citation here is a repository path. The claim that a pinned link to a + nonexistent file passes was established against the validator, not against GitHub, which + is exactly the point being made. +- **The validator was not exercised against a corpus containing two nodes that cite each + other's paths.** Nothing in `find_citation_problems` treats a corpus path differently + from any other, so no difference is expected; it was not confirmed. +- **`git cat-file -e` was run for this node's own recorded revision and no other.** The + §6 procedure is stated from that one use. From e8db1a6bf09f6bc81f89278904336b09d9b4bd06 Mon Sep 17 00:00:00 2001 From: Serina Mcfall Date: Wed, 26 Aug 2026 18:13:52 +1200 Subject: [PATCH 3/6] docs(corpus): fix MUST 2 contradicting MUST 6 and SHOULD 1 (#1308) Blocker from a review-final pass, confirmed at Blocker by review-adjudicate after both measured it. MUST 2 required "a bare repository-relative path". "Bare path" is not loose prose in this document -- section 2's first table row defines it as the no-position form, evidence entry 5 treats path:line as a distinct shape, and evidence entry 14 records as a FACT that CONTRACT.md section 3 enumerates file range, file line and bare path as three separate shapes. So MUST 2 read as forbidding the two positional shapes that MUST 6 expressly permits, that SHOULD 1 merely disprefers, and that section 2's own table records as ok. It also falsified section 1's claim that "each MUST corresponds to a verdict that command returns today". Measured -- no verdict rejects a position: Justfile:1 -> ok Justfile:1-99999999 -> ok MUST 2 now requires a repository-relative path and says explicitly that the position is MUST 6's and SHOULD 1's business, not its own. The rule it was always trying to state -- root-relative, not document-relative -- is unchanged. Fixed in the same edit, because it is the same bullet and leaving a known false sentence in place while correcting its neighbour would be perverse: MUST 2's illustration said the citation validate.py "fails from anywhere except the root", implying the verdict depends on the working directory. It does not -- repo_root() resolves from the validator's own module path. Measured from /tmp: root = /home/serina/Launchpad/buzz/__worktrees/task-1308-corpus-standard-code-references 'validate.py' -> CitationVerdict(status='error', detail='does not resolve to a real file in the repository') 'Justfile' -> CitationVerdict(status='ok', detail='') Evidence entry 4 is widened to carry the cwd-independence claim, with the same citation, since repo_root() is what establishes both halves of it. Correcting the previous commit's message while here: it said the ledger's "17 FACT, each citing a file that was opened". Entry 1 is a FACT whose sole citation is a commit, which MUST 9 and section 6 expressly bless as the one permitted exception -- the same message conceded it two paragraphs later by reporting two unverified revision citations. The count is right; that clause was not. Verification after the fix: python3 launchpad/project-intelligence/corpus/validate.py PASS corpus validation found no errors; 2 item(s) reported unverified exit=0 python3 -m unittest discover -s launchpad/project-intelligence/corpus/tests -p "test_*.py" Ran 79 tests -- OK python3 -m unittest discover -s launchpad/docs/corpus/schema/tests -p "test_*.py" Ran 27 tests -- OK Nine further findings were confirmed at High, Medium and Low and are filed rather than fixed here, per this task's standing policy that only Blockers are fixed in place: #1473, #1474, #1475, #1476, #1478, #1479. Signed-off-by: Serina Mcfall --- launchpad/docs/corpus/standards/code-references.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/launchpad/docs/corpus/standards/code-references.md b/launchpad/docs/corpus/standards/code-references.md index 93ffce67b58..8aa93404e2e 100644 --- a/launchpad/docs/corpus/standards/code-references.md +++ b/launchpad/docs/corpus/standards/code-references.md @@ -20,7 +20,7 @@ evidence: entry_class: FACT evidence: - "launchpad/project-intelligence/corpus/validate.py" - - statement: "A bare path is resolved against the repository root rather than the citing document, and after resolution it must still lie inside the repository, so an absolute path and a path that escapes the tree are both rejected." + - statement: "A repository path is resolved against the repository root rather than the citing document or the current working directory, and after resolution it must still lie inside the repository, so an absolute path and a path that escapes the tree are both rejected." entry_class: FACT evidence: - "launchpad/project-intelligence/corpus/validate.py" @@ -167,10 +167,15 @@ checked, and a GitHub link is not checked at all. 1. **A code reference MUST be a citation in the node's frontmatter `evidence` array.** The schema defines no other field for one, and rejects any field beyond the seven it names. -2. **A reference to a file in this repository MUST be a bare repository-relative path, +2. **A reference to a file in this repository MUST be a repository-relative path, resolved from the repository root, naming a file that exists.** Not a path relative to - the citing document — `validate.py` is a real file, but the citation `validate.py` - fails from anywhere except the root. + the citing document: `launchpad/project-intelligence/corpus/validate.py` is a real + file, and the citation `validate.py` names nothing, because the root is the only + anchor. That verdict does not depend on the directory you run the check from — the + root is resolved from the validator's own location, so the citation fails identically + from anywhere. **Whether the path also carries a position is not this rule's + business:** MUST 6 sets the permitted position syntax and SHOULD 1 sets the + preference between them. This rule governs the anchor only. 3. **A reference MUST NOT be an absolute path and MUST NOT resolve outside the repository**, before or after `..` segments and symlinks are followed. 4. **A file in this repository MUST NOT be cited as a GitHub link when a repository path From af691d811c07daab0d6a32d7762c5615cabb4be1 Mon Sep 17 00:00:00 2001 From: Serina Mcfall Date: Wed, 26 Aug 2026 18:37:09 +1200 Subject: [PATCH 4/6] docs(corpus): stop asserting the unsettled revision policy (#1308) Found while measuring #1472's prediction against the branches. This node reproduced AGENTS.md's "What the recorded revision means" paragraph, stating as settled that the recorded revision tracks verification rather than editing. That paragraph was deleted from AGENTS.md in a1e8bbcd0, after three consecutive cross-model review passes refused it as a corpus-wide policy no authorized source establishes. #1321 owns the question. This node was cut before that commit and carried the claim forward with no ledger entry behind it -- unsourced normative prose in a standards document, which is the defect class #1472 predicted, and the only place across three stale-base siblings where it actually materialised. Now states only what #636's definition of done supports and defers the rest to #1321, matching what AGENTS.md does at its current head. Neither validate.py nor CI can see this class of defect: a claim whose source is silent on the subject exits 0. It was found by diffing what the base document removed against what the siblings still said. Refs #1308 #1472 Signed-off-by: Serina Mcfall --- launchpad/docs/corpus/standards/code-references.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/launchpad/docs/corpus/standards/code-references.md b/launchpad/docs/corpus/standards/code-references.md index 8aa93404e2e..f6171fc0c45 100644 --- a/launchpad/docs/corpus/standards/code-references.md +++ b/launchpad/docs/corpus/standards/code-references.md @@ -325,10 +325,14 @@ ahead of the branch that introduces `corpus-agents`, because an unmatched target Every sibling standard is likewise unmerged. Edges get declared once the set has landed, which is a follow-up, not an oversight. -**What the recorded revision means.** It is the revision this node's claims were *checked -against*, not a record of when the file was last edited. Editing prose without re-checking -a source leaves it where it is; re-checking the sources moves it whether or not the body -changed. +**What the recorded revision means is not settled here.** #636's definition of done +requires that a draft is "checked against the repository revision recorded in provenance", +so the revision is at minimum the one this node's claims were checked against. Whether it +may stay put across later edits, and what to do when only some claims are re-verified, is +**#1321's** to decide (`document corpus standard for provenance`, unlanded). An earlier +draft of this section asserted the wider rule as settled — it was copied from a version of +`AGENTS.md` that has since removed it, after three cross-model passes refused it as a +corpus-wide policy no authorized source establishes. **Expected but not verified when this node was written:** From 9a9ebfc22a8559d5c7d14c5a02cdef39a88eb42d Mon Sep 17 00:00:00 2001 From: Serina Mcfall Date: Thu, 27 Aug 2026 09:59:49 +1200 Subject: [PATCH 5/6] docs(corpus): reconcile three ledger self-contradictions (#1308) Addresses all three findings from the review panel on PR #1480. Each verdict below was measured by calling validate._classify_citation directly rather than read off the document. High -- entry 15 and section 8 asserted as FACT that AGENTS.md "introduces its citation table as CONTRACT.md section 3's six shapes and then lists seven rows". The AGENTS.md this branch carries says the opposite in as many words: the table "is not a summary of section 3", because its two URL rows are forms validate.py recognises and section 3 does not enumerate. That correction landed in ebe2daf72, after this node recorded its claim against 60d4947b. The entry and section 8 now describe the AGENTS.md that actually ships beside them. Section 8 also now records what happened, because the node is a standard about citation discipline and this was a live instance of the failure it teaches against: a claim recorded against one revision of a moving document is not a claim about the document that finally ships. AGENTS.md records the same incident from its own side. The open CONTRACT.md-versus-validator divergence is unchanged and still points at #1478. Medium -- the ledger said a bare repository path "is opened on disk" while a later entry said a citation resolving to a real file "is never opened". Both cannot hold. Measured: a bare path returns ok on resolution alone and the file's contents are never read. The first entry now says resolved, and says explicitly that resolution establishes only that the file is there. Medium -- the ledger scoped the UNVERIFIED channel to "non-GitHub URLs", while the node's own table records GitHub issue and pull-request URLs as unverified. Measured: https://github.com/launchpad-26/buzz/issues/1459 -> unverified https://github.com/launchpad-26/buzz/pull/1462 -> unverified https://example.com/spec -> unverified .../blob//path -> ok .../blob/launchpad/path -> error (mutable ref, ADR-0003) The entry now scopes the channel to external URLs that are not pinned repository links, and names GitHub issue and pull-request URLs as included -- which matches the table and the measured behaviour. Also merges origin/launchpad, which gained the corpus tree when #1468, #1469 and #1477 merged. No conflict: this branch already carried the same AGENTS.md blob. Verification: python3 launchpad/project-intelligence/corpus/validate.py PASS corpus validation found no errors; 5 item(s) reported unverified Signed-off-by: Serina Mcfall --- .../docs/corpus/standards/code-references.md | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/launchpad/docs/corpus/standards/code-references.md b/launchpad/docs/corpus/standards/code-references.md index f6171fc0c45..3a921090e62 100644 --- a/launchpad/docs/corpus/standards/code-references.md +++ b/launchpad/docs/corpus/standards/code-references.md @@ -16,7 +16,7 @@ evidence: entry_class: FACT evidence: - "launchpad/docs/corpus/schema/node.schema.json" - - statement: "A bare repository path is opened on disk and must resolve to a real file: a directory, a path that does not exist, and a path naming no file all fail." + - statement: "A bare repository path is resolved on disk and must name a real file: a directory, a path that does not exist, and a path naming no file all fail. Resolution establishes only that the file is there; the file's contents are never read." entry_class: FACT evidence: - "launchpad/project-intelligence/corpus/validate.py" @@ -40,7 +40,7 @@ evidence: entry_class: FACT evidence: - "launchpad/decisions/ADR-0003-handbook-page-provenance-contract.md" - - statement: "Commit references, graph edges, tool results and non-GitHub URLs are routed to a non-fatal UNVERIFIED channel that always prints and never changes the exit status." + - statement: "Commit references, graph edges, tool results and external URLs that are not pinned repository links -- including GitHub issue and pull-request URLs -- are routed to a non-fatal UNVERIFIED channel that always prints and never changes the exit status." entry_class: FACT evidence: - "launchpad/project-intelligence/corpus/validate.py" @@ -64,7 +64,7 @@ evidence: entry_class: FACT evidence: - "launchpad/project-intelligence/CONTRACT.md" - - statement: "AGENTS.md introduces its citation table as CONTRACT.md section 3's six shapes and then lists seven rows, two of which are URL forms CONTRACT.md does not enumerate." + - statement: "AGENTS.md presents a seven-row citation table and states explicitly that it is not a summary of CONTRACT.md section 3, because the two URL rows are forms validate.py recognises and section 3 does not enumerate." entry_class: FACT evidence: - "launchpad/docs/corpus/AGENTS.md" @@ -311,12 +311,20 @@ forever after going stale. **A divergence found while writing this node, reported rather than fixed.** `CONTRACT.md` §3 enumerates six shapes and none of them is a URL — the section contains no occurrence of -"url", "http" or "github". `validate.py` nevertheless implements a whole URL branch, and -`AGENTS.md` presents a seven-row table introduced as "CONTRACT.md §3 defines the six -shapes", two of whose rows are URL forms §3 does not contain. This node describes the -forms the validator accepts and says plainly which of them §3 enumerates. Reconciling the -three documents is not this node's to do: it may not edit `AGENTS.md`, and it does not own -`CONTRACT.md`. +"url", "http" or "github". `validate.py` nevertheless implements a whole URL branch. +`AGENTS.md` presents a seven-row table and says explicitly that it **is not** a summary of +§3: its two URL rows are forms the validator recognises and §3 does not enumerate. This +node describes the forms the validator accepts and says plainly which of them §3 +enumerates. Reconciling `CONTRACT.md` with what the validator implements is still open — +filed as #1478 — but it is not this node's to do: it may not edit `AGENTS.md`, and it does +not own `CONTRACT.md`. + +An earlier draft of this node asserted the opposite — that `AGENTS.md` introduced the table +*as* §3's six shapes and then listed seven. That was true of an earlier `AGENTS.md`, +corrected in `ebe2daf72`, and the miscount had already been used here to build a scope +argument before review caught it. `AGENTS.md` records the same incident from its own side. +The lesson is the one this standard exists to teach: a claim recorded against one revision +of a moving document is not a claim about the document that finally ships beside it. **No `relationships` in this node's frontmatter.** The reason is merge order, not an empty corpus. At the recorded revision `corpus-agents` is loadable, so an edge to it would From 91d2b3d012cce646af5752b8c936fff8268137d8 Mon Sep 17 00:00:00 2001 From: Serina Mcfall Date: Thu, 27 Aug 2026 12:25:10 +1200 Subject: [PATCH 6/6] docs(corpus): reconcile to #1313's documentation-standard (#1308) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per Serina's decision on #1486: this standard, drafted alongside #1313, reconciles to it rather than being grandfathered. G4 -- top-level sections were numbered ("## 1. Scope and authority" through "## 8. Scope and omissions"), which SHOULD NOT is now honoured rather than departed from silently. Removed the numbering; the relative order of D1's six required sections plus the two extras was already correct and needed no reordering. Internal cross-references that pointed at a section by its number (section "MUST N", "SHOULD N" identifiers are unaffected -- only "§5" and "§6" self-references to this document's own sections) now name the section instead: *Enforcement*, *Exceptions and escalation*. External references to CONTRACT.md's own §3 are untouched -- that numbering belongs to a different document. Recorded the reconciliation as a ledger entry attributed to #1486. Signed-off-by: Serina Mcfall --- .../docs/corpus/standards/code-references.md | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/launchpad/docs/corpus/standards/code-references.md b/launchpad/docs/corpus/standards/code-references.md index 3a921090e62..411abfacc70 100644 --- a/launchpad/docs/corpus/standards/code-references.md +++ b/launchpad/docs/corpus/standards/code-references.md @@ -91,6 +91,9 @@ evidence: - statement: "This standard addresses developers as well as agents and reviewers, because a developer is one of the two authors the parent feature names." entry_class: TEAM_KNOWLEDGE provided_by: "launchpad-26/buzz#605 outcome: 'A developer or agent can create one atomic corpus node and deterministic validation accepts or rejects it against one documented contract.'" + - statement: "Per Serina's decision on launchpad-26/buzz#1486, this node reconciles to #1313's documentation-standard: top-level sections are no longer numbered (G4), and internal cross-references that pointed at a section by its number now name the section instead." + entry_class: TEAM_KNOWLEDGE + provided_by: "launchpad-26/buzz#1486, decided 2026-08-27" --- # Standard: code references @@ -99,7 +102,7 @@ How a corpus node points at code, what each reference form actually proves, and reference stays honest once the code moves underneath it. Look up the rule you need; this is reference material, not a tutorial. -## 1. Scope and authority +## Scope and authority **This node governs** every citation, in any node's `evidence` ledger, that names code in a repository: which forms are permitted, which are forbidden, how they are pinned and @@ -124,7 +127,7 @@ accepts a bare pinned URL and documents in its own docstring that requiring the wrapper on corpus evidence is #605's call, not the validator's. This node describes that state and leaves it open. -## 2. The forms, and what a pass proves +## The forms, and what a pass proves Six shapes are enumerated in `CONTRACT.md` §3. Four of them can name code in this repository; the validator additionally accepts a seventh form — a URL — that §3 does not @@ -141,7 +144,7 @@ revision this node records. | Path with a line, out of range | `Justfile:999999` | `ok` | **The file exists.** Nothing else — the file is 1005 lines long. | | Path with a range | `Justfile:1-99999999` | `ok` | Same: path checked, bounds not. | | Path with a malformed position | `Justfile:0`, `Justfile:5-1` | `error` | — the position is inconsistent with itself | -| Path with a column or fragment | `…kind.rs:219:5`, `…kind.rs#symbol=Kind` | `error` | — not a supported form; see §5 for the misleading message | +| Path with a column or fragment | `…kind.rs:219:5`, `…kind.rs#symbol=Kind` | `error` | — not a supported form; see *Enforcement* for the misleading message | | GitHub file link, pinned | `…/blob/<40-hex>/Justfile` | `ok` | **Nothing about the target.** Syntax only. | | GitHub file link, pinned, target never existed | `…/blob/<40-hex>/does-not-exist.md` | `ok` | **Nothing.** The validator never contacts GitHub. | | GitHub file link, mutable ref | `…/blob/main/Justfile` | `error` | — not pinned to a full SHA | @@ -151,7 +154,7 @@ revision this node records. | `raw.githubusercontent.com`, pinned | `…/<40-hex>/Justfile` | `ok` | Syntax only, as above. | | GitHub issue or pull-request URL | `…/issues/1459` | `unverified` | Nothing. Recognised, unopenable. | | Other external URL | `https://example.com/spec` | `unverified` | Nothing. | -| Commit reference | `commit <7-40 hex>` | `unverified` | Nothing on disk. See §6. | +| Commit reference | `commit <7-40 hex>` | `unverified` | Nothing on disk. See *Exceptions and escalation*. | | Graph edge, tool result | `a -> b (1 hop)` | `unverified` | Nothing. Owned by #1314. | | Anything else | `#1459`, `issue #1459`, free text | `error` | — hard error, never a notice | @@ -162,7 +165,7 @@ accepted wherever its bare target would be, and rejected wherever its target wou return `ok` while establishing less than an author would assume: a line number is not checked, and a GitHub link is not checked at all. -## 3. MUST +## MUST 1. **A code reference MUST be a citation in the node's frontmatter `evidence` array.** The schema defines no other field for one, and rejects any field beyond the seven it @@ -187,18 +190,18 @@ checked, and a GitHub link is not checked at all. is the source of the pinning rule; the other two are the validator's. 6. **A citation MUST NOT carry a column, a symbol fragment, or any suffix beyond `:line` or `:start-end`.** Editor and compiler output (`file:219:5`) and index fragments - (`file#symbol=Name`) are hard errors, reported confusingly — see §5. + (`file#symbol=Name`) are hard errors, reported confusingly — see *Enforcement*. 7. **An issue or pull request MUST NOT be cited as `#1459` or `owner/repo#1459`.** Both are hard errors. Cite the full URL, which is recorded `unverified`, or attribute the - claim through `provided_by` — see §6. + claim through `provided_by` — see *Exceptions and escalation*. 8. **A claim classified `FACT` MUST rest on at least one citation the validator can - open**, with exactly one exception, in §6. A `FACT` supported only by `unverified` - citations has been checked by nothing. + open**, with exactly one exception, in *Exceptions and escalation*. A `FACT` supported + only by `unverified` citations has been checked by nothing. 9. **A node MUST carry at most one commit-only `FACT`** — the entry recording the revision the node was checked against. Nothing enforces this; a second one produces another non-fatal notice and still exits 0. It is a rule a reviewer holds. -## 4. SHOULD +## SHOULD 1. **Prefer a bare path to `path:line`.** The line is not verified against the file, so a position that has silently drifted is worse than no position: it looks precise. This @@ -215,7 +218,7 @@ checked, and a GitHub link is not checked at all. 5. **For code in another repository, use a pinned `blob` link** — and record, in the `statement` itself, what you actually opened, because nothing downstream will. -## 5. Enforcement +## Enforcement Run it locally, from the repository root: @@ -249,7 +252,7 @@ on every pull request and every push to `launchpad` that touches MUST 8 (a `FACT` rests on something openable), MUST 9 (one commit-only `FACT`), and every SHOULD. All four pass validation whether honoured or not. -## 6. Exceptions and escalation +## Exceptions and escalation **The one permitted commit-only `FACT`** is the entry recording the revision the node's claims were checked against. It is exempt from MUST 8 because the citation *is* the @@ -280,7 +283,7 @@ sources, not an inconvenient rule. document is the defect. Fix it here, with a new measured verdict, rather than working around it in a node. -## 7. Read these instead of trusting a copy here +## Read these instead of trusting a copy here | For | Read | |---|---| @@ -297,7 +300,7 @@ Enum member lists and the schema's field-combination rules are **not** repeated document. The validator never reads body prose, so a copy of them here would stay green forever after going stale. -## 8. Scope and omissions +## Scope and omissions **Not covered here, and these are gaps rather than silence:** @@ -352,4 +355,4 @@ corpus-wide policy no authorized source establishes. other's paths.** Nothing in `find_citation_problems` treats a corpus path differently from any other, so no difference is expected; it was not confirmed. - **`git cat-file -e` was run for this node's own recorded revision and no other.** The - §6 procedure is stated from that one use. + *Exceptions and escalation* procedure is stated from that one use.