Skip to content

test: refuse a duplicated entry in the vacuity inventory (#432) - #1029

Merged
jdatcmd merged 1 commit into
commandprompt:mainfrom
OffgridwithJD:docs/1029-inventory-names-no-bullet-twice
Sep 13, 2026
Merged

jdatcmd merged 1 commit into
commandprompt:mainfrom
OffgridwithJD:docs/1029-inventory-names-no-bullet-twice

Conversation

@OffgridwithJD

Copy link
Copy Markdown
Collaborator

What this fixes

VACUITY_MODES.md section 3.4 carried the same six-id bullet twice, verbatim, two
lines each:

231  - `same-broken-helper-both-sides`, `truthy-error-string`, `assert-not-unset-error`,
232    `zero-on-both-arms`, `tuple-assert-always-true`, `approx-of-nothing`
233  - `same-broken-helper-both-sides`, `truthy-error-string`, `assert-not-unset-error`,
234    `zero-on-both-arms`, `tuple-assert-always-true`, `approx-of-nothing`

The second copy is deleted, and three arms in test_docs_cover_the_corpus.py now refuse
a duplicated entry.

Why nothing caught it, measured rather than guessed

Every count this document states is checked, and every one of those checks is blind
to this by construction. _named_modes_in builds set(MODE_ID.findall(chunk)) per
section, so each total is over distinct ids. Measured with the second copy present and
then deleted:

with the duplicate      (28, 44, 72)
without the duplicate   (28, 44, 72)

So test_the_mode_inventory_states_its_own_totals_correctly,
test_the_prose_totals_match_the_counted_modes and
test_the_two_halves_of_the_refused_sentence_sum_to_the_named_total were all green with
a duplicated entry in the file.

Deduping ids is right, and a total must not move because a line was pasted twice. The
cost falls on the reader instead: one group of open modes reads as two. So the new arm is
about entries, and the counting rule is unchanged.

My own first sweep missed it, and that decided the rule's unit

An adjacent duplicate-LINE sweep over every document in the directory reported
nothing. The duplicate is a two-line bullet, so line 1 of the first copy and line 1 of
the second are not adjacent. Re-keyed on the bullet ENTRY, the same sweep found it,
and found exactly one tree-wide.

Both fixture arms therefore plant a two-line bullet rather than a one-line one: a
one-line fixture would pass against the sweep that missed the real thing. The rule also
carries its false-positive budget as an arm, measured at the 40-character floor — the
inventory legitimately repeats short bullets, and a guard that reddened on those would be
switched off.

And the section that checks for stale documents carried a stale count

TESTS.md section 6 said "the five fixture arms". Five was right when written, at
3d6e1216 on 2026-09-09, and counted the arms taking tmp_path. There are eight of
those now, and thirteen fixture arms in total. Nothing read the number.

It is removed rather than corrected, which is what the paragraph above it already
decided for the same reason: test_the_document_states_no_totals_for_a_merge_to_get_wrong
exists to keep a totals line out. A count in prose that no arm reads is a claim waiting
to go wrong.

Arms added

test what it asserts
test_the_inventory_names_no_entry_twice no bullet entry in VACUITY_MODES.md is written twice, with a coverage premise
test_a_duplicated_entry_is_caught_on_a_fixture removal proof: the two-line shape that got through, with its clean control
test_a_short_repeated_bullet_is_not_flagged the false-positive budget, measured at the length floor in both directions

Verification

the new real-document arm, BEFORE the deletion
    FAILED test_the_inventory_names_no_entry_twice
    AssertionError: the inventory names no entry twice: got 'lines 231 and 233' want 'none'

after the deletion, the full guard half with the expectation armed
    280 passed in 9.10s
    checks run: 689   accounting: 689 pass + 0 fail + 0 unrun = 689

docs_style.sh            PASSED, 11 checks
selftest 350             5 PASS, 0 FAIL
long sentences           TESTS.md 299 -> 299, CHANGELOG 857 -> 857 (unchanged)
guard_tests              277 -> 280, re-derived by collection, not by adding three

Run with the pinned environment from requirements-test.txt (pytest 9.1.1, xdist 3.8.0,
psycopg 3.3.5), which is what the pytest-guards job installs.

Merge note

This adds no new TESTS.md section, so it carries none of the section-number
collision that #1022, #1027 and #1028 have with each other. Its only overlapping line is
guard_tests in expected_tests.txt, which #1028 also moves. Whichever of the two lands
second needs the count re-derived by collection — one number, and the recipe is in the
file.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Uf6UoeBRZYLQZa4KxNiw8a

@linuxhikerpm linuxhikerpm left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving a83a6ffb51c20462f2ad61861bcdbe27573e08af.

The count guards cannot see this: they set() ids, so (28, 44, 72) is unchanged with the duplicate present. Keying on a two-line ENTRY is the unit that found it, and both fixture arms use that shape rather than a one-line bullet the adjacent-line sweep would have caught. The 40-character floor is measured in both directions. Removing the unread "five fixture arms" total is the same decision as test_the_document_states_no_totals_for_a_merge_to_get_wrong.

CI is green, guard_tests 280 collected. That number collides with #1022 and #1028; re-derive on rebase. I will not merge it.

OffgridwithJD added a commit to OffgridwithJD/pgcolumnar that referenced this pull request Sep 12, 2026
…pt#1026)

docs_style.sh enforced seven rules over every user-facing page and all seven are
about PROSE: sentence length, the idiom list, em and en dashes, prose
double-hyphens, conflict markers, the nav entry, VERSION citations. Nothing checked
structure, so a markdown table that had stopped being a table passed the gate whose
whole purpose is keeping those pages readable.

The measured case, on commandprompt#1022: a note and a second table spliced into the middle of
configuration.md's set_options argument table left six of the nine arguments as a
headerless block. docs_style.sh passed, 14 checks. Found in review by
@linuxhikerpm -- I had reviewed that change twice, checking sentence length, a
guard's scoping claim and a three-row mutation table, and never once asked whether
the markdown still rendered.

Second splice of the day. The first gave configuration.md's GUC table no blank
lines, which made an awk RS='' guard read two GUC rows as one record and pass on
main. Both are the same fact: a markdown table is a contiguous run of | lines, and
a blank line is structural.

FENCES TRACKED BY LINE, not stripped by regex. The regex form already in this file
is fine for counting but loses line numbers, and a report that cannot say WHERE is
one somebody has to re-derive. It also breaks on an unclosed fence, where
state-tracking under-reports instead -- the safe direction, since it cannot invent
a table.

FIVE ARMS, and the control comes first: a rule flagging every table would catch the
defect and be switched off the same day. Then the defect with its line number, a
shell pipeline in a fence WITH its unfenced control, an unclosed fence, and the
false-positive budget as a standing arm rather than a number measured once.

THE BUDGET, measured before landing: 0 across docs/*.md and README.md, which is the
gate's scope. 5 elsewhere in the tree and all five are REAL -- 3 in
test/pytest/TESTS.md and 2 in design/, neither in scope. Not fixed here; the rule
does not reach them and widening the scope is a separate decision.

Proved by removal: splicing the commandprompt#1022 shape into configuration.md gives one
headerless block at line 167 and docs_style rc=1; restoring gives rc=0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uf6UoeBRZYLQZa4KxNiw8a

REBASED onto 6f7691b after commandprompt#1023 merged, and the resolution fixed a defect commandprompt#1023
left in main. Both conflict hunks were keep-both -- a TOC line and a whole new
section -- but placing mine correctly meant reading the order, and main's TOC was
not in order:

    main's TOC      ... 29, 31, 30      (out of order at two transitions)
    main's sections ... 29, 30, 31      (contiguous, correct)

commandprompt#1023's TOC entry for section 30 landed after 31. Nothing caught it: this file's
link arms assert every contents-list link RESOLVES, which both orders do, and
nothing asserts the numbering is monotonic. Now:

    TOC       32 entries, 1..32, 0 out-of-order
    sections  32 sections, 1..32, 0 out-of-order

guard_tests re-derived by collection on the new base rather than carried: 282
collected. cluster_tests 202 comes from main unchanged.

Re-verified after the rebase: 282 passed / 688 checks with --pgc-expect-tests 282
armed; docs_style.sh PASSED (11 checks); the headerless rule is active in the report
(`3 headerless table` on TESTS.md, all three pre-existing and outside the gate's
scope) and `violations()` returns its 5 members.

AND THE GUARD FOR THE ORDERING, added here rather than in commandprompt#1029 because a guard
belongs with its fix. Putting it in commandprompt#1029 would have reddened commandprompt#1029 until this PR
merged, which is a dependency between two independent PRs.

Two arms in test_docs_cover_the_corpus.py. The first requires TESTS.md's contents
numbers and its section numbers each to count 1..N with no gap, and one contents entry
per section. The second is the removal proof on a fixture, using the 29, 31, 30 shape
that shipped rather than a single swap.

MEASURED, by restoring main's order under the new arm:

    the new arm    FAIL  got '[(29, 31), (31, 30), (30, 32)]' want 'none'
    the link arms  1 passed

So the existing link sweep is not a weaker version of this rule. It asks whether a
link RESOLVES and both orders resolve, which is why a shuffled contents list was
outside every arm in that file.

The gap rule catches the section-number COLLISION too, which is the cause rather than
a coincidence: three open PRs each claimed a number another had taken, and a number
used twice leaves a gap in the section sequence. One rule reddens on a duplicate and
on an omission, and the fixture names them apart -- a missing entry gives [(1, 3)] and
a shuffle gives [(1, 3), (3, 2)].

guard_tests 282 -> 284, re-derived by collection. Re-verified: 284 passed / 698
checks with --pgc-expect-tests 284 armed; docs_style.sh PASSED (11 checks); TOC and
sections both 1..32 with zero out-of-order transitions. The CHANGELOG's long-sentence
count is unchanged at 857.
OffgridwithJD added a commit to OffgridwithJD/pgcolumnar that referenced this pull request Sep 13, 2026
…pt#1026)

docs_style.sh enforced seven rules over every user-facing page and all seven are
about PROSE: sentence length, the idiom list, em and en dashes, prose
double-hyphens, conflict markers, the nav entry, VERSION citations. Nothing checked
structure, so a markdown table that had stopped being a table passed the gate whose
whole purpose is keeping those pages readable.

The measured case, on commandprompt#1022: a note and a second table spliced into the middle of
configuration.md's set_options argument table left six of the nine arguments as a
headerless block. docs_style.sh passed, 14 checks. Found in review by
@linuxhikerpm -- I had reviewed that change twice, checking sentence length, a
guard's scoping claim and a three-row mutation table, and never once asked whether
the markdown still rendered.

Second splice of the day. The first gave configuration.md's GUC table no blank
lines, which made an awk RS='' guard read two GUC rows as one record and pass on
main. Both are the same fact: a markdown table is a contiguous run of | lines, and
a blank line is structural.

FENCES TRACKED BY LINE, not stripped by regex. The regex form already in this file
is fine for counting but loses line numbers, and a report that cannot say WHERE is
one somebody has to re-derive. It also breaks on an unclosed fence, where
state-tracking under-reports instead -- the safe direction, since it cannot invent
a table.

FIVE ARMS, and the control comes first: a rule flagging every table would catch the
defect and be switched off the same day. Then the defect with its line number, a
shell pipeline in a fence WITH its unfenced control, an unclosed fence, and the
false-positive budget as a standing arm rather than a number measured once.

THE BUDGET, measured before landing: 0 across docs/*.md and README.md, which is the
gate's scope. 5 elsewhere in the tree and all five are REAL -- 3 in
test/pytest/TESTS.md and 2 in design/, neither in scope. Not fixed here; the rule
does not reach them and widening the scope is a separate decision.

Proved by removal: splicing the commandprompt#1022 shape into configuration.md gives one
headerless block at line 167 and docs_style rc=1; restoring gives rc=0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uf6UoeBRZYLQZa4KxNiw8a

REBASED onto 6f7691b after commandprompt#1023 merged, and the resolution fixed a defect commandprompt#1023
left in main. Both conflict hunks were keep-both -- a TOC line and a whole new
section -- but placing mine correctly meant reading the order, and main's TOC was
not in order:

    main's TOC      ... 29, 31, 30      (out of order at two transitions)
    main's sections ... 29, 30, 31      (contiguous, correct)

link arms assert every contents-list link RESOLVES, which both orders do, and
nothing asserts the numbering is monotonic. Now:

    TOC       32 entries, 1..32, 0 out-of-order
    sections  32 sections, 1..32, 0 out-of-order

guard_tests re-derived by collection on the new base rather than carried: 282
collected. cluster_tests 202 comes from main unchanged.

Re-verified after the rebase: 282 passed / 688 checks with --pgc-expect-tests 282
armed; docs_style.sh PASSED (11 checks); the headerless rule is active in the report
(`3 headerless table` on TESTS.md, all three pre-existing and outside the gate's
scope) and `violations()` returns its 5 members.

AND THE GUARD FOR THE ORDERING, added here rather than in commandprompt#1029 because a guard
belongs with its fix. Putting it in commandprompt#1029 would have reddened commandprompt#1029 until this PR
merged, which is a dependency between two independent PRs.

Two arms in test_docs_cover_the_corpus.py. The first requires TESTS.md's contents
numbers and its section numbers each to count 1..N with no gap, and one contents entry
per section. The second is the removal proof on a fixture, using the 29, 31, 30 shape
that shipped rather than a single swap.

MEASURED, by restoring main's order under the new arm:

    the new arm    FAIL  got '[(29, 31), (31, 30), (30, 32)]' want 'none'
    the link arms  1 passed

So the existing link sweep is not a weaker version of this rule. It asks whether a
link RESOLVES and both orders resolve, which is why a shuffled contents list was
outside every arm in that file.

The gap rule catches the section-number COLLISION too, which is the cause rather than
a coincidence: three open PRs each claimed a number another had taken, and a number
used twice leaves a gap in the section sequence. One rule reddens on a duplicate and
on an omission, and the fixture names them apart -- a missing entry gives [(1, 3)] and
a shuffle gives [(1, 3), (3, 2)].

guard_tests 282 -> 284, re-derived by collection. Re-verified: 284 passed / 698
checks with --pgc-expect-tests 284 armed; docs_style.sh PASSED (11 checks); TOC and
sections both 1..32 with zero out-of-order transitions. The CHANGELOG's long-sentence
count is unchanged at 857.

REBASED AGAIN onto 03c6c9c, and the section moved 32 -> 33 because commandprompt#1027 merged and
took 32. That is the collision I measured on commandprompt#1027 before it merged, arriving exactly
as predicted, and the renumbering is the one-hunk-plus-a-sort it was said to be.

Main's contents list is still out of numeric order at three transitions --
(29, 31), (31, 30), (30, 32) -- because commandprompt#1023's entry for section 30 landed after 31
and commandprompt#1027 then appended 32. This resolution sorts all of it:

    TOC       33 entries, 1..33, 0 out-of-order
    sections  33 sections, 1..33, 0 out-of-order

guard_tests 284, re-derived by collection rather than carried. cluster_tests 205 comes
from main unchanged. Re-verified after both rebases: 284 collected, 284 passed / 698
checks with --pgc-expect-tests 284 armed, docs_style.sh PASSED (11 checks), and the
CHANGELOG's long-sentence count matches main at 860.
…pt#432)

VACUITY_MODES.md section 3.4 carried the same six-id bullet twice, verbatim, two
lines each. It is deleted, and three arms in test_docs_cover_the_corpus.py now
refuse a duplicated entry.

WHY NOTHING CAUGHT IT, MEASURED. Every count this document states is checked, and
every one of those checks is blind to this by construction: _named_modes_in builds
set(MODE_ID.findall(chunk)) per section, so each total is over distinct ids.
Measured with the second copy present and then deleted:

    with the duplicate      (28, 44, 72)
    without the duplicate   (28, 44, 72)

So the totals arm, the prose-totals arm and the sum arm were all green with a
duplicated entry in the file. Deduping ids is right, and a total must not move
because a line was pasted twice. The cost falls on the reader instead: one group of
open modes reads as two. So the new arm is about entries, and the counting rule is
unchanged.

MY OWN FIRST SWEEP MISSED IT, which decided the unit the rule uses. An adjacent
duplicate-LINE sweep over every document in the directory reported nothing: the
duplicate is a two-line bullet, so line 1 of the first copy and line 1 of the second
are not adjacent. Re-keyed on the bullet ENTRY, the same sweep found it, and found
exactly one tree-wide. Both fixture arms therefore use a two-line bullet rather than
a one-line one, and the rule carries its false-positive budget measured at the
40-character floor.

AND THE SECTION THAT CHECKS FOR STALE DOCUMENTS CARRIED A STALE COUNT. TESTS.md
section 6 said "the five fixture arms". Five was right at 3d6e121 (2026-09-09) and
counted the arms taking tmp_path; there are eight of those now and thirteen fixture
arms in total. Nothing read the number. It is removed rather than corrected, which is
what the paragraph above it already decided for the same reason:
test_the_document_states_no_totals_for_a_merge_to_get_wrong exists to keep a totals
line out.

guard_tests 277 -> 280, re-derived by collection rather than by adding three.

Verified: 280 passed / 689 checks with --pgc-expect-tests 280 armed; the new
real-document arm red first at "lines 231 and 233" before the deletion;
docs_style.sh PASSED (11 checks); selftest 350 5 PASS 0 FAIL. The long-sentence
count is unchanged in both documents (TESTS.md 299, CHANGELOG 857).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uf6UoeBRZYLQZa4KxNiw8a

REBASED onto 03c6c9c, which also removed a stale number this branch was carrying.
`cluster_tests` said 177 against main's 205: the branch never changed that line, so a
three-way merge would have taken main's value and nothing would have gone wrong, but
the file on the branch was stating a count that was three merges out of date. It now
reads what main reads.

guard_tests 280, re-derived by collection on the new base (280 collected) rather than
carried. Re-verified: 280 passed / 698 checks with --pgc-expect-tests 280 armed;
docs_style.sh PASSED (11 checks); the duplicate this PR removes is still present on
main, 2 occurrences there against 1 here, so the fix still applies to the tree it is
merging into.

@jdatcmd jdatcmd left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. The duplicate is real and the blindness is structural, not an oversight.

Verified

VACUITY_MODES.md:231 carries the six-id bullet twice, verbatim. Driven against the real text:

with the duplicate   raw ids=126  distinct=91
without it           raw ids=120  distinct=91

Six raw ids appear and vanish; the distinct count does not move. And the reason is one line — test_docs_cover_the_corpus.py:350:

chunks[head] = set(MODE_ID.findall(chunk))

Every total the document states is over those sets, so no count over them can ever see a repeat. That is a stronger claim than "nothing happened to check it": the checks that exist are blind by construction, and adding more counts of the same kind would stay blind.

My first attempt to drive it was invalid and said so

I pasted the bullet text with the display indentation still on it, so replace matched nothing and both arms measured the same string — identical numbers that looked like confirmation. What caught it was the probe printing duplicate present: False one line after sed had shown me the duplicate. Two outputs contradicting each other, rather than any judgement of mine.

That is the fourth time today a sweep or probe of mine keyed on how something was written rather than on what it is. Locating the pair structurally — two matching bullets two lines apart — is what made the second attempt mean anything.

The fix is the right shape

Deleting the second copy and adding arms that refuse a duplicated entry, rather than adjusting a count. A count that had been tuned to accept 126 would have locked the duplicate in.

Merging.

@jdatcmd
jdatcmd merged commit 14c9dd4 into commandprompt:main Sep 13, 2026
14 checks passed
OffgridwithJD added a commit to OffgridwithJD/pgcolumnar that referenced this pull request Sep 13, 2026
…pt#1026)

docs_style.sh enforced seven rules over every user-facing page and all seven are
about PROSE: sentence length, the idiom list, em and en dashes, prose
double-hyphens, conflict markers, the nav entry, VERSION citations. Nothing checked
structure, so a markdown table that had stopped being a table passed the gate whose
whole purpose is keeping those pages readable.

The measured case, on commandprompt#1022: a note and a second table spliced into the middle of
configuration.md's set_options argument table left six of the nine arguments as a
headerless block. docs_style.sh passed, 14 checks. Found in review by
@linuxhikerpm -- I had reviewed that change twice, checking sentence length, a
guard's scoping claim and a three-row mutation table, and never once asked whether
the markdown still rendered.

Second splice of the day. The first gave configuration.md's GUC table no blank
lines, which made an awk RS='' guard read two GUC rows as one record and pass on
main. Both are the same fact: a markdown table is a contiguous run of | lines, and
a blank line is structural.

FENCES TRACKED BY LINE, not stripped by regex. The regex form already in this file
is fine for counting but loses line numbers, and a report that cannot say WHERE is
one somebody has to re-derive. It also breaks on an unclosed fence, where
state-tracking under-reports instead -- the safe direction, since it cannot invent
a table.

FIVE ARMS, and the control comes first: a rule flagging every table would catch the
defect and be switched off the same day. Then the defect with its line number, a
shell pipeline in a fence WITH its unfenced control, an unclosed fence, and the
false-positive budget as a standing arm rather than a number measured once.

THE BUDGET, measured before landing: 0 across docs/*.md and README.md, which is the
gate's scope. 5 elsewhere in the tree and all five are REAL -- 3 in
test/pytest/TESTS.md and 2 in design/, neither in scope. Not fixed here; the rule
does not reach them and widening the scope is a separate decision.

Proved by removal: splicing the commandprompt#1022 shape into configuration.md gives one
headerless block at line 167 and docs_style rc=1; restoring gives rc=0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uf6UoeBRZYLQZa4KxNiw8a

REBASED onto 6f7691b after commandprompt#1023 merged, and the resolution fixed a defect commandprompt#1023
left in main. Both conflict hunks were keep-both -- a TOC line and a whole new
section -- but placing mine correctly meant reading the order, and main's TOC was
not in order:

    main's TOC      ... 29, 31, 30      (out of order at two transitions)
    main's sections ... 29, 30, 31      (contiguous, correct)

link arms assert every contents-list link RESOLVES, which both orders do, and
nothing asserts the numbering is monotonic. Now:

    TOC       32 entries, 1..32, 0 out-of-order
    sections  32 sections, 1..32, 0 out-of-order

guard_tests re-derived by collection on the new base rather than carried: 282
collected. cluster_tests 202 comes from main unchanged.

Re-verified after the rebase: 282 passed / 688 checks with --pgc-expect-tests 282
armed; docs_style.sh PASSED (11 checks); the headerless rule is active in the report
(`3 headerless table` on TESTS.md, all three pre-existing and outside the gate's
scope) and `violations()` returns its 5 members.

AND THE GUARD FOR THE ORDERING, added here rather than in commandprompt#1029 because a guard
belongs with its fix. Putting it in commandprompt#1029 would have reddened commandprompt#1029 until this PR
merged, which is a dependency between two independent PRs.

Two arms in test_docs_cover_the_corpus.py. The first requires TESTS.md's contents
numbers and its section numbers each to count 1..N with no gap, and one contents entry
per section. The second is the removal proof on a fixture, using the 29, 31, 30 shape
that shipped rather than a single swap.

MEASURED, by restoring main's order under the new arm:

    the new arm    FAIL  got '[(29, 31), (31, 30), (30, 32)]' want 'none'
    the link arms  1 passed

So the existing link sweep is not a weaker version of this rule. It asks whether a
link RESOLVES and both orders resolve, which is why a shuffled contents list was
outside every arm in that file.

The gap rule catches the section-number COLLISION too, which is the cause rather than
a coincidence: three open PRs each claimed a number another had taken, and a number
used twice leaves a gap in the section sequence. One rule reddens on a duplicate and
on an omission, and the fixture names them apart -- a missing entry gives [(1, 3)] and
a shuffle gives [(1, 3), (3, 2)].

guard_tests 282 -> 284, re-derived by collection. Re-verified: 284 passed / 698
checks with --pgc-expect-tests 284 armed; docs_style.sh PASSED (11 checks); TOC and
sections both 1..32 with zero out-of-order transitions. The CHANGELOG's long-sentence
count is unchanged at 857.

REBASED AGAIN onto 03c6c9c, and the section moved 32 -> 33 because commandprompt#1027 merged and
took 32. That is the collision I measured on commandprompt#1027 before it merged, arriving exactly
as predicted, and the renumbering is the one-hunk-plus-a-sort it was said to be.

Main's contents list is still out of numeric order at three transitions --
(29, 31), (31, 30), (30, 32) -- because commandprompt#1023's entry for section 30 landed after 31
and commandprompt#1027 then appended 32. This resolution sorts all of it:

    TOC       33 entries, 1..33, 0 out-of-order
    sections  33 sections, 1..33, 0 out-of-order

guard_tests 284, re-derived by collection rather than carried. cluster_tests 205 comes
from main unchanged. Re-verified after both rebases: 284 collected, 284 passed / 698
checks with --pgc-expect-tests 284 armed, docs_style.sh PASSED (11 checks), and the
CHANGELOG's long-sentence count matches main at 860.

REBASED onto 14c9dd4 after commandprompt#1029 merged, and the resolution is the one this PR's
sibling work is about. `expected_tests.txt` conflicted and keep-both produced TWO
guard_tests lines:

    guard_tests 280     <- main, after commandprompt#1029
    guard_tests 284     <- this branch, from the old base

Keep-both is right for the CHANGELOG hunk in the same merge and wrong for a key-value
file. One line, re-derived by collection rather than by adding: 287 collected.

Re-verified: 287 passed / 707 checks with --pgc-expect-tests 287 armed; docs_style.sh
PASSED (11 checks); TOC and sections both 1..33 with zero out-of-order; both CHANGELOG
entries survived the merge.
OffgridwithJD added a commit to OffgridwithJD/pgcolumnar that referenced this pull request Sep 13, 2026
…pt#1026)

docs_style.sh enforced seven rules over every user-facing page and all seven are
about PROSE: sentence length, the idiom list, em and en dashes, prose
double-hyphens, conflict markers, the nav entry, VERSION citations. Nothing checked
structure, so a markdown table that had stopped being a table passed the gate whose
whole purpose is keeping those pages readable.

The measured case, on commandprompt#1022: a note and a second table spliced into the middle of
configuration.md's set_options argument table left six of the nine arguments as a
headerless block. docs_style.sh passed, 14 checks. Found in review by
@linuxhikerpm -- I had reviewed that change twice, checking sentence length, a
guard's scoping claim and a three-row mutation table, and never once asked whether
the markdown still rendered.

Second splice of the day. The first gave configuration.md's GUC table no blank
lines, which made an awk RS='' guard read two GUC rows as one record and pass on
main. Both are the same fact: a markdown table is a contiguous run of | lines, and
a blank line is structural.

FENCES TRACKED BY LINE, not stripped by regex. The regex form already in this file
is fine for counting but loses line numbers, and a report that cannot say WHERE is
one somebody has to re-derive. It also breaks on an unclosed fence, where
state-tracking under-reports instead -- the safe direction, since it cannot invent
a table.

FIVE ARMS, and the control comes first: a rule flagging every table would catch the
defect and be switched off the same day. Then the defect with its line number, a
shell pipeline in a fence WITH its unfenced control, an unclosed fence, and the
false-positive budget as a standing arm rather than a number measured once.

THE BUDGET, measured before landing: 0 across docs/*.md and README.md, which is the
gate's scope. 5 elsewhere in the tree and all five are REAL -- 3 in
test/pytest/TESTS.md and 2 in design/, neither in scope. Not fixed here; the rule
does not reach them and widening the scope is a separate decision.

Proved by removal: splicing the commandprompt#1022 shape into configuration.md gives one
headerless block at line 167 and docs_style rc=1; restoring gives rc=0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uf6UoeBRZYLQZa4KxNiw8a

REBASED onto 6f7691b after commandprompt#1023 merged, and the resolution fixed a defect commandprompt#1023
left in main. Both conflict hunks were keep-both -- a TOC line and a whole new
section -- but placing mine correctly meant reading the order, and main's TOC was
not in order:

    main's TOC      ... 29, 31, 30      (out of order at two transitions)
    main's sections ... 29, 30, 31      (contiguous, correct)

link arms assert every contents-list link RESOLVES, which both orders do, and
nothing asserts the numbering is monotonic. Now:

    TOC       32 entries, 1..32, 0 out-of-order
    sections  32 sections, 1..32, 0 out-of-order

guard_tests re-derived by collection on the new base rather than carried: 282
collected. cluster_tests 202 comes from main unchanged.

Re-verified after the rebase: 282 passed / 688 checks with --pgc-expect-tests 282
armed; docs_style.sh PASSED (11 checks); the headerless rule is active in the report
(`3 headerless table` on TESTS.md, all three pre-existing and outside the gate's
scope) and `violations()` returns its 5 members.

AND THE GUARD FOR THE ORDERING, added here rather than in commandprompt#1029 because a guard
belongs with its fix. Putting it in commandprompt#1029 would have reddened commandprompt#1029 until this PR
merged, which is a dependency between two independent PRs.

Two arms in test_docs_cover_the_corpus.py. The first requires TESTS.md's contents
numbers and its section numbers each to count 1..N with no gap, and one contents entry
per section. The second is the removal proof on a fixture, using the 29, 31, 30 shape
that shipped rather than a single swap.

MEASURED, by restoring main's order under the new arm:

    the new arm    FAIL  got '[(29, 31), (31, 30), (30, 32)]' want 'none'
    the link arms  1 passed

So the existing link sweep is not a weaker version of this rule. It asks whether a
link RESOLVES and both orders resolve, which is why a shuffled contents list was
outside every arm in that file.

The gap rule catches the section-number COLLISION too, which is the cause rather than
a coincidence: three open PRs each claimed a number another had taken, and a number
used twice leaves a gap in the section sequence. One rule reddens on a duplicate and
on an omission, and the fixture names them apart -- a missing entry gives [(1, 3)] and
a shuffle gives [(1, 3), (3, 2)].

guard_tests 282 -> 284, re-derived by collection. Re-verified: 284 passed / 698
checks with --pgc-expect-tests 284 armed; docs_style.sh PASSED (11 checks); TOC and
sections both 1..32 with zero out-of-order transitions. The CHANGELOG's long-sentence
count is unchanged at 857.

REBASED AGAIN onto 03c6c9c, and the section moved 32 -> 33 because commandprompt#1027 merged and
took 32. That is the collision I measured on commandprompt#1027 before it merged, arriving exactly
as predicted, and the renumbering is the one-hunk-plus-a-sort it was said to be.

Main's contents list is still out of numeric order at three transitions --
(29, 31), (31, 30), (30, 32) -- because commandprompt#1023's entry for section 30 landed after 31
and commandprompt#1027 then appended 32. This resolution sorts all of it:

    TOC       33 entries, 1..33, 0 out-of-order
    sections  33 sections, 1..33, 0 out-of-order

guard_tests 284, re-derived by collection rather than carried. cluster_tests 205 comes
from main unchanged. Re-verified after both rebases: 284 collected, 284 passed / 698
checks with --pgc-expect-tests 284 armed, docs_style.sh PASSED (11 checks), and the
CHANGELOG's long-sentence count matches main at 860.

REBASED onto 14c9dd4 after commandprompt#1029 merged, and the resolution is the one this PR's
sibling work is about. `expected_tests.txt` conflicted and keep-both produced TWO
guard_tests lines:

    guard_tests 280     <- main, after commandprompt#1029
    guard_tests 284     <- this branch, from the old base

Keep-both is right for the CHANGELOG hunk in the same merge and wrong for a key-value
file. One line, re-derived by collection rather than by adding: 287 collected.

Re-verified: 287 passed / 707 checks with --pgc-expect-tests 287 armed; docs_style.sh
PASSED (11 checks); TOC and sections both 1..33 with zero out-of-order; both CHANGELOG
entries survived the merge.
OffgridwithJD pushed a commit to OffgridwithJD/pgcolumnar that referenced this pull request Sep 13, 2026
…one (commandprompt#982)

A ledger row is keyed on (suite, part, name). Two checks with the same name in one
part share a row, and two ROWS with the same key collapse into one. Neither is
mis-recorded while everything passes. Both lose a red observation the moment one
appears.

--- THE GATE COULD NOT SEE TWO CHECKS IN ONE RUN -------------------------------

`merge` has printed "duplicate check name in one run" since commandprompt#982 was filed and
returns 0, which is how three of them sat in one part of selftest/400 for a day. The
instance was fixed by c3b13ae; this is the mechanism the issue called the more
valuable half.

`cmd_gate` builds its records as `sorted({(s, p, n, m) for ...})`. A set collapses the
duplicate before any arm can count it, so the same canonicalisation that makes the
rest of that function correct made this one class unreachable. The count now comes
from the raw records through `_by_run`, which already existed for the
two-runs-versus-one-duplicate distinction.

EVERY SUITE, DELIBERATELY UNLIKE THE NEW-CHECK REFUSAL. That one is restricted to
covered suites because it cannot know which of an uncovered suite's checks are new.
This one needs no history: two records, one key, one log is decidable from the log
alone. The ledger covers four suites of 253, so copying the restriction would close
the class in four places only, and the next collision would sit in one of the other
249 until that suite was seeded.

--- AND THE LEDGER COULD NOT SEE TWO ROWS IN ONE FILE --------------------------

`read_ledger` did `rows[key] = [...]`, so a duplicated key in the tracked file
collapsed silently and the LAST line won. Measured on a two-line fixture, both
orders:

    never first, then 2026-09-01   survivor last_red='2026-09-01'
    2026-09-01 first, then never   survivor last_red='never'      the red is GONE

Line order decided whether a recorded red observation survived. A merge that keeps
both sides of a changed row turns `ever red` back into `never`.

NOTHING ELSE COULD CATCH IT, and bounding the census cannot. check_ledger_budget.txt
says `checks_never_observed_red` is a CENSUS and must not become a ceiling, because
every new check enters as `never` and bounding it deadlocks. The gate compares the
budget's number with the ledger's, and both come from the same dict, so they agree
either way. Measured: with the budget regenerated alongside, an erased red passes the
gate at rc=0. It is now refused as an integrity failure (rc=2), beside the other
inputs that do not parse.

So the two halves are the same shape at two levels. A SET hid two checks in one run;
a DICT hid two rows in one file. The question that found both is what the input
canonicalises before the guard sees it.

--- MEASURED BEFORE WIDENING IT -----------------------------------------------

A gate that reddens 250 unmeasured suites is a gate somebody turns off, so the
refusal was not widened on reasoning. A full PG 18 matrix ran with it armed for
every suite:

    247 suites ran, 6 skipped, 0 incomplete | ALL VERSIONS PASSED, RC=0 | 0 shared keys

and a mid-run snapshot of the per-suite logs agrees from the other side: 244 logs
carrying records, 6651 RESULT records, 6651 distinct keys, 0 collisions. That also
answers what commandprompt#982 said nobody had measured -- the gap between "checks that ran" and
"rows the ledger can hold" across the other 250 suites is zero. Check names are
static, so one major's matrix measures this class completely rather than sampling it.

--- VERIFICATION --------------------------------------------------------------

The committed ledger still loads at 1197 rows. The gate against the COMMITTED ledger
and budget over a real 934-record harness_selftest log: rc=0, no shared-key line,
census agrees at 1189. A planted duplicate check: rc=1, naming the key. A planted
duplicate row: rc=2, naming the line and what it would lose.

The refusal arm also asserts no Traceback in the output, because an unhandled
exception exits 1 too and would satisfy an rc check on its own. Measured, it did: an
earlier draft referenced `covered_suites` before it was defined, which compiles and
fails at runtime.

guard_tests 277 -> 283, re-derived by collection. 283 passed / 698 checks with
--pgc-expect-tests 283 armed. docs_style.sh PASSED (11 checks). Long-sentence counts
unchanged: CHANGELOG 860, TESTS.md 319.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uf6UoeBRZYLQZa4KxNiw8a

--- AND A THIRD INSTANCE, IN THE ARM THAT POLICES THE OTHER TRACKED FILE -------

test_harness_deps.py read expected_tests.txt with `nums[f[0]] = int(f[1])`, so a
duplicated key collapsed and the last line won -- exactly as read_ledger did, one file
over. Measured on one fixture read both ways:

    the line form   names guard_tests as duplicated
    the dict form   sees two keys and keeps 280, the LAST line

NOT HYPOTHETICAL. Three PRs were open at once, each moving guard_tests, and resolving
all three keep-both produced three of those lines. ci.yml reads the value with
`awk '$1=="guard_tests"{print $2}'`, which prints one line per match. So WANT becomes
multi-line, `test -n "$WANT"` still passes, and the flag refuses it:

    pytest: error: argument --pgc-expect-tests: invalid int value: '284\n280\n283'
    exit 4

It FAILS CLOSED, so these two arms are about legibility rather than a hole. What exit 4
does not say is that a line is duplicated. The removal proof is on the real file: with a
duplicate planted, the new arm reddens and the pre-existing one stays green.

Keep-both is right for a changelog and wrong for a key-value file, and nothing in the
tree said so.

cluster_tests 205 -> 207, NOT guard_tests: test_harness_deps.py DEFINES NO_CLUSTER and
is not in it. I bumped the wrong number first and --pgc-expect-tests caught it --
`collected 283 test(s) but expected 285` -- which is the argument for the mechanism.
Both halves re-derived by collection: guard 283, cluster 207.

REBASED onto 14c9dd4 after commandprompt#1029 merged, and the conflict was the exact shape the third
arm here is about. `expected_tests.txt` conflicted on `guard_tests`:

    guard_tests 280     <- main, after commandprompt#1029
    guard_tests 283     <- this branch, from the old base

Keep-both would have produced two lines and, through ci.yml's
`awk '$1=="guard_tests"{print $2}'`, a multi-line value the flag refuses at exit 4. One
line, and both halves re-derived by collection rather than by arithmetic:

    guard_tests 286, cluster_tests 207

Re-verified: 286 passed / 707 checks with --pgc-expect-tests 286 armed; docs_style.sh
PASSED (11 checks); the gate against the committed ledger and budget over the real
934-record log still returns 0. Long-sentence counts unchanged against the new base:
CHANGELOG 860, TESTS.md 319.
OffgridwithJD pushed a commit to OffgridwithJD/pgcolumnar that referenced this pull request Sep 13, 2026
…one (commandprompt#982)

A ledger row is keyed on (suite, part, name). Two checks with the same name in one
part share a row, and two ROWS with the same key collapse into one. Neither is
mis-recorded while everything passes. Both lose a red observation the moment one
appears.

--- THE GATE COULD NOT SEE TWO CHECKS IN ONE RUN -------------------------------

`merge` has printed "duplicate check name in one run" since commandprompt#982 was filed and
returns 0, which is how three of them sat in one part of selftest/400 for a day. The
instance was fixed by c3b13ae; this is the mechanism the issue called the more
valuable half.

`cmd_gate` builds its records as `sorted({(s, p, n, m) for ...})`. A set collapses the
duplicate before any arm can count it, so the same canonicalisation that makes the
rest of that function correct made this one class unreachable. The count now comes
from the raw records through `_by_run`, which already existed for the
two-runs-versus-one-duplicate distinction.

EVERY SUITE, DELIBERATELY UNLIKE THE NEW-CHECK REFUSAL. That one is restricted to
covered suites because it cannot know which of an uncovered suite's checks are new.
This one needs no history: two records, one key, one log is decidable from the log
alone. The ledger covers four suites of 253, so copying the restriction would close
the class in four places only, and the next collision would sit in one of the other
249 until that suite was seeded.

--- AND THE LEDGER COULD NOT SEE TWO ROWS IN ONE FILE --------------------------

`read_ledger` did `rows[key] = [...]`, so a duplicated key in the tracked file
collapsed silently and the LAST line won. Measured on a two-line fixture, both
orders:

    never first, then 2026-09-01   survivor last_red='2026-09-01'
    2026-09-01 first, then never   survivor last_red='never'      the red is GONE

Line order decided whether a recorded red observation survived. A merge that keeps
both sides of a changed row turns `ever red` back into `never`.

NOTHING ELSE COULD CATCH IT, and bounding the census cannot. check_ledger_budget.txt
says `checks_never_observed_red` is a CENSUS and must not become a ceiling, because
every new check enters as `never` and bounding it deadlocks. The gate compares the
budget's number with the ledger's, and both come from the same dict, so they agree
either way. Measured: with the budget regenerated alongside, an erased red passes the
gate at rc=0. It is now refused as an integrity failure (rc=2), beside the other
inputs that do not parse.

So the two halves are the same shape at two levels. A SET hid two checks in one run;
a DICT hid two rows in one file. The question that found both is what the input
canonicalises before the guard sees it.

--- MEASURED BEFORE WIDENING IT -----------------------------------------------

A gate that reddens 250 unmeasured suites is a gate somebody turns off, so the
refusal was not widened on reasoning. A full PG 18 matrix ran with it armed for
every suite:

    247 suites ran, 6 skipped, 0 incomplete | ALL VERSIONS PASSED, RC=0 | 0 shared keys

Check names are static, so one major's matrix measures this class completely rather
than sampling it.

THE LOAD-BEARING EVIDENCE IS THAT RUN, not a log snapshot. An earlier draft of this
message cited "244 logs, 6651 records, 6651 distinct keys, 0 collisions" from
per-suite logs copied out of the build directory while the matrix was still running.
That figure is withdrawn: the copies were taken mid-write, and measuring the same way
again showed 150 of 253 had no `checks run:` line yet. Zero collisions across
truncated logs is not evidence of zero across complete ones. The full-matrix figure
stands because the gate reads the logs after each suite has finished.

It does still answer what commandprompt#982 said nobody had measured -- the gap between "checks
that ran" and "rows the ledger can hold" across the other 250 suites -- because the
gate saw every suite's complete log and refused nothing.

--- VERIFICATION --------------------------------------------------------------

The committed ledger still loads at 1197 rows. The gate against the COMMITTED ledger
and budget over a real 934-record harness_selftest log: rc=0, no shared-key line,
census agrees at 1189. A planted duplicate check: rc=1, naming the key. A planted
duplicate row: rc=2, naming the line and what it would lose.

The refusal arm also asserts no Traceback in the output, because an unhandled
exception exits 1 too and would satisfy an rc check on its own. Measured, it did: an
earlier draft referenced `covered_suites` before it was defined, which compiles and
fails at runtime.

guard_tests 277 -> 283, re-derived by collection. 283 passed / 698 checks with
--pgc-expect-tests 283 armed. docs_style.sh PASSED (11 checks). Long-sentence counts
unchanged: CHANGELOG 860, TESTS.md 319.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uf6UoeBRZYLQZa4KxNiw8a

--- AND A THIRD INSTANCE, IN THE ARM THAT POLICES THE OTHER TRACKED FILE -------

test_harness_deps.py read expected_tests.txt with `nums[f[0]] = int(f[1])`, so a
duplicated key collapsed and the last line won -- exactly as read_ledger did, one file
over. Measured on one fixture read both ways:

    the line form   names guard_tests as duplicated
    the dict form   sees two keys and keeps 280, the LAST line

NOT HYPOTHETICAL. Three PRs were open at once, each moving guard_tests, and resolving
all three keep-both produced three of those lines. ci.yml reads the value with
`awk '$1=="guard_tests"{print $2}'`, which prints one line per match. So WANT becomes
multi-line, `test -n "$WANT"` still passes, and the flag refuses it:

    pytest: error: argument --pgc-expect-tests: invalid int value: '284\n280\n283'
    exit 4

It FAILS CLOSED, so these two arms are about legibility rather than a hole. What exit 4
does not say is that a line is duplicated. The removal proof is on the real file: with a
duplicate planted, the new arm reddens and the pre-existing one stays green.

Keep-both is right for a changelog and wrong for a key-value file, and nothing in the
tree said so.

cluster_tests 205 -> 207, NOT guard_tests: test_harness_deps.py DEFINES NO_CLUSTER and
is not in it. I bumped the wrong number first and --pgc-expect-tests caught it --
`collected 283 test(s) but expected 285` -- which is the argument for the mechanism.
Both halves re-derived by collection: guard 283, cluster 207.

REBASED onto 14c9dd4 after commandprompt#1029 merged, and the conflict was the exact shape the third
arm here is about. `expected_tests.txt` conflicted on `guard_tests`:

    guard_tests 280     <- main, after commandprompt#1029
    guard_tests 283     <- this branch, from the old base

Keep-both would have produced two lines and, through ci.yml's
`awk '$1=="guard_tests"{print $2}'`, a multi-line value the flag refuses at exit 4. One
line, and both halves re-derived by collection rather than by arithmetic:

    guard_tests 286, cluster_tests 207

Re-verified: 286 passed / 707 checks with --pgc-expect-tests 286 armed; docs_style.sh
PASSED (11 checks); the gate against the committed ledger and budget over the real
934-record log still returns 0. Long-sentence counts unchanged against the new base:
CHANGELOG 860, TESTS.md 319.
OffgridwithJD pushed a commit to OffgridwithJD/pgcolumnar that referenced this pull request Sep 13, 2026
…one (commandprompt#982)

A ledger row is keyed on (suite, part, name). Two checks with the same name in one
part share a row, and two ROWS with the same key collapse into one. Neither is
mis-recorded while everything passes. Both lose a red observation the moment one
appears.

--- THE GATE COULD NOT SEE TWO CHECKS IN ONE RUN -------------------------------

`merge` has printed "duplicate check name in one run" since commandprompt#982 was filed and
returns 0, which is how three of them sat in one part of selftest/400 for a day. The
instance was fixed by c3b13ae; this is the mechanism the issue called the more
valuable half.

`cmd_gate` builds its records as `sorted({(s, p, n, m) for ...})`. A set collapses the
duplicate before any arm can count it, so the same canonicalisation that makes the
rest of that function correct made this one class unreachable. The count now comes
from the raw records through `_by_run`, which already existed for the
two-runs-versus-one-duplicate distinction.

EVERY SUITE, DELIBERATELY UNLIKE THE NEW-CHECK REFUSAL. That one is restricted to
covered suites because it cannot know which of an uncovered suite's checks are new.
This one needs no history: two records, one key, one log is decidable from the log
alone. The ledger covers four suites of 253, so copying the restriction would close
the class in four places only, and the next collision would sit in one of the other
249 until that suite was seeded.

--- AND THE LEDGER COULD NOT SEE TWO ROWS IN ONE FILE --------------------------

`read_ledger` did `rows[key] = [...]`, so a duplicated key in the tracked file
collapsed silently and the LAST line won. Measured on a two-line fixture, both
orders:

    never first, then 2026-09-01   survivor last_red='2026-09-01'
    2026-09-01 first, then never   survivor last_red='never'      the red is GONE

Line order decided whether a recorded red observation survived. A merge that keeps
both sides of a changed row turns `ever red` back into `never`.

NOTHING ELSE COULD CATCH IT, and bounding the census cannot. check_ledger_budget.txt
says `checks_never_observed_red` is a CENSUS and must not become a ceiling, because
every new check enters as `never` and bounding it deadlocks. The gate compares the
budget's number with the ledger's, and both come from the same dict, so they agree
either way. Measured: with the budget regenerated alongside, an erased red passes the
gate at rc=0. It is now refused as an integrity failure (rc=2), beside the other
inputs that do not parse.

So the two halves are the same shape at two levels. A SET hid two checks in one run;
a DICT hid two rows in one file. The question that found both is what the input
canonicalises before the guard sees it.

--- MEASURED BEFORE WIDENING IT -----------------------------------------------

A gate that reddens 250 unmeasured suites is a gate somebody turns off, so the
refusal was not widened on reasoning. A full PG 18 matrix ran with it armed for
every suite:

    247 suites ran, 6 skipped, 0 incomplete | ALL VERSIONS PASSED, RC=0 | 0 shared keys

Check names are static, so one major's matrix measures this class completely rather
than sampling it.

THE LOAD-BEARING EVIDENCE IS THAT RUN, not a log snapshot. An earlier draft of this
message cited "244 logs, 6651 records, 6651 distinct keys, 0 collisions" from
per-suite logs copied out of the build directory while the matrix was still running.
That figure is withdrawn: the copies were taken mid-write, and measuring the same way
again showed 150 of 253 had no `checks run:` line yet. Zero collisions across
truncated logs is not evidence of zero across complete ones. The full-matrix figure
stands because the gate reads the logs after each suite has finished.

It does still answer what commandprompt#982 said nobody had measured -- the gap between "checks
that ran" and "rows the ledger can hold" across the other 250 suites -- because the
gate saw every suite's complete log and refused nothing.

--- VERIFICATION --------------------------------------------------------------

The committed ledger still loads at 1197 rows. The gate against the COMMITTED ledger
and budget over a real 934-record harness_selftest log: rc=0, no shared-key line,
census agrees at 1189. A planted duplicate check: rc=1, naming the key. A planted
duplicate row: rc=2, naming the line and what it would lose.

The refusal arm also asserts no Traceback in the output, because an unhandled
exception exits 1 too and would satisfy an rc check on its own. Measured, it did: an
earlier draft referenced `covered_suites` before it was defined, which compiles and
fails at runtime.

guard_tests 277 -> 283, re-derived by collection. 283 passed / 698 checks with
--pgc-expect-tests 283 armed. docs_style.sh PASSED (11 checks). Long-sentence counts
unchanged: CHANGELOG 860, TESTS.md 319.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uf6UoeBRZYLQZa4KxNiw8a

--- AND A THIRD INSTANCE, IN THE ARM THAT POLICES THE OTHER TRACKED FILE -------

test_harness_deps.py read expected_tests.txt with `nums[f[0]] = int(f[1])`, so a
duplicated key collapsed and the last line won -- exactly as read_ledger did, one file
over. Measured on one fixture read both ways:

    the line form   names guard_tests as duplicated
    the dict form   sees two keys and keeps 280, the LAST line

NOT HYPOTHETICAL. Three PRs were open at once, each moving guard_tests, and resolving
all three keep-both produced three of those lines. ci.yml reads the value with
`awk '$1=="guard_tests"{print $2}'`, which prints one line per match. So WANT becomes
multi-line, `test -n "$WANT"` still passes, and the flag refuses it:

    pytest: error: argument --pgc-expect-tests: invalid int value: '284\n280\n283'
    exit 4

It FAILS CLOSED, so these two arms are about legibility rather than a hole. What exit 4
does not say is that a line is duplicated. The removal proof is on the real file: with a
duplicate planted, the new arm reddens and the pre-existing one stays green.

Keep-both is right for a changelog and wrong for a key-value file, and nothing in the
tree said so.

cluster_tests 205 -> 207, NOT guard_tests: test_harness_deps.py DEFINES NO_CLUSTER and
is not in it. I bumped the wrong number first and --pgc-expect-tests caught it --
`collected 283 test(s) but expected 285` -- which is the argument for the mechanism.
Both halves re-derived by collection: guard 283, cluster 207.

REBASED onto 14c9dd4 after commandprompt#1029 merged, and the conflict was the exact shape the third
arm here is about. `expected_tests.txt` conflicted on `guard_tests`:

    guard_tests 280     <- main, after commandprompt#1029
    guard_tests 283     <- this branch, from the old base

Keep-both would have produced two lines and, through ci.yml's
`awk '$1=="guard_tests"{print $2}'`, a multi-line value the flag refuses at exit 4. One
line, and both halves re-derived by collection rather than by arithmetic:

    guard_tests 286, cluster_tests 207

Re-verified: 286 passed / 707 checks with --pgc-expect-tests 286 armed; docs_style.sh
PASSED (11 checks); the gate against the committed ledger and budget over the real
934-record log still returns 0. Long-sentence counts unchanged against the new base:
CHANGELOG 860, TESTS.md 319.

--- FIXTURE CORRECTED AFTER REVIEW (@jdatcmd) -----------------------------------

test_the_gate_refuses_two_checks_sharing_one_ledger_key asserted rc == 1 on a
fixture where the gate returned 1 for TWO independent reasons, so the arm did not
discriminate. Found by mutation, and I reproduced it before changing anything:

    with `rc = 1` deleted from the shared-key block, the OLD fixture's arm PASSED
    with the same mutation, the corrected fixture's arm FAILS: got 0 want 1

The second route was the pre-existing new-check refusal. The ledger named only
`some other check` in that part, which made `demo` a covered suite whose log carried
a check the ledger had never seen:

    not in the ledger: demo   part1   shared name   (on major 18)

The ledger now NAMES `shared name`, so that refusal has nothing to say and only the
shared-key refusal can move rc.

This is the same defect class the PR is about, in my own arm: an assertion that
passes for a reason other than the one it is named for. My docstring claimed I had
measured this and closed it -- I had closed the COVERAGE-CEILING route and not the
new-check route, and the note said "routes" as though it were all of them. The
comment now enumerates all three, including the unhandled-exception route that also
exits 1.

It also described the refusal as "restricted to suites a row exists for", which was
the design I abandoned two pushes earlier when the matrix measurement said refusing
everywhere was safe. That sentence is gone.

--- REBASED onto 2ea7366 ------------------------------------------------------

guard_tests 293 and cluster_tests 207, both re-derived by COLLECTION on this base.

And a sharper point than the one I had, measured by @jdatcmd on commandprompt#1022: two branches
each derived `guard_tests 280` correctly, each against a tree holding only its own
three arms, and the merged value was 283. Both numbers were right for the tree they
were taken on and both were wrong for the merge. So "derive rather than add" is
necessary and not sufficient -- it has to be re-derived after every rebase, which
expected_tests.txt now says.

Re-verified: 293 passed / 725 checks with --pgc-expect-tests 293 armed; docs_style.sh
PASSED (11 checks); the gate against the committed ledger and budget over the real
934-record log returns 0; long-sentence counts unchanged at CHANGELOG 860 and
TESTS.md 319.
OffgridwithJD pushed a commit to OffgridwithJD/pgcolumnar that referenced this pull request Sep 13, 2026
…one (commandprompt#982)

A ledger row is keyed on (suite, part, name). Two checks with the same name in one
part share a row, and two ROWS with the same key collapse into one. Neither is
mis-recorded while everything passes. Both lose a red observation the moment one
appears.

--- THE GATE COULD NOT SEE TWO CHECKS IN ONE RUN -------------------------------

`merge` has printed "duplicate check name in one run" since commandprompt#982 was filed and
returns 0, which is how three of them sat in one part of selftest/400 for a day. The
instance was fixed by c3b13ae; this is the mechanism the issue called the more
valuable half.

`cmd_gate` builds its records as `sorted({(s, p, n, m) for ...})`. A set collapses the
duplicate before any arm can count it, so the same canonicalisation that makes the
rest of that function correct made this one class unreachable. The count now comes
from the raw records through `_by_run`, which already existed for the
two-runs-versus-one-duplicate distinction.

EVERY SUITE, DELIBERATELY UNLIKE THE NEW-CHECK REFUSAL. That one is restricted to
covered suites because it cannot know which of an uncovered suite's checks are new.
This one needs no history: two records, one key, one log is decidable from the log
alone. The ledger covers four suites of 253, so copying the restriction would close
the class in four places only, and the next collision would sit in one of the other
249 until that suite was seeded.

--- AND THE LEDGER COULD NOT SEE TWO ROWS IN ONE FILE --------------------------

`read_ledger` did `rows[key] = [...]`, so a duplicated key in the tracked file
collapsed silently and the LAST line won. Measured on a two-line fixture, both
orders:

    never first, then 2026-09-01   survivor last_red='2026-09-01'
    2026-09-01 first, then never   survivor last_red='never'      the red is GONE

Line order decided whether a recorded red observation survived. A merge that keeps
both sides of a changed row turns `ever red` back into `never`.

NOTHING ELSE COULD CATCH IT, and bounding the census cannot. check_ledger_budget.txt
says `checks_never_observed_red` is a CENSUS and must not become a ceiling, because
every new check enters as `never` and bounding it deadlocks. The gate compares the
budget's number with the ledger's, and both come from the same dict, so they agree
either way. Measured: with the budget regenerated alongside, an erased red passes the
gate at rc=0. It is now refused as an integrity failure (rc=2), beside the other
inputs that do not parse.

So the two halves are the same shape at two levels. A SET hid two checks in one run;
a DICT hid two rows in one file. The question that found both is what the input
canonicalises before the guard sees it.

--- MEASURED BEFORE WIDENING IT -----------------------------------------------

A gate that reddens 250 unmeasured suites is a gate somebody turns off, so the
refusal was not widened on reasoning. A full PG 18 matrix ran with it armed for
every suite:

    247 suites ran, 6 skipped, 0 incomplete | ALL VERSIONS PASSED, RC=0 | 0 shared keys

Check names are static, so one major's matrix measures this class completely rather
than sampling it.

THE LOAD-BEARING EVIDENCE IS THAT RUN, not a log snapshot. An earlier draft of this
message cited "244 logs, 6651 records, 6651 distinct keys, 0 collisions" from
per-suite logs copied out of the build directory while the matrix was still running.
That figure is withdrawn: the copies were taken mid-write, and measuring the same way
again showed 150 of 253 had no `checks run:` line yet. Zero collisions across
truncated logs is not evidence of zero across complete ones. The full-matrix figure
stands because the gate reads the logs after each suite has finished.

It does still answer what commandprompt#982 said nobody had measured -- the gap between "checks
that ran" and "rows the ledger can hold" across the other 250 suites -- because the
gate saw every suite's complete log and refused nothing.

--- VERIFICATION --------------------------------------------------------------

The committed ledger still loads at 1197 rows. The gate against the COMMITTED ledger
and budget over a real 934-record harness_selftest log: rc=0, no shared-key line,
census agrees at 1189. A planted duplicate check: rc=1, naming the key. A planted
duplicate row: rc=2, naming the line and what it would lose.

The refusal arm also asserts no Traceback in the output, because an unhandled
exception exits 1 too and would satisfy an rc check on its own. Measured, it did: an
earlier draft referenced `covered_suites` before it was defined, which compiles and
fails at runtime.

guard_tests 277 -> 283, re-derived by collection. 283 passed / 698 checks with
--pgc-expect-tests 283 armed. docs_style.sh PASSED (11 checks). Long-sentence counts
unchanged: CHANGELOG 860, TESTS.md 319.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uf6UoeBRZYLQZa4KxNiw8a

--- AND A THIRD INSTANCE, IN THE ARM THAT POLICES THE OTHER TRACKED FILE -------

test_harness_deps.py read expected_tests.txt with `nums[f[0]] = int(f[1])`, so a
duplicated key collapsed and the last line won -- exactly as read_ledger did, one file
over. Measured on one fixture read both ways:

    the line form   names guard_tests as duplicated
    the dict form   sees two keys and keeps 280, the LAST line

NOT HYPOTHETICAL. Three PRs were open at once, each moving guard_tests, and resolving
all three keep-both produced three of those lines. ci.yml reads the value with
`awk '$1=="guard_tests"{print $2}'`, which prints one line per match. So WANT becomes
multi-line, `test -n "$WANT"` still passes, and the flag refuses it:

    pytest: error: argument --pgc-expect-tests: invalid int value: '284\n280\n283'
    exit 4

It FAILS CLOSED, so these two arms are about legibility rather than a hole. What exit 4
does not say is that a line is duplicated. The removal proof is on the real file: with a
duplicate planted, the new arm reddens and the pre-existing one stays green.

Keep-both is right for a changelog and wrong for a key-value file, and nothing in the
tree said so.

cluster_tests 205 -> 207, NOT guard_tests: test_harness_deps.py DEFINES NO_CLUSTER and
is not in it. I bumped the wrong number first and --pgc-expect-tests caught it --
`collected 283 test(s) but expected 285` -- which is the argument for the mechanism.
Both halves re-derived by collection: guard 283, cluster 207.

REBASED onto 14c9dd4 after commandprompt#1029 merged, and the conflict was the exact shape the third
arm here is about. `expected_tests.txt` conflicted on `guard_tests`:

    guard_tests 280     <- main, after commandprompt#1029
    guard_tests 283     <- this branch, from the old base

Keep-both would have produced two lines and, through ci.yml's
`awk '$1=="guard_tests"{print $2}'`, a multi-line value the flag refuses at exit 4. One
line, and both halves re-derived by collection rather than by arithmetic:

    guard_tests 286, cluster_tests 207

Re-verified: 286 passed / 707 checks with --pgc-expect-tests 286 armed; docs_style.sh
PASSED (11 checks); the gate against the committed ledger and budget over the real
934-record log still returns 0. Long-sentence counts unchanged against the new base:
CHANGELOG 860, TESTS.md 319.

--- FIXTURE CORRECTED AFTER REVIEW (@jdatcmd) -----------------------------------

test_the_gate_refuses_two_checks_sharing_one_ledger_key asserted rc == 1 on a
fixture where the gate returned 1 for TWO independent reasons, so the arm did not
discriminate. Found by mutation, and I reproduced it before changing anything:

    with `rc = 1` deleted from the shared-key block, the OLD fixture's arm PASSED
    with the same mutation, the corrected fixture's arm FAILS: got 0 want 1

The second route was the pre-existing new-check refusal. The ledger named only
`some other check` in that part, which made `demo` a covered suite whose log carried
a check the ledger had never seen:

    not in the ledger: demo   part1   shared name   (on major 18)

The ledger now NAMES `shared name`, so that refusal has nothing to say and only the
shared-key refusal can move rc.

This is the same defect class the PR is about, in my own arm: an assertion that
passes for a reason other than the one it is named for. My docstring claimed I had
measured this and closed it -- I had closed the COVERAGE-CEILING route and not the
new-check route, and the note said "routes" as though it were all of them. The
comment now enumerates all three, including the unhandled-exception route that also
exits 1.

It also described the refusal as "restricted to suites a row exists for", which was
the design I abandoned two pushes earlier when the matrix measurement said refusing
everywhere was safe. That sentence is gone.

--- REBASED onto 2ea7366 ------------------------------------------------------

guard_tests 293 and cluster_tests 207, both re-derived by COLLECTION on this base.

And a sharper point than the one I had, measured by @jdatcmd on commandprompt#1022: two branches
each derived `guard_tests 280` correctly, each against a tree holding only its own
three arms, and the merged value was 283. Both numbers were right for the tree they
were taken on and both were wrong for the merge. So "derive rather than add" is
necessary and not sufficient -- it has to be re-derived after every rebase, which
expected_tests.txt now says.

Re-verified: 293 passed / 725 checks with --pgc-expect-tests 293 armed; docs_style.sh
PASSED (11 checks); the gate against the committed ledger and budget over the real
934-record log returns 0; long-sentence counts unchanged at CHANGELOG 860 and
TESTS.md 319.

REBASED again onto 1d76ccf after commandprompt#1022 merged. Two hunks in expected_tests.txt, and the
second one is worth a note: my side carried the new `cluster_tests 207` comment PLUS two
stale fragments left by earlier keep-both resolutions of the same file ("177 -> 180",
"166 -> 182"), describing values the file no longer holds. Resolved to ONE coherent block
rather than the union, which is the same lesson the arms here are about: keep-both is
right for a changelog and wrong for a file where each key appears once.

guard_tests 296 and cluster_tests 207, both re-derived by collection on this base.
Re-verified: 296 passed / 733 checks armed; docs_style.sh PASSED; the gate over the real
934-record log returns 0.
OffgridwithJD pushed a commit to OffgridwithJD/pgcolumnar that referenced this pull request Sep 13, 2026
…one (commandprompt#982)

A ledger row is keyed on (suite, part, name). Two checks with the same name in one
part share a row, and two ROWS with the same key collapse into one. Neither is
mis-recorded while everything passes. Both lose a red observation the moment one
appears.

--- THE GATE COULD NOT SEE TWO CHECKS IN ONE RUN -------------------------------

`merge` has printed "duplicate check name in one run" since commandprompt#982 was filed and
returns 0, which is how three of them sat in one part of selftest/400 for a day. The
instance was fixed by c3b13ae; this is the mechanism the issue called the more
valuable half.

`cmd_gate` builds its records as `sorted({(s, p, n, m) for ...})`. A set collapses the
duplicate before any arm can count it, so the same canonicalisation that makes the
rest of that function correct made this one class unreachable. The count now comes
from the raw records through `_by_run`, which already existed for the
two-runs-versus-one-duplicate distinction.

EVERY SUITE, DELIBERATELY UNLIKE THE NEW-CHECK REFUSAL. That one is restricted to
covered suites because it cannot know which of an uncovered suite's checks are new.
This one needs no history: two records, one key, one log is decidable from the log
alone. The ledger covers four suites of 253, so copying the restriction would close
the class in four places only, and the next collision would sit in one of the other
249 until that suite was seeded.

--- AND THE LEDGER COULD NOT SEE TWO ROWS IN ONE FILE --------------------------

`read_ledger` did `rows[key] = [...]`, so a duplicated key in the tracked file
collapsed silently and the LAST line won. Measured on a two-line fixture, both
orders:

    never first, then 2026-09-01   survivor last_red='2026-09-01'
    2026-09-01 first, then never   survivor last_red='never'      the red is GONE

Line order decided whether a recorded red observation survived. A merge that keeps
both sides of a changed row turns `ever red` back into `never`.

NOTHING ELSE COULD CATCH IT, and bounding the census cannot. check_ledger_budget.txt
says `checks_never_observed_red` is a CENSUS and must not become a ceiling, because
every new check enters as `never` and bounding it deadlocks. The gate compares the
budget's number with the ledger's, and both come from the same dict, so they agree
either way. Measured: with the budget regenerated alongside, an erased red passes the
gate at rc=0. It is now refused as an integrity failure (rc=2), beside the other
inputs that do not parse.

So the two halves are the same shape at two levels. A SET hid two checks in one run;
a DICT hid two rows in one file. The question that found both is what the input
canonicalises before the guard sees it.

--- MEASURED BEFORE WIDENING IT -----------------------------------------------

A gate that reddens 250 unmeasured suites is a gate somebody turns off, so the
refusal was not widened on reasoning. A full PG 18 matrix ran with it armed for
every suite:

    247 suites ran, 6 skipped, 0 incomplete | ALL VERSIONS PASSED, RC=0 | 0 shared keys

Check names are static, so one major's matrix measures this class completely rather
than sampling it.

THE LOAD-BEARING EVIDENCE IS THAT RUN, not a log snapshot. An earlier draft of this
message cited "244 logs, 6651 records, 6651 distinct keys, 0 collisions" from
per-suite logs copied out of the build directory while the matrix was still running.
That figure is withdrawn: the copies were taken mid-write, and measuring the same way
again showed 150 of 253 had no `checks run:` line yet. Zero collisions across
truncated logs is not evidence of zero across complete ones. The full-matrix figure
stands because the gate reads the logs after each suite has finished.

It does still answer what commandprompt#982 said nobody had measured -- the gap between "checks
that ran" and "rows the ledger can hold" across the other 250 suites -- because the
gate saw every suite's complete log and refused nothing.

--- VERIFICATION --------------------------------------------------------------

The committed ledger still loads at 1197 rows. The gate against the COMMITTED ledger
and budget over a real 934-record harness_selftest log: rc=0, no shared-key line,
census agrees at 1189. A planted duplicate check: rc=1, naming the key. A planted
duplicate row: rc=2, naming the line and what it would lose.

The refusal arm also asserts no Traceback in the output, because an unhandled
exception exits 1 too and would satisfy an rc check on its own. Measured, it did: an
earlier draft referenced `covered_suites` before it was defined, which compiles and
fails at runtime.

guard_tests 277 -> 283, re-derived by collection. 283 passed / 698 checks with
--pgc-expect-tests 283 armed. docs_style.sh PASSED (11 checks). Long-sentence counts
unchanged: CHANGELOG 860, TESTS.md 319.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uf6UoeBRZYLQZa4KxNiw8a

--- AND A THIRD INSTANCE, IN THE ARM THAT POLICES THE OTHER TRACKED FILE -------

test_harness_deps.py read expected_tests.txt with `nums[f[0]] = int(f[1])`, so a
duplicated key collapsed and the last line won -- exactly as read_ledger did, one file
over. Measured on one fixture read both ways:

    the line form   names guard_tests as duplicated
    the dict form   sees two keys and keeps 280, the LAST line

NOT HYPOTHETICAL. Three PRs were open at once, each moving guard_tests, and resolving
all three keep-both produced three of those lines. ci.yml reads the value with
`awk '$1=="guard_tests"{print $2}'`, which prints one line per match. So WANT becomes
multi-line, `test -n "$WANT"` still passes, and the flag refuses it:

    pytest: error: argument --pgc-expect-tests: invalid int value: '284\n280\n283'
    exit 4

It FAILS CLOSED, so these two arms are about legibility rather than a hole. What exit 4
does not say is that a line is duplicated. The removal proof is on the real file: with a
duplicate planted, the new arm reddens and the pre-existing one stays green.

Keep-both is right for a changelog and wrong for a key-value file, and nothing in the
tree said so.

cluster_tests 205 -> 207, NOT guard_tests: test_harness_deps.py DEFINES NO_CLUSTER and
is not in it. I bumped the wrong number first and --pgc-expect-tests caught it --
`collected 283 test(s) but expected 285` -- which is the argument for the mechanism.
Both halves re-derived by collection: guard 283, cluster 207.

REBASED onto 14c9dd4 after commandprompt#1029 merged, and the conflict was the exact shape the third
arm here is about. `expected_tests.txt` conflicted on `guard_tests`:

    guard_tests 280     <- main, after commandprompt#1029
    guard_tests 283     <- this branch, from the old base

Keep-both would have produced two lines and, through ci.yml's
`awk '$1=="guard_tests"{print $2}'`, a multi-line value the flag refuses at exit 4. One
line, and both halves re-derived by collection rather than by arithmetic:

    guard_tests 286, cluster_tests 207

Re-verified: 286 passed / 707 checks with --pgc-expect-tests 286 armed; docs_style.sh
PASSED (11 checks); the gate against the committed ledger and budget over the real
934-record log still returns 0. Long-sentence counts unchanged against the new base:
CHANGELOG 860, TESTS.md 319.

--- FIXTURE CORRECTED AFTER REVIEW (@jdatcmd) -----------------------------------

test_the_gate_refuses_two_checks_sharing_one_ledger_key asserted rc == 1 on a
fixture where the gate returned 1 for TWO independent reasons, so the arm did not
discriminate. Found by mutation, and I reproduced it before changing anything:

    with `rc = 1` deleted from the shared-key block, the OLD fixture's arm PASSED
    with the same mutation, the corrected fixture's arm FAILS: got 0 want 1

The second route was the pre-existing new-check refusal. The ledger named only
`some other check` in that part, which made `demo` a covered suite whose log carried
a check the ledger had never seen:

    not in the ledger: demo   part1   shared name   (on major 18)

The ledger now NAMES `shared name`, so that refusal has nothing to say and only the
shared-key refusal can move rc.

This is the same defect class the PR is about, in my own arm: an assertion that
passes for a reason other than the one it is named for. My docstring claimed I had
measured this and closed it -- I had closed the COVERAGE-CEILING route and not the
new-check route, and the note said "routes" as though it were all of them. The
comment now enumerates all three, including the unhandled-exception route that also
exits 1.

It also described the refusal as "restricted to suites a row exists for", which was
the design I abandoned two pushes earlier when the matrix measurement said refusing
everywhere was safe. That sentence is gone.

--- REBASED onto 2ea7366 ------------------------------------------------------

guard_tests 293 and cluster_tests 207, both re-derived by COLLECTION on this base.

And a sharper point than the one I had, measured by @jdatcmd on commandprompt#1022: two branches
each derived `guard_tests 280` correctly, each against a tree holding only its own
three arms, and the merged value was 283. Both numbers were right for the tree they
were taken on and both were wrong for the merge. So "derive rather than add" is
necessary and not sufficient -- it has to be re-derived after every rebase, which
expected_tests.txt now says.

Re-verified: 293 passed / 725 checks with --pgc-expect-tests 293 armed; docs_style.sh
PASSED (11 checks); the gate against the committed ledger and budget over the real
934-record log returns 0; long-sentence counts unchanged at CHANGELOG 860 and
TESTS.md 319.

REBASED again onto 1d76ccf after commandprompt#1022 merged. Two hunks in expected_tests.txt, and the
second one is worth a note: my side carried the new `cluster_tests 207` comment PLUS two
stale fragments left by earlier keep-both resolutions of the same file ("177 -> 180",
"166 -> 182"), describing values the file no longer holds. Resolved to ONE coherent block
rather than the union, which is the same lesson the arms here are about: keep-both is
right for a changelog and wrong for a file where each key appears once.

guard_tests 296 and cluster_tests 207, both re-derived by collection on this base.
Re-verified: 296 passed / 733 checks armed; docs_style.sh PASSED; the gate over the real
934-record log returns 0.
OffgridwithJD pushed a commit to OffgridwithJD/pgcolumnar that referenced this pull request Sep 13, 2026
…one (commandprompt#982)

A ledger row is keyed on (suite, part, name). Two checks with the same name in one
part share a row, and two ROWS with the same key collapse into one. Neither is
mis-recorded while everything passes. Both lose a red observation the moment one
appears.

--- THE GATE COULD NOT SEE TWO CHECKS IN ONE RUN -------------------------------

`merge` has printed "duplicate check name in one run" since commandprompt#982 was filed and
returns 0, which is how three of them sat in one part of selftest/400 for a day. The
instance was fixed by c3b13ae; this is the mechanism the issue called the more
valuable half.

`cmd_gate` builds its records as `sorted({(s, p, n, m) for ...})`. A set collapses the
duplicate before any arm can count it, so the same canonicalisation that makes the
rest of that function correct made this one class unreachable. The count now comes
from the raw records through `_by_run`, which already existed for the
two-runs-versus-one-duplicate distinction.

EVERY SUITE, DELIBERATELY UNLIKE THE NEW-CHECK REFUSAL. That one is restricted to
covered suites because it cannot know which of an uncovered suite's checks are new.
This one needs no history: two records, one key, one log is decidable from the log
alone. The ledger covers four suites of 253, so copying the restriction would close
the class in four places only, and the next collision would sit in one of the other
249 until that suite was seeded.

--- AND THE LEDGER COULD NOT SEE TWO ROWS IN ONE FILE --------------------------

`read_ledger` did `rows[key] = [...]`, so a duplicated key in the tracked file
collapsed silently and the LAST line won. Measured on a two-line fixture, both
orders:

    never first, then 2026-09-01   survivor last_red='2026-09-01'
    2026-09-01 first, then never   survivor last_red='never'      the red is GONE

Line order decided whether a recorded red observation survived. A merge that keeps
both sides of a changed row turns `ever red` back into `never`.

NOTHING ELSE COULD CATCH IT, and bounding the census cannot. check_ledger_budget.txt
says `checks_never_observed_red` is a CENSUS and must not become a ceiling, because
every new check enters as `never` and bounding it deadlocks. The gate compares the
budget's number with the ledger's, and both come from the same dict, so they agree
either way. Measured: with the budget regenerated alongside, an erased red passes the
gate at rc=0. It is now refused as an integrity failure (rc=2), beside the other
inputs that do not parse.

So the two halves are the same shape at two levels. A SET hid two checks in one run;
a DICT hid two rows in one file. The question that found both is what the input
canonicalises before the guard sees it.

--- MEASURED BEFORE WIDENING IT -----------------------------------------------

A gate that reddens 250 unmeasured suites is a gate somebody turns off, so the
refusal was not widened on reasoning. A full PG 18 matrix ran with it armed for
every suite:

    247 suites ran, 6 skipped, 0 incomplete | ALL VERSIONS PASSED, RC=0 | 0 shared keys

Check names are static, so one major's matrix measures this class completely rather
than sampling it.

THE LOAD-BEARING EVIDENCE IS THAT RUN, not a log snapshot. An earlier draft of this
message cited "244 logs, 6651 records, 6651 distinct keys, 0 collisions" from
per-suite logs copied out of the build directory while the matrix was still running.
That figure is withdrawn: the copies were taken mid-write, and measuring the same way
again showed 150 of 253 had no `checks run:` line yet. Zero collisions across
truncated logs is not evidence of zero across complete ones. The full-matrix figure
stands because the gate reads the logs after each suite has finished.

It does still answer what commandprompt#982 said nobody had measured -- the gap between "checks
that ran" and "rows the ledger can hold" across the other 250 suites -- because the
gate saw every suite's complete log and refused nothing.

--- VERIFICATION --------------------------------------------------------------

The committed ledger still loads at 1197 rows. The gate against the COMMITTED ledger
and budget over a real 934-record harness_selftest log: rc=0, no shared-key line,
census agrees at 1189. A planted duplicate check: rc=1, naming the key. A planted
duplicate row: rc=2, naming the line and what it would lose.

The refusal arm also asserts no Traceback in the output, because an unhandled
exception exits 1 too and would satisfy an rc check on its own. Measured, it did: an
earlier draft referenced `covered_suites` before it was defined, which compiles and
fails at runtime.

guard_tests 277 -> 283, re-derived by collection. 283 passed / 698 checks with
--pgc-expect-tests 283 armed. docs_style.sh PASSED (11 checks). Long-sentence counts
unchanged: CHANGELOG 860, TESTS.md 319.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uf6UoeBRZYLQZa4KxNiw8a

--- AND A THIRD INSTANCE, IN THE ARM THAT POLICES THE OTHER TRACKED FILE -------

test_harness_deps.py read expected_tests.txt with `nums[f[0]] = int(f[1])`, so a
duplicated key collapsed and the last line won -- exactly as read_ledger did, one file
over. Measured on one fixture read both ways:

    the line form   names guard_tests as duplicated
    the dict form   sees two keys and keeps 280, the LAST line

NOT HYPOTHETICAL. Three PRs were open at once, each moving guard_tests, and resolving
all three keep-both produced three of those lines. ci.yml reads the value with
`awk '$1=="guard_tests"{print $2}'`, which prints one line per match. So WANT becomes
multi-line, `test -n "$WANT"` still passes, and the flag refuses it:

    pytest: error: argument --pgc-expect-tests: invalid int value: '284\n280\n283'
    exit 4

It FAILS CLOSED, so these two arms are about legibility rather than a hole. What exit 4
does not say is that a line is duplicated. The removal proof is on the real file: with a
duplicate planted, the new arm reddens and the pre-existing one stays green.

Keep-both is right for a changelog and wrong for a key-value file, and nothing in the
tree said so.

cluster_tests 205 -> 207, NOT guard_tests: test_harness_deps.py DEFINES NO_CLUSTER and
is not in it. I bumped the wrong number first and --pgc-expect-tests caught it --
`collected 283 test(s) but expected 285` -- which is the argument for the mechanism.
Both halves re-derived by collection: guard 283, cluster 207.

REBASED onto 14c9dd4 after commandprompt#1029 merged, and the conflict was the exact shape the third
arm here is about. `expected_tests.txt` conflicted on `guard_tests`:

    guard_tests 280     <- main, after commandprompt#1029
    guard_tests 283     <- this branch, from the old base

Keep-both would have produced two lines and, through ci.yml's
`awk '$1=="guard_tests"{print $2}'`, a multi-line value the flag refuses at exit 4. One
line, and both halves re-derived by collection rather than by arithmetic:

    guard_tests 286, cluster_tests 207

Re-verified: 286 passed / 707 checks with --pgc-expect-tests 286 armed; docs_style.sh
PASSED (11 checks); the gate against the committed ledger and budget over the real
934-record log still returns 0. Long-sentence counts unchanged against the new base:
CHANGELOG 860, TESTS.md 319.

--- FIXTURE CORRECTED AFTER REVIEW (@jdatcmd) -----------------------------------

test_the_gate_refuses_two_checks_sharing_one_ledger_key asserted rc == 1 on a
fixture where the gate returned 1 for TWO independent reasons, so the arm did not
discriminate. Found by mutation, and I reproduced it before changing anything:

    with `rc = 1` deleted from the shared-key block, the OLD fixture's arm PASSED
    with the same mutation, the corrected fixture's arm FAILS: got 0 want 1

The second route was the pre-existing new-check refusal. The ledger named only
`some other check` in that part, which made `demo` a covered suite whose log carried
a check the ledger had never seen:

    not in the ledger: demo   part1   shared name   (on major 18)

The ledger now NAMES `shared name`, so that refusal has nothing to say and only the
shared-key refusal can move rc.

This is the same defect class the PR is about, in my own arm: an assertion that
passes for a reason other than the one it is named for. My docstring claimed I had
measured this and closed it -- I had closed the COVERAGE-CEILING route and not the
new-check route, and the note said "routes" as though it were all of them. The
comment now enumerates all three, including the unhandled-exception route that also
exits 1.

It also described the refusal as "restricted to suites a row exists for", which was
the design I abandoned two pushes earlier when the matrix measurement said refusing
everywhere was safe. That sentence is gone.

--- REBASED onto 2ea7366 ------------------------------------------------------

guard_tests 293 and cluster_tests 207, both re-derived by COLLECTION on this base.

And a sharper point than the one I had, measured by @jdatcmd on commandprompt#1022: two branches
each derived `guard_tests 280` correctly, each against a tree holding only its own
three arms, and the merged value was 283. Both numbers were right for the tree they
were taken on and both were wrong for the merge. So "derive rather than add" is
necessary and not sufficient -- it has to be re-derived after every rebase, which
expected_tests.txt now says.

Re-verified: 293 passed / 725 checks with --pgc-expect-tests 293 armed; docs_style.sh
PASSED (11 checks); the gate against the committed ledger and budget over the real
934-record log returns 0; long-sentence counts unchanged at CHANGELOG 860 and
TESTS.md 319.

REBASED again onto 1d76ccf after commandprompt#1022 merged. Two hunks in expected_tests.txt, and the
second one is worth a note: my side carried the new `cluster_tests 207` comment PLUS two
stale fragments left by earlier keep-both resolutions of the same file ("177 -> 180",
"166 -> 182"), describing values the file no longer holds. Resolved to ONE coherent block
rather than the union, which is the same lesson the arms here are about: keep-both is
right for a changelog and wrong for a file where each key appears once.

guard_tests 296 and cluster_tests 207, both re-derived by collection on this base.
Re-verified: 296 passed / 733 checks armed; docs_style.sh PASSED; the gate over the real
934-record log returns 0.
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.

3 participants