Skip to content

test: every spec clause this repo cites still exists - #104

Merged
dereuromark merged 1 commit into
mainfrom
test/spec-citations-resolve
Aug 18, 2026
Merged

test: every spec clause this repo cites still exists#104
dereuromark merged 1 commit into
mainfrom
test/spec-citations-resolve

Conversation

@dereuromark

Copy link
Copy Markdown
Contributor

This repo carries about eighty PART N section M citations across its tests and comments. They are how a reader checks that an asserted behavior is the behavior the language actually requires, and nothing validated them, so a wrong PART number read exactly like a correct citation forever.

One was wrong. test/reverse.test.mjs attributed the frontmatter opener rule to PART 9, when the canonical writer is PART 11 and PART 9 carries no clause with that label at all. The assertion itself was right; only the pointer was wrong, which is the worst combination, because it sends the next reader to a clause that does not exist and looks authoritative doing it.

The spec repo found the same class in its own tests/normativity.test.mjs, which read PART 9 and PART 12 only and therefore could not see a dangling PART 10 or PART 11 citation (markup-carve/carve#1367). Widening it surfaced eight. This is that gate for this repo's side of the same citations.

Why a containment test rather than a parser

The obvious approach is to extract every section label per PART and check membership. That needs a parser for a heading format right-aligned on the period, so 9. and 10a. sit at different indents, and which PART 8 uses twice with two independent runs of numbers. A parser that under-collects reports live clauses as dangling; one that over-collects quietly stops failing. Both are worse than the question actually being asked, which is only ever whether PART N contains a section labelled M. So the grammar is sliced between PART banners and asked exactly that. A nested numbered list item can at worst let a real clause resolve, never a missing one, because the label still has to appear inside the right PART.

Withdrawn clauses, and why the ledger is keyed by site

A citation can dangle because the clause was retired rather than mistyped, and that means something different: the repo may still describe behavior the language removed. Both halves of the quote-attribution withdrawal (markup-carve/carve#1213) are in that state, and this repo legitimately names one of them where the engine pin is checked against the withdrawal.

So deliberate references go in a ledger, keyed by file and clause, not by clause alone. A ledger keyed by the clause exempts it everywhere, so a brand new citation to a withdrawn clause would pass on the strength of an unrelated historical mention elsewhere. I built it that way first and the ablation caught it: a fresh PART 11 section 10d reference added to src/convert.ts stayed green. Keyed by site, it fails.

Each entry also asserts the clause is gone, so it fails if a later spec pin brings it back, and a companion check fails when an exemption no site uses any more. A stale exemption cannot sit here quietly the way a magic number can.

The gate goes red on each thing it claims to catch

Eight perturbations, each restored afterwards, each confirmed to have actually applied before its result was believed:

perturbation result
restore the real reverse.test.mjs typo red, names test/reverse.test.mjs:119
new dangling PART 10 section 10a in src/ red
new citation to retired PART 11 section 10d in src/ red, names src/convert.ts:1
new citation to retired PART 9 section 4a in src/ red
ledger exemption granted to the wrong file red at the real site, and red as an unused exemption
ledger exempts a clause that still exists red
file list matches nothing red, the scan reports it read no files
all restored green

The file list comes from git ls-files rather than a glob, and the scan asserts it read files and found citations, so it cannot go vacuous the way a glob that stops matching does.

Full suite on this branch: 362 tests, 0 failing, 71 skipped for the absent pandoc binary on the machine that ran it, which CI installs.

Sibling: #103 replaces the round trip's population floor with a derived count. Different files, no overlap, but the two land together as the same freeze sweep.

The repo carries about eighty `PART N section M` citations across its tests
and comments. They are how a reader checks that an asserted behavior is the
behavior the language requires, and nothing validated them, so a wrong PART
number read exactly like a correct citation forever.

One was wrong. `test/reverse.test.mjs` cited the frontmatter opener rule as
PART 9 section 6b; the canonical writer is PART 11, and PART 9 has no section
6b at all. The assertion was right and only the pointer was wrong, which is
the worst combination: it sends the next reader to a clause that does not
exist and looks authoritative doing it.

The spec repo found the same class in its own normativity test, which read
PART 9 and PART 12 only and therefore could not see a dangling PART 10 or
PART 11 citation. Widening it surfaced eight. This is that gate for this
repo's side of the same citations.

Resolution is a containment test, not a parser. Extracting section labels
needs to parse a heading format that is right-aligned on the period and that
PART 8 uses twice with two independent runs of numbers; a parser that
under-collects reports live clauses as dangling, and one that over-collects
stops failing. The question actually being asked is narrower - does PART N
contain a section labelled M - so the grammar is sliced between PART banners
and asked exactly that. A nested list item can at worst let a real clause
resolve, never a missing one.

A citation to a clause the spec withdrew on purpose goes in a ledger with its
reason, and the ledger is itself checked: an entry asserts the clause is gone,
so it fails if a later pin brings it back. Both halves of the quote-attribution
withdrawal are pinned as absent.

The file list comes from `git ls-files` rather than a glob, and the scan
asserts it read files and found citations, so the gate cannot quietly go
vacuous.
@dereuromark
dereuromark force-pushed the test/spec-citations-resolve branch from 2cf8699 to ec730e5 Compare August 18, 2026 03:37
@dereuromark
dereuromark merged commit dc1aa8f into main Aug 18, 2026
2 checks passed
@dereuromark
dereuromark deleted the test/spec-citations-resolve branch August 18, 2026 03:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant