Repository navigation
Conversation
Pins the documentation the SIPP income-and-resources registry is verified
against, with no microdata requested or opened:
- the Census SIPP variable API for 2022-2025 (2018-2021 return HTTP 404;
the 404 bodies are kept);
- each release's data dictionary PDF, its pdftotext layout and the parsed
per-variable metadata, the public-use and replicate storage schemas,
the replicate dictionaries and Census's Python input examples;
- the locator pages they were found from.
capture_manifest.{txt,json} records every URL, UTC retrieval time, byte
size and SHA-256; derived_manifest.json pins the derived files and the
parser. The parser now refuses an inverted range (min above max) instead
of admitting an empty domain: the 2021 dictionary prints EHRESIDENCID as
"Minimum 100001, Maximum 40999". A folder .gitattributes keeps the CRLF
pages and input examples byte-identical to their pinned hashes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sipp_income_registry.py embeds, per release 2018-2025, each admitted
concept's Census name, label, type, value codes and ranges, generated by
data/external/sipp_income/build_registry.py from the committed metadata
only (API for 2022-2025, the release dictionary and storage schema for
2018-2021). Unknown releases, concepts and codes raise; a concept absent,
suppressed or without a verified domain in a release is refused there,
with the reason in refused_concepts.json.
sipp_income.py reads a pipe-delimited pu{year} file with usecols, every
column as a string first, then validates each token against that
release's exact domain before conversion. SSUID stays a string; the
person key is panel:SSUID:PNUM; replicate weights attach many-to-one on
SSUID, PNUM and MONTHCODE only when the sidecar's keys are unique and
complete and REPWGT0 equals WPFINWGT.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Invented pipe-delimited files only (INVENTED_* names); no staging directory is read. Covers column selection, dtypes, refusal of unverified releases, concepts and codes, release-specific sentinels, the entry-year and roster crosswalks, replicate linkage, and Hypothesis properties: row count and order preserved, person ids stable across months and waves, weights carried unchanged, unverified codes refused. The evidence tests replay the registry from the committed metadata. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…otes Verification now uses every Census source a release has and records each disagreement: - 2018-2021 labels come from the release dictionary (the verifying source); the storage-schema label is kept and checked against it. Four conflicts: 2018 EJSOWNRE/EJSOWNRP resolve to the dictionary on Census's user note; 2020 TDIS6AMT (state vs local) and EDIS8MNYN (military vs railroad) stay open and are refused. - 2022-2025 values must satisfy both the variable API and the release dictionary (API missing codes exempt). This admits GHLFSAM and GVARSTR, whose API entries list only a missing code, and narrows owner pointers to Census's documented codes (domain_checks.json lists all 72 cases). - source_rulings.json holds every hand ruling with its evidence; the generator stops on an unruled label conflict. Open: ESSI_BRSN in 2021 and 2022 (code order flips against Census's 2018 correction note) and 70 joint-asset concept-years in 2020 whose metadata predate Census's 2020 joint-assets note. - TSSSAMT for 2018-2021 is gated on the download date: Census re-released those files on 2025-07-24 with corrected amounts under the same names. - Captured the release notes, Census's 2018-2022 crosswalks, the 2018 metadata and topic dictionaries, and screened all 355 user-note pages; the 109 naming an admitted variable are stored and attached per concept. - release_changes.json lists every change in name, label, universe, codes, domain, missing codes or admission across releases. - Census's input examples are stored as .py.txt (bytes unchanged) so the repository-wide black and ruff checks skip them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…walk Unit tier (107, invented pipe-delimited files only): - design codes in 2022-2025 come from the dictionary when the API lists only a missing code; a value one source admits and the other does not refuses (owner pointers 70 versus 80); - the TSSSAMT gate refuses 2018-2021 reads without, or before, a 2025-07-24 download date, before any file is opened; - ESSI_BRSN, the 2020 joint families and the 2020 disability sources are refused where their sources conflict; universes travel per release; - Hypothesis: row count and order preserved, person ids stable across months, waves and releases, weights and replicate weights carried unchanged, an unverified code always refuses, and a differential test that the reader admits exactly what an independent restatement of the domain rule admits (400 examples over every numeric concept). Artifact tier (72): the registry replays from each release's own metadata; schema labels agree with the dictionary or carry a ruling; every refusal has a cause in the evidence; each ruling's claim appears in the Census note it cites; the crosswalk agrees with Census's 2018-2022 crosswalk workbooks except one recorded Census anomaly; the change ledger holds the documented universe and label changes; user notes, captures, derived files and the regenerated tables match their pins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The variable API documents a missing code for WPFINWGT in 2022-2025 (-99900000000 in 2022, -999.00000000 in 2023-2025). The reader admitted it as a value and never checked the weight, so a file carrying it would have entered with a weight of -999. Every structural key and the weight must now be present and differ from each of that release's documented missing codes, compared as decimals. A parametrized test covers all 32 documented key and weight missing codes; on the previous reader the four weight cases loaded without error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
metadata_notes.md now records the captures, the per-release verification rules, every ruling and open question, and the Census anomalies found. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two adversarial reviews (code, and claims against the Census evidence) found problems; each fixed one was reproduced first. Reader (sipp_income.py): - Count fields on every line before parsing. With usecols pandas stops checking, so a short row's missing fields read as structural blanks and an extra field shifted values between columns. Repeated header names and corrupt or truncated gzip files also refuse. - Tokens must be plain ASCII decimals, and string-stored identifiers the dictionary's fixed-width digits (SSUID 14, ERESIDENCEID 6, SHHADID 3, GVARSTR 3, GHLFSAM 2). Decimal() accepted "+11", "1.2345E4", "0_1" and full-width digits, which split one key into several or put the record value into a pandas error message. - downloaded_on accepts a datetime. Registry and generator: - Blanks are refused for items whose universe is all persons or all households (citizenship, nativity, household status, design codes). - 2022-2025 API labels are checked against the dictionary too (no conflicts); a variable one source suppresses and another documents is a ruled conflict (2018 EDIS8MNYN, open). - 2018 EJSOWNRE/EJSOWNRP take label and universe verbatim from Census's correcting user note; the dictionary's EJSOWNRP universe read "or". - Misprinted universes are cleared under cited rulings: 2021 ERETTYPnYN (empty as printed) and 2024-2025 TRET1AMT-TRET7AMT (all name source 8). - The dictionary parser reads comma-grouped codes (TSCNTAMT1/2's 9,999,999 special code now verifies and is labelled) and marks 2018-2020 entries whose value list runs onto an unjoined page as unverified (30, 33 and 33 entries; none selected). - Census record levels: SSI spell items and child Social Security flags are person-month (period monthly); ETENURE and TLIVQTR household; SSUID, SPANEL, SWAVE design keys; EHRESIDENCID person. - The registry embeds its tables as one JSON string literal, so regeneration needs no formatter pass over megabytes of tables. - Text corrections: 101 user notes are stored (plus 8 index pages; the earlier commit said 109 notes), the 2020 joint-debt treatment, the roster slot 15 years, the ERETANY and TSSAGESS changes, and the correction ruling no longer claims unchanged file names. Tests: the evidence suite passes (77) with an independent boundary probe of every API-dictionary difference and a record-level check; reader tests gain layout, spelling, universe-blank, datetime and string-identifier differential cases (full reader run pending on a loaded host). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Attempt a2 stopped on a network error while rerunning the reader tests; these edits have not yet passed that run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Eight design-code cases now supply zero-padded tokens and check that an unpadded token is refused; the ninth expects the recorded Census correction note as the label source. The notes' count of concept-years where the API and dictionary domains differ is 64, not 72. Co-Authored-By: Codex <noreply@openai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The birth-evidence identity check seals every source under src/populace_dynamics except listed opt-in modules. List the two new reader modules as post-review exclusions, in the test's expected tuple, and in the reachability test, which asserts the historical reducer cannot import them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Record-bearing user notes (high). Eight stored Census user notes carried individual survey identifiers with case values. Their whole-page captures are removed. The note inventory keeps each one's URL, title, release and variables, marked excluded with no stored body. The capture script now refuses those URLs before any request and refuses any note page whose tables or text carry identifier columns or identifiers followed by values. A test checks every stored capture with that guard, and its failure message names only the file. The evidence pins drop the eight bodies, and metadata_notes.md corrects its claim and its counts (93 stored notes). CSV quoting (medium). The reader's pandas call now passes csv.QUOTE_NONE, so its record boundaries agree with the physical-line layout validator. A quote in an unselected field can no longer absorb the next person-month. Adds the minimized invented regression and a property with quotes in selected and unselected fields. Domain rulings (medium). source_rulings.json gains 13 named domain-conflict rulings covering all 64 API/dictionary disagreements, each listing its members and citing both sources' locations. The generator now refuses a disagreement without an exact, cited, settled ruling. Every admitted domain is unchanged: only the ruling references and their pins move. Also adds Hypothesis properties for the vintage gate, malformed layouts, replicate keys and the registry's source-conflict, ownership and evidence-pin invariants, on invented inputs through the production code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
M1, the capture guard. record_bearing_note now refuses a page holding any of these forms, and its docstring lists them: - a column headed by an identifier name, including a heading that opens with one, such as "SSUID (sample unit)"; - a table row with an identifier name and, in another cell, three or more digits, even in a variable-definition table; - a table row of three or more numeric cells; - an identifier name followed by digits with only punctuation between, or by three or more digits within 40 characters of the same sentence, in the text or inside an HTML comment, which is stored though not shown; - a run of nine or more digits in the text a reader sees; - a preformatted block naming an identifier and holding a digit. Variable-definition rows and prose may still name an identifier without a value. Tests add 16 invented record pages, which the guard refuses (the parent guard missed 13 of them), and 4 invented definition pages, which it admits. Three properties cover identifier-and-value sentences, long digit runs where rendered, and rows of three numbers. Every stored user note still passes the guard. metadata_notes.md now states the guard as these forms. M2, physical records. _check_layout strips one LF and then one CR from each line, and refuses any other carriage return in a record. The line check and pandas therefore see the same records: QUOTE_NONE already kept quotes from joining lines, and a lone CR can no longer split one. Tests add the review's minimized regression (two invented rows joined by a CR in an unselected field, which gave two person-months before), a CRLF file that keeps every record, and a carriage return in the quote property's alphabet. The property expects one row per LF-delimited data line, or a refusal. L1. The THEQ_BUS ruling's reason now describes the printed range as it is: its upper bound is malformed, and its lower bound differs from the API's. The registry pin of source_rulings.json is regenerated. L2. build_registry checks that a ruling member's PDF citations name its own release's dictionary at exactly the pages its dictionary entry holds. The invented ruling cites its page, and the damage property adds a wrong page and another release's PDF. Invariants: - No stored page shows a form record_bearing_note refuses. - The reader yields one person-month per LF-delimited data line, or refuses. - Every ruling member's PDF citations equal its dictionary pages. Tests (invented data only): test_sipp_income 183 passed; test_sipp_income_evidence 106 passed; test_sipp_income_refusal_properties 6 passed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Round 4 approved 7521c6d with seven low findings and four notes. This commit answers each. L1, rules without a failing test. Every invented record page carried the 15-digit invented SSUID, so the digit-run rules refused each page before the rule it was meant to test. INVENTED_RULE_TWINS pairs a refused page with a twin that differs only in what one rule reads, and the test requires the rule to refuse the page and admit the twin. There are eight pairs: an identifier beside a three-digit value in a definition row, an exact identifier heading, a preformatted identifier with a digit, a preformatted line of three numbers, a table row of three numbers, and short values in an attribute, a script and a comment with markup inside it. L2, stored content not shown. The identifier rules now also read the page source with its tags, attributes and scripts, entities decoded, and a run of 14 or more digits, an SSUID's length, refuses the page wherever it appears. The nine-digit rule still skips comments, noscript blocks, scripts, styles and tags, where tracking numbers sit; the tracking definition pages now put a 12-digit number in comment text after a ">", in a noscript block and in an attribute, each admitted. L3, years beside identifier names. The 40-character and same-row rules no longer count a year from 1900 to 2099. Admitted pages add a universe footer without a period, a panel year, an index link titled with a year and a definition row with a year, and a property draws identifier sentences ending in any such year, in text, a comment or an attribute. An identifier followed directly by digits, such as "SSUID 2022", still refuses. L4, numeric forms. A numeric cell now admits Census's negative-dollar forms (-$250, $-250, the Unicode minus) and bracketed amounts, and a preformatted line of three or more such numbers refuses. The property's numeric text draws these forms too. L5, claims. The docstring, metadata_notes.md and the module header now state the rules as the code applies them. A correction to 7521c6d's message: it said a column headed by a heading that opens with an identifier, "such as SSUID (sample unit)", refuses. Only a cell that is exactly an identifier name refuses as a heading; a cell that opens with one refuses only when a cell of digits alone sits below it or a value of three or more digits sits in its row. L6, PDF citations. Every citation containing ".pdf", in any case, now counts: a member's PDF citations must equal one "{year}_dictionary.pdf#page={page}" per page of its dictionary entry. The damage property adds a pageless own-release PDF, a pageless other-release PDF and a release-notes PDF with a page. Each damage now runs as its own case and must fail at its own check, by message. With the parent check, the two pageless damages pass generation. L7, the window. A test pins the 40-character window: 40 characters between an identifier and a three-digit value refuse, 41 admit. Notes. The THEQ_BUS reason now says only the malformed upper bound makes the entry unverified, and that its lower bound also differs from the API's; the regenerated registry changes only the source_rulings.json pin. The reader's docstring now says quotes are literal characters, so the line check and pandas split the same records, and only a stray carriage return refuses. Invariants: - No stored page shows a form record_bearing_note refuses (all 101 stored captures pass). - Each guard rule alone refuses its minimal page and admits its twin. - Every ruling member's PDF citations equal its dictionary pages, one citation per page. Results: - 17 of the 129 evidence tests fail against 7521c6d's guard. - 16 mutants, one per guard rule or exemption, are all caught. - Tests (invented data only): test_sipp_income 183 passed; test_sipp_income_evidence 129 passed; test_sipp_income_refusal_properties 15 passed. Tiers: unit 183, artifact 144. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # scripts/first_estimates_birth_evidence.py # tests/estimates/test_birth_evidence_artifact.py
The round-5 delta review (an Opus 5.5 reviewer, at ffc4d48) approved, with five low findings and some notes. - L1: reading the page source refused pages that only name an identifier, and index links, because the 40-character window ran across attribute boundaries and the adjacency rule fired on link slugs such as "ssuid-2024". In the source, the window now holds no quote or equals sign as well as no period or tag, so it stays inside one attribute value or string, and href and src values are removed from tags before the two identifier rules read it. The 14-digit rule still reads them. The review's four pages that only name an identifier, and an anchor whose title is an identifier name, are now admitted definition pages, as are a tracking number in a link target outside noscript and a row header outside a definition table. A 14-digit run in a link target, such as a timestamp, is still refused. - L2: the mutants that survived now fail tests. Twins pin the window and the adjacency rule each alone in the source, a tag and a quote as window limits, and the removal of link targets; record pages pin the year exemption's lookahead and its absence from the adjacency rule; a definition page with two numbers per preformatted line and a property over preformatted lines pin that rule's threshold and line split; and a row header outside a definition table pins that exemption. - L3: twins now cover the digit-below, adjacency, nine-digit and 14-digit rules too, so every rule, and each limit on what the identifier rules read, has a refused page and an admitted twin (17 pairs). The 40-character window in visible text is pinned by the width test, which has letters between. - L4: the notes and the docstring now say which rules read the source ("the two rules that follow an identifier name"), that the same-row rule needs a cell that begins with an identifier name, and that the window allows no period between, and in the source no tag either. - L5a: a first-row or header cell that names an identifier anywhere, as in "Person number (PNUM)", with a cell of digits alone below it, is now refused. The other forms the review lists (a value before its identifier, <br> CSV text with no identifier, div grids) stay out of scope, as the docstring states. - Notes: the reader's carriage-return sentence now says a CR is allowed at a line's end, before its LF or last in a final line without one. The other notes need no change: the top-code row is the three-number rule's accepted cost, and the year exemption admits a 1900-2099 value after an identifier with words between. Found by this fix's own mutants: the visible-text window stopped at an angle bracket, though the text holds no tags by then, so a decoded < or > between an identifier name and a value admitted the page. The window there now stops only at a period, as the round-3 rule meant ("within 40 characters of the same sentence"); in the text and comments a tag counts as a space, and the source reading still stops at tags. A twin pins it, 18 pairs in all, and mutant G23 puts the old limit back. Corrections to 04a2b89's message: - "Each guard rule alone refuses its minimal page and admits its twin" held for the eight pairs then present, which covered five rules and three readings; the digit-below, adjacency, nine-digit and 14-digit rules had no twin until now. - "16 mutants, one per guard rule or exemption": the 16 had two for the window width and none for the digit-below rule or the row-header and definition-table exemptions. - "With the parent check, the two pageless damages pass generation": pageless_pdf does, but pageless_other_release_pdf stops earlier on a file missing from the invented folder. - "Every invented record page carried the 15-digit invented SSUID": 14 of the 16 did; header_after_title_row_with_dashed_values and person_months_without_identifier don't. - The heading correction's "a value of three or more digits sits in its row" omits "that is not a year". Checks: - Each of the 18 twins isolates its rule or limit: disabling the rule admits its page, and dropping the limit refuses its twin, with the head refusing each page and admitting each twin. - All 32 guard mutants fail at least one test, in Hypothesis seeds 0 and 7, and the guard is restored after each. - With ffc4d48's guard, 9 of the 153 tests in test_sipp_income_evidence.py fail, the same 9 in each of three Hypothesis seeds. - Every stored capture still passes the guard (the stored-capture test). - The three D2 test modules through the wrapper: 351 passed. By collection, unit 183 and artifact 168, 24 artifact tests more than at ffc4d48. - black and ruff are clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Master brings SM1 (#570). The merge has no conflicts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Round 6 reviewed c1a3c7b and its merge 60b67f8 and returned APPROVE, with three low findings and four notes. This commit answers each. - Low 1: the source window's limits admit an identifier and its value that sit in different attribute values or script strings, or that a quote or equals sign splits within one, and a value in an href or src value other than a 14-digit run. The docstring said the window stays "inside one attribute value or string", which overstated it. This commit takes the review's first option: the docstring, metadata_notes.md and the PR body now list these forms as out of scope, with a value before its identifier, CSV text, div grids and a body cell that names an identifier after other words. The review's second option, reading each attribute value and script string alone, would close three of the seven forms; the script forms would need a rule of their own, and the link-target form would stay. - Low 2: nine of the review's ten mutants of the changed rules survived, so "every rule and each limit has a twin" overstated the tests. New twins pin each mark that stops the source window alone (equals sign, single quote, double quote), unquoted href values and src values, adjacency in the text reading alone, and both heading-cell rules: 26 twins in all. Two record pages pin the heading-names rule's cell conditions, a header cell after the first row and a first-row cell that is not a header cell, and a definition page pins its limit to those cells. - Low 3: a first-row or header cell that names an identifier after other words now also counts for the same-row rule, so a run of three or more digits that is not a year elsewhere in its row is refused (the review's K2). A twin pins it. A body cell that names an identifier after other words stays out of scope; the review's K1 would also refuse such definition tables. - Note 1: the heading-cell rule refuses some definition and index tables. The docstring and the notes now say so; no stored capture is refused. - Note 2: a tag now opens with a letter, "!" or "/", so a comparison such as "1 < 2" in a script no longer hides a src assignment from the source reading. A record page pins it, and the test comment says so. - Note 3, corrections to c1a3c7b's message and to the notes: - "the other L5 forms stay out of scope, as the docstring states": only the PR body stated it; the docstring does from this commit; - "are now admitted definition pages": the parent already admitted tracking_number_in_link_target and row_header_outside_definition_table; they are new test pages, not new admissions; - "The 40-character window in visible text is pinned by the width test": the width page is also refused by the source reading, so the test pins the width in both readings; comment_text and text_window_crosses_decoded_brackets pin the text reading alone; - the notes said the table rules read cells without their attributes, but the row-header exemption reads scope. The notes now say so, and their unreflowed line is reflowed. - Note 4: "PNUM > 100" is now refused, as "PNUM greater than 100" already was. No change. Checks: - each of the 26 twins isolates its rule or limit (twin_isolation_r7.py); - all 44 guard mutants fail a test in Hypothesis seeds 0 and 7: round 6's 32, and 12 new ones, for the review's R1-R7, R9 and R10, the double quote, the same-row rule's heading cells and the tag pattern (mutate_guard_r7.py); - with c1a3c7b's guard, 2 of the 165 evidence tests fail, the same 2 in seeds 0, 1 and 2: the script-comparison record page and the twin for the same-row rule's heading cells, which pin this commit's two code changes. The other new tests pin limits the parent already kept; - the guard refuses none of the 101 stored captures (counts only), and the stored-capture test passes; - 375 passed and 1 failed over D2's three modules and the birth-evidence check: 363 from D2's modules and 12 birth-evidence tests. The failure is the track-U assertion, which needs modules this sparse clone leaves out; CI runs it; - tiers by collection: unit 183, artifact 180 (12 more artifact tests); - black -l 79 --check, ruff check and git diff --check are clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Round 7 reviewed c8dfe4f and its merge 695798e and returned APPROVE, with four low findings and four notes. This commit answers each, taking the review's code options for Low 1 to Low 3. - Low 1: a "<" followed by a letter, "/" or "!" in a script still opened a "tag" whose href and src values were removed, so a minified loop (i<n), a CDATA marker or "a</b" hid a src assignment from the source reading. The source reading now splits out script and style elements, up to their end tag or the end of the page. Their contents are kept as they stand, and only their opening tags lose href and src values. Six record pages pin it: a minified comparison, CDATA, an end-tag-like span, an unquoted src assignment, a script without an end tag and a style block. A twin pins reading the contents as they stand, and a definition page and a twin pin the removal from opening tags. - Low 2: the source window stops at any angle bracket, raw or decoded, which the docstring did not say, and the out-of-scope list left out angle-bracket splits and script comparisons. The identifier rules now also read a third thing: each quoted attribute value other than href and src, and each quoted string in a script, one at a time. Values are decoded, read with the text's window and joined by periods, so the window never spans two. This refuses the review's A1 and A3, S7 and S8, and round 6's Q3, Q4 and Q9. Eight record pages pin it, and four twins pin reading each value alone, the period join, the link-target exclusion and script strings. The docstring now says "no angle bracket (a tag, or a < or > decoded from an entity)", and the out-of-scope list now names an identifier and its value with one in a string and the other in script code, a script string after an unpaired quote mark, an identifier compared with a value in script code, and an attribute value that holds a raw ">". - Low 3: the same-row rule skipped any other cell that began with an identifier name, which no list stated. The exclusion is dropped, so the review's K5 and K5b are refused. Two record pages and a twin pin it. - Low 4: the review's V1 to V6, mutants of the tag pattern and of the same-row rule's cell conditions, survived. Pages from the review's fix_pages pin each: definition pages for an upper-case tag, CDATA and DOCTYPE tags, and an end tag, each with a link target; a record page for "<=" before a src outside scripts; and record pages for a first-row cell and a later header cell that name an identifier beside a value. - Note 1: the table rules also refuse some definition and index rows that name an identifier in a heading cell beside a run of three or more digits that is not a year in its row (K12, K13). The docstring, the notes and the PR body now say so. No stored capture is refused. - Note 2: the quote twins' comma is load-bearing; isolation holds, since G35 and G36 refuse the twins. No change. - Note 3: "(begins or names)" was always true after the continue above it. With the exclusion gone, the condition is dropped. - Note 4: the L4b page is now refused, as the new wording says. No change. Found by this commit's own checks: - the new reading also refused the attribute_source and script_source twins, so removing the source reading no longer admitted them. Their pages now use an unquoted attribute value and script code without a string, so that only the source reading refuses them; - four new mutants changed no page, so four record pages pin them: an unquoted data-src value, decoded entities in a quoted value, values in an upper-case tag and strings in a script without an end tag; - a script string with a backslash escape was not read whole. Strings are now read past their escapes, and a record page pins it. Checks: - 144 invented pages behave as expected, and no page the parent guard refuses is admitted at the head: over the test pages, the review's probes and round-6 forms, and 2 x 100,000 random invented pages (prescreen_r8.py); - each of the 33 twins isolates its rule or limit (twin_isolation_r8.py); - all 67 guard mutants fail a test in Hypothesis seeds 0 and 7: round 7's 44, with G33, G42 and G44 ported to the moved code, and 23 new ones, for the split, the quoted-value reading, the same-row rule and the review's V1-V6 and V8 (mutate_guard_r8.py; V7 is now the head's own condition); - with 695798e's guard, 26 of the 201 evidence tests fail, the same 26 in seeds 0, 1 and 2: 20 of the new record pages and 6 of the new twins, which pin this commit's code changes. The other 10 new tests pin limits the parent already kept (parent_guard_r8.sh); - on invented pages of about 1 MB (prose, script code and strings, unpaired quotes, escapes, attributes, a table) the guard takes 0.07 to 0.24 s, against the parent's 0.03 to 0.22 s. A page of 0.5 MB of unclosed "<a" tags takes 126 s against the parent's 101 s, and 0.25 MB of "<script>" start tags 35 s against 34 s; - the guard refuses none of the 101 stored captures (counts only), and the stored-capture test passes; - 411 passed and 1 failed over D2's three modules and the birth-evidence check: 399 from D2's modules and 12 birth-evidence tests. The failure is the track-U assertion, which needs modules this sparse clone leaves out; CI runs it; - tiers by collection: unit 183, artifact 216 (36 more artifact tests); - black -l 79 --check, ruff check and git diff --check are clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch was successfully deployed
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.
WIP: round 7 approved
695798edwith four low findings and four notes, answered in6e96c64dand merged with master at085a33b9; the round-8 delta review is next. This is milestone D2 of the income-and-resources design (#559, the D2 row of the milestone table). It adds readers for the SIPP releases of 2018 through 2025 (reference years 2017–2024). The tier-count update waits for the coordinator's slot.What it adds
src/populace_dynamics/data/sipp_income.py:read_sipp_income_months, a person-month reader.usecols.quoting=csv.QUOTE_NONE), so the reader sees the same physical records as the layout validator.src/populace_dynamics/data/sipp_income_registry.py: canonical concepts and each release's Census definitions: labels, source and storage types, codes, ranges, universes, ownership level, period, corrections and user notes. It needs no network access at run time.data/external/sipp_income/: the evidence and its tooling.-text, so git stores the bytes the registry hashes.tests/income_resources/test_sipp_income.py,test_sipp_income_evidence.pyandtest_sipp_income_refusal_properties.py.Concepts: 561 are selected, covering:
Verification sources: the Census variable API verifies the 2022–2025 releases. Its 2018–2021 endpoints return 404, so each of those releases is verified against its own dictionary and storage schema.
Every disagreement between sources is either refused or carries a named ruling:
source_rulings.jsonnames 13 domain rulings covering all 64 release-and-variable disagreements indomain_checks.json, with both sources' locations and intervals;User notes: the inventory lists 355 Census user notes and indexes. 101 are stored (93 notes and 8 indexes). Eight notes quoted individual survey cases, so they are kept as exclusions: their URL, title, release and variables stay, but not their bodies. The capture script refuses those URLs before any request. A guard,
record_bearing_note, refuses to store any new page holding a case record in any form it lists:The two rules that follow an identifier name read three things, all with entities decoded: the visible text with HTML comments; the page source with its tags, attributes and scripts; and each quoted attribute value other than href and src, and each quoted string in a script, one at a time. In the text and comments a tag counts as a space. In the source, the 40 characters also hold no angle bracket, quote or equals sign, and href and src values, whose slugs name identifiers without values, are removed from every tag outside scripts and styles and from their opening tags. A tag opens with a letter,
!or/. Script and style contents, up to their end tag or the end of the page, are read as they stand, so no<in script code hides asrcassignment. The table and preformatted rules read each cell's or block's text without its tags; the row-header exemption also reads a header cell'sscopeattribute. The nine-digit rule skips comments and noscript blocks, whose tracking numbers are not page content.These forms are out of scope: a value before its identifier name;
<br>-separated CSV text without an identifier; div grids; an identifier name and its value in different attribute values or script strings, or one of them in a string and the other in script code; a script string after an unpaired quote mark, as in a comment such as// it's; an identifier compared with a value in script code, as inPNUM < 101; an attribute value that holds a raw>, which ends its tag; a value in an href or src value, unless it is a run of 14 or more digits; and a cell outside a table's first row and header cells that names an identifier after other words. The table rules in turn refuse some definition and index tables that name an identifier in a heading cell with digits below it, or beside a run of three or more digits that is not a year in its row; such a page stops the capture loudly.Invariants
TSSSAMTrequires a file downloaded on or after Census's 2025-07-24 correction.record_bearing_noterefuses.{year}_dictionary.pdf#page={page}per page its dictionary entry holds.Each invariant has a Hypothesis property or an example test. The domain rule and Census's own crosswalks give differential tests.
Open questions
Each of these refuses the affected concepts rather than guessing;
refused_concepts.jsonandsource_rulings.jsonlist every case.ESSSMNYN, 2018–2020): it has no verified codes. Annual receipt and amounts remain.ESSI_BRSN, 2021–2022: the category order conflicts.TDIS6AMTandEDIS8MNYNconflict.TSSI_ERSNandEBOATOWNER3lack value codes, and the 2021 interview address identifier has an inverted printed range.Tests
Counted by collection over the three test modules:
All 399 pass locally with two workers at
085a33b9, and so do 12 of the 13 birth-evidence seal tests. The other, the reachability test's track-U assertion, needs modules this sparse clone leaves out. CI runs that test and the U2 isolation tests.Review
Round 1 was stopped before it finished, for a reason unrelated to the code.
Round 2 (fresh, at
1f51b60a): REVISE, with one high and two medium findings.Fix (
eb77fc19):QUOTE_NONE, with a minimized regression and a quote property;The regenerated concept, definition, release, replicate, correction and variable-to-note tables are identical to
1f51b60a's. The note table keeps all 101 entries: the eight exclusions have an empty body path and the statusexcluded_record_bearing. The evidence pins lose the eight bodies and change only forsource_rulings.jsonanduser_notes_manifest.json.Round 3 (delta, at
eb77fc19): REVISE, with two medium and two low findings.THEQ_BUSruling misdescribed the dictionary's printed range.Fix (
7521c6d8):_check_layoutstrips one LF, then one CR, and refuses any other carriage return. Tests add the review's minimized regression, a CRLF file and a carriage return in the quote property's alphabet;THEQ_BUSreason now says the printed upper bound is malformed and the lower bound differs from the API's. The pin ofsource_rulings.jsonis regenerated, and no other table changes;Round 4 (delta, at
7521c6d8): APPROVE, with seven low findings and four notes.<br>CSV text and div grids; those stay admitted and out of scope.)Fix (
04a2b89a):.pdfcitation is checked, and each damage case must fail at its own check;THEQ_BUSreason, the reader's docstring and the notes are corrected. Only thesource_rulings.jsonpin changes in the registry.17 of the 129 evidence tests fail against
7521c6d8's guard, and 16 mutants are all caught. Every stored note still passes. (Round 5 corrected four claims in this fix's message: the eight twins covered five rules and three readings, not every rule; the 16 mutants had two for the window width and none for the digit-below rule or the row-header and definition-table exemptions; onlypageless_pdfpasses generation under the parent check, whilepageless_other_release_pdfstops on a file missing from the invented folder; and 14 of the 16 invented record pages, not all, carried the invented SSUID. The heading correction also needs "that is not a year".)Merge (
ffc4d485):origin/masterat1ec57a5d(D1a, PSID income and wealth readers and field registry (D1a) #575). The birth-evidence check keeps D1a's exclusions and reachability assertion, then D2's.Round 5 (delta, at
ffc4d485): APPROVE, with five low findings and five notes.Fix (
c1a3c7b6):<or>between an identifier name and a value admitted the page. The window there now stops only at a period, as the round-3 rule meant ("within 40 characters of the same sentence"); the source reading still stops at tags. A twin pins it, 18 pairs in all.With
ffc4d485's guard, 9 of the 153 evidence tests fail, the same 9 in each of three Hypothesis seeds. All 32 guard mutants are caught in seeds 0 and 7, each of the 18 twins isolates its rule or limit, and every stored note still passes. (Round 6 corrected two claims in this fix: the 18 twins did not cover the heading-cell rule, each mark that stops the source window alone, unquoted href and src link targets, or adjacency in the text alone; and the other L5 forms were out of scope only in this body, not in the docstring. Two of the "now admitted" definition pages,tracking_number_in_link_targetandrow_header_outside_definition_table, were already admitted by the parent.)Merge (
60b67f82):origin/masteratd8302233(SM1, SM1: differential mortality by lifetime earnings, education and race (normalized within age-sex-year cells) #570). It has no conflicts; git auto-merged the birth-evidence check and its script, which both branches changed.Round 6 (delta, at
60b67f82): APPROVE, with three low findings and four notes.srcassignment from the source reading; four wording corrections;PNUM > 100is now refused.Fix (
c8dfe4f1):!or/, so a comparison in a script no longer hides asrcassignment;With
c1a3c7b6's guard, 2 of the 165 evidence tests fail, the same 2 in each of three Hypothesis seeds: the two that pin this fix's code changes. All 44 guard mutants are caught in seeds 0 and 7, each of the 26 twins isolates its rule or limit, and every stored note still passes. (Round 7 corrected two claims in this fix: a minified comparison, a CDATA marker ora</bin a script still hid asrcassignment, and the bounds on link-target removal were pinned only against a<followed by a space or digit.)Merge (
695798ed):origin/masterat0f69bbb2(OP1, OP1: open-population harness around the sealed loop #566, and its report fix, Fix review r10's report findings for OP1 #589). It has no conflicts; git auto-merged the birth-evidence check and its script, which both branches changed.Round 7 (delta, at
695798ed): APPROVE, with four low findings and four notes.<followed by a letter,/or!in a script still opened a "tag" whose href and src values were removed, so a minified comparison, a CDATA marker ora</bhid asrcassignment.Fix (
6e96c64d):With
695798ed's guard, 26 of the 201 evidence tests fail, the same 26 in each of three Hypothesis seeds: the ones that pin this fix's code changes. All 67 guard mutants are caught in seeds 0 and 7; this fix's own checks found four of them unpinned, and record pages now pin them. Each of the 33 twins isolates its rule or limit, no page the parent guard refuses is admitted, and every stored note still passes.Merge (
085a33b9):origin/masterat172f690f(Held-out data registry: round 7's follow-ups (unset event path, record ids, zero push boundary) #580 and the commits before it). It has no conflicts and changes no D2 path.Round 8 (delta, at
085a33b9): next.The eight removed bodies remain in this branch's earlier commits. A squash merge keeps them out of master's history.
Status
0482dc31and5bdd595bhold the later attempts' edits.1f51b60alists the two reader modules among the birth-evidence check's post-review exclusions;dac0d5f9,ffc4d485,60b67f82,695798edand085a33b9merge master.Data
No SIPP microdata was downloaded, opened or used to compute a statistic, because a SIPP release will be held out for the SSI gate. Tests use invented records and committed metadata.
axiom: n/a: survey-file readers and metadata registry for the microsim; no PolicyEngine country-model or RuleSpec encoding changed
🤖 Generated with Claude Code