docs(corpus): document the corpus standard for atomicity - #1470
Conversation
Reviewed by an independent cross-model review-plan pass (Codex, gpt-5.6-sol, high effort): eleven findings, all applied. Three more were found afterwards, the load-bearing one being that the plan blocked its own STEP 2 on an OPEN item -- an OPEN item a step must consume is a missing input, not an open question. Refs #636 Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
The corpus's first hand-authored node. Frontmatter validates against node.schema.json with zero errors; 11 evidence entries; no relationships, because no sibling node exists to target and an unresolved target is a hard validator error. The repository revision is recorded in the evidence ledger -- the schema calls that array the provenance ledger and permits no other field, so it is the only schema-legal place for it. STEP 3 (RUNS HERE) proved the validator actually scans the node rather than skipping it: mutating type: to a value outside the enum produced 'FAIL corpus-agents: schema violation at type' and exit 1, naming the node's id; restoring it returned exit 0. Also replaces test_real_corpus_root_currently_has_no_content_outside_schema, which asserted the corpus root is EMPTY and therefore could not survive the first authored node. Authorised by Serina as a deliberate widening of the plan's LEFT OUT scope, recorded in the plan. The replacement asserts what the original's own comment said it was for -- content present AND nothing from schema/ -- and both halves were negative-controlled before being trusted. Refs #636 Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
Adds the lookup table of authoritative sources and the 'what a corpus node is' section: one file per node, one idea per node, where nodes go, id permanence, relationship resolution, and the authored-vs-generated boundary. Reproduces no enum member list and no field-combination matrix -- those stay canonical in node.schema.json and schema/README.md and are linked instead. The checker never reads body prose, so a copy here would stay green while drifting. Verified: no type-enum member and none of entry_class/provided_by/ confidence appear in the body. Refs #636 Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
The part that lives nowhere else: what the checker actually does with each of CONTRACT.md's six citation shapes, and three things a passing run does not mean -- that a citation supports its claim (checking is structural, the file is never opened and compared), that UNVERIFIED is a pass, or that a line number was verified (#1459). Names the three evidence classes and what each is FOR, but not which fields the schema requires per class -- that matrix stays in node.schema.json. Verified absent from the body: entry_class, provided_by, confidence. Refs #636 Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
This is #605's acceptance criterion for the file -- a cold-start agent creating, updating or retiring one node without oral guidance. Three numbered procedures, each ending in the same check command. Adds a 'Running the check' section giving the interpreter form (works without Hermit; the just recipe needs activation first) and documenting --root, since without it the command always validates the real corpus whatever directory you are standing in. Retire covers the three things most likely to be got wrong: inbound relationships resolved before retirement, status set rather than the file deleted, and the id never reused or renamed. Refs #636 Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
Names each deferred area with its owning issue rather than leaving a reader unable to tell a gap from an omission: the standards and templates (#1307-#1351, none merged), generated-artifact provenance (#1316), claim-type and flagged state (#1410), the human entry point (#639), and unverified line numbers in citations (#1459). Records why this node carries no relationships -- at its recorded revision it was the only authored node, and a target no node carries is a hard error -- so the absence reads as deliberate rather than forgotten. Every repo path cited in the body verified to resolve to a real file. Refs #636 Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
The audit found two things the earlier steps had missed. The document's own rule -- 'a FACT resting only on UNVERIFIED citations has not been checked by anything' -- condemned the node's own ledger entry 1, the provenance record, whose only citation is a commit reference. Resolved by stating the one carve-out narrowly and giving it a real check (git cat-file -e <sha>, run, exit 0) rather than by quietly exempting it. A commit citation on a claim about repository CONTENT is explicitly still not covered. Ledger entry 11 overreached: 'every change under launchpad/docs/corpus is gated in CI' where the workflow triggers on pull requests and pushes to launchpad. Narrowed to what the workflow actually does. Also records a scope judgement the DoD asks for: the citation-shape table is reference material rather than instruction and belongs in the evidence standard (#1314) when that lands. Noted in place rather than folded in silently. Verified: all 11 ledger entries resolve, every body path is a real file, merge-base equals the recorded revision, and exactly one hand-authored .md was added under the corpus root. Refs #636 Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
… finding) An independent review-tests pass defeated the first replacement: patching discover_markdown_files to a hardcoded 'return [root / "AGENTS.md"]' -- a constant that never touches the filesystem -- satisfied both 'non-empty' and 'nothing from schema/' while proving neither discovery nor exclusion. My own negative control had broken the exclusion set and emptied the corpus, but never tried a constant. Showing that assertions CAN fail is not the same as showing they can only pass for the right reason. The expectation is now derived from an independent filesystem walk and compared for equality, which catches partial walks and both exclusion directions. It does NOT catch the constant today, and the docstring says so rather than claiming otherwise: the corpus holds exactly one node, so [root/'AGENTS.md'] IS the correct answer and no assertion against the real tree can tell a constant from a real walk. That resolves itself at the second node. test_sibling_discovered_schema_dir_excluded catches it now -- verified FAIL under that mutant -- and is the real proof of discovery behaviour. Measured, after fixing a mutation harness that had patched a different module instance than the test uses and so reported every mutant as caught: returns nothing -> FAIL (caught) exclusion disabled -> FAIL (caught) constant return -> PASS (not caught; sibling catches it) Refs #636 Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
FINDING A -- the carve-out claimed enforcement it does not have. 'There is exactly one carve-out, and widening it defeats the rule' read as though some check held the line. Nothing does: a second, third or tenth commit-only FACT produces extra non-fatal UNVERIFIED notices and still exits 0, which the reviewer proved by adding one. Now says plainly that this is a convention a REVIEWER holds, names the signal to look for (more than one commit-only FACT in a ledger), and states that no check will raise it. FINDING B -- create-node step 3 asked the author to record four categories of evidence and gave a destination to exactly one of them. Adds the mapping: revision to the ledger, sources to the citations of the claims they support, and expected-but-unverified to the body's scope section. Plus the rule that anything reaching none of the three was either a missing claim or a stale note. Applying B to this node exposed that it did not follow its own new rule -- the same self-contradiction class STEP 8 caught. Its scope section now names the two things unverified when it was written: no agent harness was tested reading it as a resolved AGENTS.md, and relationships.schema.json's enum was never read directly. Re-audited after the change: exactly one commit-only FACT remains, the enforcement claim is gone, validator exits 0, 79 tests pass. Refs #636 Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
Codex review-final returned REQUEST_CHANGES with seven conditions, then a
second pass confirmed five fixed and refused two. Both refusals were correct.
This commit is the whole of that work.
1. LEDGER COMPLETENESS. Seven entries added (11 -> 18) for claims the body
taught with no classified entry behind them: the evidence classes, the
"supersedes" vocabulary, the syntax-only GitHub check, the external-URL
verdict, and the delete-vs-retire distinction.
The recheck caught two of these still wrong. An entry said the schema
"permits no field outside that set" after listing the six required fields
-- it also permits "relationships", so the entry was wrong about the file
it cited. And the "supersedes" entry cited node.schema.json, which carries
only the enum; the directionality it asserts ("source replaces target;
target becomes historical") lives in relationships.schema.json:30, a file
this node had listed as read-but-unverified and cited anyway. Read it,
cited it.
2. RETIREMENT WAS BUILT ON A FALSE PREMISE. It claimed inbound relationships
"no longer resolve" after retirement. Measured: with the file retained --
which the same procedure requires -- they resolve fine; only deletion
breaks them. Rewritten so the reason matches the mechanism, the danger is
stated correctly (edges keep pointing at a node that stopped being
current, and nothing warns you), and a replacement declares "supersedes",
which the procedure never mentioned.
3. CITATION TABLE OVERSTATED VERIFICATION. A GitHub link pinned to a real SHA
naming a file that never existed returns ok -- the checker never contacts
GitHub. The table now carries a "does it prove the target exists?" column,
gains the external-URL row it was missing, and names the trap. All seven
rows independently confirmed against the classifier.
4. PROVENANCE SEMANTICS -- and the defect the recheck was right to refuse.
The update procedure said to bump the revision on every edit; this node
kept its original across seven. The first attempt defined the field as an
evidence snapshot and classified that as INFERENCE citing node.schema.json.
That schema says nothing whatever about revisions, so the citation could
not support the statement: a policy choice had been given a class that made
it look derived. It is now TEAM_KNOWLEDGE attributed to #636's own
definition of done -- "the draft is checked against the repository revision
recorded in provenance" -- which is where the meaning comes from. ADR-0029
requires exactly that: history and team knowledge stay attributed rather
than being promoted to fact.
The node also claimed it was "the only authored node in the corpus" at the
recorded revision. It did not exist at that revision and neither did any
other node: git cat-file -e on that path at that sha exits 128, and the
corpus held zero .md files outside schema/. Corrected.
The revision still does not move, and the reason is checkable rather than
asserted: every cited source is byte-identical between that revision and
now, so verifying a claim at HEAD and at the recorded revision were the
same act. git diff --name-only <sha> -- <cited paths> returns nothing.
5. AUDIENCE. Added "reviewer": the document assigns reviewers an enforcement
duty no tool performs, so they are addressed by it. The adjudicator had
declined this finding (nothing consumes the field today); the final pass
argued audience describes who is addressed, not who parses it. Went with
the latter. Whether "developer" also belongs is left undecided.
6. The test module docstring claimed absolute fixture isolation that was false
before this branch and more visibly false after it. States the rule with
its one named exception instead. Flagged independently by the adjudicator
and the final pass.
Pre-existing, fixed while in the file: the same docstring advertised
"python3 -m unittest launchpad.project_intelligence.corpus.tests.test_validate",
which has never worked -- the directory is "project-intelligence" with a
hyphen, not a legal package name. Confirmed ModuleNotFoundError, removed.
7. Full suites re-run in a writable environment: 79 validator tests OK, 27
schema tests OK, real corpus exit 0. The plan's two-node create/update/
retire charter ran with its negative control -- a deliberately invalid node
failed and named itself, proving the scratch root was the one scanned;
retirement kept beta's edge resolving; deleting alpha instead broke it
exactly as the corrected text now says.
Final state: 18 ledger entries, schema errors 0, every citation resolves, no
cited source changed since the recorded revision, exactly one commit-only
FACT, 79 + 27 tests green, real corpus exit 0.
Refs #636
Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
Creates launchpad/docs/corpus/standards/ and its first node, with schema-valid front matter and the scope-and-authority section only. Front matter follows the conventions settled on #636: no provenance field exists, so the revision this node was checked against is recorded as the single permitted commit-only FACT inside the evidence ledger. No relationships are declared -- every sibling standard is unmerged and an unresolvable target is a hard validation error. type: governance, because the node states policy rather than instructing a harness. audiences: agent and reviewer, matching the instruction node, because the addressees are the agent authoring a node and the reviewer holding the rule at the pull request. The section names seven adjacent subjects this standard does not decide, each with the sibling task that owns it, so the boundary is recorded rather than left implicit. done when: python3 launchpad/project-intelligence/corpus/validate.py exits 0 (PASS, 2 unverified commit citations) and git cat-file -e 60d4947 exits 0. Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
…EP 2) Adds the normative core -- a MUST table and a SHOULD table kept separate -- and the five ordered tests an author applies to decide whether a subject is one node or two. The tests are derived rather than asserted. Test 2 reads the schema: type, status and origin each hold exactly one value per node, so a subject needing two at once cannot be described by one node. Test 3 reads the instruction node: one recorded revision covers a whole ledger, so halves that go stale on different schedules force every update into a choice with no correct answer. Test 4 reads the relationship schema: a target is a node id, so no edge can point at half a node. Test 5 runs the other way and vetoes over-splitting. The asymmetry section explains why a balanced call goes to two nodes: splitting later leaves inbound edges resolving at content that moved, and the checker only matches ids, so nothing reports it. Merging later retires an id by status change, keeps the file and declares supersedes, so the reader is told where to go. Row-to-ledger pairing, stated so a reviewer can check it: A1 -> AGENTS.md one-idea FACT + #1307 DoD TEAM_KNOWLEDGE A2 -> single-valued-fields FACT + its INFERENCE A3 -> #1307 DoD TEAM_KNOWLEDGE A4 -> state-what-you-do-not-cover FACT A5 -> length-does-not-track-boundaries INFERENCE B2 -> asymmetry INFERENCE (+ edge-target FACT, id-permanence FACT) B4 -> second-copy-drifts-silently FACT B1, B3, B5 -> no entry, and the body says why: they are this document's procedure for using itself, not claims about the repo. done when: python3 launchpad/project-intelligence/corpus/validate.py exits 0 (PASS, 2 unverified commit citations); no MUST or SHOULD row restates a schema enum member list, checked by grep for enum members. Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
…STEP 3) Adds the test-precedence rule, six boundary cases, and what an author does at the moment a second concept surfaces. Precedence had to be stated or every boundary case becomes an argument: test 2 is decisive and cannot be vetoed, test 5 vetoes tests 1, 3 and 4, a test 5 veto means "not two nodes" rather than "one node", and test 1 never overrides anything. Each case resolves one way, stated in its own heading: A concept + the procedure using it two nodes B rule + its exception one node C stable concept + volatile detail two nodes, or neither D flagged claim beside settled ones two nodes E node too small to stand alone one node F sections joined by part-of not permitted C is the case the precedence rule exists for: test 3 fires alone against tests 1 and 5, and the third outcome -- the detail belongs in the executable source, not the corpus -- is what a two-way rule would have missed. D notes that splitting to isolate a conflict must not be used to quarantine it out of a reader's path. The mid-draft procedure ends on the point that matters: do not summarise what you split off. A short summary for context is the second copy the linking rules exist to prevent, and it is the shape folding takes after an author has agreed not to fold. done when: python3 launchpad/project-intelligence/corpus/validate.py exits 0 (PASS, 2 unverified commit citations); every boundary-case heading carries its verdict, checked by grep, and none reads "it depends". Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
…STEP 4) States plainly that nothing automated enforces any requirement on the page. The checker validates structure -- schema, duplicate ids, relationship targets, citation forms, non-canonical files, non-Markdown files -- and every one of those is a property of a node's shape, not of how many ideas it holds. A node covering six subjects passes as cleanly as one covering one, and so does a node split into six fragments. Enforcement is the pull-request review, and that is by design rather than by omission: ADR-0028 chose Markdown over a machine-readable record format precisely so the corpus stays reviewable as a human-read diff, and named that review as the mechanism the corpus rests on. The instruction node already names a second convention in the same class -- more than one commit-only FACT -- and says a reviewer has to hold it. Adds a five-question reviewer checklist. Question 5 is the one worth having: a split-off subject that is also summarised in the body has been folded in while appearing not to have been, and the filed issue makes it look handled. Escalation is four steps and grants no waivers, because the disputable thing is whether a subject IS one idea, not whether a node may be two. An unresolved author/reviewer disagreement ships as two nodes, applying B2's tie-break to a human disagreement for the same reason it applies to an author's own uncertainty. Records that status: flagged is NOT this process -- it states that a node's evidence is contested, and a granularity dispute contests its boundary. Omissions name four gaps with owners, and three things expected but not verified, the first of which matters most: no test in this procedure has been applied to a real second corpus subject, because none exists yet. The tests are reasoned, not measured. done when: python3 launchpad/project-intelligence/corpus/validate.py exits 0 (PASS, 2 unverified commit citations); grep -c for a front-matter relationships key prints 0; and the body states the absence with its reason at line 493. One fix during the step: the absence sentence wrapped across two lines, so the line-based grep for it found nothing. The sentence was rewrapped rather than the check loosened -- a check that passes on a wrapped sentence would also pass on a sentence that says something else. Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
#636) Third cross-model pass, third refusal on the same condition. It was right three times, and the third refusal finally identified why the first two fixes failed: the document was writing corpus-wide provenance policy it had no authority to write. Reclassifying it (INFERENCE, then TEAM_KNOWLEDGE) only changed the label on an unsourced decision. WHAT ACTUALLY CHANGED: the document stops making the claim. #1321 ("document corpus standard for provenance", unlanded) owns the question of whether a recorded revision may stay put across edits. This node now says so, states its own approach as working practice pending that standard rather than as a rule others must follow, and defers. The ledger entry no longer asserts the policy -- it records only what #636's definition of done actually requires, which is a fact about the issue and is attributed to it. Also fixes a self-contradiction the last fix opened, exactly the failure shape this repository keeps producing. The previous commit added a FACT citing relationships.schema.json for the supersedes directionality. The same node still said, in its unverified list, that relationships.schema.json had never been read. Both could not stand. The file WAS read; the stale disclaimer is now narrowed to what remains genuinely unchecked -- that the two enum lists agree, which rests on a test that was not run. Ledger completeness, third sweep: entries added for the generated-artifact rejection, the non-enforcement of the one-commit-only-FACT convention, and positional citations not being bounds-checked. Prose that asserted this node's own history -- node counts at the recorded revision, byte-identity of cited sources -- is removed rather than given entries: it told the reader to trust the document about a fact they can check themselves in one command, so the document now gives them the command instead. TEAM_KNOWLEDGE's description corrected. It said "a person told you", which the schema does not require (it asks who or what told the corpus) and which made the class look unavailable for an attributed issue or decision record. It now also says outright what it is not: a place to park a decision you made yourself. Attributing an extrapolation to the thing it started from does not make it something you were told. Updating step 4 restated as four explicit branches including the byte-identical case, which the earlier "bump on every edit" wording omitted while this very node relied on it -- the inconsistency the pass named. Verified: 21 ledger entries, schema errors 0, every citation resolves, exactly one commit-only FACT, no cited source changed since the recorded revision, 79 validator tests OK, real corpus exit 0. Refs #636 Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
Reads the finished node against AGENTS.md's create procedure and fixes what the audit found. The one that mattered: the body maps nine sibling issue numbers to subjects -- 1313 documentation standard, 1314 evidence, 1316 generated content, 1317 identifiers, 1318 linking, 1319 naming, 1320 normative language, 1322 review requirements, 1324 taxonomy -- and every one of those mappings was resting on a citation to AGENTS.md, which names the subjects and the range 1307-1351 but never pairs a number with a subject. That is the exact shape of the defect caught on #636: a claim sourced to a file that does not contain it. The mapping came from the issue tracker, so it now carries a tool-result citation naming the query that produced it, in CONTRACT.md's tool-result form. The validator recognises the form and reports it UNVERIFIED, which is correct -- it cannot run gh -- and the class stays FACT because the source was opened. Also fixed: a doubled preposition in the enforcement section; a sentence calling a reviewer a failure mode; an over-claim that the single-value question is the only reviewer check not requiring a guess about the future, when question 1 does not either; a missing #1316 in the no-relationships list; and the line wrapping left behind by STEP 4. Audit results, all checked rather than asserted: exactly one commit-only FACT grep count 1 no schema enum member list in prose grep for enum members, none every body claim has a ledger entry read pairwise every ledger entry backs a body claim read pairwise no restatement of AGENTS.md's content the one-line rule is quoted and attributed; the tests, precedence, boundary cases, asymmetry, reviewer checklist and escalation are new done when: python3 launchpad/project-intelligence/corpus/validate.py exits 0 (PASS, 3 unverified: two commit references, one tool result); python3 -m unittest discover -s launchpad/project-intelligence/corpus/tests runs 79 tests OK; the schema suite runs 27 tests OK; and the node carries exactly one commit citation. Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
…de (#1307) Three findings raised by review-adjudicate, all inside the one file this issue owns, so all fixed here rather than filed. N1 (Medium) -- the stated reason for declaring no relationships was false. It said every node this document points at is an unmerged task with no id, "so the edges wait until the nodes exist". That is true of the nine sibling standards and untrue of corpus-agents, which exists at the recorded revision, loads in the validator, and would resolve cleanly as a target. This node derives its authority from it, so it is the obvious edge. The paragraph had inherited its shape from AGENTS.md, where the identical reasoning was accurate because that node genuinely had nothing to point at; the circumstance changed and the sentence did not. A document about recording boundaries accurately was recording its own inaccurately. The absence is still correct -- which relationship type expresses that authority, and in which direction, is #1318's subject, and the standards set is getting its edges in one pass once it has landed. So the fix records the real reason rather than adding the edge, which would have been this node deciding a sibling's question. That fix asserted two new things, so both got ledger entries rather than riding as unsourced prose: that corpus-agents is the one other node at the recorded revision (FACT, against AGENTS.md and validate.py), and that edges are deferred to a single follow-up pass (TEAM_KNOWLEDGE, attributed to the #605 task brief that says so). This repository's documented failure mode is a fix closing one hole and opening its neighbour; the neighbour here was a fix that adds claims. N2 (Low) -- boundary case C said tests 1 and 5 both answer "one" and then that the outcome turns on test 5. Test 5 cannot both have answered and be pending. Rewritten so test 1 answers "one", is overridden per the precedence rule, and test 5 decides between the two outcomes still live. The case's final verdict is unchanged. N3 (Low) -- a FACT rendered ADR-0028's "the enforcement mechanism the rest of Ruling 12 depends on" as "the rest of the corpus rests on". Close, but a substitution, in a FACT, in the passage the whole Enforcement section rests on. Both the ledger statement and the body now use ADR-0028's own words. done when: python3 launchpad/project-intelligence/corpus/validate.py exits 0 (PASS, 3 unverified: two commit references, one tool result); the node still carries exactly one commit citation and no front-matter relationships key; the absence sentence still greps. Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
) Two findings from the whole-branch final pass. MEDIUM -- test 2's type row taught a wrong fact about the schema. It illustrated a split with "an interface" and "the runbook for operating it". Neither interface nor runbook is a member of node.schema.json's type enum; both are terms from AGENTS.md's separate node-type/template list, a different taxonomy this document explicitly disclaims deciding two paragraphs earlier. So the single most decisive test in the procedure -- the reviewer checklist calls it "the only one that settles the question on its own" -- was teaching its reader a wrong fact in its worked example. The row now describes the surfaces in ordinary words. Fixing it opened a hole immediately, which is this repository's documented failure mode and worth recording. The first fix added a sentence claiming the rows "name surfaces in general terms rather than quoting enum members" -- and the status row on the very next line quotes active and draft, correctly and usefully. The sentence was rewritten to say what is actually true: the rows are illustrations, and the list of values each field admits lives in node.schema.json. LOW -- a FACT generalised beyond its source. It read "...which is why a node links an authoritative source rather than restating it", but AGENTS.md's cited sentence establishes only the mechanism, that the checker never reads body prose so a copy there stays green while going stale. The normative consequence was mine, not the source's. The statement is now narrowed to the mechanism and cites validate.py alongside AGENTS.md, since the mechanism is checkable in the code. Raised and not treated as a defect: applying test 1 in isolation to this document's own subtitle -- "how many corpus nodes a subject becomes, and how an author decides" -- flags its conjunction. The reviewer noted, and I agree, that the full procedure resolves it correctly: test 1 never overrides anything, and test 5 finds one idea, because "how many nodes" has no answer independent of "how an author decides". No change made. done when: python3 launchpad/project-intelligence/corpus/validate.py exits 0 (PASS, 3 unverified: two commit references, one tool result); no member of node.schema.json's type enum is quoted in the document; exactly one commit citation remains. Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
|
Diff base note for reviewers. This branch is cut from So the diff against
Once #1462 merges, its commits become ancestors and this diff reduces to the two files above. To review only this PR's work before then: That is 692 insertions across exactly the two files. |
|
Escalations addendum. Two issues were filed from this task and belong in the Escalations section above; adding them here rather than editing the body, which follows a fixed template.
|
#636) Three sibling agents authored corpus nodes following this document literally, and reported what broke. These four are the defects that produced real false claims in their work, not stylistic complaints. Filed as #1471; fixed here because #1462 is still open and 45 further nodes would inherit them. 1. THE ONLY-NODE JUSTIFICATION WENT FALSE, AND TWO AGENTS COPIED IT. "A node with no sibling to point at correctly declares none" read as a general rule. It was a fact about one moment -- when this was the corpus's only node -- and stopped holding as soon as a second existed. Both the #1309 and #1307 agents reproduced the reasoning and wrote a justification that was false at the time they wrote it; their adjudicators caught it, not their own reviews. Now says to enumerate what exists and give the real reason, and records why. 2. AN ISSUE-ONLY SOURCE HAD NO HONEST CLASS. The citation table lists tool results as legitimate while "Three things a passing run does not mean" says a FACT resting only on UNVERIFIED citations "has not been checked by anything", with one named exception. A claim whose only source is a GitHub issue has no openable form and cannot be SHA-pinned, so both passages applied and disagreed. The #1307 agent hit this with nothing honest to choose. Now states it: TEAM_KNOWLEDGE with provided_by naming the issue, which is what ADR-0029 requires of GitHub history anyway. 3. A RANGE WAS READ AS A MAPPING. The not-covered table paired eight subjects with "#1307-#1351", which is 45 issues and no subject-to-issue pairing at all. The #1307 agent cited this table for nine invented mappings -- exactly the "FACT cited to a file that does not discuss the claim" failure the document warns about two sections earlier. Now says outright that it is a range, not a mapping, and gives the search command. 4. CREATE STEP 3 ROUTED SOMETHING STEP 8 DID NOT ACCEPT. Step 3 sends expected-but-unverified items to the scope section; step 8 said only "state what the node does not cover". A boundary and a confidence disclosure are different things, so working the steps in order left that category homeless. Both the #1307 and #1309 agents reported it independently. Step 8 now names both. Verified: schema errors 0, 21 ledger entries, validator exit 0, 79 tests OK. Refs #636 #1471 Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
#636) Two more defects reported by the #1308 agent after authoring against this document. Both are mine, and the first is embarrassing in context. 1. THE CITATION TABLE MISATTRIBUTED ITSELF, IN THE SECTION ABOUT NOT DOING THAT. It said "CONTRACT.md §3 defines the six shapes" above a SEVEN-row table whose GitHub-link and external-URL rows appear nowhere in §3. Measured: grepping that section for http/url/github returns zero hits. So the sentence cited a file that does not discuss two of the rows beneath it -- the exact failure this document warns about, committed by this document. The #1308 agent took the table as an accurate summary and built a scope argument on "four of six shapes name code" before their plan review caught it. Now states what §3 actually enumerates, that the two URL forms are the validator's and not §3's, and that the table is seven rows and not a summary. 2. "ADD RELATIONSHIPS ONLY TO NODES THAT EXIST" WAS UNFOLLOWABLE, AND DANGEROUSLY SO. "Exist" was ambiguous between the branch you are working on and the branch you merge into, and the checker loads whatever is present where it runs. An agent branched off this unmerged node could therefore target `corpus-agents`, validate clean locally, and break CI on `launchpad`, where the node is absent. The #1308 agent hit exactly that and their review-code raised it as a Blocker. Step 9 now says "exists on the branch you are merging INTO", explains why the distinction is the trap, and gives the command to check the merge base rather than the local tree. This is the second round of AGENTS.md fixes sourced from agents authoring against it, and the pattern is worth naming: every defect found this way was invisible to three review passes over the document itself, and obvious within minutes to someone trying to follow it. Reviewing a procedure is not the same as executing one. Verified: validator exit 0, 79 tests OK, schema clean. Refs #636 #1471 #1478 Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
Held in draft deliberately — the cross-model gate has not runDo not mark this ready for review yet. This is not an oversight. The review pipeline for corpus work under #605 requires a cross-vendor final pass. That No alternative external provider is installed ( Same-model reviews did run and their findings were addressed — see this PR's own Decision (Serina, 2026-08-26): hold every corpus PR in draft until credits are When credits return, the sequence is: run the cross-model final on this branch's current |
…task/1307-corpus-standard-atomicity Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
Correction: the draft hold above is liftedMy earlier comment on this PR said "do not mark this ready for review". That no longer Serina marked this PR ready for review deliberately, superseding the earlier hold. I What is still true, and is the reason the earlier comment existed: The cross-vendor final review has not run on this branch. So this PR is review-ready with a known, recorded gap in review coverage, rather than When credits return, the cross-model pass on the current head is still worth running. |
tucktuck101
left a comment
There was a problem hiding this comment.
Request changes
Medium — records unsettled revision semantics as settled FACT
launchpad/docs/corpus/standards/atomicity.md:49-52 records as FACT "one node carries one recorded revision covering its whole ledger" and makes that premise load-bearing in the maintenance-clock test (§3). The corpus AGENTS.md explicitly states that recorded-revision semantics beyond the minimum (whether a revision may stay put across edits) are #1321's to settle and are working practice, not settled policy (launchpad/docs/corpus/AGENTS.md "What the corpus has NOT settled about revisions"). Recording it as a FACT in a standard and building a MUST/SHOULD test on it overstates provisional practice as canonical.
Recast the entry and §3 to attribute the rule to the current working practice / defer full semantics to #1321, or reclassify it honestly.
Low — bundle / merge-order
This PR carries the shared #636 base (AGENTS.md + plan + test) also present in open PR #1462. Merge #1462 first (or explicitly supersede it), then this PR should contain only the atomicity standard.
What looks good
The atomicity tests themselves (one-idea, two-simultaneous-fields, no-split-by-length) are concrete, schema-consistent, and validated cleanly; adjacent standards are correctly deferred rather than folded in. [panel: fable+codex]
…ed at (#636) Closes the review panel's High finding and one of its two Mediums on #1462. HIGH -- the provenance-update shortcut could certify stale evidence. Two passages said an empty `git diff --name-only <recorded-sha> -- <ledger paths>` established that every cited source was unchanged and every claim still stood, and the second went further: "the command is the check". Both are false for citation forms this document itself permits. Measured, not argued. A file that DOES differ reports as changed with a bare path and reports empty output with exit status 0 once `:127` or `:219-221` is appended -- no error, no warning. So an unnormalized `path:line` citation makes a changed file indistinguishable from an unchanged one, which is the worst available failure shape for a provenance check. Recorded as a new FACT entry with the tool-result citation that demonstrates it. The rule is now stated with its reach: normalize positions off the path first; only bare path, file line and file range are in scope; graph edge, tool result, commit and the two URL forms are excluded explicitly, so the branch is simply unavailable when a ledger contains one. And the conclusion is narrowed to what a diff can support -- those files are unchanged -- with re-verification, not an empty path-only diff, left as the only thing that establishes a FACT still holds. MEDIUM -- the one-node rule had no supporting ledger entry. "One node is one independently maintainable idea" is a substantive instruction and the ledger's only #636 entry backed the recorded-revision requirement instead. Added as TEAM_KNOWLEDGE attributed to #636's definition of done, which states it near-verbatim, matching the existing entry's classification for the same source. Also corrected a wrong-direction cross-reference: "*Updating a node* below" in Scope and omissions, where that section is above it. The recorded revision stays at 0052f5a. Checked by the corrected procedure rather than asserted: the one non-file citation was excluded, the nine normalized file paths were passed to `git diff` against 0052f5a, and the result was empty -- so the cited sources are unchanged and moving the revision would assert a re-check that added nothing. The second Medium is not addressed because it is stale, and the evidence is in the PR thread rather than in this commit: the citation table was already corrected by ebe2daf and now says outright that it is seven rows and is not a summary of CONTRACT.md section 3. The remaining cross-document disagreement between CONTRACT.md, validate.py and this file is tracked as #1478. Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
…task/1307-corpus-standard-atomicity Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
…d FACT (#1307) Addresses the Medium finding from the review panel on PR #1470. The ledger recorded "One node carries one recorded revision covering its whole ledger, and moving that revision makes a statement about every claim the node holds" as a FACT cited to AGENTS.md, and section 3's maintenance-clock test rested on it as though it were settled. AGENTS.md says the opposite about its own status: whether a recorded revision may stay put while a node is edited is #1321's to decide, is unlanded, and what AGENTS.md states is that document's working practice rather than a corpus-wide rule -- three review passes having already rejected attempts to present it as one. The entry now states what AGENTS.md actually says, including that it is working practice pending #1321. That is a FACT about a document this branch carries, which is checkable; the previous entry asserted the underlying rule, which is not settled. Section 3 now names the premise as working practice, defers to #1321 explicitly, and says what survives if #1321 rules the other way: two halves on different maintenance clocks still force a choice about what the recorded revision covers, so the test is worth running either way and only its sharpness depends on the ruling. The section 6 checklist item is scoped the same way. Also merges the current head of task/636-corpus-agents-md. The branch was carrying AGENTS.md at e422283 while the base had advanced to 8c6c21a, which rewrote the revision-shortcut procedure this finding is about -- fixing the claim against the stale copy would have described text that had already changed. Verification, after the merge and the edits: python3 launchpad/project-intelligence/corpus/validate.py PASS corpus validation found no errors; 4 item(s) reported unverified python3 -m unittest discover -s launchpad/docs/corpus/schema/tests -p "test_*.py" Ran 27 tests -- OK python3 -m unittest discover -s launchpad/project-intelligence/corpus/tests -p "test_*.py" Ran 79 tests -- OK The review's second finding, on merge order, is not addressed here: it asks that #1462 merge first so this PR carries only the atomicity standard. That is a sequencing decision, not a change to this branch. Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
launchpad gained launchpad/docs/corpus/AGENTS.md while this branch was open, via PRs #1468, #1469 and #1477 merging -- each carried the shared #636 base. That made an add/add conflict against the copy this branch had merged from task/636-corpus-agents-md. Resolved in favour of launchpad's copy (e422283), NOT this branch's newer one (8c6c21a). The newer copy carries #1462's fixes for its outstanding review findings. Those fixes belong to #1462 and are still under review; landing them through this PR would merge unreviewed changes to another PR's file under cover of an atomicity-standard change. This branch's own fix is unaffected either way: the "What the corpus has NOT settled about revisions" passage that the recast ledger entry cites is present in both copies, so the claim is true against whichever version ends up on launchpad. Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
|
Medium finding addressed in Medium — unsettled revision semantics recorded as settled FACT. Confirmed and fixed. §3 now names the premise as working practice, defers to #1321 explicitly, and says what Low — merge order. Not addressed here; it is a sequencing decision, not a change to I resolved it in favour of Verification after the merge: |
…r siblings reconcile (#1313) Serina decided #1486 on 2026-08-27: this node's built scope (a meta-standard for what a corpus standard document must itself be and contain) is the intended reading, and the four sibling standards drafted alongside it -- #1470, #1480, #1468, #1477 -- reconcile to it before merging, including the two (#1468, #1477) already merged onto launchpad. Cites the decision in scope-and-authority, states it as settled rather than provisional in Exceptions and escalation, corrects Scope and omissions' stale "pull requests are open" framing to name which two have already merged, and records the decision as a TEAM_KNOWLEDGE ledger entry attributed to #1486. This closes the Blocking finding from the review-final pass (fable+codex panel) that #1496 raised -- the node no longer publishes a binding meta-standard ahead of its authority being decided, because the authority is now decided. Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
Per Serina's decision on #1486: this standard, drafted alongside #1313, reconciles to it rather than being grandfathered. D10 -- H1 was "# Atomicity", not "# Standard: <topic>". Changed to "# Standard: atomicity", matching the node's id. D1/D3 -- MUST and SHOULD were H3 subsections nested under a "## Requirements" wrapper rather than top-level sections named MUST and SHOULD. Promoted both to top-level; the wrapper carried no shared prose to preserve. Recorded the reconciliation as a ledger entry attributed to #1486. Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
New: reconciled to #1313's documentation-standardSeparate from the round-1 findings already fixed and awaiting re-review — this is new work following Serina's decision on #1486, which requires every sibling standard drafted alongside #1313 (this one included) to reconcile to it before merging. Two structural gaps, both fixed at
Recorded as a ledger entry attributed to #1486. Validator passes clean; full test suite green (79 tests). Not re-requesting review again here since the round-1 re-review request is already pending — flagging this addition so the reviewer sees it alongside the earlier fixes. |
Fixed since this review by follow-up commit b8c4cce: the revision-semantics claim is now correctly attributed to AGENTS.md's working practice rather than stated as a corpus-wide settled FACT, with a note that #1321 is what actually decides this. The bundled #636/#1462 payload issue also resolved since #1462 merged separately. Verified directly against current text. Dismissing as stale/resolved.
Summary
Adds
launchpad/docs/corpus/standards/atomicity.md, the canonical treatment of the one-node-one-idea rule, and creates thestandards/directory it is the first document in.AGENTS.mdstates the rule in a single line and refers the treatment to a per-type standard task; this is that task, so the document supplies what the line does not — five ordered tests, a precedence rule for when they disagree, six resolved boundary cases, and the enforcement and escalation path. It is the node the "file the second concept as a separate task" clause in every sibling issue's Definition of Done points at.Related issue
Closes #1307
Issue type
Task
Agent provenance
claude-opus-5[1m]Objective
One corpus node stating how many nodes a subject becomes and how an author decides.
Impacted components
No generated corpus index changed — none exists yet.
find_ownership_violationsin the validator rejects any non-Markdown file under the corpus root, so this change adds Markdown only.Approach and rejected alternatives
The document is derived rather than asserted. Each of the five tests is grounded in something already committed:
type,statusandorigineach hold exactly one value per node, so a subject needing two at once cannot be described by one node; the evidence ledger carries one recorded revision covering every claim, so two halves going stale on different schedules force every update into a choice with no correct answer; arelationships[].targetis a nodeid, so no edge can point at half a node. A fifth test runs the other way and vetoes over-splitting, and a stated precedence rule settles the disagreements the first four produce.Rejected: restating the rule with worked examples. The obvious shape for a standard whose subject
AGENTS.mdalready names in a line. Rejected because a second copy of an instruction the checker never reads goes stale with nothing reporting it — the exact failure mode the corpus's own linking discipline exists to prevent, and the issue asks for a canonical treatment rather than a second copy.Rejected: declaring a
depends-onedge tocorpus-agents. That node exists and would resolve cleanly, and this document derives its authority from it, so the edge is the obvious one. Not declared, because which type expresses that relationship and in which direction is #1318's subject, and the standards set is getting its edges in one follow-up pass once it has landed. Declaring one ahead of that rule would be this node deciding a sibling's question — the move its own scope table refuses. The document states both reasons explicitly, so a reader does not conclude no target was available.Rejected:
type: agent. WhatAGENTS.mduses, because it instructs a harness. This node states policy, sogovernanceis the surface it documents.audiencesisagentandreviewerand deliberately excludesdeveloper: the addressees are the agent authoring a node and the reviewer holding the rule at the pull request. That choice is recorded in the plan'sOPENsection as unsettled rather than presented as decided.Verification
Command run:
Raw output:
Three notes on that output, so none of it is read as more or less than it is. The
FAIL corpus root does not exist:line inside the corpus suite is a fixture asserting the validator's own missing-root behaviour — it is that test's expected stderr, and the suite reportsOK. The threeUNVERIFIEDnotices are not a pass: two are commit references and one is a tool result, all forms the validator recognises and cannot open, and it prints them so aPASSnever claims more than it checked.git cat-file -eexiting 0 is what makes the provenance entry aFACTrather than an unchecked assertion.Not verified
corpus-agentsis the only other node in the corpus, so the five tests are reasoned from the schema, the ADRs and the instruction node rather than distilled from practice. The document says so in its own omissions section. The first few real uses are evidence about the procedure as much as about the nodes.review-finalpass on a different Claude model was run as a substitute and states in its own report that it is same-vendor and does not discharge that gate. Filed as task: the mandatory cross-model review gate has a single provider, and it is unavailable #1467. This is why the PR is a draft.pull_requestpaths includinglaunchpad/docs/corpus/**, so it will; it had not at the time this body was written.Security implications
None to the running system: the change adds two Markdown documents and no code, configuration, dependency or workflow. The relevant exposure question for a corpus node is whether it embeds private source material in a public artefact, and it does not — every citation is a repository-relative path to a tracked public file, a commit SHA in this repository, or a tool-result citation naming a
gh issue listquery against public issues. No path outside the repository is cited, and the validator's own credential-shaped-path blocklist raised nothing.Escalations
#1467 — the mandatory cross-model review gate has a single provider, and it is unavailable. Raised by the inability to run it here. It is not specific to this task: every remaining sibling under #605 carries the same gate, so as things stand none of them can discharge it. Deferred rather than fixed because refilling a paid workspace and installing a second vendor's CLI are both owner decisions.
Eight review findings were fixed on this branch rather than filed as issues, and that is a departure from the standing policy worth a reviewer's attention. The policy is that only Blockers are fixed in place and everything else becomes a tracked issue. Every one of these was a false or self-contradicting statement inside the single file this issue owns, so filing them would have meant shipping known-wrong sentences in a document whose subject is recording boundaries accurately, and fixing them is the issue's own Definition of Done rather than scope expansion. Nothing was fixed silently — each has its own commit and its own message. A reviewer who disagrees can say so cheaply, and the commits are separable.
done wheninvertedgrep -c's exit-code convention, so the desired state read as failure and invited addingrelationships: []review-planALREADY TRUEclaimedgit status --shortwas empty; it printed one untracked filereview-planrelationshipswas false — it covered only the unmerged siblings and silently skippedcorpus-agents, which exists and is targetablereview-adjudicatereview-adjudicateFACTrendered ADR-0028's "the rest of Ruling 12 depends on" as "the rest of the corpus rests on"review-adjudicateinterfaceandrunbook, neither a member of the schema'stypeenum — a wrong fact in the most decisive testreview-finalFACTgeneralised beyond its source, asserting a linking principle the cited sentence establishes only a mechanism forreview-finalRaised and refuted, so not filed.
review-codereported no findings at any severity;review-adjudicaterefuted that as a completeness claim and then found three the earlier passes had missed, which is the evidence for running it.review-finalobserved that applying test 1 in isolation to this document's own subtitle flags its conjunction, and judged it not a defect — the full procedure resolves it, because test 1 never overrides anything and test 5 finds one idea. No change was made.One decision left open rather than taken. Whether
developerbelongs inaudiencesis deliberately unsettled across this document set. It is excluded here with the reasoning stated in the plan'sOPENsection, not presented as settled. A later standard establishing that corpus policy nodes address developers makes this a one-line change.AGENTS.mdwas not touched, including to point its own not-covered table at this node. The pointer is a follow-up once this merges.