Skip to content

State §4.3.1 item 5's mark re-sort as a rule, not a list of causes - #139

Merged
gvonnessi merged 1 commit into
mainfrom
fix/134-mark-resort
Sep 5, 2026
Merged

gvonnessi merged 1 commit into
mainfrom
fix/134-mark-resort

Conversation

@gvonnessi

Copy link
Copy Markdown
Collaborator

Closes #134.

§4.3.1 item 5 enumerated the causes of its post-rewrite mark re-sort — "relabeling an anchor id or a link href" — instead of stating the condition, and the enumeration was short. The same item rewrites an academic:theorem-ref/equation-ref/algorithm-ref target, which sits on a mark; and its walk relabels ids inside a mark's own content. The reference re-sorts every text node's marks unconditionally and so was already correct — but nothing in spec/ required it, so an implementer following the written text computes a different document ID.

Why it survived CI

Not because the divergence is hard to reach. It needs only two relabeled ids whose string order runs against their document order, and relabel-marks-resort-after-rewrite has been such a witness in the suite since before this change.

It survived because every pre-existing case that depends on the re-sort reorders through a link href — a cause the enumeration names, and which a selective implementation therefore handles. Measured by deleting the re-sort against main: exactly 2 of 380 checks fail, both [link, link]. The suite had no witness for an unrecognized cause.

The measured matrix

Six variants of the re-sort, each built as a real patch and run through check:conformance:

vector A: two named causes B: + *-ref E: only if JCS moved D: no dedup F: skip inside mark content N: digit-aware order
relabel-marks-resort-not-only-anchor-or-href ✗ ✗
relabel-marks-resort-id-inside-mark-content ✗ ✗ ✗
relabel-marks-resort-two-ids-authored-order ✗
relabel-marks-resort-inside-mark-content-no-relabel ✗ ✗ ✗ ✗ ✗
relabel-marks-resort-inside-mark-content-permuted ✗ ✗ ✗ ✗ ✗

No single vector is individually indispensable — an earlier draft of the changelog claimed otherwise and the panel disproved it. Three groupings are: the two mark-content vectors jointly reach a position nothing else in the suite touches (verified across 220 vectors and all 164 .cdx archives — zero other hits), not-only/id-inside jointly catch the digit-aware comparator, and two-ids-authored-order is dominated outright and published for legibility, which the changelog says in those words.

The permuted twin carries an identical expectedCanonicalJcs and expectedId from different parts.content. That pair binds alpha-equivalence on a third-party implementation, which a single vector cannot express.

Also here

Review

Two /review-fix cycles. Cycle 1: six lenses, 11 verified findings. Cycle 2: three bounded lenses against a closed list, plus a dedicated claim sweep that enumerated 74 clauses, decided 69 by a command it ran, and falsified 8. A third panel was refused by the review-cycle guard — correctly, since the delivered code was byte-identical to what cycle 2 reviewed — so the remaining prose was verified in place by measurement.

No finding in either cycle was a runtime-behaviour defect in shipped code. The reference was correct throughout. All eight falsifications were in prose written about it, every one an explanatory clause or a count hung off a true statement — two of them introduced by the fix for the previous one. Item 5's addition went from ~120 words to ~45; everything cut was either false or explanation.

Notes for the reviewer

Item 5 enumerated the causes of its post-rewrite mark re-sort — "relabeling
an `anchor` id or a `link` `href`" — and the enumeration was short. The same
item rewrites an `academic:*-ref` `target`, which sits on a mark, and its walk
relabels ids inside a mark's `content`. The reference already re-sorted every
text node's marks unconditionally, so it was right while nothing in spec/
required it: an implementer following the written text computed a different
document ID.

The divergence needs only two relabeled ids whose string order runs against
their document order, and the suite has held such a witness since before this
change. It survived because every pre-existing case that depends on the
re-sort reorders through a `link` `href` — a cause the enumeration names. The
suite had no witness for an unrecognized one.

Item 5's walk definition now also states that the walk enters a mark's
`content`, unlike item 4. That reach decides which ids receive canonical names
and was stated nowhere, while item 4 primes the opposite reading one item
earlier; over-generalizing that premise is the recorded root cause of the
reverted #121 PR 2.

Both additions are rule with no explanatory clause. Earlier drafts carried
three such clauses and a review panel falsified each by construction; the
reasoning lives in the changelog instead, where being wrong costs a correction
rather than a false normative claim.

Five canonicalize vectors, hand-derived and digested through
canonicalize_oracle.py before the reference was consulted. Their kill sets are
recorded as measured: no single vector is individually indispensable, the two
mark-content vectors jointly reach a position nothing else in the suite does,
and two vectors are dominated and published for legibility rather than
coverage. A test-canonicalize case pins alpha-equivalence inside a mark's
`content`, the one position where this rule is what makes two orderings agree.

canonicalize_oracle.py gains a floor: a vector may pin no expectedId only if
it is a reject vector, since otherwise every gate counts it as a pass with its
id never compared (#137).

suiteVersion 0.2.5 -> 0.2.6, 216 -> 221 vectors, 380 -> 385 checks. No
published expectation changes and no document ID moves; canonicalize.ts is
comments only.

Closes #134. Review also produced #136, #137 and #138.
@gvonnessi
gvonnessi merged commit 9fd496f into main Sep 5, 2026
2 checks passed
@gvonnessi
gvonnessi deleted the fix/134-mark-resort branch September 5, 2026 00:36
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.

§4.3.1 item 5 enumerates the causes of its mark re-sort, missing one — two implementations diverge at ten ids

1 participant