Repository navigation
Tie source-conflict markers to the register shared with Axiom - #10287
Merged
Merged
Conversation
PolicyEngine-US follows the statute when it conflicts with a regulation, form, instructions, manual or stated agency practice; forms and instructions fill gaps where the statute is silent. Each such choice is an entry in the source-conflict register in TheAxiomFoundation/rulespec-us, and the deciding line carries `# Source conflict <jurisdiction>:<id>`. - Vendor the register at a pinned rulespec-us commit (pin.yaml: commit and sha256), refreshed by scripts/update_source_conflicts.py. - tests/code_health/test_source_conflicts.py: markers resolve to entries that list their file; registered files keep their marker; comments that read like a source conflict may not grow, file by file. - Document the rule and the steps in README, CONTRIBUTING, CLAUDE.md, AGENTS.md and the PR template. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e register at rulespec-us ff213980 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From a sweep of PolicyEngine-US pull request bodies since July 2026, the claimable-filer and claim-of-right research, the review notes and the code comments, deduplicated and triaged. 60 are cases where the model follows the non-statutory source against the statute. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…2025 booklet page Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ow registers from the backlog Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
marked this pull request as ready for review
October 19, 2026 22:18
…ntries in the backlog The vendored copy is #1710's register (it moves to rulespec-us main when #1710 merges). The seven entries drafted in rulespec-us#1825 stay in the backlog until they register there, so the guard removes them then. The Maryland marker waits for its entry. Captures now hold only pdftotext output or official HTML. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…est tree
CI: the selective runner treats every .yaml under policyengine_us/tests/ as
a policy test, and the dead-URL check flagged one backlog link. The
register, pin, backlog and captures move to source_conflicts/ at the
repository root (out of the wheel too), which the dead-URL check now scans;
the Texas HHS link uses its live host.
Review findings:
- Markers: any comment starting like a marker, in any spacing or case
("# Source conflict", "# Source\tconflict", "#Source conflict"), must be
exactly "# Source conflict <id>" on its own line; inline markers are
rejected.
- Comments are read syntax-aware: Python comment tokens (text in strings is
not a comment), and YAML comments outside quoted and block scalars,
inline ones included.
- The backlog privacy scan reads the raw file, so comments and mapping keys
are covered; code paths must be relative and resolve to a file inside the
repository; years need a whole-year from, an optional to not before it, a
type, and a note for a program year.
- Backlog: us:eitc-table-versus-continuous-formula is dropped (IRC 32(f)
prescribes the tables; a model approximation, not a source conflict); the
Oregon and Wisconsin duplicates merge into their claim-of-right items; the
Puerto Rico EITC maxima are unknown pending the Hacienda bulletin on
indexing; Kansas 2021-2023 is unknown because the code does not do what the
item said. 225 candidates.
- CONTRIBUTING lists every check, says they are structural, and that a
marked file is exempt from the ratchet.
Every probe from the review now fails the guard; a docstring that contains a
marker-like line no longer does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Markers: "source conflict" is found with any number of #s and with spaces, a hyphen, an underscore or nothing between the words, and when an id-shaped token follows a colon or "conflicts"; the ratchet counts "Source-conflict" prose too. Marker classification is one tested helper. - YAML comments: a quote opens a scalar only at the start of a value, '' and \" escapes are honoured, quoted scalars and flow collections carry across lines, and lines break where PyYAML breaks them. Across all 6,383 scanned YAML files, cutting each found comment leaves PyYAML's value unchanged and every skipped # is inside a scalar; a test asserts no file ends inside a quote. - Python comments: inline detection reads the token's own line, so form feeds and Unicode separators no longer shift rows. - Backlog privacy: scan the raw text and every parsed value and key, ignoring case and allowing six-digit ids; code paths must be files git tracks, with no hidden component. - The dead-URL check skips the byte-pinned vendored register. - Backlog: drop the Puerto Rico EITC item (Hacienda's bulletin gives the Schedule CT maxima as the indexed statutory amounts, so the sources agree), and keep only the merged Oregon and Wisconsin items' linked sources. 224 items. - Docs give the marker as <jurisdiction>:<id> and the guard's full path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…P3 gaps The third review of the guard approved 1b81648 and listed seven P3 items. This commit addresses all of them. - YAML comments are now the ones PyYAML's scanner skips, recorded by a BaseLoader subclass. The hand-written scanner missed comments glued to a token, trailing comments under a block scalar, tagged or anchored headers, plain continuation lines and a BOM. Over all 6,383 scanned files the recorder finds exactly the comments the old scanner did, and the BaseLoader soundness and completeness checks still hold. - A file whose comments cannot be read (it doesn't tokenize or parse) is reported as malformed, rather than read as having no comments. - Privacy: - decision ids joined by an underscore are caught; - bare UUIDs are caught (but not UUIDs in URL paths); - more local-path forms are caught; - bytes, sets, tuples and keys in parsed values are scanned. - A marker attempt may have any separator between the words, including a dash, a dot or a zero-width space. - Kill inputs for the reviewer's surviving mutants: escaped keys and list members in the privacy scan, years.to's type, a block-scalar header comment, and unscannable files. - Backlog, 223 items: - drop us-mt:disability-income-exclusion-cap: MCA 15-30-2110 caps the exclusion at $100 a week, so the instructions follow the statute; - restate 16 items' "the input" wording in terms of the sources. - The docstring and CONTRIBUTING describe the git-tracked, hidden-component and parsed-value rules. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…one qualifier Review of c5b524b (approved; three P3s): - R4-1: PyYAML's reader does not advance its column over U+FEFF, so a BOM inside a line shifted the extracted comment. Record the absolute index and slice the text by it. Regression: two embedded BOMs before an inline marker. - R4-2: a test runs a real unscannable file through _cached_comments, _comments and _markers, so a cache hand-off that swallowed the error would fail. - R4-3: us:filing-claimable-spouse-unearned-income-additions says the same-year instructions for the separate 2026 issues are not cited here, rather than that none exist. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TheAxiomFoundation/rulespec-us#1710 landed. Its register has eight entries: two Social Security entries that pinned an unmerged microcosm-dynamics draft (#530) were deferred, and the saving-clause entry keeps only shipped texts. No PolicyEngine-US marker or candidate refers to them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
added a commit
to TheAxiomFoundation/rulespec-us
that referenced
this pull request
Oct 20, 2026
… the runner runs YAML The pin runner executes Python pins only, so the entry's one test pin, a PolicyEngine-US YAML case, would fail the pinned-tests job. A followed reading must be pinned by a test, so the implementation goes with it. The entry stays, open, recording the conflict. Both come back in the follow-up that runs PolicyEngine-US YAML cases through policyengine-core's runner (eng hub ruling). Removed, to restore then: - implementation: PolicyEngine/policyengine-us@79249f0 policyengine_us/variables/gov/states/md/tax/income/credits/poverty_line/md_poverty_line_credit_potential.py (follows and adopts `reading`; PolicyEngine ruling 2026-10-19, PolicyEngine/policyengine-us#10287) - test: the same commit, policyengine_us/tests/policy/baseline/gov/states/md/tax/income/credits/poverty_line/md_poverty_line_credit_earned_income.yaml case "A farm loss is netted against wages like other self-employment (2024)", pinning `reading` Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
Merge audit (admin merge: the only block is the required approving review; this is Max's own PR, which no one can self-approve). Head merged: Independent reviews (GPT-6.1 Sol):
Gates at this head: |
MaxGhenis
added a commit
to TheAxiomFoundation/rulespec-us
that referenced
this pull request
Oct 20, 2026
PolicyEngine/policyengine-us#10287 squash-merged as ce9377ee, and its captures moved to source_conflicts/sources/ at the repository root. The ten pending_texts snapshot refs (eight distinct files) now name that commit and path. Each file at ce9377ee hashes to the sha256 already recorded; the re-pin script refuses to write otherwise. GitHub reports every external commit in the register as shipped: canonical, not a fork, and on its default branch (the PolicyEngine-US one is `identical` to main). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hua7450
added a commit
that referenced
this pull request
Oct 21, 2026
The new source-conflict guard (#10287) registers statute conflicts only; this NOTE compares a regulation with another regulation or a handbook. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hua7450
added a commit
that referenced
this pull request
Oct 21, 2026
…stered The new guard (#10287) reserves the phrase for registered markers. The NOTE's content is unchanged; the conflict goes to source_conflicts/candidates.yaml when main is merged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hua7450
added a commit
that referenced
this pull request
Oct 21, 2026
The new source-conflict guard (#10287) registers statute conflicts only; this NOTE compares a regulation with another regulation or a handbook. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 21, 2026
MaxGhenis
added a commit
that referenced
this pull request
Oct 21, 2026
…seline (#10334) The guard (#10287) took its KNOWN_UNMARKED baseline at 0f21a63. FL LIHEAP (#9969) and SD LIHEAP (#9974) merged before the guard did, each with comments the ratchet reads as unmarked source conflicts, so test_conflict_sounding_comments_do_not_grow fails on main from ce9377e. These five files were on main when the guard landed, so they belong in the baseline, one comment each. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 21, 2026
This was referenced Oct 21, 2026
Open
hua7450
added a commit
that referenced
this pull request
Oct 22, 2026
* Add New Hampshire state supplementation for 2026 * Normalize New Hampshire SSP parameter and test formatting * Fix issues from review: New Hampshire SSP immigrant rule, minimum grant and parental resources - Apply He-W 616.02's five-year entry rule instead of SSI's 40-quarter test - Pay nothing when the grant is below the $2 minimum (He-W 670.03(a)(4)) - Deem parental resources through the federal pool, which counts stepparents; drop the shared helper - Couple status from the SSI spouse signal; couple grant reduction independent of member order - Derive employment expenses and support deductions from existing variables - Registry placement and comments, SNAP reference title, shorter programs.yaml note, reference locators - Tests for the immigrant rule, minimum grant, stepparent, spouse earnings and couple cases Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address review: New Hampshire SSP 40-quarter exception, COLA-linked standards and tests - Follow 8 U.S.C. 1622(b)(2): a permanent resident credited with 40 qualifying quarters is exempt from the 5-year wait; document the conflict with AAM 305.13. - Compute the standards of need as the SSI maximum plus the minimum payment level less the standard disregard (He-W 658.03(e), 648.04(b)), so they follow each SSI COLA; correct the three-person standard to the published $1,976. - Add nh_ssp_assistance_group_size and key the standard disregard by group size. - Add cases for untested branches, the one-third reduction, boundaries, mixed and nonapplicant-spouse couples, and the 2027 COLA pass-through; fix descriptions, references, defined_for gates and the changelog. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Cite New Hampshire's January 1998 release for the minimum payment levels Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix New Hampshire SSP crash in mixed-state simulations Default nh_ssp_assistance_group_size to 1 so people outside New Hampshire still find a standard_disregard key. Add a two-state case, four boundary cases and a note on 8 U.S.C. 1624. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Count gross wages in New Hampshire's SSP income test He-W 601.04(m) and 654.02 count wages before payroll deductions, so the state test no longer nets out pre-tax health premiums; federal SSI keeps SSA's exclusion. Note that blind-child parental deeming still uses SSI's wage count. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Drop the source-conflict label from a NOTE until the conflict is registered The new guard (#10287) reserves the phrase for registered markers. The NOTE's content is unchanged; the conflict goes to source_conflicts/candidates.yaml when main is merged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * List New Hampshire's 8 U.S.C. 1622(b)(2) conflict as a source-conflict candidate The model follows the statute over Adult Assistance Manual 305.13; the entry waits in source_conflicts/candidates.yaml until it is registered. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Place shared-list entries apart from sibling SSP pull requests Each sibling SSP PR adds its line to the same unsorted lists, so the entries now sit at different anchors and the PRs merge without conflicts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
hua7450
added a commit
that referenced
this pull request
Oct 22, 2026
* Add Ohio state supplementation for 2026 * Normalize Ohio SSP parameter and test formatting * Fix issues from review: Ohio RSS registries, rounding and tests - Registry placement and comments, SNAP reference title, shorter programs.yaml note - Rule-level OAC references; document the one-spouse resource-standard reading - Guard the daily-rate ceiling against float error on exact-cent amounts - State-neutral wording in the shared Medicaid helper documentation (same as UT) - Add interest/dividend, couple pooling and exact-cent partial-month cases; realistic Case 3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Leave Ohio RSS out of HUD income to avoid a Medicaid cycle Counting oh_rss as HUD income made Medicaid enrollment, rent-related tax deductions and HUD income circular, so the shared SSP Medicaid helper had to run a full-population branch in every year and the microsimulation job ran out of time and memory. RSS recipients live in licensed residential care, so RSS stays out of HUD income, and the helper and its core test return to main's version (only the docstring wording differs). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address review findings on Ohio RSS Replace the days-of-placement formula input with a zero-default partial-month input, cite ORC 5119.41 and document that the rules pay non-recipients, add NOTEs for the couple standard, resources, federal SSI gaps and the Medicaid gate, update parameter metadata and the registry entry, and pin the readings with new cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Cover Ohio's state-supplement-only Medicaid group and fix proration rounding - Meet the RSS Medicaid condition through the 42 CFR 435.232 group (SPA 15-015) for candidates who meet SSI's other criteria but whose income is too high. - Allow a thousandth of a cent before rounding the daily amount up. - Pin the one-spouse income standard and the computed-Medicaid couple. - Start the minimum age on 2017-07-15 and note microsimulation in programs.yaml. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Reword a source NOTE that involves no statute The new source-conflict guard (#10287) registers statute conflicts only; this NOTE compares a regulation with another regulation or a handbook. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Place shared-list entries apart from sibling SSP pull requests Each sibling SSP PR adds its line to the same unsorted lists, so the entries now sit at different anchors and the PRs merge without conflicts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
hua7450
added a commit
that referenced
this pull request
Oct 22, 2026
* Add Wisconsin state supplementation for 2026 * Normalize Wisconsin SSP parameter and test formatting * Fix issues from review: Wisconsin SSP spouse rate, HUD exclusion and Caretaker Supplement groups - Pay the one-eligible-spouse rate only with an SSI-ineligible spouse - HUD SSI-E exclusion uses the HUD disability test (plus blindness); one boolean caregiver input - Receipt gates use (ssi > 0) | receives_ssi in SSP, CTS and W-2; drop the state-only SSI input - CTS: one group per SSI parent, co-parent filing unit fix, paroled children eligible, no marital-unit proxy - Remove the redundant large-group input; SSI-E not payable in household of another - Registry placement and comments, SNAP title, HUD metadata revert, programs.yaml note, references - Tests for each fix; realistic households Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address review: Wisconsin CTS descriptions, inputs, care cap and tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Count gross wages in Wisconsin's Caretaker Supplement income tests 45 CFR 233.20(a)(6)(iii)-(iv), adopted by Wis. Stat. 49.775(2)(c), counts wages before any deductions, so the gross test, net test and countable earnings (which also set the care cap) read a new wi_cts_gross_earned_income instead of ssi_earned_income, which nets out pre-tax premiums. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Reword a source NOTE that involves no statute The new source-conflict guard (#10287) registers statute conflicts only; this NOTE compares a regulation with another regulation or a handbook. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Place shared-list entries apart from sibling SSP pull requests Each sibling SSP PR adds its line to the same unsorted lists, so the entries now sit at different anchors and the PRs merge without conflicts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <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.
Lands after TheAxiomFoundation/rulespec-us#1710 (the register), which merged on 2026-10-20 as 5796861e; the pin is now that merge commit on rulespec-us main. TheAxiomFoundation/rulespec-us#1825 (PolicyEngine-US fields and first entries) lands after this, because its entries pin the source captures this PR adds.
What and why
PolicyEngine US's rule, from 2026-10-19: when a statute conflicts with a regulation, a tax form, form instructions, an agency manual or stated agency practice, the model follows the statute. Forms and instructions fill gaps where the statute is silent.
This PR makes that rule hard to skip and tracks every such conflict we know of:
The register. It is shared with Axiom:
known-source-conflicts.yamlin TheAxiomFoundation/rulespec-us (introduced in DC Keep Child Care Affordable Tax Credit #1710, extended for PolicyEngine US in Add NYC taxes and refundable credits to relevant household variables #1825). An entry records:pinned-testsjob runs each pinned Python test at its commit and passes onlypassed. It does not run YAML cases yet, so a PolicyEngine US YAML case can't pin a reading until it does;This PR vendors the register byte for byte at a pinned commit (
source_conflicts/pin.yamlholds the commit and sha256).scripts/update_source_conflicts.py --commit <sha>refreshes it, and--checkcompares it with upstream. CI never reads a moving branch.The marker. Code that decides such a reading carries
# Source conflict <jurisdiction>:<id>at the deciding line, the convention PolicyEngine/microcosm-dynamics already uses. This PR adds no markers. The first entries register after it lands. The Maryland marker follows once the register lists Maryland's implementation, which needs a runnable test pin, and so waits for the runner to execute YAML cases.The backlog.
source_conflicts/candidates.yamlholds 228 known conflicts (including the five entries drafted in rulespec-us#1825, under the ids they will register with, so the guard removes them when they do) that are not yet registered. Each has its sources, what PolicyEngine US does today (statute,conflicting-source,gap-fill,not-modelledorunknown), the code and PRs, and whether PolicyEngine has ruled. A candidate leaves the backlog by becoming a register entry, and the guard fails if a registered id is still listed.conflicting-source, with a note.Source captures.
source_conflicts/sources/holds pdftotext or official-HTML captures of the forms, instructions and statutes that register entries cite but the Axiom corpus does not yet hold (pending_texts, pinned there by this repository, commit and sha256).The guard.
policyengine_us/tests/code_health/test_source_conflicts.py; see Invariants.Docs. README, CONTRIBUTING ("Source conflicts"), CLAUDE.md, AGENTS.md and the PR template state the rule and the steps: register, mark, refresh the pin.
Scope. The register and backlog hold conflicts between official sources. A model that departs from the statute with no official source behind it is a bug, not an entry. An example is the North Carolina Special Assistance 2027 rate, which used the unrounded CPI-W ratio where G.S. 108A-42.1 says the approved COLA. Such bugs go to fixes and issues.
Drafted in rulespec-us#1825. Hawaii and Arkansas claim-of-right floors, Ohio's federal-claim condition, Colorado OAP interest, and Maryland Worksheet 18B. The register records only shipped code: the open PolicyEngine US PRs (#10200, #10195, #10203, #10176) are listed there as
proposed. Maryland's implementation is onmain, but its only test is a YAML case, so the entry lists neither until the runner executes YAML cases.Invariants
These hold on every run of the guard:
policyengine_us/{variables,parameters,reforms}is well formed. It names an entry in the pinned register, and that entry lists the marker's file as aPolicyEngine/policyengine-usimplementation.PolicyEngine/policyengine-usimplementation that the register says cites its entry (cites_entry: true) exists here and still carries its marker.KNOWN_UNMARKEDis lowered. The starting count is 45 files and 46 lines. This is a count ratchet, not a ban.rulespec-us checks the other half at pinned commits. Its verify job checks that every excerpt is verbatim, each listed file and test exists, and each
cites_entryclaim matches its file. Itspinned-testsjob checks that each pinned test's commit is on its repository's default branch, then runs the test there and passes onlypassed. TheAxiomFoundation/rulespec-us#1825 extends verify's default-branch check to every external commit.Test plan
pytest policyengine_us/tests/code_health/test_source_conflicts.pygives 103 passed. CI runs it in Rest Python'sremaininggroup. It costs about 1 s and 180 MB RSS (file scan and YAML only, no model build).ruff formatandruff check(0.15.5, as locked).changelog.d/.axiom: n/a: tooling. The register itself is TheAxiomFoundation/rulespec-us#1825.
🤖 Generated with Claude Code