Let the card check tell a site that grew from a wrong card - #212
Merged
Merged
Conversation
This was referenced Sep 25, 2026
Closed
realmarcin
force-pushed
the
fix/card-check-semantics
branch
from
September 25, 2026 20:48
1710250 to
b008369
Compare
This was referenced Sep 25, 2026
realmarcin
force-pushed
the
fix/card-check-semantics
branch
from
September 25, 2026 21:05
b008369 to
c15af8a
Compare
This was referenced Sep 25, 2026
check_cards: a figure_at_pin that is a string or float, or missing, silently switches WRONG off
#260
Closed
The nightly check failed on every card a fast Mech had outgrown since the refresh's pins, and passed on a source that returned 404, lost its figure, or could not be reached at all. It now warns on a site up to 10% ahead of its card and fails past that, on a site behind its card, on a 4xx, on a source with no readable figure, on an unpaired card or SOURCES entry, and when more than half the sources are unread (#148, #113, #115, #176). CultureMech's figure is read only from the README block its generator writes (#176). The cards are now parsed once, card by card, in card_markup.py, which the assembler, the check and the tests share, so a card without a figure is missing rather than reading its neighbour's (#114). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A 10% allowance went red a day after every refresh, because CellStructureMech adds about 9% a day, and it let a card mistyped inside 10% pass (#217). Growth now warns for 14 days after the pins in site_audit.json while the site is at most half as large again as the card, and a card that differs from a source still byte-identical to its pin fails as WRONG. Throttles (408, 425, 429) and a connection dropped mid-body are unread, not GONE or a traceback (#219, #220). A card without exactly one headline figure, or a figure outside every card, is a MARKUP failure here and an error in the assembler (#218). The update skill derives audit figures through read_source(), which applies REGIONS (#221), and the tests cover the parse-exception path, the more-than-half boundary and a half-marked region (#222). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
WRONG compared the live source's hash with its pinned copy, so it stopped working the moment a source changed at all, and five of ten already had (#231). site_audit.json now records figure_at_pin, read from each source's committed copy at the pin with check_cards.figure(), the nightly's own parser; a test requires it to equal the card, so a typo fails on the PR, and the nightly reports WRONG from it however far the site has moved. A pin time with no offset is UTC and an unreadable one is an AUDIT failure, not a traceback (#232). The docstring states the lead limit the code applies (#233), the tests cover the assembler's stray-figure refusal, more 4xx codes and main()'s exit for WRONG, STALE and UNCHECKED (#234), and the README names every failing verdict's remedy (#235). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…remedy A mistyped card fails the provenance tests first, and the card check used to be skipped with them, so its WRONG line and every other card's verdict never printed; the step now runs unless the job was cancelled (#239). WRONG's remedy is to correct the card or the audit, not a full refresh (#240). The README's remedy list no longer swallows the next paragraph (#241). A pin time in the future is an AUDIT failure, and the provenance test bounds it by the newest pinned commit and the check (#242). The tests pin the 14-day grace, a missing pin time, AUDIT on its own, "no offset means UTC" under a non-UTC zone, and the 400/499/500 edges (#243). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ve a bad audit CultureMech's CHANGED detail said its missing generated block was "found" (#247). WRONG's remedy names every copy of a card figure and says to rerun the assembler, and a new test holds each MECHS records: to its card (#248). A missing or malformed site_audit.json is an AUDIT row instead of a traceback, so the rest of the report prints (#250). The tests assert the remedy text, AUDIT on its own, a pin a minute ahead and an overstated WRONG card (#249). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…he figure
An audit of null, {} or one without repositories got no AUDIT row: grown sites
read STALE and a mistyped card could pass (#257). WRONG's remedy now says to grep
the tree for the old figure, as the update skill's step 6 does, since it also
appears in the MECHS extra: prose and cross-references (#258). The tests cover
those audit shapes and the remedy's content (#259).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…at_pin
A second tile with a stray space escaped the one-figure rule, and "<b>,</b>"
parsed and then crashed int(""); the parser now counts every headline tile and
reads a figure only when it starts with a digit (#261). A second card for one
Mech is MARKUP, not a card the nightly silently skips (#262). A figure_at_pin
that is a string, float or missing is an AUDIT row, and the provenance test
requires an int (#260). The review skill names both growth limits (#263).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
realmarcin
force-pushed
the
fix/card-check-semantics
branch
from
September 25, 2026 21:45
d14a066 to
e6437e3
Compare
"32,06" was read as 3206 and passed every gate while the page showed it malformed; a figure is now plain digits or digits grouped in threes (#264). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #148, closes #113, closes #115, closes #176, closes #114, closes #217, closes #218, closes #219, closes #220, closes #221, closes #222, closes #231, closes #232, closes #233, closes #234, closes #235, closes #239, closes #240, closes #241, closes #242, closes #243, closes #247, closes #248, closes #249, closes #250, closes #257, closes #258, closes #259, closes #260, closes #261, closes #262, closes #263, closes #264.
What changes
scripts/fleet/check_cards.pysorts each card into one verdict, judged against_fleet/data/site_audit.json, which the refresh writes:pinned_at_utc(GRACE_DAYS), and at most 50% ahead (MAX_LEAD)figure_at_pin, the figure the audit read from the source's committed copy at the pinSOURCESentry, or the reversesite_audit.jsonmissing or malformed (includingnull,{}or norepositories), afigure_at_pinmissing or not a whole number, orpinned_at_utcmissing, unreadable or in the future (a time with no offset is taken as UTC)check_cards.py cannot tell a site that grew past a pinned card from a wrong card #148, The nightly card check stays red for Mechs that publish after a refresh's pins #113, The 10% growth tolerance goes red a day after a refresh, and passes a card mistyped inside 10% #217: the page is a snapshot at a refresh's pins, and fast Mechs publish within hours of them. A fixed 10% allowance (round 1 of this PR) went red a day after every refresh, because CellStructureMech adds about 9% a day. It also passed a card mistyped inside 10%.
figure_at_pin, whichsite_audit.jsonnow records for the nine sources with a committed copy. A test requires it to equal each card, so a typo fails on the PR, and the nightly reports it however far the site has moved. Round 2's version compared the source's hash with its pinned copy, which stopped working as soon as a source changed at all (check_cards: WRONG fires only while a source is byte-identical to its pin, so a mistyped card on a moved source passes #231).check_cards.py passes when a source returns 404 or its wording changes, against its own docstring #176: CultureMech's figure is read only between its GENERATED CORPUS STATS markers (
REGIONS).The card markup is parsed by three independent regexes #114, check_cards: an extra card figure is accepted, and a card with an unreadable figure is reported as missing #218: the new
scripts/fleet/card_markup.pyis the one card parser.assemble_page.pyrefuses a card without exactly one figure, as it did before this PR. A card with an unreadable figure is reported as MARKUP, not as a missing card.Docs:
_fleet/README.mdand both skills are updated. Step 7 of the update skill now derives audit figures throughread_source(), which appliesREGIONS(update skill step 7 derives the audit figure through check_cards.published(), which skips REGIONS #221). Step 8 says what grew and STALE mean.The nightly now runs the card check even when an earlier step failed. A mistyped card fails the provenance tests first, and the card report, with its WRONG line and every other card's verdict, still prints (The nightly skips check_cards.py whenever a unit test fails, so WRONG and AUDIT never print in CI #239). WRONG's remedy is to correct every occurrence of the figure, found by grepping the tree for it, not a refresh (check_cards: the closing line sends a WRONG card to a full refresh; the README gives it its own remedy #240, check_cards: WRONG's remedy names only the card, but its figure is repeated in the MECHS block and on other pages #248, check_cards: WRONG's remedy claims to name every copy of a card figure but misses MECHS extra: prose and cross-reference text #258).
Review history: five internal review rounds, then a Codex review, which found check_cards: a figure_at_pin that is a string or float, or missing, silently switches WRONG off #260 to review-open-issues skill says a growing card only warns for 14 days, leaving out the 50% lead limit #263, then a verification round, which found card_markup accepts a figure with misplaced commas, such as 32,06 #264. All are fixed here.
Evidence
python3 -m unittest discover -s tests: 74 tests pass. That includes a new test holding each MECHSrecords:to its card (check_cards: WRONG's remedy names only the card, but its figure is repeated in the MECHS block and on other pages #248).CardCheckTestscovers every verdict, the grace and lead boundaries, 429/408/425/503, a truncated body, a json source serving HTML, the 5-of-10 and 6-of-10 unread boundary, a half-marked region, three markup defects, andmain()'s exit code (check_cards tests miss the parse-exception path, the more-than-half boundary and a half-marked region #222).python3 scripts/fleet/assemble_page.py --check:mechs.mdis unchanged.Judgement calls
figure_at_pin. Its data file is built in CI, so there is no committed copy at the pin. Its card is checked only against the live site.figure_at_pinin the current audit was read from the committed copies at the Refresh the X-Mech page from the Mechs as they are now, and add the skill that does it #120 pins in the refresh snapshot. Each copy's sha256 matched the audit's recorded*_sha256_at_pin, and each figure equals its card.🤖 Generated with Claude Code