From 67561d7a629d25ecb96af42ee4cab79f164173c1 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Thu, 22 Oct 2026 22:14:33 -0400 Subject: [PATCH 1/4] Stage the references on policyengine-us 2.60.0 for the next board release The fourth engine upgrade of PolicyBench's US references, from 2.41.0 to 2.60.0, the newest PyPI release when the sweep began (01:45:50 UTC, 2026-10-23). The build is staged in reference_audit/2026-10-22-engine-upgrade/ build/; the published board (release 20261014) stays on 2.41.0 until the next board release installs it. - Four scored references change, each approved: scenario_031 SNAP $0 to $288 (#10036, California MCE without the net income test; one-person minimum allotment) and the free school meals flag of scenario_028, 117 and 123, 0 to 1 (#10238, Pennsylvania and Arkansas universal free breakfast). - No exclusion is regenerated. The four r24 outputs (scenario_002, 107, 121 federal; 121 state) land on their records' alternative values (#10185), but their records are unlisted-input exclusions: the prompt does not say who paid for the disability coverage, and the engine reaches the alternative by a default. They stay excluded with 12 other rechecks (scenario_118 SNAP moves on #10158, New York's SSI supplement). - 49 exclusion records, 1,935 scored outputs, unchanged. - A first sweep on 2.59.0 was cut off by a host restart; 2.60.0 differs from it on the three school-meal flags, so the sweep began again on 2.60.0. - Publication check: 2.60.0 still the newest release at 02:11 UTC. Co-Authored-By: Claude Opus 5.5 --- .../2026-10-22-engine-upgrade/README.md | 151 ++ .../actions_from_cells.py | 693 +++++ .../final_actions.json | 363 +++ .../hand_corrected_narratives.json | 6 + .../hand_corrected_narratives.md | 27 + .../scripts/build_references_upgrade.py | 1675 ++++++++++++ .../scripts/narratives_upgrade.py | 449 ++++ .../scripts/sweep_timing.py | 795 ++++++ .../verification/superseded_2_59_0.json | 60 + .../verification/sweep_timing.json | 41 + tests/test_build_references_upgrade_1022.py | 2373 +++++++++++++++++ tests/test_sweep_timing_1022.py | 890 +++++++ 12 files changed, 7523 insertions(+) create mode 100644 reference_audit/2026-10-22-engine-upgrade/README.md create mode 100644 reference_audit/2026-10-22-engine-upgrade/actions_from_cells.py create mode 100644 reference_audit/2026-10-22-engine-upgrade/final_actions.json create mode 100644 reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.json create mode 100644 reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.md create mode 100644 reference_audit/2026-10-22-engine-upgrade/scripts/build_references_upgrade.py create mode 100644 reference_audit/2026-10-22-engine-upgrade/scripts/narratives_upgrade.py create mode 100644 reference_audit/2026-10-22-engine-upgrade/scripts/sweep_timing.py create mode 100644 reference_audit/2026-10-22-engine-upgrade/verification/superseded_2_59_0.json create mode 100644 reference_audit/2026-10-22-engine-upgrade/verification/sweep_timing.json create mode 100644 tests/test_build_references_upgrade_1022.py create mode 100644 tests/test_sweep_timing_1022.py diff --git a/reference_audit/2026-10-22-engine-upgrade/README.md b/reference_audit/2026-10-22-engine-upgrade/README.md new file mode 100644 index 00000000..6fa1bda3 --- /dev/null +++ b/reference_audit/2026-10-22-engine-upgrade/README.md @@ -0,0 +1,151 @@ +# Reference upgrade, October 23, 2026 + +This directory records how PolicyBench's US references move from policyengine-us 2.41.0 to +policyengine-us 2.60.0 for the next board release. 2.60.0 was the newest PyPI release when +PolicyBench began sweeping the references (`verification/sweep_timing.json`): its wheel was +uploaded at 22:47:49 UTC on 2026-10-22 and installed at 01:44:20 UTC on 2026-10-23, and the +sweep wrote its first output at 01:45:50. The directory is named for the day the audit began +(2026-10-22); the records date the upgrade by its UTC day, 2026-10-23. + +The build is staged, not installed. `build/` holds the reference CSV, sidecar and exclusion +record that the next board release installs into +`paper/snapshot/20260501/runs/us_full_run_20260612_policyengine_4_16_1_populace/`. Until then +the published board, release 20261014, stays on 2.41.0. + +Of the 1,984 outputs: +- 4 scored outputs change, and each is approved (table below). +- 16 excluded outputs differ from the values they were decided on. Each was rechecked, and + each stays excluded at its decided value. Five of them changed since 2.41.0: scenario_118's + SNAP and the four r24 outputs below. The other eleven keep 2.41.0's values, which already + differed from their decided values. +- No exclusion is regenerated, and nothing is newly excluded. + +The exclusion record keeps its 49 records, so each model is still scored on the same 1,935 +outputs; four of their references change. + +| Output | Fix | 2.41.0 | 2.60.0 | Law | +|---|---|---|---|---| +| scenario_031 (CA) SNAP | #10036 | $0 | $288 | California MCE has no net income test; a one-person household gets the $24 minimum | +| scenario_028 (PA) free school meals | #10238 | 0 | 1 | Pennsylvania Act 33 of 2023, universal free breakfast | +| scenario_117 (AR) free school meals | #10238 | 0 | 1 | Arkansas Act 123 of 2025, universal free breakfast | +| scenario_123 (PA) free school meals | #10238 | 0 | 1 | Pennsylvania Act 33 of 2023, universal free breakfast | + +All four come from law in force before the 2026-07-03 reference freeze. California's MCE waiver +dates from CDSS's 2011-2015 letters. Pennsylvania codified its breakfast program on 2023-12-13, +and Arkansas's applies from the 2025-26 school year. Both are standing statutes. + +The school-meal output asks "whether PolicyEngine returns positive annual free school meal +support". Each of these households is in the paid tier for lunch, but its K-12 children now +get a free breakfast. `final_actions.json` gives each change's basis, with the figures from +`build/reference_traces.json`. + +Each named pull request (#10036, #10158, #10185 and #10238) is an ancestor of 2.60.0's release +commit, 2bc4ccc970. #10238 is not in 2.59.0's, 05813807e1. + +## The r24 outputs stay excluded + +Four outputs land exactly on their exclusion records' alternative values: + +| Output | 2.60.0 = alternative value | +|---|---| +| scenario_002 federal income tax | $1,890.30 | +| scenario_107 federal income tax | $211.23 | +| scenario_121 federal income tax | $875.34 | +| scenario_121 state income tax | $212.23 | + +#10185 (released in 2.50.0) counts employment disability benefits in gross income less a new +input, `tax_exempt_disability_benefits`, the part from coverage the recipient paid for. That +input defaults to zero, so the engine treats the benefits as coming from an employer-paid plan. + +The four records are not engine defects; they are `reference_depends_on_unlisted_input`. The +prompt lists "disability benefits" without saying who paid for the coverage, and that decides +whether they are taxable (26 U.S.C. 105(a); 104(a)(3)). +`reference_audit/2026-09-22/root_causes.json` classes r24 `unlisted_input`, and its fix module +"encodes the employer-paid reading". + +The engine now takes that reading by default, but the stated facts still do not decide it. The +builder regenerates only engine-defect records. The 2026-10-12 upgrade kept scenario_080, 052 +and 081 excluded on the same ground: their defects were fixed, but a second reason stood. So +these four stay excluded at their decided $0. + +Scoring them at the engine's values would mean ruling that the employer-paid default is the +reference reading. That ruling would move the four entries from `excluded_rechecked` to +`regenerated_exclusions`, and the builder's engine-defect guard would have to admit an +unlisted-input record. + +## scenario_118 SNAP + +It moves from 2.41.0's $2,868 to $2,400 a year. #10158 models New York's state supplement to +SSI, $87 a month for a person living alone (`ny_ssp`), and SNAP counts it as unearned income. +Gross income rises from $1,014 to $1,101 a month, and the allotment falls from $239 to $200. + +The record's unlisted input still decides the output: whether the listed mortgage interest is on +the home the household lives in. So it stays excluded at $2,903.94. + +## The first sweep, on 2.59.0 + +PolicyBench first swept on 2.59.0, the newest release at 19:49 UTC on 2026-10-22. A host restart +cut the session off before the build. When it resumed, 2.60.0 was out and moved three scored +outputs that 2.59.0 does not, the school-meal flags (#10238), so the sweep began again on +2.60.0. + +`verification/superseded_2_59_0.json` keeps the 2.59.0 record and that difference. Every other +output is identical on the two releases. + +## Publication check + +At 02:11 UTC on 2026-10-23, PolicyBench read PyPI again, and 2.60.0 was still the newest release +(`verification/sweep_timing.json`, `publication_check`). The next board release checks again +before it publishes. After installing the build, it runs: + +``` +scripts/sweep_timing.py check --build build --snapshot +``` + +with `--check-venv` if a newer release is out. + +## Installing the build (the next board release) + +1. Copy `build/reference_outputs.csv`, `reference_outputs.csv.meta.json` and + `reference_exclusions.json` into the run directory, and move pyproject's policyengine-us pin + (and `uv.lock`) to 2.60.0. +2. Rebuild the reference narratives of the four changed outputs. No writer call is needed: + + ``` + scripts/narratives_upgrade.py --references build \ + --explanations annotations/us_full_run_20260612_policyengine_4_16_1_populace/us_case_reference_explanations.csv \ + --hand-corrected hand_corrected_narratives.json --out + ``` + + On release 20261014's explanations this gives sha256 `a1691832…`. +3. Re-score and re-freeze the board, then rerun the publication check. Judges' prompts render a + case's reference value and narrative, so the cases on the four changed outputs are judged + again. + +`tests/test_build_references_upgrade_1022.py` holds the snapshot to either the base's three +files or this build's. + +## Files + +- `final_actions.json`: the reviewed actions the build ran on. Its sha256, `a6a4e07b…`, is the + sidecar's `provenance.actions_sha256`. It is `actions_from_cells.py`'s draft with figures and + upstream pull requests added to four bases and five reasons; no placement changed. +- `actions_from_cells.py`: drafts the actions from a first pass. Its rules recognize the two + kinds of scored move this upgrade makes. +- `scripts/build_references_upgrade.py`: the builder (sha256 `2aa0a6b1…`, which the sidecar + pins). It is the 2026-10-12 builder on release 20261014's references, without a release spec. +- `scripts/sweep_timing.py`: the timing record and the publication check. The check takes + `--snapshot`, the committed copy the build must equal. +- `scripts/narratives_upgrade.py`: the reference narratives. A run whose narratives are all + hand-corrected needs no API key. +- `build/`: the build. `computed.csv` is every output on 2.60.0, byte-identical to the sweep's + first output. +- `hand_corrected_narratives.json` and `.md`: the four changed outputs' reference narratives. +- `verification/sweep_timing.json` and `verification/superseded_2_59_0.json`. + +There is no `evidence/` or `fixes/` directory, because no regeneration here needs a +`fix_modules` target. If a later one does, the 2026-10-12 audit's `check_against_evidence.py` +applies. + +The builder leaves the reference CSV's `impact_weight` column as it was, as every earlier +upgrade did. diff --git a/reference_audit/2026-10-22-engine-upgrade/actions_from_cells.py b/reference_audit/2026-10-22-engine-upgrade/actions_from_cells.py new file mode 100644 index 00000000..2af78959 --- /dev/null +++ b/reference_audit/2026-10-22-engine-upgrade/actions_from_cells.py @@ -0,0 +1,693 @@ +"""Draft an actions file for build_references_upgrade.py from a first compute pass. + +Adapted from reference_audit/2026-10-12-engine-upgrade/actions_from_cells.py. +Input: the builder's first-pass computed.csv on the new release (every output +against the 20261014 references: fix, scenario_id, state, variable, frozen, +recomputed, delta, moved), or a cells table in the US hub's cells_pe.csv +form, and the exclusion records (20261014's, read from git). No release spec +rules exclusions here: the build is staged for the next board release. + +Output: a DRAFT actions file ("draft": true, which the builder refuses until a +reviewer clears it) and, on stdout, every judgment call it drafted. Nothing is +decided silently: each moved output is classified by + + status scored, or excluded in 20261014; + audited target whether the new value lands within $1 of its record's + corrected value (alternative_value) or, with --evidence, of + the corrected value the record's fix modules give on a + pre-fix engine (a "fix_modules" target, which the builder + also checks the modules leave unchanged on the new engine); + and the hub's own column; + reason engine defect or unlisted input; + +and lands in exactly one place: + + regenerated_exclusions an engine-defect record the new engine lands on + (PROPOSED: confirm the upstream fix and its release); + excluded_rechecked any other excluded output that moves, with a drafted + reason (PROPOSED: check the reason). An unlisted-input record + stays excluded even when the new engine lands on its + alternative value: the engine then assumes that reading by + default, and the prompt still does not state the input; + approved / new_exclusions a scored move a RULES entry recognizes, with drafted + cause and basis or a drafted record (PROPOSED: check every + sentence against the build's trace); + review only a scored move no rule recognizes (UNDECIDED: the builder + refuses it as an unreviewed move until a reviewer adds it). + + PYTHONPATH= python actions_from_cells.py \\ + --computed /computed.csv --engine X.Y.Z [--date YYYY-MM-DD] \\ + [--evidence reference_audit/2026-10-22-engine-upgrade/evidence/pe.json] \\ + [--upstreams reference_audit/2026-10-22-engine-upgrade/upstreams.json] \\ + --out actions.draft.json +""" + +from __future__ import annotations + +import argparse +import csv +import datetime +import json +import re +import sys +from dataclasses import dataclass +from pathlib import Path + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE / "scripts")) + +from build_references_upgrade import ( # noqa: E402 + ENGINE_DEFECT, + PREVIOUS_ENGINE, + ROOT, + TARGET_FIX_MODULES, + UNNAMED_UPSTREAM, + Refusal, + beyond, + key_of, + load_base, + load_evidence, + sha256, +) + +UNLISTED = "reference_depends_on_unlisted_input" +CELL_TOL = 0.006 # the hub's table rounds to cents +TARGET_TOL = 1.0 + + +@dataclass(frozen=True) +class Cell: + scenario_id: str + state: str + variable: str + previous: float + new: float + status: str + audited_target: str + + @property + def key(self) -> tuple[str, str]: + return (self.scenario_id, self.variable) + + +def money(value: float) -> str: + return f"${value:,.2f}" + + +# --- Rules for scored moves ------------------------------------------------- +# Each rule recognizes one documented kind of scored move and drafts its action. +# The text states what the upstream pull request documents and what the +# 2.60.0 first pass's traces show; a reviewer checks it against the build's +# trace (reference_traces.json). + +CA_MCE_PR = "PolicyEngine/policyengine-us#10036" +BREAKFAST_PR = "PolicyEngine/policyengine-us#10238" +# The FY2026 SNAP minimum allotment for the 48 states and DC (7 U.S.C. +# 2017(a)), as policyengine-us carries it for every month of 2026 under the +# pre-freeze conventions. +SNAP_MIN_ALLOTMENT_2026 = 24.0 +# States whose free breakfast for every public school student #10238 models, +# by standing statute in force for all of 2026, enacted before the +# 2026-07-03 reference freeze. +UNIVERSAL_BREAKFAST = { + "PA": "Pennsylvania Act 33 of 2023 (24 P.S. § 13-1337.1(c.2), codified " + "December 13, 2023)", + "AR": "Arkansas Act 123 of 2025 (SB 59; A.C.A. § 6-18-722(f)), from the " + "2025-26 school year,", +} + + +def _ca_mce_minimum_allotment(cell: Cell, engine: str, date: str) -> dict: + return { + "action": "approved", + "rule": "ca_snap_mce_no_net_income_test", + "entry": { + "scenario_id": cell.scenario_id, + "variable": cell.variable, + "value": cell.new, + "cause": "ca_snap_mce_no_net_income_test_10036", + "basis": ( + "California's Modified Categorical Eligibility (MCE) makes a " + "household with gross income within 200% of the poverty guideline " + "categorically eligible for CalFresh without the net income test, " + "elderly or disabled households included (CDSS ACL 12-62, 13-32, " + "14-56 and 15-42; 7 CFR 273.2(j)(2)), and gives an eligible one- " + "or two-person household the minimum allotment (CDSS MCE letter, " + "June 30, 2014; 7 U.S.C. 2017(a); 7 CFR 273.10(e)(2)(ii)(C)). " + f"{PREVIOUS_ENGINE} applied the net income test to MCE households " + "with an elderly or disabled member, so a one-person household " + "whose net income exceeds 100% of the guideline was ineligible " + f"and its SNAP was $0. {CA_MCE_PR} (Remove the BBCE net income " + "test from California's Modified Categorical Eligibility) drops " + f"that test; on {engine} the household is categorically eligible " + "and its calculated allotment, the maximum less 30% of net income, " + f"is below the ${SNAP_MIN_ALLOTMENT_2026:,.0f} minimum, so it " + f"receives ${SNAP_MIN_ALLOTMENT_2026:,.0f} a month " + f"(snap_min_allotment): {money(cell.new)} for 2026." + ), + }, + "call": ( + "APPROVE (CalFresh MCE net income test removed, #10036; minimum " + "allotment) - confirm the gross and net income, the 200% gross limit " + "and the minimum in the build trace" + ), + } + + +def _state_universal_breakfast(cell: Cell, engine: str, date: str) -> dict: + law = UNIVERSAL_BREAKFAST[cell.state] + return { + "action": "approved", + "rule": "state_universal_free_breakfast", + "entry": { + "scenario_id": cell.scenario_id, + "variable": cell.variable, + "value": cell.new, + "cause": "state_universal_free_breakfast_10238", + "basis": ( + f"{law} gives every public school student a free breakfast " + f"regardless of household income. {BREAKFAST_PR} (Model state " + "school meal coverage beyond universal meals) models it: on " + f"{engine} state_has_universal_free_school_breakfast is true for " + f"{cell.state}, so the household's K-12 children take the free " + "breakfast tier (school_meal_breakfast_tier) whatever their " + "income while lunch stays in the paid tier " + "(school_meal_lunch_tier), and free_school_meals is positive. " + "The output asks whether PolicyEngine returns positive annual " + f"free school meal support, so it is 1; on {PREVIOUS_ENGINE} the " + "household's income put both meals in the paid tier and it was 0." + ), + }, + "call": ( + f"APPROVE ({cell.state} universal free breakfast, #10238) - confirm " + "the breakfast tier, the paid lunch tier and the enactment date" + ), + } + + +RULES = ( + ( + lambda c: ( + c.state == "CA" + and c.variable == "snap" + and c.previous == 0 + and abs(c.new - 12 * SNAP_MIN_ALLOTMENT_2026) <= CELL_TOL + ), + _ca_mce_minimum_allotment, + ), + ( + lambda c: ( + c.state in UNIVERSAL_BREAKFAST + and c.variable == "free_school_meals_eligible" + and c.previous == 0 + and c.new == 1 + ), + _state_universal_breakfast, + ), +) + + +# --- Inputs -------------------------------------------------------------------- + + +def read_cells(path: Path, board: dict, computed: dict | None) -> list[Cell]: + with Path(path).open(newline="") as source: + rows = list(csv.DictReader(source)) + keys = {(r["scenario_id"], r["variable"]) for r in rows} + if keys != set(board) or len(rows) != len(board): + raise Refusal("the cells table does not list exactly the 20261014 outputs") + cells = [] + for r in rows: + k = (r["scenario_id"], r["variable"]) + if abs(float(r["frozen_20261014"]) - board[k]) > CELL_TOL: + raise Refusal(f"{k}: the table's frozen value is not 20261014's") + new = float(r["new"]) + if computed is not None: + if abs(computed[k] - new) > CELL_TOL: + raise Refusal(f"{k}: computed {computed[k]} is not the table's {new}") + new = computed[k] + cells.append( + Cell( + k[0], + r["state"], + k[1], + board[k], + new, + r["status"], + r.get("audited_target", ""), + ) + ) + return cells + + +def cells_from_computed(path: Path, board: dict, records: dict) -> list[Cell]: + """Every output of a builder pass's computed.csv as a cell: its 20261014 + reference (which must be the row's frozen column), its new value and its + status. No hub column: the audited target is left to the evidence.""" + with Path(path).open(newline="") as source: + rows = list(csv.DictReader(source)) + keys = [(r["scenario_id"], r["variable"]) for r in rows] + if set(keys) != set(board) or len(keys) != len(board): + raise Refusal("computed.csv does not list exactly the 20261014 outputs") + cells = [] + for r, k in zip(rows, keys): + if abs(float(r["frozen"]) - board[k]) > 1e-6: + raise Refusal(f"{k}: computed.csv's frozen value is not 20261014's") + status = ( + "excluded 20261014: " + + str(records[k].get("root_cause") or records[k]["reason_code"]) + if k in records + else "scored" + ) + cells.append(Cell(k[0], r["state"], k[1], board[k], float(r["recomputed"]), status, "")) + return cells + + +def read_computed(path: Path) -> dict: + with Path(path).open(newline="") as source: + return { + (r["scenario_id"], r["variable"]): float(r["recomputed"]) + for r in csv.DictReader(source) + } + + +def engine_from_path(path: Path) -> str: + match = re.fullmatch(r"cells_pe(\d+\.\d+\.\d+)\.csv", Path(path).name) + if not match: + raise Refusal(f"cannot read the engine from {Path(path).name}; pass --engine") + return match.group(1) + + +# --- Drafting ------------------------------------------------------------------ + + +def last_upgrade(meta: dict) -> dict: + """The base's last engine upgrade revision (2026-10-13, on 2.41.0).""" + return [r for r in meta["revisions"] if r["kind"] == "engine_upgrade"][-1] + + +def last_upgrade_rechecks(meta: dict) -> dict: + """The base's last engine upgrade's rechecks, by output.""" + return {key_of(r): r for r in last_upgrade(meta)["excluded_outputs_rechecked"]} + + +def value_key(engine: str) -> str: + """A recheck's field for its engine's value ("value_on_2_41_0").""" + return "value_on_" + engine.removeprefix("policyengine-us ").replace(".", "_") + + +# What an earlier upgrade's recheck says of an output whose reference the +# stated facts do not decide (scenario_080's SNAP, 2026-09-29). +INDETERMINATE = "indeterminate on the stated facts" + + +def indeterminate_rechecks(meta: dict) -> dict: + """The outputs an earlier engine upgrade's recheck found indeterminate on + the stated facts, each with that upgrade's date (the first such recheck).""" + found: dict = {} + for revision in meta["revisions"]: + if revision["kind"] != "engine_upgrade": + continue + for item in revision.get("excluded_outputs_rechecked", []): + if INDETERMINATE in item.get("reason", ""): + found.setdefault(key_of(item), revision["date"]) + return found + + +def second_reason(record: dict) -> str: + """The record's note when it names an unlisted input besides the defect.""" + note = str(record.get("note", "")) + return note if "unlisted input" in note.lower() else "" + + +def record_basis(record: dict) -> str: + return str( + record.get("unlisted_input") + or record.get("root_cause") + or record["reason_code"] + ) + + +def upstream_for(record: dict, key, upstreams: dict | None) -> str: + """The upstream fix a regeneration names: the output's own entry in + ``upstreams``, else each of its root causes' (joined with "; "), else the + record's own upstream.""" + if not upstreams: + return record.get("upstream", "") + own = upstreams.get("outputs", {}).get(f"{key[0]}|{key[1]}") + if own: + return own + causes = str(record.get("root_cause", "")).split("+") + fixes = [upstreams.get("root_causes", {}).get(cause) for cause in causes] + if causes and all(fixes): + return "; ".join(dict.fromkeys(fixes)) + return record.get("upstream", "") + + +def draft_actions( + cells: list[Cell], + records: dict, + previous_rechecks: dict, + previous_upgrade: dict, + *, + engine_version: str, + date: str, + precise: bool, + evidence: dict | None = None, + upstreams: dict | None = None, + indeterminate: dict | None = None, +) -> tuple[dict, list[dict]]: + """The draft actions file and the judgment calls, one per moved output. + + ``records`` maps each excluded output to its 20261014 record. + ``previous_rechecks`` and ``previous_upgrade`` are the base's last engine + upgrade's rechecks and revision (last_upgrade): a recheck whose engine + value has not moved since says so. ``evidence`` is {"ref": {path, sha256}, + "doc": the loaded evidence file}: a pre-fix engine's values for + engine-defect outputs without and with their fix modules. ``indeterminate`` + maps an output an earlier upgrade's recheck found indeterminate on the + stated facts to that upgrade's date (indeterminate_rechecks): such an + output stays excluded even where the new engine fixes its defect, since an + engine cannot settle the facts.""" + indeterminate = indeterminate or {} + evidence_items = {} + if evidence is not None: + for item in evidence["doc"]["items"]: + evidence_items[key_of(item)] = item + engine = f"policyengine-us {engine_version}" + previous_engine = previous_upgrade["engine_version"] + previous_number = previous_engine.removeprefix("policyengine-us ") + previous_date = previous_upgrade["date"] + ver_key = value_key(previous_engine) + actions = { + "engine": engine, + "previous_engine": PREVIOUS_ENGINE, + "date": date, + "draft": True, + "approved": [], + "regenerated_exclusions": [], + "new_exclusions": [], + "excluded_rechecked": [], + } + calls = [] + + def call(cell: Cell, decision: str, text: str, where: str) -> None: + calls.append( + { + "scenario_id": cell.scenario_id, + "state": cell.state, + "variable": cell.variable, + "previous": cell.previous, + "new": cell.new, + "status": cell.status, + "hub_audited_target": cell.audited_target, + "decision": decision, + "placed_in": where, + "call": text, + } + ) + + def lands(cell: Cell, aim: float) -> bool: + return abs(cell.new - aim) <= TARGET_TOL and not beyond( + cell.variable, aim, cell.new + ) + + for cell in cells: + k = cell.key + if not beyond(cell.variable, cell.previous, cell.new): + continue + if k in records: + record = records[k] + source = "20261014" + kept_value = cell.previous + earlier = previous_rechecks.get(k) + unmoved = earlier is not None and abs(float(earlier[ver_key]) - cell.new) <= 1e-3 + if record["reason_code"] == ENGINE_DEFECT: + target = float(record["alternative_value"]) + target_spec = {"kind": "record"} + target_text = f"the corrected value {money(target)} the " + target_text += f"{record['decided_on']} record computed" + item = evidence_items.get(k) + if not lands(cell, target) and item is not None: + target = float(item["corrected_value"]) + target_spec = { + "kind": TARGET_FIX_MODULES, + "modules": list(item["modules"]), + "evidence": dict(evidence["ref"]), + } + target_text = ( + f"the corrected value {money(target)} its fix modules " + f"({' + '.join(item['modules'])}) give on " + f"{evidence['doc']['engine']}, which still has the defect " + f"({money(float(item['engine_value']))} without them)" + ) + on_target = lands(cell, target) + second = second_reason(record) + if on_target and k in indeterminate: + reason = ( + f"Stays excluded on {engine}: the engine gives " + f"{money(cell.new)}, on the record's corrected value " + f"{money(target)}, so its defect ({record['root_cause']}) " + f"is fixed there, but the {indeterminate[k]} recheck found " + f"the output {INDETERMINATE}, a second reason that a new " + f"engine does not settle; the record keeps {money(kept_value)}." + ) + text = ( + f"RECHECK ({source} engine defect {record['root_cause']} " + f"lands on target, but the {indeterminate[k]} recheck found " + f"it {INDETERMINATE}): regenerate only if a reviewer rules " + "that reason out" + ) + elif on_target and second: + reason = ( + f"Stays excluded on {engine}: the engine gives " + f"{money(cell.new)}, on the record's corrected value " + f"{money(target)}, but the record names a second reason " + f"that a new engine does not settle ({second}); the record " + f"keeps {money(kept_value)}." + ) + text = ( + f"RECHECK ({source} engine defect {record['root_cause']} " + "lands on target, but the record's note names an unlisted " + "input too): regenerate only if a reviewer rules that " + "reason out" + ) + elif on_target: + upstream = upstream_for(record, k, upstreams) + actions["regenerated_exclusions"].append( + { + "scenario_id": k[0], + "variable": k[1], + "alternative_value": float(record["alternative_value"]), + "tolerance": TARGET_TOL, + "upstream": upstream, + "basis": ( + f"An engine defect fixed upstream ({upstream}) is " + f"regenerated with the fix: {engine} gives " + f"{money(cell.new)}, within $1 of {target_text} " + f"({record['root_cause']}: {record['defect']})." + ), + "target": target_spec, + } + ) + hub = cell.audited_target + note = ( + "" + if hub in ("", "yes") + else f" The hub's table disagrees ({hub}); resolve it first." + ) + if earlier is not None: + note += ( + f" It was rechecked on {previous_date}: read that " + f"reason in the {previous_date} engine_upgrade revision." + ) + if upstream.strip().lower() in UNNAMED_UPSTREAM: + note += ( + " The record names no upstream fix; the builder " + "refuses the regeneration until upstream names it." + ) + call( + cell, + "PROPOSED", + f"REGENERATE ({source} engine defect {record['root_cause']}): " + f"lands on {money(cell.new)} vs target {money(target)}. " + "Confirm the fix is released upstream and name it in " + f"upstream ({upstream or 'empty'}).{note}", + "regenerated_exclusions", + ) + continue + elif ( + second + and unmoved + and "corrected value" in earlier.get("reason", "") + and "second reason" in earlier.get("reason", "") + ): + # The previous upgrade's recheck found this value on its + # corrected value (directly, or as the value an earlier + # recheck found there), and the engine has not moved it + # since. The record's own alternative value predates that + # evidence, so missing it says nothing about the defect; + # the second reason keeps the output excluded. + reason = ( + f"Stays excluded on {engine}: the engine gives " + f"{money(cell.new)}, the value {previous_engine} gave when " + f"the {previous_date} recheck found it on its corrected " + "value, but the record names a second reason that a new " + f"engine does not settle ({second}); the record keeps " + f"{money(kept_value)}." + ) + text = ( + f"RECHECK ({source} engine defect {record['root_cause']}, " + f"on the corrected value the {previous_date} recheck found, " + "with a second reason)" + ) + else: + reason = ( + f"Stays excluded on {engine}: the engine gives " + f"{money(cell.new)}, {money(abs(cell.new - target))} from " + f"the record's corrected value {money(target)}, so the " + f"defect ({record['root_cause']}) is not fixed in this " + f"release; the record keeps {money(kept_value)}." + ) + if cell.audited_target.startswith("pending"): + reason += ( + " The US hub's sweep marks it pending on more than one " + f"fix ({cell.audited_target.removeprefix('pending: ')})." + ) + text = ( + f"RECHECK ({source} engine defect {record['root_cause']}, " + f"off target by {money(abs(cell.new - target))})" + ) + elif lands(cell, float(record["alternative_value"])): + # The engine now takes the record's alternative reading, by a + # default for the input the prompt does not state; the stated + # facts still do not decide the output. + reason = ( + f"Stays excluded on {engine}: the engine gives " + f"{money(cell.new)}, the record's alternative value, since it " + "takes that reading by default, but the reference depends on " + f"an input the prompt does not state ({record_basis(record)}; " + f"{record['reason_code']}), and an engine default does not " + f"settle it; the record keeps {money(kept_value)}." + ) + text = ( + f"RECHECK ({source} {record['reason_code']}; the engine lands on " + "the alternative reading): regenerate only if a reviewer rules " + "that the stated facts decide it" + ) + else: + reason = ( + f"Stays excluded on {engine}: the reference depends on " + f"{record_basis(record)} ({record['reason_code']}), which an " + f"engine release does not settle; the record keeps " + f"{money(kept_value)}, and {engine} gives {money(cell.new)}." + ) + text = f"RECHECK ({source} {record['reason_code']})" + if unmoved: + reason += ( + f" The value is {previous_number}'s, rechecked on " + f"{previous_date} (the {previous_date} engine_upgrade " + "revision's excluded_outputs_rechecked)." + ) + elif earlier is not None: + reason += ( + f" {previous_engine} gave {money(float(earlier[ver_key]))} " + f"when it was rechecked on {previous_date}." + ) + actions["excluded_rechecked"].append( + {"scenario_id": k[0], "variable": k[1], "reason": reason} + ) + call( + cell, + "PROPOSED", + text + " - check the drafted reason", + "excluded_rechecked", + ) + continue + for matches, propose in RULES: + if matches(cell): + proposal = propose(cell, engine, date) + actions[proposal["action"]].append(proposal["entry"]) + text = proposal["call"] + if not precise: + text += ( + "; the value is the table's, rounded to cents: rerun with " + "--computed (the builder's computed.csv) before the build" + ) + call(cell, "PROPOSED", text, proposal["action"]) + break + else: + call( + cell, + "UNDECIDED", + "scored move no rule recognizes: approve it (cause, basis) or " + "exclude it (a complete record); the builder refuses it until then", + "review only", + ) + for name in ( + "approved", + "regenerated_exclusions", + "new_exclusions", + "excluded_rechecked", + ): + actions[name].sort(key=key_of) + actions["review"] = calls + return actions, calls + + +def print_calls(calls: list[dict]) -> None: + print(f"{len(calls)} moved outputs; every call below needs a reviewer:") + for c in calls: + print( + f" [{c['decision']}] {c['scenario_id']} {c['state']} {c['variable']}: " + f"{c['previous']:,.2f} -> {c['new']:,.2f} ({c['status']}) -> " + f"{c['placed_in']}\n {c['call']}" + ) + + +def main(argv: list[str] | None = None) -> None: + parser = argparse.ArgumentParser() + parser.add_argument("--cells") + parser.add_argument("--computed") + parser.add_argument("--engine") + parser.add_argument("--date") + parser.add_argument("--evidence", help="a committed evidence file, repo-relative") + parser.add_argument("--upstreams", help="upstreams.json: the fix each regeneration names") + parser.add_argument("--out", required=True) + args = parser.parse_args(argv) + evidence = None + if args.evidence: + ref = {"path": args.evidence, "sha256": sha256(ROOT / args.evidence)} + evidence = {"ref": ref, "doc": load_evidence(ref)} + if not (args.cells or args.computed): + parser.error("pass --computed (a builder pass) or --cells (a hub table)") + engine_version = args.engine or engine_from_path(Path(args.cells)) + date = args.date or datetime.datetime.now(datetime.timezone.utc).date().isoformat() + base = load_base() + records = {key_of(r): r for r in base.exclusions["exclusions"]} + computed = read_computed(Path(args.computed)) if args.computed else None + if args.cells: + cells = read_cells(Path(args.cells), base.reference.values(), computed) + else: + cells = cells_from_computed( + Path(args.computed), base.reference.values(), records + ) + actions, calls = draft_actions( + cells, + records, + last_upgrade_rechecks(base.meta), + last_upgrade(base.meta), + engine_version=engine_version, + date=date, + precise=computed is not None, + evidence=evidence, + upstreams=json.loads(Path(args.upstreams).read_text()) if args.upstreams else None, + indeterminate=indeterminate_rechecks(base.meta), + ) + Path(args.out).write_text(json.dumps(actions, indent=2) + "\n") + print_calls(calls) + print(f"DRAFT -> {args.out} (draft: true; the builder refuses it until reviewed)") + + +if __name__ == "__main__": + main() diff --git a/reference_audit/2026-10-22-engine-upgrade/final_actions.json b/reference_audit/2026-10-22-engine-upgrade/final_actions.json new file mode 100644 index 00000000..5ec7a4dc --- /dev/null +++ b/reference_audit/2026-10-22-engine-upgrade/final_actions.json @@ -0,0 +1,363 @@ +{ + "engine": "policyengine-us 2.60.0", + "previous_engine": "policyengine-us 2.41.0", + "date": "2026-10-23", + "draft": false, + "approved": [ + { + "scenario_id": "scenario_028", + "variable": "free_school_meals_eligible", + "value": 1.0, + "cause": "state_universal_free_breakfast_10238", + "basis": "Pennsylvania Act 33 of 2023 (24 P.S. \u00a7 13-1337.1(c.2), codified December 13, 2023) gives every public school student a free breakfast regardless of household income. PolicyEngine/policyengine-us#10238 (Model state school meal coverage beyond universal meals) models it: on policyengine-us 2.60.0 state_has_universal_free_school_breakfast is true for PA, so the household's K-12 children take the free breakfast tier (school_meal_breakfast_tier) whatever their income while lunch stays in the paid tier (school_meal_lunch_tier), and free_school_meals is positive. Here its three K-12 children, at 186% of the poverty guideline, get $1,112.40 of free breakfast support for 2026. The output asks whether PolicyEngine returns positive annual free school meal support, so it is 1; on policyengine-us 2.41.0 the household's income put both meals in the paid tier and it was 0." + }, + { + "scenario_id": "scenario_031", + "variable": "snap", + "value": 288.0, + "cause": "ca_snap_mce_no_net_income_test_10036", + "basis": "California's Modified Categorical Eligibility (MCE) makes a household with gross income within 200% of the poverty guideline categorically eligible for CalFresh without the net income test, elderly or disabled households included (CDSS ACL 12-62, 13-32, 14-56 and 15-42; 7 CFR 273.2(j)(2)), and gives an eligible one- or two-person household the minimum allotment (CDSS MCE letter, June 30, 2014; 7 U.S.C. 2017(a); 7 CFR 273.10(e)(2)(ii)(C)). policyengine-us 2.41.0 applied the net income test to MCE households with an elderly or disabled member, so this one-person household, an elderly member with $1,987.79 of monthly gross income (within the $2,608.33 MCE limit) and $1,611 of net income (above the $1,304.17 guideline), was ineligible and its SNAP was $0. PolicyEngine/policyengine-us#10036 (Remove the BBCE net income test from California's Modified Categorical Eligibility) drops that test; on policyengine-us 2.60.0 the household is categorically eligible and its calculated allotment, the $298 maximum less 30% of net income ($484), is below the $24 minimum, so it receives $24 a month (snap_min_allotment): $288.00 for 2026." + }, + { + "scenario_id": "scenario_117", + "variable": "free_school_meals_eligible", + "value": 1.0, + "cause": "state_universal_free_breakfast_10238", + "basis": "Arkansas Act 123 of 2025 (SB 59; A.C.A. \u00a7 6-18-722(f)), from the 2025-26 school year, gives every public school student a free breakfast regardless of household income. PolicyEngine/policyengine-us#10238 (Model state school meal coverage beyond universal meals) models it: on policyengine-us 2.60.0 state_has_universal_free_school_breakfast is true for AR, so the household's K-12 children take the free breakfast tier (school_meal_breakfast_tier) whatever their income while lunch stays in the paid tier (school_meal_lunch_tier), and free_school_meals is positive. Here its two K-12 children, at 643% of the poverty guideline, get $741.60 of free breakfast support for 2026. The output asks whether PolicyEngine returns positive annual free school meal support, so it is 1; on policyengine-us 2.41.0 the household's income put both meals in the paid tier and it was 0." + }, + { + "scenario_id": "scenario_123", + "variable": "free_school_meals_eligible", + "value": 1.0, + "cause": "state_universal_free_breakfast_10238", + "basis": "Pennsylvania Act 33 of 2023 (24 P.S. \u00a7 13-1337.1(c.2), codified December 13, 2023) gives every public school student a free breakfast regardless of household income. PolicyEngine/policyengine-us#10238 (Model state school meal coverage beyond universal meals) models it: on policyengine-us 2.60.0 state_has_universal_free_school_breakfast is true for PA, so the household's K-12 children take the free breakfast tier (school_meal_breakfast_tier) whatever their income while lunch stays in the paid tier (school_meal_lunch_tier), and free_school_meals is positive. Here its one K-12 child, at 531% of the poverty guideline, gets $370.80 of free breakfast support for 2026. The output asks whether PolicyEngine returns positive annual free school meal support, so it is 1; on policyengine-us 2.41.0 the household's income put both meals in the paid tier and it was 0." + } + ], + "regenerated_exclusions": [], + "new_exclusions": [], + "excluded_rechecked": [ + { + "scenario_id": "scenario_002", + "variable": "federal_income_tax_before_refundable_credits", + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $1,890.30, the record's alternative value, since it takes that reading by default, but the reference depends on an input the prompt does not state (who paid for the coverage behind listed employment disability benefits, which decides whether they are taxable; reference_depends_on_unlisted_input), and an engine default does not settle it; the record keeps $0.00. policyengine-us#10185 (Count taxable employment disability benefits in federal gross income (IRC 105(a)), released in 2.50.0) counts disability_benefits less tax_exempt_disability_benefits, the part from coverage the recipient paid for with after-tax money (IRC 104(a)(3)), in gross income, and that input defaults to zero: the engine treats the benefits as coming from an employer-paid plan. The prompt lists only the benefits, so who paid for the coverage is still unstated." + }, + { + "scenario_id": "scenario_005", + "variable": "federal_income_tax_before_refundable_credits", + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $108,525.58, the value policyengine-us 2.41.0 gave when the 2026-10-13 recheck found it on its corrected value, but the record names a second reason that a new engine does not settle (Corrected value applies r02_ira_219g_v2 with every publication convention and upstream fix. The output also moves under r25_niit_in_federal_output (unlisted input).); the record keeps $106,505.90. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_020", + "variable": "federal_income_tax_before_refundable_credits", + "reason": "Stays excluded on policyengine-us 2.60.0: the reference depends on whether federal income tax before refundable credits includes the net investment income tax, which the output's definition does not say (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $68,056.71, and policyengine-us 2.60.0 gives $68,334.73. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_023", + "variable": "snap", + "reason": "Stays excluded on policyengine-us 2.60.0: the reference depends on meets_ssi_disability_criteria (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $461.34, and policyengine-us 2.60.0 gives $408.00. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_052", + "variable": "federal_income_tax_before_refundable_credits", + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $104,225.26, on the record's corrected value $104,225.26, but the record names a second reason that a new engine does not settle (Corrected value applies r02_ira_219g_v2 with every publication convention and upstream fix. The output also moves under r25_niit_in_federal_output (unlisted input).); the record keeps $104,211.41. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_056", + "variable": "snap", + "reason": "Stays excluded on policyengine-us 2.60.0: the reference depends on weekly_hours_worked_before_lsr and whether the listed home mortgage interest is on the home the SNAP household occupies (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $1,140.00, and policyengine-us 2.60.0 gives $95.00. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_057", + "variable": "snap", + "reason": "Stays excluded on policyengine-us 2.60.0: the reference depends on meets_ssi_disability_criteria (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $2,669.22, and policyengine-us 2.60.0 gives $2,628.00. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_080", + "variable": "snap", + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $3,240.00, on the record's corrected value $3,240.00, so its defect (r30_snap_heat_and_eat_sua) is fixed there, but the 2026-09-29 recheck found the output indeterminate on the stated facts, a second reason that a new engine does not settle; the record keeps $3,596.04. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_081", + "variable": "state_income_tax_before_refundable_credits", + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $8,232.90, on the record's corrected value $8,232.90, but the record names a second reason that a new engine does not settle (Corrected value applies ma_part_a_loss_offset with every publication convention and upstream fix. The output also moves under r23_ma_interest_source (unlisted input).); the record keeps $8,238.41. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_100", + "variable": "snap", + "reason": "Stays excluded on policyengine-us 2.60.0: the reference depends on meets_ssi_disability_criteria (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $8,625.89, and policyengine-us 2.60.0 gives $6,924.00. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_107", + "variable": "federal_income_tax_before_refundable_credits", + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $211.23, the record's alternative value, since it takes that reading by default, but the reference depends on an input the prompt does not state (who paid for the coverage behind listed employment disability benefits, which decides whether they are taxable; reference_depends_on_unlisted_input), and an engine default does not settle it; the record keeps $0.00. policyengine-us#10185 (Count taxable employment disability benefits in federal gross income (IRC 105(a)), released in 2.50.0) counts disability_benefits less tax_exempt_disability_benefits, the part from coverage the recipient paid for with after-tax money (IRC 104(a)(3)), in gross income, and that input defaults to zero: the engine treats the benefits as coming from an employer-paid plan. The prompt lists only the benefits, so who paid for the coverage is still unstated." + }, + { + "scenario_id": "scenario_112", + "variable": "snap", + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $0.00, the record's alternative value, since it takes that reading by default, but the reference depends on an input the prompt does not state (weekly_hours_worked_before_lsr; reference_depends_on_unlisted_input), and an engine default does not settle it; the record keeps $287.68. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_118", + "variable": "snap", + "reason": "Stays excluded on policyengine-us 2.60.0: the reference depends on whether the listed home mortgage interest is on the home the SNAP household occupies (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $2,903.94, and policyengine-us 2.60.0 gives $2,400.00. policyengine-us 2.41.0 gave $2,868.00 when it was rechecked on 2026-10-13. It moves because policyengine-us#10158 (Add New York state supplementation for 2026) models New York's state supplement to SSI, $87 a month for this person living alone (ny_ssp), which counts as SNAP unearned income: gross income rises from $1,014 to $1,101 a month, net income from $194 to $325, and the allotment from $239 to $200 a month." + }, + { + "scenario_id": "scenario_120", + "variable": "federal_income_tax_before_refundable_credits", + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $40,423.18, the value policyengine-us 2.41.0 gave when the 2026-10-13 recheck found it on its corrected value, but the record names a second reason that a new engine does not settle (Corrected value applies r02_ira_219g_v2 with every publication convention and upstream fix. The output also moves under r25_niit_in_federal_output (unlisted input). The output also moves under the state income tax withheld reading (unlisted input): the reference's SALT uses the Connecticut withholding estimate ($12,010.05); with the engine's own liability ($11,917.18) the 2.15.17 value is $40,438.95, and with no state income tax paid it is $43,619.93. With r02's IRA fix on 2.15.17 the value is $40,423.18 under the withholding estimate, $40,445.46 under the liability and $43,629.21 with no state income tax paid. policyengine-us 2.15.17 also leaves the household's Connecticut paid leave contributions ($827.98) out of SALT (Rev. Rul. 2025-4); with them the 2.15.17 value is $40,217.95.); the record keeps $40,021.82. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_121", + "variable": "federal_income_tax_before_refundable_credits", + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $875.34, the record's alternative value, since it takes that reading by default, but the reference depends on an input the prompt does not state (who paid for the coverage behind listed employment disability benefits, which decides whether they are taxable; reference_depends_on_unlisted_input), and an engine default does not settle it; the record keeps $0.00. policyengine-us#10185 (Count taxable employment disability benefits in federal gross income (IRC 105(a)), released in 2.50.0) counts disability_benefits less tax_exempt_disability_benefits, the part from coverage the recipient paid for with after-tax money (IRC 104(a)(3)), in gross income, and that input defaults to zero: the engine treats the benefits as coming from an employer-paid plan. The prompt lists only the benefits, so who paid for the coverage is still unstated." + }, + { + "scenario_id": "scenario_121", + "variable": "state_income_tax_before_refundable_credits", + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $212.23, the record's alternative value, since it takes that reading by default, but the reference depends on an input the prompt does not state (who paid for the coverage behind listed employment disability benefits, which decides whether they are taxable; reference_depends_on_unlisted_input), and an engine default does not settle it; the record keeps $0.00. policyengine-us#10185 (Count taxable employment disability benefits in federal gross income (IRC 105(a)), released in 2.50.0) counts disability_benefits less tax_exempt_disability_benefits, the part from coverage the recipient paid for with after-tax money (IRC 104(a)(3)), in gross income, and that input defaults to zero: the engine treats the benefits as coming from an employer-paid plan. The prompt lists only the benefits, so who paid for the coverage is still unstated." + } + ], + "review": [ + { + "scenario_id": "scenario_002", + "state": "WA", + "variable": "federal_income_tax_before_refundable_credits", + "previous": 0.0, + "new": 1890.300048828125, + "status": "excluded 20261014: reference_depends_on_unlisted_input", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "excluded_rechecked", + "call": "RECHECK (20261014 reference_depends_on_unlisted_input; the engine lands on the alternative reading): regenerate only if a reviewer rules that the stated facts decide it - check the drafted reason" + }, + { + "scenario_id": "scenario_005", + "state": "CA", + "variable": "federal_income_tax_before_refundable_credits", + "previous": 106505.8984375, + "new": 108525.578125, + "status": "excluded 20261014: r02_ira_219g", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "excluded_rechecked", + "call": "RECHECK (20261014 engine defect r02_ira_219g, on the corrected value the 2026-10-13 recheck found, with a second reason) - check the drafted reason" + }, + { + "scenario_id": "scenario_020", + "state": "TX", + "variable": "federal_income_tax_before_refundable_credits", + "previous": 68056.7109375, + "new": 68334.734375, + "status": "excluded 20261014: reference_depends_on_unlisted_input", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "excluded_rechecked", + "call": "RECHECK (20261014 reference_depends_on_unlisted_input) - check the drafted reason" + }, + { + "scenario_id": "scenario_023", + "state": "CA", + "variable": "snap", + "previous": 461.3397216796875, + "new": 408.0, + "status": "excluded 20261014: reference_depends_on_unlisted_input", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "excluded_rechecked", + "call": "RECHECK (20261014 reference_depends_on_unlisted_input) - check the drafted reason" + }, + { + "scenario_id": "scenario_028", + "state": "PA", + "variable": "free_school_meals_eligible", + "previous": 0.0, + "new": 1.0, + "status": "scored", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "approved", + "call": "APPROVE (PA universal free breakfast, #10238) - confirm the breakfast tier, the paid lunch tier and the enactment date" + }, + { + "scenario_id": "scenario_031", + "state": "CA", + "variable": "snap", + "previous": 0.0, + "new": 288.0, + "status": "scored", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "approved", + "call": "APPROVE (CalFresh MCE net income test removed, #10036; minimum allotment) - confirm the gross and net income, the 200% gross limit and the minimum in the build trace" + }, + { + "scenario_id": "scenario_052", + "state": "TX", + "variable": "federal_income_tax_before_refundable_credits", + "previous": 104211.40625, + "new": 104225.2578125, + "status": "excluded 20261014: r02_ira_219g", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "excluded_rechecked", + "call": "RECHECK (20261014 engine defect r02_ira_219g lands on target, but the record's note names an unlisted input too): regenerate only if a reviewer rules that reason out - check the drafted reason" + }, + { + "scenario_id": "scenario_056", + "state": "NJ", + "variable": "snap", + "previous": 1140.0, + "new": 95.0, + "status": "excluded 20261014: reference_depends_on_unlisted_input", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "excluded_rechecked", + "call": "RECHECK (20261014 reference_depends_on_unlisted_input) - check the drafted reason" + }, + { + "scenario_id": "scenario_057", + "state": "LA", + "variable": "snap", + "previous": 2669.217041015625, + "new": 2628.0, + "status": "excluded 20261014: reference_depends_on_unlisted_input", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "excluded_rechecked", + "call": "RECHECK (20261014 reference_depends_on_unlisted_input) - check the drafted reason" + }, + { + "scenario_id": "scenario_080", + "state": "PA", + "variable": "snap", + "previous": 3596.039794921875, + "new": 3240.0, + "status": "excluded 20261014: r30_snap_heat_and_eat_sua", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "excluded_rechecked", + "call": "RECHECK (20261014 engine defect r30_snap_heat_and_eat_sua lands on target, but the 2026-09-29 recheck found it indeterminate on the stated facts): regenerate only if a reviewer rules that reason out - check the drafted reason" + }, + { + "scenario_id": "scenario_081", + "state": "MA", + "variable": "state_income_tax_before_refundable_credits", + "previous": 8238.40625, + "new": 8232.900390625, + "status": "excluded 20261014: r22_ma_part_a_loss_offset", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "excluded_rechecked", + "call": "RECHECK (20261014 engine defect r22_ma_part_a_loss_offset lands on target, but the record's note names an unlisted input too): regenerate only if a reviewer rules that reason out - check the drafted reason" + }, + { + "scenario_id": "scenario_100", + "state": "MT", + "variable": "snap", + "previous": 8625.8896484375, + "new": 6924.0, + "status": "excluded 20261014: reference_depends_on_unlisted_input", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "excluded_rechecked", + "call": "RECHECK (20261014 reference_depends_on_unlisted_input) - check the drafted reason" + }, + { + "scenario_id": "scenario_107", + "state": "OH", + "variable": "federal_income_tax_before_refundable_credits", + "previous": 0.0, + "new": 211.232421875, + "status": "excluded 20261014: reference_depends_on_unlisted_input", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "excluded_rechecked", + "call": "RECHECK (20261014 reference_depends_on_unlisted_input; the engine lands on the alternative reading): regenerate only if a reviewer rules that the stated facts decide it - check the drafted reason" + }, + { + "scenario_id": "scenario_112", + "state": "TX", + "variable": "snap", + "previous": 287.68316650390625, + "new": 0.0, + "status": "excluded 20261014: reference_depends_on_unlisted_input", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "excluded_rechecked", + "call": "RECHECK (20261014 reference_depends_on_unlisted_input; the engine lands on the alternative reading): regenerate only if a reviewer rules that the stated facts decide it - check the drafted reason" + }, + { + "scenario_id": "scenario_117", + "state": "AR", + "variable": "free_school_meals_eligible", + "previous": 0.0, + "new": 1.0, + "status": "scored", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "approved", + "call": "APPROVE (AR universal free breakfast, #10238) - confirm the breakfast tier, the paid lunch tier and the enactment date" + }, + { + "scenario_id": "scenario_118", + "state": "NY", + "variable": "snap", + "previous": 2903.9404296875, + "new": 2400.0, + "status": "excluded 20261014: reference_depends_on_unlisted_input", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "excluded_rechecked", + "call": "RECHECK (20261014 reference_depends_on_unlisted_input) - check the drafted reason" + }, + { + "scenario_id": "scenario_120", + "state": "CT", + "variable": "federal_income_tax_before_refundable_credits", + "previous": 40021.81640625, + "new": 40423.17578125, + "status": "excluded 20261014: r02_ira_219g", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "excluded_rechecked", + "call": "RECHECK (20261014 engine defect r02_ira_219g, on the corrected value the 2026-10-13 recheck found, with a second reason) - check the drafted reason" + }, + { + "scenario_id": "scenario_121", + "state": "SC", + "variable": "federal_income_tax_before_refundable_credits", + "previous": 0.0, + "new": 875.3375244140625, + "status": "excluded 20261014: reference_depends_on_unlisted_input", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "excluded_rechecked", + "call": "RECHECK (20261014 reference_depends_on_unlisted_input; the engine lands on the alternative reading): regenerate only if a reviewer rules that the stated facts decide it - check the drafted reason" + }, + { + "scenario_id": "scenario_121", + "state": "SC", + "variable": "state_income_tax_before_refundable_credits", + "previous": 0.0, + "new": 212.23350524902344, + "status": "excluded 20261014: reference_depends_on_unlisted_input", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "excluded_rechecked", + "call": "RECHECK (20261014 reference_depends_on_unlisted_input; the engine lands on the alternative reading): regenerate only if a reviewer rules that the stated facts decide it - check the drafted reason" + }, + { + "scenario_id": "scenario_123", + "state": "PA", + "variable": "free_school_meals_eligible", + "previous": 0.0, + "new": 1.0, + "status": "scored", + "hub_audited_target": "", + "decision": "PROPOSED", + "placed_in": "approved", + "call": "APPROVE (PA universal free breakfast, #10238) - confirm the breakfast tier, the paid lunch tier and the enactment date" + } + ], + "note": "Reviewed 2026-10-23 on policyengine-us 2.60.0, the newest PyPI release when the sweep began (verification/sweep_timing.json). A first sweep on 2.59.0 (2026-10-22 19:49 UTC) was cut off by a host restart; when it resumed, 2.60.0 was out and moved three scored outputs 2.59.0 does not (verification/superseded_2_59_0.json), so the references are built on 2.60.0. Each named pull request is an ancestor of 2.60.0's release commit 2bc4ccc970. Four scored outputs move, each approved: scenario_031 SNAP (#10036, California MCE) and the free school meals flag of scenario_028, 117 and 123 (#10238, Pennsylvania and Arkansas universal free breakfast, standing statutes enacted before the 2026-07-03 freeze). No exclusion is regenerated: the four outputs that land on their records' alternative values (scenario_002, 107 and 121 federal income tax, scenario_121 state income tax; #10185) are reference_depends_on_unlisted_input records (r24 is classed unlisted_input in reference_audit/2026-09-22/root_causes.json), and the engine reaches the alternative through a default for the unstated input, so they stay excluded with the other rechecks. Of the 16 rechecks, only scenario_118 SNAP (#10158) and the four r24 outputs change value from 2.41.0; the other eleven keep 2.41.0's values and are rechecked because their decided values differ from the engine's. No new exclusion." +} diff --git a/reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.json b/reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.json new file mode 100644 index 00000000..21ae708a --- /dev/null +++ b/reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.json @@ -0,0 +1,6 @@ +{ + "scenario_028|free_school_meals_eligible": "PolicyEngine determined that this Pennsylvania household of four receives free school meal support in 2026, so the value is 1. School meals count the household's income of $61,277: $60,000 of wages, $10 of interest and $1,267 of child support received. That is 1.86 times the $33,000 poverty guideline for a household of four, above the 185% limit for reduced-price meals, so on income alone both meals are in the paid tier. Pennsylvania gives every public school student a free breakfast regardless of household income (Act 33 of 2023, 24 P.S. § 13-1337.1(c.2)), so breakfast is in the free tier for the household's three K-12 children while lunch stays paid. PolicyEngine values that breakfast at $1,112.40 for the year: $2.06 a school day for each child (the $2.90 daily subsidy less the $0.84 paid-meal rate) over 180 school days. That free school meal support is positive, so the value is 1.", + "scenario_031|snap": "PolicyEngine calculated a SNAP benefit of $288 for this California household in 2026: the $24 monthly minimum allotment for each of the twelve months. The household is one 67-year-old, so the elderly-or-disabled rules apply. Its countable gross income is $1,987.79 a month ($9,445.47 of Social Security, $13,608.00 of private pension income and $800.00 of IRA distributions a year), within the $2,608.33 limit of California's Modified Categorical Eligibility (200% of the $1,304.17 monthly poverty guideline for one person), and its $4,200 of bank assets pass the asset test. That makes the household categorically eligible for CalFresh, which waives the net income test, so its net income of $1,611 a month, above the poverty guideline, does not disqualify it. The benefit formula gives the $298 maximum allotment less 30% of net income ($484), which is below zero, so as an eligible one-person household it receives the $24 minimum allotment (7 U.S.C. 2017(a)) each month: $288 for the year.", + "scenario_117|free_school_meals_eligible": "PolicyEngine determined that this Arkansas household of five receives free school meal support in 2026, so the value is 1. School meals count the household's $248,675 of wages, 6.43 times the $38,680 poverty guideline for a household of five, so on income alone both meals are in the paid tier. Arkansas gives every public school student a free breakfast regardless of household income from the 2025-26 school year (Act 123 of 2025, A.C.A. § 6-18-722(f)), so breakfast is in the free tier for the household's two K-12 children while lunch stays paid. PolicyEngine values that breakfast at $741.60 for the year: $2.06 a school day for each child (the $2.90 daily subsidy less the $0.84 paid-meal rate) over 180 school days. That free school meal support is positive, so the value is 1.", + "scenario_123|free_school_meals_eligible": "PolicyEngine determined that this Pennsylvania household of three receives free school meal support in 2026, so the value is 1. School meals count the household's income of $145,002: $145,000 of wages and $2 of interest. That is 5.31 times the $27,320 poverty guideline for a household of three, so on income alone both meals are in the paid tier. Pennsylvania gives every public school student a free breakfast regardless of household income (Act 33 of 2023, 24 P.S. § 13-1337.1(c.2)), so breakfast is in the free tier for the household's one K-12 student, the 16-year-old, while lunch stays paid. PolicyEngine values that breakfast at $370.80 for the year: $2.06 a school day (the $2.90 daily subsidy less the $0.84 paid-meal rate) over 180 school days. That free school meal support is positive, so the value is 1." +} diff --git a/reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.md b/reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.md new file mode 100644 index 00000000..2b7e691e --- /dev/null +++ b/reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.md @@ -0,0 +1,27 @@ +# Hand-corrected reference narratives + +`hand_corrected_narratives.json` gives the reference narratives of the four outputs the +2026-10-22 engine upgrade changes. It is applied through +`scripts/narratives_upgrade.py --hand-corrected`, so the narrative writer (claude-haiku-4-5) is +not called. The 2026-10-12 upgrade's writer misstated the change behind six of its nine outputs. + +Each text states figures from the 2.60.0 build's traces (`build/reference_traces.json`). +`tests/test_build_references_upgrade_1022.py` checks each figure against the trace and +recomputes every sum the texts state. Each rule a text names is the one the upstream pull +request encodes, with its law: #10036 for California's MCE, and #10238 for the Pennsylvania and +Arkansas breakfast statutes. + +The narratives these replace were stale: + +- **scenario_031 SNAP.** The old text said the household's income "places it above the + threshold for SNAP eligibility". On 2.60.0, California's MCE waives the net income test. The + household is categorically eligible, and as a one-person household it gets the $24 minimum. +- **scenario_028 free school meals.** The old text predates the 2026-09-29 change that counts + child support as school-meal income. It gave $60,010 of income and a 1.82 ratio, and said the + household qualifies for reduced-price meals. The reference has counted the $1,267 of child + support since then: $61,277, 1.86, the paid tier, as the household's reduced-price narrative + already says. +- **scenario_117 and scenario_123 free school meals.** The old texts said the state does not + offer universal free school meals. That is still true of lunch, but the households' K-12 + children now get a free breakfast, valued at $2.06 a school day ($2.90 less the $0.84 paid + rate) over 180 days. diff --git a/reference_audit/2026-10-22-engine-upgrade/scripts/build_references_upgrade.py b/reference_audit/2026-10-22-engine-upgrade/scripts/build_references_upgrade.py new file mode 100644 index 00000000..00b39db4 --- /dev/null +++ b/reference_audit/2026-10-22-engine-upgrade/scripts/build_references_upgrade.py @@ -0,0 +1,1675 @@ +"""Rebuild PolicyBench's US references on the newest policyengine-us (the fourth +engine upgrade, after release dashboard-data-20261014). + +Adapted from reference_audit/2026-10-12-engine-upgrade/scripts/ +build_references_upgrade.py, which moved the references from policyengine-us +2.38.6 to 2.41.0 for release 20261013; that builder was adapted in turn from +the 2026-10-09 and 2026-09-28 ones (PR #182). + +Rulings: +- Max, 2026-09-28: "we should be using the latest pe for this always!" +- Max, 2026-10-09: "yes i want to wait for hte fixed engine". A cell the new + engine fixes is regenerated and its exclusion record removed (the #178 + precedent, cb312fd7). +- Rule 5: an excluded output keeps the value it was decided on; an excluded + output that moves gets an excluded_rechecked entry. + +Base (read from git, never from the checkout, whose snapshot holds whatever was +last installed): release 20261014 at BASE_COMMIT, i.e. the 2.41.0 references +and the 49-record exclusion record, each file pinned by sha256. No release is +being frozen with this build, so no release spec rules an exclusion: the +record this script edits is the base's own. The next board release installs +the build (reference_audit/2026-10-22-engine-upgrade/build/); a release that +rules exclusions of its own applies them after installing it. The original +v1.1 frozen values (each change's "frozen") come from FROZEN_COMMIT. + +Method: every output is computed on the installed policyengine-us with +reference_audit/2026-09-28/fixes/latest_final.py (the pre-freeze conventions and +the Maryland local-scope adapter), imported in place from --fixes-dir, with the +households built by reference_audit/2026-09-28/scripts/sweep.py's +build_situation. Every fix module's sha256 must equal the one the 2026-09-29 +engine_upgrade revision records; latest_final.py, sweep.py and the sales tax +tables (r19_irs_sales_tax_2025.json, which latest_c_irs_sales_tax_2025.py reads +from its own directory) must each equal the bytes committed at BASE_COMMIT (the +tables as reference_audit/2026-09-22/fixes holds them). + +A move is a change beyond the exact-match tolerance +(policybench.paper_results.moves_beyond_tolerance: more than $1 for an amount, +any change for a 0/1 flag), measured from the base's reference value. An +excluded output's reference is the value it was decided on, which can differ +from what the previous engine gave; such an output moves on every upgrade until +its record is removed, so each upgrade rechecks it. A scored output takes the +computed value; one that changes by $1 or less (more than EPS) is recorded as +engine_upgrade_within_1. + +ACTIONS FILE (JSON; every list optional except where a move needs it): + + engine "policyengine-us X.Y.Z"; must equal the installed release. + previous_engine "policyengine-us 2.41.0"; must equal the base sidecar's + last engine_upgrade engine_version. + date UTC day of the build (YYYY-MM-DD): the revision's date, the + derivation's, and each new record's decided_on. The sidecar's + regenerated_at_utc must fall on it. + draft true for actions_from_cells.py's output; the builder + refuses a draft unless --allow-draft (rehearsals only). + review, note free text for reviewers; ignored. + approved [{scenario_id, variable, value, cause, basis}]: scored + outputs allowed to move; the engine must give value within + APPROVED_TOL (half a cent). + regenerated_exclusions [{scenario_id, variable, alternative_value, + tolerance, upstream, basis, target}]: excluded outputs + whose reference_engine_defect the new engine fixes. + alternative_value must be the record's; tolerance is at most + $1; upstream must name the fix ("to be filed" does not). The + engine must land within the tolerance of the audited + corrected value (a flag must equal it), which target says + how to know: + {"kind": "record"} (the default): the record's + alternative_value. Right when nothing else in the engine + has moved the output since the record was decided. + {"kind": "fix_modules", "modules": [file, ...], + "evidence": {"path", "sha256"}}: the record's audited fix + modules (reference_audit/2026-09-22/fixes, the bytes + committed at BASE_COMMIT, or this audit's own fixes/ + as committed at HEAD), on a recent engine that still + has the defect. The evidence file (--evidence-request + mode, on that engine) gives the output there without and + with the modules; they must move it beyond the tolerance + (the defect was there), and the corrected value is the + target. On the new engine the builder applies the modules + again: they must move it by no more than the tolerance + (nothing is left to fix). A record decided on an older + engine needs this kind once other engine changes have + moved the output, because its alternative_value no longer + includes them. + The record is removed and the output scored at the engine + value. + new_exclusions [complete exclusion record]: scored outputs the new engine + moves onto an input the prompt does not state (for example + Indiana county). frozen_value must be the engine value + (within 1e-3), engine_version the new engine, decided_on the + date, and the alternative must differ beyond the tolerance. + excluded_rechecked [{scenario_id, variable, reason}]: excluded outputs that + move but stay excluded, keeping the decided value. + +The builder refuses, listing every problem with exact engine values: an +unexplained move (scored or excluded), an approved output that does not move or +lands elsewhere, a regenerated output off its target or not an engine defect, a +new exclusion on an output that does not move, a rechecked output that does not +move, an entry on an unknown output, and an output named by two actions. + +It writes to --out-dir: + reference_outputs.csv release 20261014's rows byte for byte, except each + changed row, whose value field is rewritten. + reference_exclusions.json release 20261014's record less the regenerated + records, with the new exclusions before the trailing + 2026-09-29 audit record and one sentence appended to + the derivation naming the upgrade. + reference_outputs.csv.meta.json the base sidecar with the US bundle, csv + sha256 and regenerated_at_utc updated and a fourth + engine_upgrade revision appended; every earlier revision + is kept byte for byte. + reference_traces.json engine traces of every changed output. + computed.csv (also with --computed-csv, written before any refusal) + every output on the new engine, in sweep.py's columns. + +Run (PYTHONPATH is the checkout; the fixes directory needs the sales tax tables): + + PYTHONDONTWRITEBYTECODE=1 OPENBLAS_NUM_THREADS=1 PYTHONPATH= \\ + /bin/python \\ + reference_audit/2026-10-22-engine-upgrade/scripts/build_references_upgrade.py \\ + --actions --out-dir [--fixes-dir ] [--allow-draft] + +or through scripts/sweep_timing.py run, which checks the engine first in the +same process. + +EVIDENCE MODE (on a pre-fix engine, for "fix_modules" targets): + + ... build_references_upgrade.py --evidence-request \\ + --evidence-out [--fixes-dir ] + +The request is {"items": [{scenario_id, variable, modules: [file, ...]}]}. The +evidence file names the installed engine and every module's sha256, and gives +each item's engine_value (the pinned conventions alone) and corrected_value +(the conventions plus the modules, applied after them). +""" + +from __future__ import annotations + +import argparse +import copy +import csv +import datetime +import hashlib +import importlib.util +import io +import json +import math +import subprocess +import sys +from dataclasses import dataclass, field +from pathlib import Path, PurePosixPath + +HERE = Path(__file__).resolve().parent +ROOT = HERE.parents[2] +RUN = "paper/snapshot/20260501/runs/us_full_run_20260612_policyengine_4_16_1_populace" +# The squash merge of PR #221 on main, whose tree holds release 20261014 (the +# board's latest): the 2.41.0 references release 20261013 (#217, bc305793) +# installed, unchanged since. +BASE_COMMIT = "bf845cbe4e92de495150c8660c35ea357d996a8c" +BASE_SHA256 = { + "reference_outputs.csv": ( + "2d00cf595adf183fcfa3d069756723b5ce09bd4123fbf3e673635474346b3a0c" + ), + "reference_outputs.csv.meta.json": ( + "0dc1ba15a11a20d9a3915a4537a33127e5406b5fde4797586d39ce5dbf170915" + ), + "reference_exclusions.json": ( + "a2ddf91634ed66124d13105a09badea39ec6b5f11863011fa51f9ca17f8f3939" + ), + "scenarios.csv": ( + "71b16212f0c0b3e5d13d8694ce57e362c23248665806c4d6dea7b23ef472858a" + ), +} +# Re-freeze on the 24-model board (#121): the snapshot's last commit holding the +# v1.1 frozen references (policyengine-us 1.755.4), the bundle the 2026-09-29 +# builder read as "frozen". +FROZEN_COMMIT = "f108a959d91567c050a99d4d1d583904b3d5a809" +FROZEN_SHA256 = "b9136a15e285f9c02ba78bee854b8a3af180e280485512642c829e8ffd7d2368" +PREVIOUS_ENGINE = "policyengine-us 2.41.0" +FIXES_REL = "reference_audit/2026-09-28/fixes" +FIXES = ROOT / FIXES_REL +HARNESS_REL = "reference_audit/2026-09-28/scripts/sweep.py" +HARNESS = ROOT / HARNESS_REL +FIX_ENTRY = "latest_final" +SALES_TAX_TABLES = "r19_irs_sales_tax_2025.json" +SALES_TAX_REL = f"reference_audit/2026-09-22/fixes/{SALES_TAX_TABLES}" +SALES_TAX_SOURCE = ROOT / SALES_TAX_REL +# The audited root-cause fix modules (2026-09-22): a "fix_modules" target +# applies them after the conventions. +AUDIT_FIXES_REL = "reference_audit/2026-09-22/fixes" +AUDIT_FIXES = ROOT / AUDIT_FIXES_REL +# This audit's own fix modules, for defects found after 2026-09-22 (none so +# far: no regeneration here needs a "fix_modules" target). A module that is not +# committed at BASE_COMMIT under AUDIT_FIXES_REL is read from here, at the bytes +# committed at HEAD: commit it before the evidence or the build runs. A target +# names such a module's path (fix_location); scripts/freeze_snapshot.py's +# verify_regeneration_target_pins holds the published pin to it. +LOCAL_FIXES_REL = "reference_audit/2026-10-22-engine-upgrade/fixes" +LOCAL_FIXES = ROOT / LOCAL_FIXES_REL +EVIDENCE_KIND = "regeneration_evidence" +# A fix module loads a sibling as Path(__file__).with_name(""); those +# siblings run too, so they are pinned with it (module_dependencies, from +# policybench.fix_module_closure, which refuses any other way of loading one). +TARGET_RECORD = "record" +TARGET_FIX_MODULES = "fix_modules" +YEAR = 2026 +EPS = 1e-6 +FROZEN_TOL = 1e-3 +APPROVED_TOL = 0.005 +MAX_REGENERATION_TOL = 1.0 +# The trailing record of 20261014's exclusion record: the 2026-09-29 audit's +# exclusion, which tests/test_reference_upgrade.py requires last. +AUDIT_TAIL = ("scenario_023", "head_medicaid_eligible") +ENGINE_DEFECT = "reference_engine_defect" +# A regeneration claims a released upstream fix and must name it. +UNNAMED_UPSTREAM = frozenset({"", "to be filed", "none", "unknown"}) +ACTION_KEYS = frozenset( + { + "engine", + "previous_engine", + "date", + "draft", + "review", + "note", + "approved", + "regenerated_exclusions", + "new_exclusions", + "excluded_rechecked", + } +) +RULE = ( + "A scored reference follows from the stated facts and from law published before " + "the 2026-07-03 reference freeze." +) +ENGINE_RULE = ( + "References come from the newest policyengine-us release when PolicyBench begins " + "the reference sweep; at publication PolicyBench checks that the newest release " + "gives the same values." +) +UPGRADE_RULE = ( + "Max, 2026-09-28: 'we should be using the latest pe for this always!'; and " + "2026-10-09, on waiting for the release that fixes the engine defects behind " + "PolicyBench's exclusions: 'yes i want to wait for hte fixed engine'. An " + "excluded output whose engine defect the new release fixes, landing on its " + "audited corrected value, is regenerated and its exclusion record removed (the " + "#178 precedent); every other excluded output keeps the value it was decided on." +) +NUMBER_WORDS = { + 1: "one", + 2: "two", + 3: "three", + 4: "four", + 5: "five", + 6: "six", + 7: "seven", + 8: "eight", + 9: "nine", + 10: "ten", +} + +Key = tuple[str, str] + + +class Refusal(SystemExit): + """The builder refuses to write references.""" + + +def sha256_bytes(raw: bytes) -> str: + return hashlib.sha256(raw).hexdigest() + + +def sha256(path: Path) -> str: + return sha256_bytes(Path(path).read_bytes()) + + +def dump_record(value: dict) -> str: + """The serialization of the sidecar and the exclusion record.""" + return json.dumps(value, indent=2) + "\n" + + +def words(n: int) -> str: + return NUMBER_WORDS.get(n, str(n)) + + +def key_of(item: dict) -> Key: + return (str(item["scenario_id"]), str(item["variable"])) + + +def engine_number(engine: str) -> str: + prefix = "policyengine-us " + if not engine.startswith(prefix): + raise Refusal(f"engine must read 'policyengine-us X.Y.Z', not {engine!r}") + return engine.removeprefix(prefix) + + +def engine_older(older: str, newer: str) -> bool: + """Whether one 'policyengine-us X.Y.Z' release precedes another.""" + + def parts(engine: str) -> tuple[int, ...]: + return tuple(int(p) for p in engine_number(engine).split(".")) + + return parts(older) < parts(newer) + + +def beyond(variable: str, before: float, after: float) -> bool: + """A move beyond the exact-match tolerance, as the paper counts it.""" + from policybench.paper_results import moves_beyond_tolerance + + return moves_beyond_tolerance(variable, before, after) + + +# --- Base ------------------------------------------------------------------ + + +def git_blob(commit: str, path: str, root: Path = ROOT) -> bytes: + result = subprocess.run( + ["git", "-C", str(root), "show", f"{commit}:{path}"], capture_output=True + ) + if result.returncode: + raise Refusal( + f"cannot read {path} at {commit[:12]} (fetch full history): " + f"{result.stderr.decode().strip()}" + ) + return result.stdout + + +@dataclass +class Row: + key: Key + fields: list[str] + raw: str + + @property + def value(self) -> float: + return float(self.fields[2]) + + +@dataclass +class ReferenceCsv: + header_raw: str + header: list[str] + rows: list[Row] + + def values(self) -> dict[Key, float]: + return {row.key: row.value for row in self.rows} + + +def physical_lines(text: str) -> list[str]: + """Split on '\\n' only, each piece keeping its terminator.""" + lines = text.split("\n") + out = [line + "\n" for line in lines[:-1]] + if lines[-1]: + out.append(lines[-1]) + return out + + +def parse_reference_csv(text: str) -> ReferenceCsv: + """Rows with their raw text, so an unchanged row is written byte for byte.""" + lines = physical_lines(text) + reader = csv.reader(iter(lines)) + records, used = [], 0 + for fields in reader: + records.append((fields, "".join(lines[used : reader.line_num]))) + used = reader.line_num + (header, header_raw), body = records[0], records[1:] + if header[:3] != ["scenario_id", "variable", "value"]: + raise Refusal(f"unexpected reference header {header}") + rows = [Row((f[0], f[1]), f, raw) for f, raw in body] + if len({row.key for row in rows}) != len(rows): + raise Refusal("the reference CSV lists an output twice") + return ReferenceCsv(header_raw, header, rows) + + +def format_row(fields: list[str]) -> str: + buffer = io.StringIO() + csv.writer(buffer, lineterminator="\n").writerow(fields) + return buffer.getvalue() + + +def render_reference_csv(reference: ReferenceCsv, new_values: dict[Key, float]) -> str: + """The base CSV with each output in new_values rewritten at that value.""" + parts = [reference.header_raw] + for row in reference.rows: + if row.key in new_values: + fields = list(row.fields) + fields[2] = repr(float(new_values[row.key])) + raw = format_row(fields) + if not row.raw.endswith("\n"): + raw = raw.removesuffix("\n") + parts.append(raw) + else: + parts.append(row.raw) + return "".join(parts) + + +@dataclass +class Base: + reference: ReferenceCsv + meta: dict + exclusions: dict + scenarios_csv: str + frozen: dict[Key, float] + + +def load_base(root: Path = ROOT) -> Base: + """Release 20261014's references at BASE_COMMIT, each file pinned.""" + blobs = {} + for name, pin in BASE_SHA256.items(): + raw = git_blob(BASE_COMMIT, f"{RUN}/{name}", root) + if sha256_bytes(raw) != pin: + raise Refusal(f"{name} at {BASE_COMMIT[:12]} does not match its pin") + blobs[name] = raw.decode() + frozen_raw = git_blob(FROZEN_COMMIT, f"{RUN}/reference_outputs.csv", root) + if sha256_bytes(frozen_raw) != FROZEN_SHA256: + raise Refusal("the v1.1 frozen references do not match their pin") + return Base( + reference=parse_reference_csv(blobs["reference_outputs.csv"]), + meta=json.loads(blobs["reference_outputs.csv.meta.json"]), + exclusions=json.loads(blobs["reference_exclusions.json"]), + scenarios_csv=blobs["scenarios.csv"], + frozen=parse_reference_csv(frozen_raw.decode()).values(), + ) + + +# --- The plan ---------------------------------------------------------------- + + +@dataclass +class Plan: + problems: list[str] = field(default_factory=list) + new_values: dict[Key, float] = field(default_factory=dict) + changed: list[dict] = field(default_factory=list) + within: list[dict] = field(default_factory=list) + rechecked: list[dict] = field(default_factory=list) + regenerated: list[dict] = field(default_factory=list) + new_records: list[dict] = field(default_factory=list) + + +def _entries(actions: dict, name: str) -> dict[Key, dict]: + entries: dict[Key, dict] = {} + for item in actions.get(name, []): + k = key_of(item) + if k in entries: + raise Refusal(f"{name} lists {k} twice") + entries[k] = item + return entries + + +def validate_actions(actions: dict, *, allow_draft: bool = False) -> None: + unknown = set(actions) - ACTION_KEYS + if unknown: + raise Refusal(f"unknown actions keys {sorted(unknown)}") + for name in ("engine", "previous_engine", "date"): + if not isinstance(actions.get(name), str) or not actions[name]: + raise Refusal(f"actions must name {name}") + datetime.date.fromisoformat(actions["date"]) + engine_number(actions["engine"]) + if actions.get("draft") and not allow_draft: + raise Refusal( + "the actions file is a draft (actions_from_cells.py output): review " + "every judgment call and set draft to false, or pass --allow-draft " + "for a rehearsal" + ) + lists = ( + "approved", + "regenerated_exclusions", + "new_exclusions", + "excluded_rechecked", + ) + # No two lists may share an output. + seen: dict[Key, str] = {} + for name in lists: + for k in _entries(actions, name): + if k in seen: + raise Refusal(f"{k} is in both {seen[k]} and {name}") + seen[k] = name + + +def target_modules(entry: dict) -> tuple[str, ...]: + """The fix modules a regeneration's target names (none for a record).""" + target = entry.get("target") or {} + modules = target.get("modules") if isinstance(target, dict) else None + if isinstance(modules, list) and all(isinstance(m, str) for m in modules): + return tuple(modules) + return () + + +def regeneration_target( + k: Key, + entry: dict, + record: dict, + value: float, + tolerance: float, + *, + engine: str, + evidence: dict[str, dict], + module_pins: dict[str, str], + module_values: dict[tuple[Key, tuple[str, ...]], float], + module_deps: dict[str, list[str]] | None = None, +) -> tuple[dict | None, list[str]]: + """The audited corrected value a regenerated output must land on, and how + it is known (the entry's target), or the problems that stop it. Pure.""" + target = entry.get("target", {"kind": TARGET_RECORD}) + if not isinstance(target, dict): + return None, [f"regenerated {k}: target is not an object"] + kind = target.get("kind") + if kind == TARGET_RECORD: + if set(target) != {"kind"}: + return None, [f"regenerated {k}: a record target takes no other fields"] + return { + "kind": TARGET_RECORD, + "value": float(record["alternative_value"]), + "engine": record["engine_version"], + }, [] + if kind != TARGET_FIX_MODULES: + return None, [f"regenerated {k}: unknown target kind {kind!r}"] + modules = target_modules(entry) + problems = [] + if set(target) != {"kind", "modules", "evidence"}: + problems.append(f"regenerated {k}: a fix_modules target takes kind, modules " + "and evidence") + if not modules or len(set(modules)) != len(modules): + problems.append(f"regenerated {k}: the target names no modules, or one twice") + unpinned = [m for m in modules if m not in module_pins] + if unpinned: + problems.append(f"regenerated {k}: unknown fix modules {unpinned}") + ref = target.get("evidence") + doc = evidence.get(ref.get("path")) if isinstance(ref, dict) else None + if doc is None: + problems.append(f"regenerated {k}: the target's evidence is not loaded") + if problems: + return None, problems + variable = k[1] + if not engine_older(doc["engine"], engine): + problems.append( + f"regenerated {k}: the evidence is computed on {doc['engine']}, not an " + f"engine older than {engine}; it must come from one that still has the " + "defect" + ) + stale = [m for m in modules if doc["modules"].get(m) != module_pins[m]] + if stale: + problems.append(f"regenerated {k}: the evidence ran other bytes of {stale}") + items = [ + item + for item in doc["items"] + if key_of(item) == k and tuple(item["modules"]) == modules + ] + if len(items) != 1: + problems.append( + f"regenerated {k}: the evidence has {len(items)} items for {list(modules)}" + ) + return None, problems + item = items[0] + before, corrected = float(item["engine_value"]), float(item["corrected_value"]) + dependencies = [] + for m in modules: + for d in (module_deps or {}).get(m, []): + if d not in modules and d not in dependencies: + dependencies.append(d) + unpinned = [ + d for d in dependencies if d not in module_pins or doc["modules"].get(d) != module_pins[d] + ] + if unpinned: + problems.append( + f"regenerated {k}: the evidence does not pin the siblings its modules " + f"load, as committed: {unpinned}" + ) + if not (math.isfinite(before) and math.isfinite(corrected)): + problems.append(f"regenerated {k}: the evidence's values are not finite") + return None, problems + if not beyond(variable, before, corrected): + problems.append( + f"regenerated {k}: on {doc['engine']} the modules move it only " + f"{before!r} -> {corrected!r}, so the evidence shows no defect" + ) + after = module_values.get((k, modules)) + if after is None: + problems.append(f"regenerated {k}: the modules were not applied on {engine}") + elif not math.isfinite(after) or abs(after - value) > tolerance or beyond( + variable, value, after + ): + problems.append( + f"regenerated {k}: the audited fix still moves it on {engine}: " + f"{value!r} -> {after!r}" + ) + if problems: + return None, problems + return { + "kind": TARGET_FIX_MODULES, + "value": corrected, + "engine": doc["engine"], + "engine_value": before, + "modules": [module_pin(m, module_pins) for m in modules], + "dependencies": [module_pin(d, module_pins) for d in dependencies], + "evidence": ref["path"], + "evidence_sha256": ref["sha256"], + "value_with_modules": after, + }, [] + + +def module_pin(name: str, module_pins: dict[str, str]) -> dict: + """A target's pin of one module: its name and sha256, and its path when it + is this audit's own (LOCAL_FIXES_REL), where the freeze finds it.""" + pin = {"module": name, "sha256": module_pins[name]} + if is_local_fix(name): + pin["path"] = f"{LOCAL_FIXES_REL}/{name}" + return pin + + +def plan_upgrade( + base: Base, + actions: dict, + computed: dict[Key, float], + *, + evidence: dict[str, dict] | None = None, + module_pins: dict[str, str] | None = None, + module_values: dict[tuple[Key, tuple[str, ...]], float] | None = None, + module_deps: dict[str, list[str]] | None = None, +) -> Plan: + """Decide every output's value and record; never raise on a move, collect + every problem instead. Pure: no engine, no files. A "fix_modules" target + reads its evidence (loaded and pinned by the caller), the modules' pins and + their values on the new engine from the keyword arguments.""" + evidence = evidence or {} + module_pins = module_pins or {} + module_values = module_values or {} + plan = Plan() + engine = actions["engine"] + date = actions["date"] + board = base.reference.values() + records = {key_of(r): r for r in base.exclusions["exclusions"]} + excluded = set(records) + approved = _entries(actions, "approved") + regenerated = _entries(actions, "regenerated_exclusions") + added = _entries(actions, "new_exclusions") + rechecked = _entries(actions, "excluded_rechecked") + if set(computed) != set(board): + missing = sorted(set(board) - set(computed))[:5] + extra = sorted(set(computed) - set(board))[:5] + plan.problems.append( + f"computed outputs differ: missing {missing} extra {extra}" + ) + for name, entries in ( + ("approved", approved), + ("regenerated_exclusions", regenerated), + ("new_exclusions", added), + ("excluded_rechecked", rechecked), + ): + for k in entries: + if k not in board: + plan.problems.append(f"{name} names {k}, which is not a reference") + if actions["previous_engine"] != PREVIOUS_ENGINE: + plan.problems.append( + f"previous_engine is {actions['previous_engine']}, not {PREVIOUS_ENGINE}" + ) + + def change(k: Key, value: float, cause: str, basis: str) -> dict: + return { + "scenario_id": k[0], + "variable": k[1], + "frozen": float(base.frozen[k]), + "previous": board[k], + "regenerated": value, + "cause": cause, + "basis": basis, + } + + within_basis = ( + f"Moves by $1 or less on {engine}; no score changes at the exact-match " + "tolerance." + ) + for row in base.reference.rows: + k = row.key + if k not in computed: + continue + value, old = float(computed[k]), board[k] + if not math.isfinite(value): + plan.problems.append(f"{k}: the engine gives a non-finite value {value!r}") + continue + moves = beyond(k[1], old, value) + if k in excluded: + for name, entries in (("approved", approved), ("new_exclusions", added)): + if k in entries: + plan.problems.append(f"{name} names {k}, which is excluded") + record = records[k] + if k in regenerated: + entry = regenerated[k] + alternative = float(record["alternative_value"]) + tolerance = float(entry.get("tolerance", -1)) + if not math.isfinite(tolerance): + tolerance = -1.0 + if record["reason_code"] != ENGINE_DEFECT: + plan.problems.append( + f"regenerated {k} is {record['reason_code']}, not an engine " + "defect" + ) + continue + if abs(float(entry["alternative_value"]) - alternative) > EPS: + plan.problems.append( + f"regenerated {k}: alternative_value " + f"{entry['alternative_value']} is not the record's " + f"{alternative}" + ) + continue + if not 0 <= tolerance <= MAX_REGENERATION_TOL: + plan.problems.append( + f"regenerated {k}: tolerance {tolerance} outside [0, " + f"{MAX_REGENERATION_TOL}]" + ) + continue + target, problems = regeneration_target( + k, + entry, + record, + value, + tolerance, + engine=engine, + evidence=evidence, + module_pins=module_pins, + module_values=module_values, + module_deps=module_deps, + ) + if problems: + plan.problems.extend(problems) + continue + # A flag must equal its target; an amount must land within the + # tolerance, which is at most the exact-match $1. + aim = target["value"] + if abs(value - aim) > tolerance or beyond(k[1], aim, value): + plan.problems.append( + f"regenerated {k} misses its audited target: engine " + f"{value!r}, target {aim!r} +/- {tolerance} " + f"({target['kind']})" + ) + continue + if not str(entry.get("basis", "")).strip(): + plan.problems.append(f"regenerated {k} has no basis") + continue + upstream = str(entry.get("upstream", "")).strip() + if upstream.lower() in UNNAMED_UPSTREAM: + plan.problems.append( + f"regenerated {k} names no upstream fix ({upstream!r})" + ) + continue + if abs(value - old) > EPS: + plan.new_values[k] = value + plan.changed.append( + change(k, value, "regenerated_upstream_fix", entry["basis"]) + ) + plan.regenerated.append( + { + "scenario_id": k[0], + "variable": k[1], + "root_cause": record["root_cause"], + "decided_on": record["decided_on"], + "kept_value": old, + f"value_on_{engine_number(engine).replace('.', '_')}": value, + "audited_alternative_value": alternative, + "target": target, + "regenerated": value, + "tolerance": tolerance, + "upstream": entry["upstream"], + "basis": entry["basis"], + "record": copy.deepcopy(record), + } + ) + continue + # Stays excluded: keeps the value it was decided on (rule 5). + if moves: + if k not in rechecked: + plan.problems.append( + f"excluded output moved without a recheck: {k}: " + f"{old!r} -> {value!r}" + ) + elif not str(rechecked[k].get("reason", "")).strip(): + plan.problems.append(f"rechecked {k} has no reason") + else: + plan.rechecked.append( + { + "scenario_id": k[0], + "variable": k[1], + "kept_value": old, + f"value_on_{engine_number(engine).replace('.', '_')}": ( + value + ), + "reason": rechecked[k]["reason"], + } + ) + elif k in rechecked: + plan.problems.append( + f"rechecked {k} does not move: {old!r} -> {value!r}" + ) + continue + # Scored in the base. + for name, entries in ( + ("regenerated_exclusions", regenerated), + ("excluded_rechecked", rechecked), + ): + if k in entries: + plan.problems.append(f"{name} names {k}, which is scored") + if k in added: + record = added[k] + problems = new_exclusion_problems(record, value, old, engine, date) + if problems: + plan.problems.extend(f"new exclusion {k}: {p}" for p in problems) + continue + plan.new_values[k] = value + plan.new_records.append(copy.deepcopy(record)) + plan.changed.append( + change( + k, + value, + f"excluded_{record['reason_code']}", + f"Newly excluded from scoring on {record['decided_on']} " + "(reference_exclusions.json): " + + str( + record.get("unlisted_input") + or record.get("root_cause") + or record["alternative_reading"] + ), + ) + ) + continue + if k in approved: + entry = approved[k] + if not moves: + plan.problems.append( + f"approved {k} does not move: {old!r} -> {value!r}" + ) + continue + if not math.isfinite(float(entry["value"])) or ( + abs(value - float(entry["value"])) > APPROVED_TOL + ): + plan.problems.append( + f"approved {k}: engine {value!r} != approved {entry['value']!r}" + ) + continue + if ( + not str(entry.get("cause", "")).strip() + or not str(entry.get("basis", "")).strip() + ): + plan.problems.append(f"approved {k} needs a cause and a basis") + continue + plan.new_values[k] = value + plan.changed.append(change(k, value, entry["cause"], entry["basis"])) + continue + if moves: + plan.problems.append(f"unreviewed move {k}: {old!r} -> {value!r}") + continue + if abs(value - old) > EPS: + plan.new_values[k] = value + plan.within.append( + change(k, value, "engine_upgrade_within_1", within_basis) + ) + plan.new_records.sort(key=key_of) + return plan + + +def new_exclusion_problems( + record: dict, value: float, old: float, engine: str, date: str +) -> list[str]: + from policybench.reference_exclusions import ( + REASON_CODES, + REQUIRED_FIELDS_BY_REASON, + ) + + variable = record["variable"] + if record.get("reason_code") not in REASON_CODES: + return [f"unknown reason_code {record.get('reason_code')!r}"] + missing = [ + name + for name in REQUIRED_FIELDS_BY_REASON[record["reason_code"]] + if record.get(name) in (None, "") + ] + if missing: + return [f"record missing {missing}"] + problems = [] + if not beyond(variable, old, value): + problems.append(f"the output does not move: {old!r} -> {value!r}") + if abs(float(record["frozen_value"]) - value) > FROZEN_TOL: + problems.append(f"frozen_value {record['frozen_value']!r} != engine {value!r}") + if not beyond( + variable, float(record["frozen_value"]), float(record["alternative_value"]) + ): + problems.append("the alternative is within the exact-match tolerance") + if record["engine_version"] != engine: + problems.append(f"engine_version {record['engine_version']!r} != {engine!r}") + if record["decided_on"] != date: + problems.append(f"decided_on {record['decided_on']!r} != {date!r}") + return problems + + +# --- Records ------------------------------------------------------------------- + + +def upgrade_sentence(plan: Plan, actions: dict) -> str: + """The derivation's sentence naming the upgrade.""" + engine, date = actions["engine"], actions["date"] + number = engine_number(engine) + parts = [ + f" On {date} the references moved from {actions['previous_engine']} to" + f" {engine} with the same pre-freeze conventions" + " (reference_audit/2026-10-22-engine-upgrade), and every output was" + " recomputed there." + ] + n = len(plan.regenerated) + if n == 1: + parts.append( + " The new engine fixes the defect behind one excluded output, which" + " lands within $1 of its audited corrected value, so its record was" + " removed and the output is scored again (the reference sidecar's fourth" + " engine_upgrade revision lists it under regenerated_exclusions)." + ) + elif n: + parts.append( + f" The new engine fixes the defects behind {words(n)} excluded outputs," + " each landing within $1 of its audited corrected value, so their" + " records were removed and the outputs are scored again (the reference" + " sidecar's fourth engine_upgrade revision lists them under" + " regenerated_exclusions)." + ) + n = len(plan.new_records) + if n == 1: + parts.append( + " One scored output the new engine moved was excluded that day; its" + f" record is computed on {number}." + ) + elif n: + parts.append( + f" {words(n).capitalize()} scored outputs the new engine moved were" + f" excluded that day; their records are computed on {number}." + ) + n = len(plan.rechecked) + if n == 1: + parts.append( + " Of the excluded outputs that stay excluded, one moved; it was" + " re-reviewed and keeps the value it was decided on" + " (excluded_outputs_rechecked)." + ) + elif n: + parts.append( + f" Of the excluded outputs that stay excluded, {words(n)} moved; each" + " was re-reviewed and keeps the value it was decided on" + " (excluded_outputs_rechecked)." + ) + else: + parts.append( + " No excluded output that stays excluded moved; each keeps the value it" + " was decided on." + ) + return "".join(parts) + + +def upgrade_exclusions(base_exclusions: dict, plan: Plan, actions: dict) -> dict: + """The base record less the regenerated, the new records before the + trailing audit record, and the derivation naming the upgrade.""" + doc = copy.deepcopy(base_exclusions) + gone = {key_of(r) for r in plan.regenerated} + records = [r for r in doc["exclusions"] if key_of(r) not in gone] + tail = records[-1:] if records and key_of(records[-1]) == AUDIT_TAIL else [] + body = records[: len(records) - len(tail)] + doc["exclusions"] = body + copy.deepcopy(plan.new_records) + tail + doc["derivation"] = doc["derivation"] + upgrade_sentence(plan, actions) + return doc + + +def upgrade_revision( + plan: Plan, + actions: dict, + *, + bundle: dict, + fix_modules: list[dict], + provenance: dict, +) -> dict: + engine = actions["engine"] + return { + "date": actions["date"], + "kind": "engine_upgrade", + "root_cause": "engine_upgrade_policyengine_us_" + + engine_number(engine).replace(".", "_"), + "outputs": "every scored output", + "rule": f"{RULE} {ENGINE_RULE} {UPGRADE_RULE}", + "engine_version": engine, + "previous_engine_version": actions["previous_engine"], + "policyengine_py": ( + f"policyengine {bundle.get('policyengine_version')}, provenance only: its " + "certified US bundle is policyengine-us " + f"{bundle.get('bundled_model_version')}" + ), + "fix_modules": fix_modules, + "builder": ( + "reference_audit/2026-10-22-engine-upgrade/scripts/" + "build_references_upgrade.py; households from " + "policybench.scenarios.Scenario.to_pe_household through " + "reference_audit/2026-09-28/scripts/sweep.py build_situation, as in the " + "2026-09-29 upgrade" + ), + "provenance": provenance, + "excluded_outputs_untouched": True, + "excluded_outputs_rechecked": plan.rechecked, + "regenerated_exclusions": plan.regenerated, + "new_exclusions": [ + { + "scenario_id": r["scenario_id"], + "variable": r["variable"], + "reason_code": r["reason_code"], + "frozen_value": r["frozen_value"], + "alternative_value": r["alternative_value"], + "decided_on": r["decided_on"], + } + for r in plan.new_records + ], + "changed": plan.changed + plan.within, + } + + +def upgrade_meta( + base_meta: dict, revision: dict, *, csv_sha256: str, bundle: dict, now: str +) -> dict: + meta = copy.deepcopy(base_meta) + meta["policyengine_bundles"]["us"] = bundle + meta["reference_csv_sha256"] = csv_sha256 + meta["regenerated_at_utc"] = now + meta["revisions"].append(revision) + return meta + + +def verify_outputs( + base: Base, + plan: Plan, + csv_text: str, + exclusions: dict, + meta: dict, +) -> None: + """The written records agree: the loader accepts the exclusion record, every + excluded output carries its frozen value, every unchanged row keeps its + bytes, and every earlier revision is kept as it was.""" + import tempfile + + import pandas as pd + + from policybench.reference_exclusions import ( + load_reference_exclusions, + verify_exclusions_against_reference, + ) + + def check(condition: bool, message: str) -> None: + if not condition: + raise Refusal(f"written records disagree: {message}") + + with tempfile.TemporaryDirectory() as scratch: + path = Path(scratch) / "reference_exclusions.json" + path.write_text(dump_record(exclusions)) + loaded = load_reference_exclusions(path) + verify_exclusions_against_reference(pd.read_csv(io.StringIO(csv_text)), loaded) + written = parse_reference_csv(csv_text) + check( + [r.key for r in written.rows] == [r.key for r in base.reference.rows], + "row order", + ) + for old, new in zip(base.reference.rows, written.rows): + if old.key in plan.new_values: + check(new.value == plan.new_values[old.key], f"{old.key} value") + else: + check(new.raw == old.raw, f"{old.key} bytes") + check(meta["revisions"][:-1] == base.meta["revisions"], "earlier revisions") + check( + dump_record({"r": meta["revisions"][:-1]}) + == dump_record({"r": base.meta["revisions"]}), + "earlier revision bytes", + ) + + +@dataclass +class Written: + csv_text: str + exclusions: dict + meta: dict + traces: dict + + +def write_outputs( + out_dir: Path, + base: Base, + plan: Plan, + actions: dict, + *, + bundle: dict, + fix_modules: list[dict], + provenance: dict, + traces: dict, + now: str, +) -> Written: + if now[:10] != actions["date"]: + raise Refusal( + f"regenerated_at_utc {now} does not fall on the actions date " + f"{actions['date']}; pass --regenerated-at or redate the actions" + ) + csv_text = render_reference_csv(base.reference, plan.new_values) + exclusions = upgrade_exclusions(base.exclusions, plan, actions) + revision = upgrade_revision( + plan, actions, bundle=bundle, fix_modules=fix_modules, provenance=provenance + ) + meta = upgrade_meta( + base.meta, + revision, + csv_sha256=sha256_bytes(csv_text.encode()), + bundle=bundle, + now=now, + ) + verify_outputs(base, plan, csv_text, exclusions, meta) + out = Path(out_dir) + out.mkdir(parents=True, exist_ok=True) + (out / "reference_outputs.csv").write_text(csv_text) + (out / "reference_exclusions.json").write_text(dump_record(exclusions)) + (out / "reference_outputs.csv.meta.json").write_text(dump_record(meta)) + (out / "reference_traces.json").write_text(json.dumps(traces, indent=1)) + return Written(csv_text, exclusions, meta, traces) + + +def write_computed(path: Path, base: Base, computed: dict[Key, float], states) -> None: + """Every output on the new engine, in sweep.py's columns.""" + path = Path(path) + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("w", newline="") as sink: + writer = csv.writer(sink, lineterminator="\n") + writer.writerow( + [ + "fix", + "scenario_id", + "state", + "variable", + "frozen", + "recomputed", + "delta", + "moved", + ] + ) + for row in base.reference.rows: + if row.key not in computed: + continue + value = float(computed[row.key]) + writer.writerow( + [ + FIX_ENTRY, + row.key[0], + states.get(row.key[0], ""), + row.key[1], + repr(row.value), + repr(value), + repr(value - row.value), + beyond(row.key[1], row.value, value), + ] + ) + + +# --- Engine ------------------------------------------------------------------ + + +def load_module(name: str, path: Path): + spec = importlib.util.spec_from_file_location(name, path) + module = importlib.util.module_from_spec(spec) + sys.modules[spec.name] = module + spec.loader.exec_module(module) + return module + + +def fix_module_pins(base_meta: dict, fixes_dir: Path) -> list[dict]: + """The modules latest_final.py composes, each the bytes the 2026-09-29 + revision pins, plus latest_final.py and the sales tax tables: the list the + base's last engine_upgrade revision (2026-10-13) pins, which must be exactly + that.""" + upgrades = [r for r in base_meta["revisions"] if r["kind"] == "engine_upgrade"] + first = upgrades[0] + expected = [e["module"] for e in first["fix_modules"]] + expected += [f"{FIX_ENTRY}.py", SALES_TAX_TABLES] + if [e["module"] for e in upgrades[-1].get("fix_modules", [])] != expected: + raise Refusal( + "the base's last engine_upgrade revision does not pin the 2026-09-29 " + "modules plus latest_final.py and the sales tax tables" + ) + entries = [] + for entry in first["fix_modules"]: + path = fixes_dir / entry["module"] + if not path.is_file() or sha256(path) != entry["sha256"]: + raise Refusal(f"{path} is not the module the 2026-09-29 upgrade pins") + entries.append( + { + "module": entry["module"], + "path": f"reference_audit/2026-09-28/fixes/{entry['module']}", + "sha256": entry["sha256"], + } + ) + # Pinned to the bytes committed at the base commit, not to FIXES: imported + # in place, fixes_dir is FIXES and that comparison would be with itself. + entry_path = fixes_dir / f"{FIX_ENTRY}.py" + committed = git_blob(BASE_COMMIT, f"{FIXES_REL}/{FIX_ENTRY}.py") + if not entry_path.is_file() or sha256(entry_path) != sha256_bytes(committed): + raise Refusal( + f"{entry_path} is not {FIX_ENTRY}.py as committed at {BASE_COMMIT[:12]}" + ) + entries.append( + { + "module": f"{FIX_ENTRY}.py", + "path": f"reference_audit/2026-09-28/fixes/{FIX_ENTRY}.py", + "sha256": sha256(entry_path), + } + ) + tables = fixes_dir / SALES_TAX_TABLES + if not tables.is_file(): + raise Refusal( + f"{tables} is missing: latest_c_irs_sales_tax_2025.py reads it from its " + f"own directory; copy {SALES_TAX_SOURCE.relative_to(ROOT)} beside the " + "fixes" + ) + committed_tables = git_blob(BASE_COMMIT, SALES_TAX_REL) + if sha256(tables) != sha256_bytes(committed_tables) or sha256( + SALES_TAX_SOURCE + ) != sha256_bytes(committed_tables): + raise Refusal(f"{tables} is not {SALES_TAX_REL} as committed") + entries.append( + { + "module": SALES_TAX_TABLES, + "path": f"reference_audit/2026-09-22/fixes/{SALES_TAX_TABLES}", + "sha256": sha256(tables), + } + ) + return entries + + +def harness_pin(path: Path = HARNESS) -> dict: + """sweep.py, whose build_situation builds every household, must be the + bytes committed at the base commit.""" + committed = git_blob(BASE_COMMIT, HARNESS_REL) + if not Path(path).is_file() or sha256(path) != sha256_bytes(committed): + raise Refusal(f"{path} is not {HARNESS_REL} as committed at {BASE_COMMIT[:12]}") + return {"path": HARNESS_REL, "sha256": sha256_bytes(committed)} + + +def compute_outputs(system, scenarios, programs, build_situation) -> dict[Key, float]: + from policyengine_us import Simulation + + from policybench.ground_truth import _extract_person_value, _pe_variable_for_output + from policybench.scenarios import scenario_from_dict + from policybench.spec import expand_programs_for_scenario + + computed = {} + for _, srow in scenarios.iterrows(): + scenario = scenario_from_dict(json.loads(srow["scenario_json"])) + situation = build_situation(scenario) + if scenario.id == "scenario_066": + head = next(iter(situation["people"].values())) + assert "weekly_hours_worked_before_lsr" in head, "builder hours mapping" + sim = Simulation(tax_benefit_system=system, situation=situation) + for variable in expand_programs_for_scenario(programs, scenario): + pe_variable = _pe_variable_for_output(variable, "us") + computed[(scenario.id, variable)] = float( + _extract_person_value( + sim.calculate(pe_variable, YEAR), scenario, variable + ) + ) + return computed + + +def module_dependencies(name: str, read) -> list[str]: + """The sibling files a fix module loads, transitively, in discovery order; + ``read(file)`` gives a file's bytes (as committed at BASE_COMMIT). Refuses + a module whose closure cannot be established + (policybench.fix_module_closure).""" + from policybench.fix_module_closure import ClosureError, dependency_closure + + try: + return dependency_closure(name, read) + except ClosureError as error: + raise Refusal(str(error)) from None + + +def fix_location(name: str) -> tuple[str, bytes]: + """An audited fix file's repository path and committed bytes: under + AUDIT_FIXES_REL as committed at BASE_COMMIT, or, for a module this audit + adds (absent there), under LOCAL_FIXES_REL as committed at HEAD.""" + try: + return f"{AUDIT_FIXES_REL}/{name}", git_blob(BASE_COMMIT, f"{AUDIT_FIXES_REL}/{name}") + except Refusal: + pass + try: + return f"{LOCAL_FIXES_REL}/{name}", git_blob("HEAD", f"{LOCAL_FIXES_REL}/{name}") + except Refusal: + raise Refusal( + f"{name} is neither in {AUDIT_FIXES_REL} at {BASE_COMMIT[:12]} nor " + f"committed at HEAD in {LOCAL_FIXES_REL}" + ) from None + + +def is_local_fix(name: str) -> bool: + """Whether a fix module is this audit's own (fix_location); a name found + in neither place is not.""" + try: + return fix_location(name)[0].startswith(LOCAL_FIXES_REL + "/") + except Refusal: + return False + + +def committed_fix(name: str) -> bytes: + """An audited fix file's committed bytes (fix_location).""" + return fix_location(name)[1] + + +def fix_path(name: str, fixes_dir: Path = AUDIT_FIXES) -> Path: + """Where a fix module is read from: ``fixes_dir`` for the 2026-09-22 + audit's modules, LOCAL_FIXES for this audit's own.""" + return (LOCAL_FIXES if is_local_fix(name) else Path(fixes_dir)) / name + + +def audit_module_pins(names, fixes_dir: Path = AUDIT_FIXES) -> dict[str, str]: + """Each named audited fix module's sha256, and each sibling it loads + (module_dependencies): the bytes committed at BASE_COMMIT under + reference_audit/2026-09-22/fixes, or, for a module this audit adds, the + bytes committed at HEAD under LOCAL_FIXES_REL (fix_location); and nothing + else. + + A module loads its siblings from its own directory + (Path(__file__).with_name), so each must be pinned from there: a sibling + whose name resolves to the other folder (a local module loading a name + the 2026-09-22 audit also has, say) is refused, since the pin would name + a file other than the one that runs.""" + names = sorted(set(names)) + for name in list(names): + home = PurePosixPath(fix_location(name)[0]).parent + for dependency in module_dependencies(name, committed_fix): + where = PurePosixPath(fix_location(dependency)[0]).parent + if where != home: + raise Refusal( + f"{name} loads {dependency} from {home}, but that name is " + f"pinned from {where}: a fix module's siblings must be " + "committed beside it" + ) + if dependency not in names: + names.append(dependency) + pins = {} + for name in sorted(set(names)): + if Path(name).name != name or not name.endswith((".py", ".json")): + raise Refusal(f"a fix module is a file name ending in .py, not {name!r}") + rel, blob = fix_location(name) + path = fix_path(name, fixes_dir) + committed = sha256_bytes(blob) + if not path.is_file() or sha256(path) != committed: + where = BASE_COMMIT[:12] if rel.startswith(AUDIT_FIXES_REL) else "HEAD" + raise Refusal(f"{path} is not {rel} as committed at {where}") + pins[name] = committed + return pins + + +def fix_module_parts(names, fixes_dir: Path = AUDIT_FIXES) -> tuple[list, list]: + """The Reform classes and household patches of the named fix modules, in + order (sweep.py's fix interface: a module defines reform, patch or both).""" + reforms, patches = [], [] + for name in names: + module = load_module(f"upgrade_fix_{Path(name).stem}", fix_path(name, fixes_dir)) + reform = getattr(module, "reform", None) + patch = getattr(module, "patch", None) + if reform is None and patch is None: + raise Refusal(f"{name} defines neither reform nor patch") + if reform is not None: + reforms.append(reform) + if patch is not None: + patches.append(patch) + return reforms, patches + + +def corrected_system(final, reforms): + """The pinned conventions, then each fix module's reform, as one system.""" + from policyengine_core.reforms import Reform + from policyengine_us import CountryTaxBenefitSystem + + parts = (final.reform, *reforms) + + class corrected(Reform): + def apply(self): + for part in parts: + part.apply(self) + + return CountryTaxBenefitSystem(reform=corrected) + + +def compute_items(system, scenarios, keys, build_situation, patches=()) -> dict: + """The named outputs on a system, households built as compute_outputs + builds them and then edited by each patch in order.""" + from policyengine_us import Simulation + + from policybench.ground_truth import _extract_person_value, _pe_variable_for_output + from policybench.scenarios import scenario_from_dict + + by_id = scenarios.set_index("scenario_id") + out = {} + for scenario_id in sorted({k[0] for k in keys}): + scenario = scenario_from_dict( + json.loads(by_id.loc[scenario_id, "scenario_json"]) + ) + situation = build_situation(scenario) + for patch in patches: + situation = patch(copy.deepcopy(situation), scenario) + sim = Simulation(tax_benefit_system=system, situation=situation) + for k in sorted(k for k in keys if k[0] == scenario_id): + pe_variable = _pe_variable_for_output(k[1], "us") + out[k] = float( + _extract_person_value(sim.calculate(pe_variable, YEAR), scenario, k[1]) + ) + return out + + +def module_values_on(final, scenarios, requests, build_situation) -> dict: + """Each (output, modules) request's value with the conventions and the + modules applied, one system per module list.""" + values = {} + by_modules: dict[tuple[str, ...], list[Key]] = {} + for k, modules in requests: + by_modules.setdefault(tuple(modules), []).append(k) + for modules, keys in sorted(by_modules.items()): + reforms, patches = fix_module_parts(modules) + system = corrected_system(final, reforms) + for k, value in compute_items( + system, scenarios, keys, build_situation, patches + ).items(): + values[(k, modules)] = value + return values + + +def load_evidence(ref: dict) -> dict: + """An evidence file a target names, at its pinned sha256.""" + if not isinstance(ref, dict) or set(ref) != {"path", "sha256"}: + raise Refusal(f"a target's evidence is {{path, sha256}}, not {ref!r}") + path = ROOT / ref["path"] + if not path.is_file() or sha256(path) != ref["sha256"]: + raise Refusal(f"{ref['path']} is missing or not the evidence its sha256 pins") + doc = json.loads(path.read_text()) + if not isinstance(doc, dict) or doc.get("kind") != EVIDENCE_KIND: + raise Refusal(f"{ref['path']} is not {EVIDENCE_KIND}") + engine_number(doc.get("engine", "")) + if not isinstance(doc.get("modules"), dict) or not isinstance( + doc.get("items"), list + ): + raise Refusal(f"{ref['path']} lacks its modules or items") + return doc + + +def write_evidence(request_path: Path, out_path: Path, fixes_dir: Path) -> dict: + """Evidence mode: each requested output on the installed engine, with the + pinned conventions alone and with its fix modules after them.""" + from importlib.metadata import version + + import pandas as pd + + request = json.loads(Path(request_path).read_text()) + items = request.get("items") if isinstance(request, dict) else None + if not isinstance(items, list) or not items: + raise Refusal("an evidence request is {\"items\": [...]} with one or more") + base = load_base() + board = base.reference.values() + requests = [] + for item in items: + k, modules = key_of(item), tuple(item.get("modules") or ()) + if k not in board or not modules: + raise Refusal(f"evidence request {k}: not a reference, or no modules") + requests.append((k, modules)) + if len(set(requests)) != len(requests): + raise Refusal("an evidence request names an item twice") + pins = audit_module_pins([m for _, modules in requests for m in modules]) + fix_module_pins(base.meta, fixes_dir) + harness_pinned = harness_pin() + harness = load_module("upgrade_sweep_harness", HARNESS) + final = load_module(f"upgrade_{FIX_ENTRY}", fixes_dir / f"{FIX_ENTRY}.py") + + from policyengine_us import CountryTaxBenefitSystem + + scenarios = pd.read_csv(io.StringIO(base.scenarios_csv)) + plain = compute_items( + CountryTaxBenefitSystem(reform=final.reform), + scenarios, + [k for k, _ in requests], + harness.build_situation, + ) + corrected = module_values_on(final, scenarios, requests, harness.build_situation) + doc = { + "kind": EVIDENCE_KIND, + "engine": f"policyengine-us {version('policyengine-us')}", + "policyengine_core": version("policyengine-core"), + "computed_at_utc": datetime.datetime.now(datetime.timezone.utc).isoformat(), + "builder_sha256": sha256(Path(__file__)), + "harness_sha256": harness_pinned["sha256"], + "conventions": f"{FIXES_REL}/{FIX_ENTRY}.py", + "base_commit": BASE_COMMIT, + "modules": pins, + "items": [ + { + "scenario_id": k[0], + "variable": k[1], + "modules": list(modules), + "engine_value": plain[k], + "corrected_value": corrected[(k, modules)], + } + for k, modules in requests + ], + } + out = Path(out_path) + out.parent.mkdir(parents=True, exist_ok=True) + out.write_text(dump_record(doc)) + return doc + + +def trace_outputs(system, scenarios, items, build_situation) -> dict: + import types + + sys.modules.setdefault("litellm", types.ModuleType("litellm")) + from policyengine_us import Simulation + + from policybench.case_reference_explanations import _find_target_tree, _render_trace + from policybench.ground_truth import _pe_variable_for_output + from policybench.scenarios import scenario_from_dict + + by_id = scenarios.set_index("scenario_id") + traces = {} + for item in items: + scenario = scenario_from_dict( + json.loads(by_id.loc[item["scenario_id"], "scenario_json"]) + ) + sim = Simulation(tax_benefit_system=system, situation=build_situation(scenario)) + sim.trace = True + pe_variable = _pe_variable_for_output(item["variable"], "us") + sim.calculate(pe_variable, YEAR) + tree = _find_target_tree(sim.tracer.trees, pe_variable) + traces[f"{item['scenario_id']}|{item['variable']}"] = { + "pe_variable": pe_variable, + "trace": "\n".join(_render_trace(tree)) if tree else "", + } + return traces + + +def main(argv: list[str] | None = None) -> None: + from importlib.metadata import version + + import pandas as pd + + parser = argparse.ArgumentParser() + parser.add_argument("--actions") + parser.add_argument("--out-dir") + parser.add_argument("--fixes-dir", default=str(FIXES)) + parser.add_argument("--computed-csv") + parser.add_argument("--regenerated-at") + parser.add_argument("--allow-draft", action="store_true") + parser.add_argument("--evidence-request") + parser.add_argument("--evidence-out") + args = parser.parse_args(argv) + + if args.evidence_request or args.evidence_out: + if not (args.evidence_request and args.evidence_out) or args.actions: + parser.error("evidence mode takes --evidence-request and --evidence-out") + doc = write_evidence( + Path(args.evidence_request), + Path(args.evidence_out), + Path(args.fixes_dir).resolve(), + ) + print(f"{doc['engine']}: {len(doc['items'])} items") + for item in doc["items"]: + print( + f" {item['scenario_id']} {item['variable']:46s} " + f"{item['engine_value']:>11.2f} -> {item['corrected_value']:>11.2f} " + f"{'+'.join(item['modules'])}" + ) + return + if not (args.actions and args.out_dir): + parser.error("a build takes --actions and --out-dir") + + actions_path = Path(args.actions) + actions = json.loads(actions_path.read_text()) + validate_actions(actions, allow_draft=args.allow_draft) + engine = engine_number(actions["engine"]) + installed = version("policyengine-us") + if installed != engine: + raise Refusal(f"need policyengine-us {engine}, have {installed}") + + base = load_base() + fixes_dir = Path(args.fixes_dir).resolve() + fix_modules = fix_module_pins(base.meta, fixes_dir) + harness_pinned = harness_pin() + harness = load_module("upgrade_sweep_harness", HARNESS) + final = load_module(f"upgrade_{FIX_ENTRY}", fixes_dir / f"{FIX_ENTRY}.py") + + from policyengine_us import CountryTaxBenefitSystem + + from policybench.policyengine_runtime import policyengine_release_bundle + + system = CountryTaxBenefitSystem(reform=final.reform) + scenarios = pd.read_csv(io.StringIO(base.scenarios_csv)) + computed = compute_outputs( + system, scenarios, base.meta["programs"], harness.build_situation + ) + states = dict(zip(scenarios["scenario_id"], scenarios["state"])) + out = Path(args.out_dir) + write_computed( + Path(args.computed_csv or out / "computed.csv"), base, computed, states + ) + targets = [ + entry + for entry in actions.get("regenerated_exclusions", []) + if isinstance(entry.get("target"), dict) + and entry["target"].get("kind") == TARGET_FIX_MODULES + ] + evidence = { + entry["target"]["evidence"]["path"]: load_evidence(entry["target"]["evidence"]) + for entry in targets + if isinstance(entry["target"].get("evidence"), dict) + } + named = sorted({m for entry in targets for m in target_modules(entry)}) + module_pins = audit_module_pins(named) + module_deps = {m: module_dependencies(m, committed_fix) for m in named} + module_values = module_values_on( + final, + scenarios, + [(key_of(entry), target_modules(entry)) for entry in targets], + harness.build_situation, + ) + plan = plan_upgrade( + base, + actions, + computed, + evidence=evidence, + module_pins=module_pins, + module_values=module_values, + module_deps=module_deps, + ) + if plan.problems: + raise Refusal("refusing to write references:\n " + "\n ".join(plan.problems)) + + traces = trace_outputs( + system, scenarios, plan.changed + plan.within, harness.build_situation + ) + now = ( + args.regenerated_at or datetime.datetime.now(datetime.timezone.utc).isoformat() + ) + provenance = { + "builder_sha256": sha256(Path(__file__)), + "harness": harness_pinned["path"], + "harness_sha256": harness_pinned["sha256"], + "actions_sha256": sha256(actions_path), + "base_commit": BASE_COMMIT, + "policyengine_core": version("policyengine-core"), + } + written = write_outputs( + out, + base, + plan, + actions, + bundle=policyengine_release_bundle("us"), + fix_modules=fix_modules, + provenance=provenance, + traces=traces, + now=now, + ) + print(f"sha256 {written.meta['reference_csv_sha256']}") + print( + f"{len(plan.changed)} reviewed changes, {len(plan.within)} within $1, " + f"{len(plan.regenerated)} regenerated exclusions, {len(plan.new_records)} new " + f"exclusions, {len(plan.rechecked)} excluded outputs rechecked, " + f"{len(written.exclusions['exclusions'])} exclusion records" + ) + for c in plan.changed + plan.within: + print( + f" {c['scenario_id']} {c['variable']:46s} {c['previous']:>11.2f} -> " + f"{c['regenerated']:>11.2f} {c['cause']}" + ) + + +if __name__ == "__main__": + main() diff --git a/reference_audit/2026-10-22-engine-upgrade/scripts/narratives_upgrade.py b/reference_audit/2026-10-22-engine-upgrade/scripts/narratives_upgrade.py new file mode 100644 index 00000000..09541a6c --- /dev/null +++ b/reference_audit/2026-10-22-engine-upgrade/scripts/narratives_upgrade.py @@ -0,0 +1,449 @@ +"""Rewrite the reference explanations of the outputs the fourth engine upgrade +changed; every other row of the explanations CSV keeps its bytes. + +Adapted from reference_audit/2026-10-12-engine-upgrade/scripts/narratives_upgrade.py, +itself from reference_audit/2026-09-28/scripts/narratives_latest.py. The writer +is every reference narrative's (policybench.case_reference_explanations: +REFERENCE_MODEL claude-haiku-4-5, TEMPERATURE, MAX_TOKENS, _prompt), given the +build's engine trace (reference_traces.json from build_references_upgrade.py) and +the change's recorded basis as grounding. A new exclusion is grounded on its +record's alternative reading, as in 2026-09-28. The narrative must state the new +reference value (an amount; a flag states none); a draft that omits it is retried +twice, then refused. --hand-corrected takes a JSON object +{"scenario_id|variable": text} that replaces the writer for a listed output; its +text must also state the value. + +--reuse-from --reuse-explanations keeps +an earlier build's narrative for an output whose writer inputs are the same in +both builds: the value, the change's cause and grounding, the PolicyEngine +variable and the trace, byte for byte. On another engine the narrative must +also not name the earlier engine's version. Judges' prompts render the narrative, so a reused one +keeps a case's verdict through a rebuild on a newer engine. The reused rows are +listed beside --out (.reused.json) with both builds' sidecar sha256. + +The rows rewritten are exactly the sidecar's last revision's changed list (a +reference that changed by more than EPS); each gets the new reference_value, +trace_lines and explanation, and an empty error. Judge prompts render a case's +reference value and explanation, so these are the cases whose verdicts +prepare_audit drops and the judge re-runs. + +The writer is Anthropic's, through litellm: a run that calls it needs +ANTHROPIC_API_KEY and never an OpenAI key (the script removes OPENAI_API_KEY +from its environment). When --hand-corrected (and --reuse-from) cover every +changed output, the writer is not called and no key is needed: + + ANTHROPIC_API_KEY=$(agent-secret get ANTHROPIC_API_KEY maxghenis) \\ + PYTHONPATH= /bin/python narratives_upgrade.py \\ + --references \\ + --explanations annotations//us_case_reference_explanations.csv \\ + --out +""" + +from __future__ import annotations + +import argparse +import csv +import io +import json +import math +import os +import re +import sys +from pathlib import Path + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) + +from build_references_upgrade import ( # noqa: E402 + BASE_COMMIT, + BASE_SHA256, + RUN, + YEAR, + Refusal, + format_row, + git_blob, + physical_lines, + sha256_bytes, +) + +FIELDS = [ + "country", + "scenario_id", + "variable", + "reference_value", + "trace_lines", + "explanation", + "error", +] +RETRIES = 2 + + +def money(value: float) -> str: + return f"{value:,.2f}".removesuffix(".00") + + +# A dollar amount as a narrative writes it: "$1,916.61", "$0", "-$12.50". +DOLLARS = re.compile(r"(-)?\$\s?(\d[\d,]*(?:\.\d+)?)") + + +def required(item: dict) -> list[float]: + """What the narrative must state: the new amount; nothing for a flag.""" + if item["variable"].endswith("_eligible"): + return [] + return [float(item["regenerated"])] + + +def states_amount(text: str, value: float) -> bool: + """Whether ``text`` states ``value`` as a dollar amount, to the cent. A + bare number does not count: for a $0 reference, "2026" states nothing.""" + for sign, number in DOLLARS.findall(text): + amount = float(number.replace(",", "")) * (-1 if sign else 1) + if abs(amount - value) <= 0.005 + 1e-9: + return True + return False + + +def missing_amounts(item: dict, text: str) -> list[str]: + return [money(v) for v in required(item) if not states_amount(text, v)] + + +def engine_note(engine: str) -> str: + return ( + f" PolicyEngine here is {engine} with the benchmark's conventions for law " + "published before July 3, 2026." + ) + + +def grounding_for(item: dict, records: dict) -> str: + """The change's recorded basis; a new exclusion's record reading instead.""" + record = records.get((item["scenario_id"], item["variable"])) + if record is not None and item["cause"] == f"excluded_{record['reason_code']}": + if record["reason_code"] == "reference_depends_on_unlisted_input": + return ( + "PolicyBench does not score this output, because the reference " + "depends on an input the prompt does not state. " + + record["alternative_reading"] + ) + return ( + "PolicyBench does not score this output. " + record["alternative_reading"] + ) + return item["basis"] + + +def parse_rows(text: str) -> tuple[str, list[tuple[list[str], str]]]: + """The header line and each record with its raw text.""" + lines = physical_lines(text) + reader = csv.reader(iter(lines)) + records, used = [], 0 + for fields in reader: + records.append((fields, "".join(lines[used : reader.line_num]))) + used = reader.line_num + (header, header_raw), body = records[0], records[1:] + if header != FIELDS: + raise Refusal(f"unexpected explanations header {header}") + return header_raw, body + + +def rewrite_explanations(text: str, rewrites: dict) -> str: + """``text`` with each listed (scenario_id, variable) row replaced by + (reference_value, trace_lines, explanation); every other row byte for byte.""" + header_raw, body = parse_rows(text) + keys = [(fields[1], fields[2]) for fields, _ in body] + for key in rewrites: + if keys.count(key) != 1: + raise Refusal(f"{key} is in the explanations {keys.count(key)} times") + parts = [header_raw] + for fields, raw in body: + key = (fields[1], fields[2]) + if key not in rewrites: + parts.append(raw) + continue + value, n_lines, explanation = rewrites[key] + row = format_row( + [ + fields[0], + key[0], + key[1], + repr(float(value)), + str(n_lines), + explanation, + "", + ] + ) + parts.append(row if raw.endswith("\n") else row.removesuffix("\n")) + out = "".join(parts) + # Every row the rewrite does not name keeps its bytes. + _, written = parse_rows(out) + for (old, old_raw), (new, new_raw) in zip(body, written, strict=True): + if (old[1], old[2]) not in rewrites and old_raw != new_raw: + raise Refusal(f"row {(old[1], old[2])} changed") + return out + + +def strip_heading(text: str) -> str: + text = text.strip() + lines = text.split("\n") + if lines and lines[0].lstrip().startswith("#"): + text = "\n".join(lines[1:]).strip() + return text + + +def write_narratives( + references: Path, + explanations_text: str, + scenarios, + *, + completion, + hand_corrected: dict | None = None, + reuse: dict | None = None, +) -> tuple[str, list[tuple]]: + """The explanations CSV with every changed output's narrative rewritten, + and the rewritten rows. ``completion`` is litellm.completion (mocked in + tests). ``reuse`` maps an output to the earlier narrative reusable_narratives + found for it; the writer is not called for those.""" + from policybench.case_reference_explanations import ( + MAX_TOKENS, + REFERENCE_MODEL, + TEMPERATURE, + _prompt, + _scenario_summary, + ) + + if not REFERENCE_MODEL.startswith("claude-"): + raise Refusal( + f"the narrative writer must be Anthropic's, not {REFERENCE_MODEL}" + ) + meta = json.loads((references / "reference_outputs.csv.meta.json").read_text()) + upgrade = meta["revisions"][-1] + if ( + upgrade["kind"] != "engine_upgrade" + or len([r for r in meta["revisions"] if r["kind"] == "engine_upgrade"]) < 4 + ): + raise Refusal("the sidecar's last revision is not the fourth engine upgrade") + traces = json.loads((references / "reference_traces.json").read_text()) + exclusions = json.loads((references / "reference_exclusions.json").read_text()) + records = {(e["scenario_id"], e["variable"]): e for e in exclusions["exclusions"]} + note = engine_note(upgrade["engine_version"]) + hand_corrected = hand_corrected or {} + reuse = reuse or {} + by_id = scenarios.set_index("scenario_id", drop=False) + + def write(item: dict, extra: str = "") -> str: + key = (item["scenario_id"], item["variable"]) + traced = traces[f"{key[0]}|{key[1]}"] + prompt = _prompt( + "us", + _scenario_summary(by_id.loc[key[0]]), + key[1], + traced["pe_variable"], + item["regenerated"], + YEAR, + traced["trace"], + grounding=grounding_for(item, records) + note + extra, + ) + response = completion( + model=REFERENCE_MODEL, + messages=[{"role": "user", "content": prompt}], + temperature=TEMPERATURE, + max_tokens=MAX_TOKENS, + ) + return strip_heading(response.choices[0].message.content) + + rewrites, results = {}, [] + for item in upgrade["changed"]: + key = (item["scenario_id"], item["variable"]) + n_lines = len(traces[f"{key[0]}|{key[1]}"]["trace"].splitlines()) + listed = f"{key[0]}|{key[1]}" + if listed in hand_corrected: + text = hand_corrected[listed] + elif key in reuse: + text = reuse[key] + else: + text = write(item) + for _ in range(RETRIES): + missing = missing_amounts(item, text) + if not missing: + break + text = write( + item, + " The narrative must state the value " + + ", ".join(f"${m}" for m in missing) + + ".", + ) + missing = missing_amounts(item, text) + if missing: + raise Refusal(f"{key[0]} {key[1]}: the narrative omits {missing}") + rewrites[key] = (item["regenerated"], n_lines, text) + results.append((key[0], key[1], item["regenerated"], n_lines, text)) + unused = set(hand_corrected) - {f"{k[0]}|{k[1]}" for k in rewrites} + if unused: + raise Refusal(f"hand-corrected outputs the upgrade did not change: {unused}") + return rewrite_explanations(explanations_text, rewrites), results + + +def writer_inputs(references: Path) -> dict: + """Each changed output's narrative-writer inputs in a build, by output: + value, cause, grounding, PolicyEngine variable and trace.""" + meta = json.loads((references / "reference_outputs.csv.meta.json").read_text()) + traces = json.loads((references / "reference_traces.json").read_text()) + exclusions = json.loads((references / "reference_exclusions.json").read_text()) + records = {(e["scenario_id"], e["variable"]): e for e in exclusions["exclusions"]} + inputs = {} + for item in meta["revisions"][-1]["changed"]: + key = (item["scenario_id"], item["variable"]) + traced = traces[f"{key[0]}|{key[1]}"] + inputs[key] = ( + repr(float(item["regenerated"])), + item["cause"], + grounding_for(item, records), + traced["pe_variable"], + traced["trace"], + ) + return inputs + + +def reusable_narratives( + references: Path, earlier: Path, earlier_explanations_text: str +) -> dict: + """The earlier build's narratives for outputs whose writer inputs both + builds share and whose narrative does not name the earlier engine.""" + def engine(path: Path) -> str: + meta = json.loads((path / "reference_outputs.csv.meta.json").read_text()) + return meta["revisions"][-1]["engine_version"] + + now, then = engine(references), engine(earlier) + number = then.removeprefix("policyengine-us ") + current = writer_inputs(references) + # The groundings name their build's engine; that name may differ, nothing else. + before = { + key: (*inputs[:2], inputs[2].replace(then, now), *inputs[3:]) + for key, inputs in writer_inputs(earlier).items() + } + _, body = parse_rows(earlier_explanations_text) + rows: dict = {} + for fields, _ in body: + rows.setdefault((fields[1], fields[2]), []).append(fields) + # The CSV must be the earlier build's narratives: each output that build + # changed appears once, for the US, with no error, at that build's value. + # Each value must parse to a finite number: abs(nan - x) > 1e-6 is false, + # so a "nan" would pass a bare comparison. + wrong = sorted( + key + for key, inputs in writer_inputs(earlier).items() + if len(rows.get(key, [])) != 1 + or rows[key][0][0] != "us" + or rows[key][0][6] != "" + or (stated := finite(rows[key][0][3])) is None + or (value := finite(inputs[0])) is None + or abs(stated - value) > 1e-6 + ) + if wrong: + raise Refusal( + "--reuse-explanations is not --reuse-from's narratives: " + f"{[f'{k[0]}|{k[1]}' for k in wrong[:5]]}" + ) + narratives = {key: found[0][5] for key, found in rows.items()} + # A narrative naming the earlier engine is stale on another engine, and + # still true on the same one. + return { + key: narratives[key] + for key, inputs in current.items() + if before.get(key) == inputs and (then == now or number not in narratives[key]) + } + + +def finite(text) -> float | None: + """A value's text as a finite float, or None (unparsable, nan or inf).""" + try: + value = float(text) + except (TypeError, ValueError): + return None + return value if math.isfinite(value) else None + + +def main(argv: list[str] | None = None) -> None: + import pandas as pd + + parser = argparse.ArgumentParser() + parser.add_argument("--references", required=True) + parser.add_argument("--explanations", required=True) + parser.add_argument("--out", required=True) + parser.add_argument("--hand-corrected") + parser.add_argument("--reuse-from") + parser.add_argument("--reuse-explanations") + args = parser.parse_args(argv) + if bool(args.reuse_from) != bool(args.reuse_explanations): + parser.error("--reuse-from and --reuse-explanations go together") + os.environ.pop("OPENAI_API_KEY", None) + raw = git_blob(BASE_COMMIT, f"{RUN}/scenarios.csv") + if sha256_bytes(raw) != BASE_SHA256["scenarios.csv"]: + raise Refusal("scenarios.csv at the base commit does not match its pin") + scenarios = pd.read_csv(io.StringIO(raw.decode())) + hand = ( + json.loads(Path(args.hand_corrected).read_text()) if args.hand_corrected else {} + ) + reuse = {} + if args.reuse_from: + reuse = reusable_narratives( + Path(args.references), + Path(args.reuse_from), + Path(args.reuse_explanations).read_text(), + ) + reuse = {k: v for k, v in reuse.items() if f"{k[0]}|{k[1]}" not in hand} + changed = json.loads( + (Path(args.references) / "reference_outputs.csv.meta.json").read_text() + )["revisions"][-1]["changed"] + to_write = [ + c + for c in changed + if f"{c['scenario_id']}|{c['variable']}" not in hand + and (c["scenario_id"], c["variable"]) not in reuse + ] + if to_write: + if not os.environ.get("ANTHROPIC_API_KEY"): + raise Refusal( + f"{len(to_write)} narratives need the writer: set ANTHROPIC_API_KEY " + "(agent-secret get ANTHROPIC_API_KEY maxghenis)" + ) + import litellm + + completion = litellm.completion + else: + + def completion(**_): + raise Refusal("every narrative is hand-corrected or reused") + + text, results = write_narratives( + Path(args.references), + Path(args.explanations).read_text(), + scenarios, + completion=completion, + hand_corrected=hand, + reuse=reuse, + ) + Path(args.out).write_text(text) + if args.reuse_from: + sidecar = "reference_outputs.csv.meta.json" + Path(args.out + ".reused.json").write_text( + json.dumps( + { + "reused": [f"{k[0]}|{k[1]}" for k in sorted(reuse)], + "from_sidecar_sha256": sha256_bytes( + (Path(args.reuse_from) / sidecar).read_bytes() + ), + "into_sidecar_sha256": sha256_bytes( + (Path(args.references) / sidecar).read_bytes() + ), + }, + indent=2, + ) + + "\n" + ) + print(f"reused {len(reuse)} narratives from {args.reuse_from}") + for scenario_id, variable, value, _, narrative in results: + print(f"--- {scenario_id} {variable} ({value:,.2f})\n{narrative}\n") + print(f"rewrote {len(results)} narratives -> {args.out}") + + +if __name__ == "__main__": + main() diff --git a/reference_audit/2026-10-22-engine-upgrade/scripts/sweep_timing.py b/reference_audit/2026-10-22-engine-upgrade/scripts/sweep_timing.py new file mode 100644 index 00000000..32048ccc --- /dev/null +++ b/reference_audit/2026-10-22-engine-upgrade/scripts/sweep_timing.py @@ -0,0 +1,795 @@ +"""Record when the 2026-10-22 reference sweep began and check the newest +policyengine-us release before publishing, as reference_audit/2026-09-28, +2026-10-09-engine-upgrade and 2026-10-12-engine-upgrade did for the 2026-09-29, +2026-10-10 and 2026-10-13 moves (verification/sweep_timing.json in each). +Adapted from reference_audit/2026-10-12-engine-upgrade/scripts/sweep_timing.py. + +The standing rule (build_references_upgrade.py's ENGINE_RULE): references +come from the newest policyengine-us release when PolicyBench begins the +reference sweep, and at publication PolicyBench checks that the newest +release gives the same values. + +Two steps, each writing into this audit's verification/ directory: + + sweep_timing.py sweep --engine 2.59.0 --venv --first-output + Reads PyPI's JSON API now and records each release's wheel upload time + from the reference engine onward, the newest release at the read, when + the engine was installed (the dist-info directory's birth time) and + when the sweep wrote its first output (the file's birth time). Refuses + unless the engine was the newest release when the sweep began: no + release newer than it was uploaded before its first output. + + sweep_timing.py run --venv --engine X.Y.Z --receipt -- + Runs the builder for the reference build through the same engine check, + in the same single process, as the check sweep (ENGINE_RUNNER); the + receipt records the check. + + sweep_timing.py check --build + [--check-venv ] + [--snapshot ] + Reads PyPI again. The build must be the committed one: its sidecar names + the sweep's engine, pins its CSV and names the committed builder, its + reference CSV, sidecar and exclusion record are the committed copy's byte + for byte (--snapshot: this audit's build/ directory while the build is + staged for the next board release, the snapshot once a release installs + it; the default is the snapshot), and its computed.csv gives every scored + reference, every value finite. When a newer release is out, check runs the check sweep + itself: this audit's builder, a first pass with empty actions, in the + given venv, which the builder refuses unless it holds that release. It + compares every output that sweep computes with the reference engine's + (publication_check_.csv) and records the result, counting + scored and excluded outputs apart; when the reference engine is still + the newest, it records that. Each input is pinned in the record by + sha256. Exits non-zero, after writing the record, when the newest + release moves a scored output: that stops the publish. + +A release whose wheels are all yanked is not one PolicyBench builds on or +checks against; the record lists any such release newer than the reference +engine (yanked_newer), so one yanked after the sweep began stays visible. + +Times are UTC. Birth times are macOS st_birthtime. +""" + +from __future__ import annotations + +import argparse +import csv +import datetime +import hashlib +import json +import math +import os +import shutil +import subprocess +import sys +import tempfile +import time +import urllib.request +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[3] +AUDIT = Path(__file__).resolve().parents[1] +VERIFICATION = AUDIT / "verification" +TIMING = VERIFICATION / "sweep_timing.json" +PYPI = "https://pypi.org/pypi/policyengine-us/json" +PACKAGE = "policyengine_us" +SAME = 1e-9 +# The builder's own tolerance for an output it did not move (its EPS): every +# scored reference is the engine's value, so the build's computed.csv gives it. +REFERENCE_EPS = 1e-6 +RUN = "us_full_run_20260612_policyengine_4_16_1_populace" +SNAPSHOT = ROOT / "paper/snapshot/20260501/runs" / RUN +BUILDER = AUDIT / "scripts" / "build_references_upgrade.py" +# The staged copy of the build the next board release installs. +STAGED_BUILD = AUDIT / "build" +# The builder's arguments that name files or directories, and its flag. +BUILDER_PATH_FLAGS = ( + "--actions", + "--out-dir", + "--fixes-dir", + "--computed-csv", + "--evidence-request", + "--evidence-out", +) +BUILDER_VALUE_FLAGS = (*BUILDER_PATH_FLAGS, "--regenerated-at") +BUILDER_SWITCHES = ("--allow-draft",) + + +def builder_arguments(argv: list[str]) -> tuple[list[str], Path | None]: + """The builder's arguments as the builder itself reads them (the same + flags, argparse's equals form, abbreviations and last-occurrence rule), + rewritten in one canonical form with every path resolved here (the child + runs in the repository root), and the computed.csv the run must write: + --computed-csv when given, else /computed.csv. Unknown arguments + are refused rather than passed on.""" + parser = argparse.ArgumentParser(prog="builder", add_help=False) + for flag in BUILDER_VALUE_FLAGS: + parser.add_argument(flag) + for flag in BUILDER_SWITCHES: + parser.add_argument(flag, action="store_true") + try: + parsed = parser.parse_args(argv) + except SystemExit: + raise Refusal(f"the builder cannot take these arguments: {argv}") from None + canonical: list[str] = [] + values = vars(parsed) + for flag in BUILDER_VALUE_FLAGS: + value = values[flag[2:].replace("-", "_")] + if value is None: + continue + if flag in BUILDER_PATH_FLAGS: + value = str(Path(value).resolve()) + canonical += [flag, value] + canonical += [ + flag for flag in BUILDER_SWITCHES if values[flag[2:].replace("-", "_")] + ] + computed = values["computed_csv"] or ( + str(Path(values["out_dir"]) / "computed.csv") if values["out_dir"] else None + ) + return canonical, Path(computed).resolve() if computed else None + + +BASE_ENGINE = "policyengine-us 2.41.0" +BUILD_FILES = ( + "computed.csv", + "reference_outputs.csv", + "reference_outputs.csv.meta.json", + "reference_exclusions.json", +) +NOTE = ( + "When PolicyBench began sweeping the references for the 2026-10-22 move, " + "which policyengine-us release was the newest then and at publication, and " + "the publication check. Times are UTC. The PyPI upload times were read from " + "the PyPI JSON API; the install and first-output times are filesystem birth " + "times (st_birthtime) of the engine's dist-info directory and of the first " + "file the sweep wrote." +) + + +class Refusal(SystemExit): + pass + + +def version_key(version: str) -> tuple[int, ...]: + return tuple(int(part) for part in version.split(".")) + + +def birth_time(path: Path) -> float: + """The file's birth time (st_birthtime). The record dates the install and + the outputs by birth times, which macOS keeps and Linux's stat does not; + there this refuses rather than date them by a modification time.""" + try: + return path.stat().st_birthtime + except AttributeError: + raise Refusal( + f"{path}: this platform's stat keeps no birth time (st_birthtime); " + "run sweep_timing.py on macOS" + ) from None + + +def utc(timestamp: float) -> str: + return ( + datetime.datetime.fromtimestamp(timestamp, datetime.timezone.utc) + .replace(microsecond=0) + .isoformat() + .replace("+00:00", "Z") + ) + + +def now_utc() -> str: + return utc(datetime.datetime.now(datetime.timezone.utc).timestamp()) + + +def wheel_uploads(pypi: dict) -> dict[str, str]: + """Each plain X.Y.Z release's wheel upload time (ISO 8601, UTC).""" + uploads = {} + for version, files in pypi.get("releases", {}).items(): + try: + version_key(version) + except ValueError: + continue # pre-releases and other non-numeric tags + wheels = [f for f in files if f.get("packagetype") == "bdist_wheel"] + if wheels and not all(f.get("yanked") for f in wheels): + uploads[version] = min(f["upload_time_iso_8601"] for f in wheels) + return uploads + + +def yanked_newer(pypi: dict, engine: str) -> dict[str, str]: + """Releases newer than the engine whose wheels are all yanked, with the + reason PyPI gives (wheel_uploads leaves them out).""" + yanked = {} + for version, files in pypi.get("releases", {}).items(): + try: + key = version_key(version) + except ValueError: + continue + wheels = [f for f in files if f.get("packagetype") == "bdist_wheel"] + if ( + key > version_key(engine) + and wheels + and all(f.get("yanked") for f in wheels) + ): + yanked[version] = wheels[0].get("yanked_reason") or "" + return dict(sorted(yanked.items(), key=lambda kv: version_key(kv[0]))) + + +def sha256(path: Path) -> str: + return hashlib.sha256(path.read_bytes()).hexdigest() + + +def newest(uploads: dict[str, str]) -> str: + return max(uploads, key=version_key) + + +def from_engine(uploads: dict[str, str], engine: str) -> dict[str, str]: + """The upload times of the engine and every release after it.""" + return { + v: uploads[v] + for v in sorted(uploads, key=version_key) + if version_key(v) >= version_key(engine) + } + + +def newer_before(uploads: dict[str, str], engine: str, moment: str) -> list[str]: + """Releases newer than the engine uploaded before a moment.""" + return sorted( + ( + v + for v, at in uploads.items() + if version_key(v) > version_key(engine) and at[:19] < moment[:19] + ), + key=version_key, + ) + + +def read_pypi(url: str = PYPI) -> dict: + with urllib.request.urlopen(url, timeout=60) as response: + return json.load(response) + + +def dist_info(venv: Path, engine: str) -> Path: + found = sorted(venv.glob(f"lib/python*/site-packages/{PACKAGE}-{engine}.dist-info")) + if len(found) != 1: + raise Refusal(f"{venv} has no single {PACKAGE}-{engine}.dist-info") + return found[0] + + +def relative(path: Path) -> str: + try: + return str(path.resolve().relative_to(ROOT)) + except ValueError: + return str(path) + + +def read_computed(path: Path) -> dict[tuple[str, str], tuple[str, float]]: + with path.open(newline="") as source: + return { + (row["scenario_id"], row["variable"]): ( + row["state"], + float(row["recomputed"]), + ) + for row in csv.DictReader(source) + } + + +def compare( + reference: dict[tuple[str, str], tuple[str, float]], + check: dict[tuple[str, str], tuple[str, float]], + reference_engine: str, + check_engine: str, + excluded: frozenset[tuple[str, str]] = frozenset(), +) -> tuple[list[dict], dict]: + """Every output on both engines, and whether the values are the same. + ``excluded`` names the outputs the release does not score: a newer release + that fixes a defect behind one moves its value without touching a scored + reference, so the summary counts scored and excluded outputs apart.""" + if set(reference) != set(check): + raise Refusal( + "the two sweeps cover different outputs: " + f"{sorted(set(reference) ^ set(check))[:5]}" + ) + rows = [] + for key in sorted(reference): + state, before = reference[key] + after = check[key][1] + if not (math.isfinite(before) and math.isfinite(after)): + raise Refusal(f"{key}: a non-finite value ({before!r}, {after!r})") + delta = after - before + rows.append( + { + "scenario_id": key[0], + "state": state, + "variable": key[1], + "reference_engine": reference_engine, + "engine": check_engine, + "reference_value": repr(before), + "value": repr(after), + "delta": repr(delta), + "same": abs(delta) <= SAME, + "scored": key not in excluded, + } + ) + unknown = sorted(excluded - set(reference)) + if unknown: + raise Refusal(f"excluded outputs the sweeps do not cover: {unknown[:5]}") + differ = [r for r in rows if not r["same"]] + scored = [r for r in rows if r["scored"]] + + def names(found: list[dict]) -> list[str]: + return [f"{r['scenario_id']}|{r['variable']}" for r in found] + + return rows, { + "outputs": len(rows), + "same": len(rows) - len(differ), + "differ": names(differ), + "scored_outputs": len(scored), + "scored_same": sum(r["same"] for r in scored), + "scored_differ": names([r for r in differ if r["scored"]]), + "excluded_differ": names([r for r in differ if not r["scored"]]), + "max_abs_delta": max((abs(float(r["delta"])) for r in rows), default=0.0), + } + + +def write_rows(path: Path, rows: list[dict]) -> str: + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("w", newline="") as out: + writer = csv.DictWriter(out, fieldnames=list(rows[0]), lineterminator="\n") + writer.writeheader() + writer.writerows(rows) + return hashlib.sha256(path.read_bytes()).hexdigest() + + +def sweep(args) -> dict: + engine = args.engine + first = Path(args.first_output).resolve() + venv = Path(args.venv).resolve() + installed = dist_info(venv, engine) + install = engine_install(venv, engine) + first_at = utc(birth_time(first)) + pypi = read_pypi() + read_at = now_utc() + uploads = wheel_uploads(pypi) + if engine not in uploads: + raise Refusal(f"PyPI lists no wheel for policyengine-us {engine}") + installed_at = utc(birth_time(installed)) + sweep_order_problems(uploads[engine], installed_at, first_at, engine) + earlier = newer_before(uploads, engine, first_at) + if earlier: + raise Refusal( + f"policyengine-us {earlier} was uploaded before the sweep's first " + f"output ({first_at}), so {engine} was not the newest release when " + "the sweep began" + ) + return { + "note": NOTE, + "pypi": { + "source": PYPI, + "read_at_utc": read_at, + "newest_at_read": newest(uploads), + "wheel_uploaded_at_utc": from_engine(uploads, engine), + "yanked_newer": yanked_newer(pypi, engine), + }, + "reference_sweep": { + "engine": engine, + "engine_installed_at_utc": installed_at, + "engine_installed_evidence": relative(installed), + "engine_install": install, + "script": ( + "reference_audit/2026-10-22-engine-upgrade/scripts/" + "build_references_upgrade.py (first pass, empty actions)" + ), + "first_output_at_utc": first_at, + "first_output": relative(first), + "first_output_sha256": sha256(first), + }, + } + + +def sweep_order_problems( + uploaded_at: str, installed_at: str, output_at: str, engine: str +) -> None: + """A sweep's output follows its engine: the wheel was on PyPI before it was + installed, and installed before the sweep wrote its output. An older file + (an earlier rehearsal's output, say) would otherwise backdate the sweep.""" + if not uploaded_at[:19] <= installed_at[:19] <= output_at[:19]: + raise Refusal( + f"policyengine-us {engine}: wheel uploaded {uploaded_at}, installed " + f"{installed_at}, output written {output_at}; an output must follow " + "its engine's install, and the install its upload" + ) + + +def build_problems( + build: Path, engine: str, snapshot: Path +) -> tuple[dict, frozenset[tuple[str, str]], dict[str, str]]: + """The reference build's computed values, its excluded outputs and the + sha256 of each build file, once the build is shown to be the release's.""" + files = {name: build / name for name in BUILD_FILES} + missing = [name for name, path in files.items() if not path.is_file()] + if missing: + raise Refusal(f"{build} lacks {missing}") + pins = {name: sha256(path) for name, path in files.items()} + meta = json.loads(files["reference_outputs.csv.meta.json"].read_text()) + revision = meta["revisions"][-1] + if ( + revision.get("kind") != "engine_upgrade" + or revision.get("engine_version") != f"policyengine-us {engine}" + ): + raise Refusal( + f"{build}'s last revision is not an engine upgrade to {engine}: " + f"{revision.get('kind')} {revision.get('engine_version')}" + ) + if meta.get("reference_csv_sha256") != pins["reference_outputs.csv"]: + raise Refusal(f"{build}'s sidecar does not pin its reference_outputs.csv") + # The check sweep runs this audit's builder, as the build did: the same + # conventions and adapter, so the sidecar must name the committed builder. + named = (revision.get("provenance") or {}).get("builder_sha256") + if named != sha256(BUILDER): + raise Refusal( + f"{build}'s sidecar names builder {named!r}, not the committed one" + ) + pins["builder"] = named + for name in ( + "reference_outputs.csv", + "reference_outputs.csv.meta.json", + "reference_exclusions.json", + ): + committed = snapshot / name + if not committed.is_file() or sha256(committed) != pins[name]: + raise Refusal( + f"{build}/{name} is not the committed snapshot's ({committed}); " + "check the build the release froze" + ) + record = json.loads(files["reference_exclusions.json"].read_text())["exclusions"] + excluded = frozenset((e["scenario_id"], e["variable"]) for e in record) + with files["reference_outputs.csv"].open(newline="") as source: + references = { + (row["scenario_id"], row["variable"]): float(row["value"]) + for row in csv.DictReader(source) + } + computed = read_computed(files["computed.csv"]) + nonfinite = sorted( + key + for key in set(references) | set(computed) + if not math.isfinite(references.get(key, 0.0)) + or not math.isfinite(computed.get(key, ("", 0.0))[1]) + ) + if nonfinite: + raise Refusal(f"{build} holds non-finite values: {nonfinite[:5]}") + if set(computed) != set(references) or not excluded <= set(references): + raise Refusal( + f"{build}'s computed.csv, references and record cover different outputs" + ) + off = sorted( + key + for key, value in references.items() + if key not in excluded and abs(computed[key][1] - value) > REFERENCE_EPS + ) + if off: + raise Refusal(f"{build}'s computed.csv is not its scored references: {off[:5]}") + return computed, excluded, pins + + +# The engine check and, when a builder is named, the builder itself, in ONE +# process under the venv's interpreter, so what is checked is what computes. +# Launched with -P (no script or working directory on sys.path) and a fresh, +# empty bytecode-cache prefix, so no __pycache__ beside the sources is read: +# every module compiles from the verified source. Before policyengine_us is +# imported, it requires the expected version, an import origin inside the +# installed package, no editable install, every package file at the hash the +# wheel's RECORD gives (sha256, sha384 or sha512), and no importable file in the +# package (a module, a sourceless .pyc, a native extension) that RECORD does not +# list. It writes what it found to PB_ENGINE_RECEIPT, then runs the builder with +# the remaining arguments, or stops (exit 3) on any problem. +ENGINE_RUNNER = r""" +import base64, hashlib, importlib.machinery as mach, importlib.metadata as md +import importlib.util, json, os, pathlib, runpy, sys +expected = os.environ["PB_EXPECTED_ENGINE"] +dist = md.distribution("policyengine-us") +spec = importlib.util.find_spec("policyengine_us") +origin = pathlib.Path(spec.origin).resolve() +site = pathlib.Path(dist.locate_file("")).resolve() +package = (site / "policyengine_us").resolve() +direct = dist.read_text("direct_url.json") +editable = bool(direct and json.loads(direct).get("dir_info", {}).get("editable")) +recorded, mismatched = set(), [] +for entry in dist.files or []: + name = str(entry) + if not name.startswith("policyengine_us/") or "__pycache__" in name: + continue + recorded.add(name) + if not entry.hash or entry.hash.mode not in ("sha256", "sha384", "sha512"): + mismatched.append(name) + continue + path = pathlib.Path(dist.locate_file(entry)) + data = path.read_bytes() if path.is_file() else None + digest = hashlib.new(entry.hash.mode, data).digest() if data is not None else b"" + if base64.urlsafe_b64encode(digest).rstrip(b"=").decode() != entry.hash.value: + mismatched.append(name) +# No symlink anywhere in the package (a linked directory hides its files from +# the scan, and a linked file leaves the package): installs must be copies. +links = sorted( + str(pathlib.Path(root, name).relative_to(site)) + for root, dirs, files in os.walk(package) + for name in dirs + files + if os.path.islink(os.path.join(root, name)) +) +if os.path.islink(site / "policyengine_us"): + links.insert(0, "policyengine_us") +suffixes = tuple(mach.all_suffixes()) +unrecorded = sorted( + str(p.relative_to(site)) + for p in package.rglob("*") + if p.is_file() and "__pycache__" not in p.parts and p.name.endswith(suffixes) + and str(p.relative_to(site)) not in recorded +) +found = { + "version": dist.version, + "origin": str(origin), + "imported_from_package": origin.is_relative_to(package), + "editable": editable, + "files_verified": len(recorded) - len(mismatched), + "files_mismatched": mismatched[:5], + "files_unrecorded": unrecorded[:5], + "symlinks": links[:5], + "pycache_prefix": sys.pycache_prefix, + "sys_path": sys.path, +} +problems = [] +if found["version"] != expected: + problems.append(f"version {found['version']}, not {expected}") +if not found["imported_from_package"]: + problems.append(f"imports policyengine_us from {found['origin']}") +if editable: + problems.append("an editable install") +if mismatched or not found["files_verified"]: + problems.append(f"files unlike the wheel's RECORD {mismatched[:5]}") +if unrecorded: + problems.append(f"importable files the wheel lacks {unrecorded[:5]}") +if links: + problems.append(f"symlinks in the package (installs must be copies) {links[:5]}") +if not sys.pycache_prefix or any(pathlib.Path(sys.pycache_prefix).iterdir()): + problems.append("no fresh bytecode-cache prefix") +found["problems"] = problems +pathlib.Path(os.environ["PB_ENGINE_RECEIPT"]).write_text(json.dumps(found)) +if problems: + sys.exit(3) +if len(sys.argv) > 1: + sys.argv = sys.argv[1:] + runpy.run_path(sys.argv[0], run_name="__main__") +""" + + +def sweep_env() -> dict[str, str]: + """The environment a sweep runs in: no inherited Python overrides.""" + return { + **{k: v for k, v in os.environ.items() if k in ("PATH", "HOME", "LANG")}, + "PYTHONPATH": str(ROOT), + "PYTHONDONTWRITEBYTECODE": "1", + "OPENBLAS_NUM_THREADS": "1", + } + + +def run_on_engine( + venv: Path, engine: str, receipt: Path, builder_args: list[str] | None = None +): + """ENGINE_RUNNER under the venv's interpreter: the engine check, then (with + ``builder_args``) the builder in the same process. Returns the completed + process and the check's record; refuses when the check found a problem.""" + receipt = receipt.resolve() + if receipt.exists(): + raise Refusal(f"{receipt} exists: each run writes a fresh receipt") + cache = Path(tempfile.mkdtemp(prefix="pb-pycache-")) + command = [str(venv / "bin" / "python"), "-P", "-c", ENGINE_RUNNER] + if builder_args is not None: + command += [str(BUILDER), *builder_args] + env = { + **sweep_env(), + "PYTHONPYCACHEPREFIX": str(cache), + "PB_EXPECTED_ENGINE": engine, + "PB_ENGINE_RECEIPT": str(receipt), + } + try: + ran = subprocess.run(command, env=env, cwd=ROOT, capture_output=True, text=True) + finally: + shutil.rmtree(cache, ignore_errors=True) + if not receipt.is_file(): + raise Refusal( + f"{venv}: the engine check did not run ({ran.stderr.strip()[-300:]})" + ) + found = json.loads(receipt.read_text()) + if found["problems"]: + raise Refusal( + f"{venv} is not policyengine-us {engine} as released: {found['problems']}" + ) + return ran, { + "version": found["version"], + "files_verified": found["files_verified"], + "editable": False, + "imported_from_package": True, + "fresh_bytecode_cache": True, + } + + +def engine_install(venv: Path, engine: str) -> dict: + """The engine check alone (ENGINE_RUNNER without a builder).""" + with tempfile.TemporaryDirectory() as scratch: + _, install = run_on_engine(venv, engine, Path(scratch) / "receipt.json") + return install + + +def run_check_sweep(venv: Path, engine: str, out_dir: Path) -> tuple[Path, dict]: + """The check sweep, run here: this audit's builder, a first pass with + empty actions naming ``engine``, in the same process as the engine check + (run_on_engine), under the venv's interpreter. The builder also refuses + before computing unless the venv holds that release, and it pins the + conventions and harness it applies, so the computed.csv it writes is that + engine's under the release's conventions. Returns the file and what ran.""" + out_dir.mkdir(parents=True, exist_ok=False) + actions = out_dir / "actions.empty.json" + actions.write_text( + json.dumps( + { + "engine": f"policyengine-us {engine}", + "previous_engine": BASE_ENGINE, + "date": now_utc()[:10], + "draft": True, + } + ) + ) + args = ["--actions", str(actions), "--out-dir", str(out_dir), "--allow-draft"] + ran, install = run_on_engine(venv, engine, out_dir / "engine_install.json", args) + (out_dir / "sweep.log").write_text(ran.stdout + ran.stderr) + computed = out_dir / "computed.csv" + if not computed.is_file(): + raise Refusal( + f"the check sweep on {engine} wrote no computed.csv " + f"(exit {ran.returncode}; see {out_dir / 'sweep.log'})" + ) + return computed, { + "builder_sha256": sha256(BUILDER), + "venv": relative(venv), + "command": "build_references_upgrade.py --actions --allow-draft", + "exit_code": ran.returncode, + "engine_install": install, + } + + +def check(args) -> dict: + timing = json.loads(TIMING.read_text()) + engine = timing["reference_sweep"]["engine"] + build = Path(args.build) + computed, excluded, pins = build_problems( + build, engine, Path(getattr(args, "snapshot", None) or SNAPSHOT) + ) + scored = len(computed) - len(excluded) + pypi = read_pypi() + read_at = now_utc() + uploads = wheel_uploads(pypi) + latest = newest(uploads) + timing["pypi"] = { + "source": PYPI, + "read_at_utc": read_at, + "newest_at_read": latest, + "wheel_uploaded_at_utc": from_engine(uploads, engine), + "yanked_newer": yanked_newer(pypi, engine), + } + inputs = { + "build": relative(build), + "build_sha256": pins, + "scored_outputs": scored, + } + if latest == engine: + timing["publication_check"] = { + "engine": engine, + "result": ( + f"policyengine-us {engine}, the reference engine, was still the " + "newest release when PolicyBench read PyPI" + ), + **inputs, + } + return timing + if not args.check_venv: + raise Refusal( + f"policyengine-us {latest} is newer than the reference engine {engine}: " + "pass --check-venv, a venv holding it, and check runs the sweep" + ) + venv = Path(args.check_venv).resolve() + installed = dist_info(venv, latest) + engine_install(venv, latest) # fail fast; the sweep's own process checks again + installed_at = utc(birth_time(installed)) + scratch = ROOT / "results/local" + scratch.mkdir(parents=True, exist_ok=True) + work = ( + Path( + getattr(args, "work_dir", None) + or tempfile.mkdtemp(prefix=f"check-sweep-{latest}-", dir=scratch) + ).resolve() + / "sweep" + ) + check_path, receipt = run_check_sweep(venv, latest, work) + output_at = utc(birth_time(check_path)) + sweep_order_problems(uploads[latest], installed_at, output_at, latest) + rows, summary = compare( + computed, read_computed(check_path), engine, latest, excluded + ) + if summary["scored_outputs"] != scored: + raise Refusal( + f"the check scored {summary['scored_outputs']} outputs, not {scored}" + ) + out = VERIFICATION / f"publication_check_{latest.replace('.', '_')}.csv" + digest = write_rows(out, rows) + timing["publication_check"] = { + "engine": latest, + "engine_installed_at_utc": installed_at, + "engine_installed_evidence": relative(installed), + "check_computed": relative(check_path), + "check_computed_sha256": sha256(check_path), + "check_sweep": receipt, + "output_at_utc": output_at, + "output": relative(out), + "output_sha256": digest, + **inputs, + **summary, + } + return timing + + +def main(argv: list[str] | None = None) -> None: + parser = argparse.ArgumentParser(description=__doc__.split("\n\n")[0]) + sub = parser.add_subparsers(dest="step", required=True) + s = sub.add_parser("sweep") + s.add_argument("--engine", required=True) + s.add_argument("--venv", required=True) + s.add_argument("--first-output", required=True) + c = sub.add_parser("check") + c.add_argument("--build", required=True) + c.add_argument("--check-venv") + c.add_argument("--snapshot") + r = sub.add_parser("run") + r.add_argument("--venv", required=True) + r.add_argument("--engine", required=True) + r.add_argument("--receipt", required=True) + r.add_argument("builder_args", nargs=argparse.REMAINDER) + args = parser.parse_args(argv) + if args.step == "run": + # The reference build itself, through the same engine check and the + # same single process as the check sweep (run_on_engine). + raw = list(args.builder_args) + if raw[:1] == ["--"]: + raw = raw[1:] + builder_args, computed = builder_arguments(raw) + if computed is not None and computed.exists(): + raise Refusal(f"{computed} exists: each run writes into a fresh out-dir") + started = time.time() + ran, install = run_on_engine( + Path(args.venv).resolve(), args.engine, Path(args.receipt), builder_args + ) + if computed is not None and ( + not computed.is_file() or birth_time(computed) < started - 1 + ): + raise Refusal( + f"the build on {args.engine} wrote no new {computed} " + f"(exit {ran.returncode})" + ) + sys.stdout.write(ran.stdout) + sys.stderr.write(ran.stderr) + print(json.dumps({"engine_install": install}), file=sys.stderr) + raise SystemExit(ran.returncode) + timing = sweep(args) if args.step == "sweep" else check(args) + VERIFICATION.mkdir(parents=True, exist_ok=True) + TIMING.write_text(json.dumps(timing, indent=2) + "\n") + print( + json.dumps(timing.get("publication_check", timing["reference_sweep"]), indent=1) + ) + moved = timing.get("publication_check", {}).get("scored_differ") + if moved: + raise Refusal( + f"policyengine-us {timing['publication_check']['engine']} moves scored " + f"outputs {moved[:5]}: do not publish (the record is in " + f"{relative(TIMING)})" + ) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/reference_audit/2026-10-22-engine-upgrade/verification/superseded_2_59_0.json b/reference_audit/2026-10-22-engine-upgrade/verification/superseded_2_59_0.json new file mode 100644 index 00000000..ae6d922c --- /dev/null +++ b/reference_audit/2026-10-22-engine-upgrade/verification/superseded_2_59_0.json @@ -0,0 +1,60 @@ +{ + "note": "The first reference sweep of this upgrade, on policyengine-us 2.59.0, the newest PyPI release when it began. A host restart at 20:01 UTC cut the session off before the build; when it resumed at 01:43 UTC on 2026-10-23, 2.60.0 (wheel uploaded 2026-10-22 22:47:49 UTC) was the newest release, and its first pass differs from 2.59.0's on the three outputs listed, all scored (PolicyEngine/policyengine-us#10238, in 2.60.0's release commit 2bc4ccc970 and not in 2.59.0's, 05813807e1). A 2.59.0 build would fail the publication check, so the sweep began again on 2.60.0 (sweep_timing.json). Every other output is identical on the two releases.", + "sweep_timing_2_59_0": { + "note": "When PolicyBench began sweeping the references for the 2026-10-22 move, which policyengine-us release was the newest then and at publication, and the publication check. Times are UTC. The PyPI upload times were read from the PyPI JSON API; the install and first-output times are filesystem birth times (st_birthtime) of the engine's dist-info directory and of the first file the sweep wrote.", + "pypi": { + "source": "https://pypi.org/pypi/policyengine-us/json", + "read_at_utc": "2026-10-22T19:49:39Z", + "newest_at_read": "2.59.0", + "wheel_uploaded_at_utc": { + "2.59.0": "2026-10-22T17:15:04.594706Z" + }, + "yanked_newer": {} + }, + "reference_sweep": { + "engine": "2.59.0", + "engine_installed_at_utc": "2026-10-22T19:44:13Z", + "engine_installed_evidence": ".venv/lib/python3.12/site-packages/policyengine_us-2.59.0.dist-info", + "engine_install": { + "version": "2.59.0", + "files_verified": 19463, + "editable": false, + "imported_from_package": true, + "fresh_bytecode_cache": true + }, + "script": "reference_audit/2026-10-22-engine-upgrade/scripts/build_references_upgrade.py (first pass, empty actions)", + "first_output_at_utc": "2026-10-22T19:49:15Z", + "first_output": "results/local/engine-upgrade-1022/pass1_2590/computed.csv", + "first_output_sha256": "39708907df73461d753b0765fd5c83af3eb35d0e93f2c4ecae3d9aeb39ef7d51" + } + }, + "first_pass_2_59_0_sha256": "39708907df73461d753b0765fd5c83af3eb35d0e93f2c4ecae3d9aeb39ef7d51", + "first_pass_2_60_0_sha256": "98b0257548477a69f8c9f3cbdd85bb6fdbc430529189821bcd45068672f06008", + "outputs": 1984, + "differ_2_59_0_vs_2_60_0": [ + { + "scenario_id": "scenario_028", + "state": "PA", + "variable": "free_school_meals_eligible", + "value_2_59_0": 0.0, + "value_2_60_0": 1.0, + "scored": true + }, + { + "scenario_id": "scenario_117", + "state": "AR", + "variable": "free_school_meals_eligible", + "value_2_59_0": 0.0, + "value_2_60_0": 1.0, + "scored": true + }, + { + "scenario_id": "scenario_123", + "state": "PA", + "variable": "free_school_meals_eligible", + "value_2_59_0": 0.0, + "value_2_60_0": 1.0, + "scored": true + } + ] +} diff --git a/reference_audit/2026-10-22-engine-upgrade/verification/sweep_timing.json b/reference_audit/2026-10-22-engine-upgrade/verification/sweep_timing.json new file mode 100644 index 00000000..a200c0c1 --- /dev/null +++ b/reference_audit/2026-10-22-engine-upgrade/verification/sweep_timing.json @@ -0,0 +1,41 @@ +{ + "note": "When PolicyBench began sweeping the references for the 2026-10-22 move, which policyengine-us release was the newest then and at publication, and the publication check. Times are UTC. The PyPI upload times were read from the PyPI JSON API; the install and first-output times are filesystem birth times (st_birthtime) of the engine's dist-info directory and of the first file the sweep wrote.", + "pypi": { + "source": "https://pypi.org/pypi/policyengine-us/json", + "read_at_utc": "2026-10-23T02:11:36Z", + "newest_at_read": "2.60.0", + "wheel_uploaded_at_utc": { + "2.60.0": "2026-10-22T22:47:49.733557Z" + }, + "yanked_newer": {} + }, + "reference_sweep": { + "engine": "2.60.0", + "engine_installed_at_utc": "2026-10-23T01:44:20Z", + "engine_installed_evidence": "results/local/venv-2600/lib/python3.12/site-packages/policyengine_us-2.60.0.dist-info", + "engine_install": { + "version": "2.60.0", + "files_verified": 19508, + "editable": false, + "imported_from_package": true, + "fresh_bytecode_cache": true + }, + "script": "reference_audit/2026-10-22-engine-upgrade/scripts/build_references_upgrade.py (first pass, empty actions)", + "first_output_at_utc": "2026-10-23T01:45:50Z", + "first_output": "results/local/engine-upgrade-1022/pass1_2600/computed.csv", + "first_output_sha256": "98b0257548477a69f8c9f3cbdd85bb6fdbc430529189821bcd45068672f06008" + }, + "publication_check": { + "engine": "2.60.0", + "result": "policyengine-us 2.60.0, the reference engine, was still the newest release when PolicyBench read PyPI", + "build": "reference_audit/2026-10-22-engine-upgrade/build", + "build_sha256": { + "computed.csv": "98b0257548477a69f8c9f3cbdd85bb6fdbc430529189821bcd45068672f06008", + "reference_outputs.csv": "eab09a0c184c14b0c33679d9ac132d6f1de720c439ac30685a67ca38655184cb", + "reference_outputs.csv.meta.json": "a222c2de9b5c1fabe2c77e4acd27ca36b8961a9879f5aeaf529be5a5cabbadb4", + "reference_exclusions.json": "91408c0f3d49e1984b436164a047f8cedc3e501feb2099ba0e7d2782ee8ac73d", + "builder": "2aa0a6b1e41fd067278303afeeea45de2ffe1bf4c2af797f532777bab587d89b" + }, + "scored_outputs": 1935 + } +} diff --git a/tests/test_build_references_upgrade_1022.py b/tests/test_build_references_upgrade_1022.py new file mode 100644 index 00000000..4e34ba66 --- /dev/null +++ b/tests/test_build_references_upgrade_1022.py @@ -0,0 +1,2373 @@ +"""The fourth engine upgrade's reference builder, its narratives, its draft +actions and its committed build (reference_audit/2026-10-22-engine-upgrade, on +release 20261014, staged for the next board release). + +Adapted from tests/test_build_references_upgrade_1012.py, which tests the +2026-10-12 audit's copies. The planning logic is the same; the base, the +previous engine and this audit's own fix modules differ, and no release spec +rules exclusions (the build is staged, not frozen with a release). + +The engine is stubbed: each test hands the builder's pure planning step a dict +of computed values. Properties (Hypothesis) state the builder's invariants: + +- every refusal fires: an unexplained move, scored or excluded; an approved + output that does not move; a regenerated output off its audited target; a new + exclusion on an output that does not move; a rechecked output that does not + move; an output named by two lists; +- a removed record's output is scored at its new engine value; +- every output the upgrade does not change keeps its bytes in the reference + CSV, and every earlier sidecar revision keeps its bytes; +- the records' order does not depend on the order of the actions' lists; +- the paper's partition of the revision's changes agrees with the builder. + +The committed build is checked against itself and its inputs: re-planning the +committed computed.csv with final_actions.json and writing the result +reproduces the committed reference CSV, sidecar and exclusion record byte for +byte (a differential test of the build that needs no engine). +""" + +from __future__ import annotations + +import copy +import importlib.util +import json +import random +import sys +import types +from pathlib import Path + +import pytest +from hypothesis import HealthCheck, given, settings +from hypothesis import strategies as st + +ROOT = Path(__file__).resolve().parents[1] +UPGRADE = ROOT / "reference_audit" / "2026-10-22-engine-upgrade" +BUILD = UPGRADE / "build" +RUN_DIR = ( + ROOT + / "paper/snapshot/20260501/runs" + / "us_full_run_20260612_policyengine_4_16_1_populace" +) +SETTINGS = settings( + max_examples=60, + deadline=None, + suppress_health_check=[HealthCheck.function_scoped_fixture], +) + + +def _module(name: str, path: Path, builder=None): + """Load ``path`` as ``name``. This audit's narratives and drafting scripts + import ``build_references_upgrade`` by name, which the 2026-10-09 and + 2026-10-12 tests may already have loaded from their folders: ``builder`` + stands in under that name while the module loads, and the earlier entry is + put back.""" + if name in sys.modules: + return sys.modules[name] + spec = importlib.util.spec_from_file_location(name, path) + module = importlib.util.module_from_spec(spec) + sys.modules[name] = module + previous = sys.modules.get("build_references_upgrade") + if builder is not None: + sys.modules["build_references_upgrade"] = builder + try: + spec.loader.exec_module(module) + finally: + if builder is not None: + if previous is None: + sys.modules.pop("build_references_upgrade", None) + else: + sys.modules["build_references_upgrade"] = previous + return module + + +build = _module( + "build_references_upgrade_1022", + UPGRADE / "scripts" / "build_references_upgrade.py", +) +narratives = _module( + "narratives_upgrade_1022", UPGRADE / "scripts" / "narratives_upgrade.py", build +) +drafting = _module("actions_from_cells_1022", UPGRADE / "actions_from_cells.py", build) + + +def test_this_audits_scripts_use_this_audits_builder(): + assert build.BASE_COMMIT == "bf845cbe4e92de495150c8660c35ea357d996a8c" + assert build.PREVIOUS_ENGINE == "policyengine-us 2.41.0" + assert build.LOCAL_FIXES_REL == "reference_audit/2026-10-22-engine-upgrade/fixes" + assert narratives.BASE_COMMIT == build.BASE_COMMIT + assert drafting.PREVIOUS_ENGINE == build.PREVIOUS_ENGINE + assert drafting.load_base is build.load_base + + +ENGINE = "policyengine-us 9.9.9" +DATE = "2026-10-23" +NOW = "2026-10-23T12:00:00+00:00" +S = "state_income_tax_before_refundable_credits" +F = "federal_income_tax_before_refundable_credits" +FLAG = "head_medicaid_eligible" + + +# --- A small synthetic base -------------------------------------------------- + + +def _defect(sid, variable, frozen, alternative, decided_on="2026-09-22"): + return { + "scenario_id": sid, + "variable": variable, + "reason_code": "reference_engine_defect", + "root_cause": f"r_{sid}", + "alternative_reading": "The rule as the law states it.", + "frozen_value": frozen, + "alternative_value": alternative, + "engine_version": "policyengine-us 1.755.4", + "decided_on": decided_on, + "decided_by": "developer", + "defect": "a defect", + "law": "a law", + "upstream": "to be filed", + "note": "a note", + } + + +def _unlisted(sid, variable, frozen, alternative, decided_on="2026-09-05"): + return { + "scenario_id": sid, + "variable": variable, + "reason_code": "reference_depends_on_unlisted_input", + "unlisted_input": "an input", + "alternative_reading": "Another reading.", + "frozen_value": frozen, + "alternative_value": alternative, + "engine_version": "policyengine-us 1.755.4", + "decided_on": decided_on, + "decided_by": "developer", + "note": "a note", + } + + +# scenario, variable, base value, impact weight +ROWS = [ + ("scenario_001", S, 1000.0, ""), + ("scenario_001", "local_income_tax", 0.0, ""), + ("scenario_002", S, 500.25, "1.5"), + ("scenario_002", F, 250.5, ""), + ("scenario_003", S, 1200.0, ""), + ("scenario_003", "snap", 3000.0, ""), + ("scenario_004", S, 700.0, ""), + ("scenario_004", F, 4100.0, ""), + ("scenario_005", S, 820.35, ""), + ("scenario_005", FLAG, 1.0, "0.0"), + ("scenario_006", "local_income_tax", 0.0, ""), + ("scenario_006", "snap", 120.0, ""), + ("scenario_007", "snap", 0.0, ""), + ("scenario_007", "free_school_meals_eligible", 0.0, "0.0"), + ("scenario_023", FLAG, 1.0, ""), +] +# Release 20261014's record, in its shape: the 2026-09-22 records, then the +# later ones (decided 2026-10-06 on 2.15.17), then the 2026-09-29 audit's tail. +LATER = [ + { + **_defect("scenario_004", S, 700.0, 690.0, decided_on="2026-10-06"), + "engine_version": "policyengine-us 2.15.17", + }, + { + **_unlisted("scenario_004", F, 4100.0, 5300.0, decided_on="2026-10-06"), + "engine_version": "policyengine-us 2.15.17", + }, + { + **_unlisted("scenario_005", S, 820.35, 820.26, decided_on="2026-10-06"), + "reason_code": "reference_law_published_after_freeze", + "root_cause": "later", + "published": "later", + "law": "a law", + "engine_version": "policyengine-us 2.15.17", + }, +] +BASE_RECORDS = [ + _defect("scenario_002", F, 250.5, 300.0), # fixed below: regenerated + _defect("scenario_003", "snap", 3000.0, 2500.0), # unfixed + _unlisted("scenario_006", "snap", 120.0, 0.0), + *LATER, +] +TAIL = _unlisted("scenario_023", FLAG, 1.0, 0.0, decided_on="2026-09-29") +FIRST_REVISION = { + "date": "2026-09-29", + "kind": "engine_upgrade", + "engine_version": "policyengine-us 2.15.17", + "previous_engine_version": "policyengine-us 1.755.4", + "fix_modules": [], + "excluded_outputs_rechecked": [], + "changed": [], +} +SECOND_REVISION = { + "date": "2026-10-10", + "kind": "engine_upgrade", + "engine_version": "policyengine-us 2.38.6", + "previous_engine_version": "policyengine-us 2.15.17", + "fix_modules": [], + "excluded_outputs_rechecked": [], + "regenerated_exclusions": [], + "changed": [], +} +# Release 20261013's upgrade, the base's last revision: this audit's builder +# upgrades from its engine. +THIRD_REVISION = { + "date": "2026-10-13", + "kind": "engine_upgrade", + "engine_version": "policyengine-us 2.41.0", + "previous_engine_version": "policyengine-us 2.38.6", + "fix_modules": [], + "excluded_outputs_rechecked": [], + "regenerated_exclusions": [], + "changed": [], +} + + +def _csv_text(rows=ROWS) -> str: + lines = ["scenario_id,variable,value,impact_weight\n"] + lines += [f"{s},{v},{repr(float(x))},{w}\n" for s, v, x, w in rows] + return "".join(lines) + + +def _base() -> build.Base: + exclusions = { + "schema_version": 1, + "rule": "rule", + "derivation": "Derived.", + "exclusions": copy.deepcopy(BASE_RECORDS) + [copy.deepcopy(TAIL)], + } + return build.Base( + reference=build.parse_reference_csv(_csv_text()), + meta={ + "programs": [], + "policyengine_bundles": {"us": {}}, + "reference_csv_sha256": "x", + "regenerated_at_utc": "2026-09-29T15:04:45+00:00", + "revisions": [ + {"date": "2026-09-22", "kind": "convention", "changed": []}, + copy.deepcopy(FIRST_REVISION), + copy.deepcopy(SECOND_REVISION), + copy.deepcopy(THIRD_REVISION), + ], + }, + exclusions=exclusions, + scenarios_csv="", + frozen={(s, v): x - 1.0 for s, v, x, _ in ROWS}, + ) + + +def _unchanged() -> dict: + return {(s, v): x for s, v, x, _ in ROWS} + + +def _new_exclusion(sid, value) -> dict: + record = _unlisted(sid, "local_income_tax", value, 0.0, decided_on=DATE) + record["engine_version"] = ENGINE + return record + + +def _actions(**lists) -> dict: + """Actions on the synthetic base.""" + actions = { + "engine": ENGINE, + "previous_engine": "policyengine-us 2.41.0", + "date": DATE, + "approved": [], + "regenerated_exclusions": [], + "new_exclusions": [], + "excluded_rechecked": [], + } + actions.update(lists) + return actions + + +def _regenerate(sid, variable, alternative, tolerance=1.0): + return { + "scenario_id": sid, + "variable": variable, + "alternative_value": alternative, + "tolerance": tolerance, + "upstream": "PolicyEngine/policyengine-us#1", + "basis": "Fixed upstream.", + } + + +def _full(): + """A complete upgrade: one approval, two regenerations (a 2026-09-22 record + and a later one), one new exclusion, one recheck, a within-$1 move.""" + computed = _unchanged() + computed[("scenario_001", S)] = 1010.0 # approved + computed[("scenario_002", F)] = 300.4 # regenerated (2026-09-22 record) + computed[("scenario_004", S)] = 690.2 # regenerated (2026-10-06 record) + computed[("scenario_006", "local_income_tax")] = 670.55 # new exclusion + computed[("scenario_003", "snap")] = 2900.0 # rechecked: off target + computed[("scenario_002", S)] = 500.75 # within $1 + actions = _actions( + approved=[ + { + "scenario_id": "scenario_001", + "variable": S, + "value": 1010.0, + "cause": "a_cause", + "basis": "A basis.", + } + ], + regenerated_exclusions=[ + _regenerate("scenario_002", F, 300.0), + _regenerate("scenario_004", S, 690.0), + ], + new_exclusions=[_new_exclusion("scenario_006", 670.55)], + excluded_rechecked=[ + {"scenario_id": "scenario_003", "variable": "snap", "reason": "Not fixed."} + ], + ) + return computed, actions + + +def _plan(computed, actions): + base = _base() + return base, build.plan_upgrade(base, actions, computed) + + +def _write(tmp_path, computed, actions): + base, plan = _plan(computed, actions) + assert plan.problems == [] + written = build.write_outputs( + tmp_path, + base, + plan, + actions, + bundle={"policyengine_version": "6.1.2", "bundled_model_version": "2.2.1"}, + fix_modules=[{"module": "m.py", "sha256": "0"}], + provenance={"builder_sha256": "0"}, + traces={ + f"{c['scenario_id']}|{c['variable']}": { + "pe_variable": c["variable"], + "trace": "t\nu", + } + for c in plan.changed + plan.within + }, + now=NOW, + ) + return base, plan, written + + +# --- The full upgrade --------------------------------------------------------- + + +def test_a_complete_upgrade_writes_consistent_records(tmp_path): + computed, actions = _full() + base, plan, written = _write(tmp_path, computed, actions) + revision = written.meta["revisions"][-1] + assert revision["kind"] == "engine_upgrade" + assert revision["engine_version"] == ENGINE + assert revision["previous_engine_version"] == "policyengine-us 2.41.0" + assert written.meta["revisions"][:-1] == base.meta["revisions"] + assert [r["kind"] for r in written.meta["revisions"]].count("engine_upgrade") == 4 + causes = { + (c["scenario_id"], c["variable"]): c["cause"] for c in revision["changed"] + } + assert causes == { + ("scenario_001", S): "a_cause", + ("scenario_002", F): "regenerated_upstream_fix", + ("scenario_004", S): "regenerated_upstream_fix", + ("scenario_006", "local_income_tax"): ( + "excluded_reference_depends_on_unlisted_input" + ), + ("scenario_002", S): "engine_upgrade_within_1", + } + (rechecked,) = revision["excluded_outputs_rechecked"] + assert rechecked == { + "scenario_id": "scenario_003", + "variable": "snap", + "kept_value": 3000.0, + "value_on_9_9_9": 2900.0, + "reason": "Not fixed.", + } + assert [build.key_of(r) for r in revision["regenerated_exclusions"]] == [ + ("scenario_002", F), + ("scenario_004", S), + ] + # No release spec rules exclusions here, so the revision lists none kept. + assert "kept_exclusions_from_release" not in revision + keys = [build.key_of(r) for r in written.exclusions["exclusions"]] + assert keys == [ + ("scenario_003", "snap"), + ("scenario_006", "snap"), + ("scenario_004", F), + ("scenario_005", S), + ("scenario_006", "local_income_tax"), + ("scenario_023", FLAG), + ] + assert written.exclusions["derivation"].startswith("Derived. On 2026-10-23") + derivation = written.exclusions["derivation"] + assert "from policyengine-us 2.41.0 to policyengine-us 9.9.9" in derivation + assert "(reference_audit/2026-10-22-engine-upgrade)" in derivation + assert "behind two excluded outputs" in derivation + assert "sidecar's fourth engine_upgrade revision" in derivation + assert "One scored output the new engine moved was excluded" in derivation + assert "that stay excluded, one moved" in derivation + values = build.parse_reference_csv(written.csv_text).values() + assert values[("scenario_003", "snap")] == 3000.0 # rule 5: kept + assert values[("scenario_006", "local_income_tax")] == 670.55 + assert set(written.traces) == {f"{k[0]}|{k[1]}" for k in causes} + on_disk = (tmp_path / "reference_outputs.csv.meta.json").read_text() + assert on_disk == build.dump_record(written.meta) + assert ( + build.sha256_bytes(written.csv_text.encode()) + == (written.meta["reference_csv_sha256"]) + ) + + +def test_the_papers_partition_agrees_with_the_builder(tmp_path): + """Differential: the paper reads the written sidecar and record as the + builder planned them (engine_upgrades_from rebuilds the record around each + upgrade from regenerated_exclusions' removed records).""" + from policybench.paper_results import engine_upgrades_from + + computed, actions = _full() + _, plan, written = _write(tmp_path, computed, actions) + *_, upgrade = engine_upgrades_from( + written.meta["revisions"], written.exclusions["exclusions"] + ) + assert (upgrade.previous_engine_version, upgrade.engine_version) == ( + "2.41.0", + "9.9.9", + ) + groups = { + name: sorted(build.key_of(c) for c in group) + for name, group in upgrade.partition.items() + } + assert groups == { + "scored_changes": [("scenario_001", S)], + "within_tolerance": [("scenario_002", S)], + "new_exclusions": [("scenario_006", "local_income_tax")], + "restored": [("scenario_002", F), ("scenario_004", S)], + } + assert upgrade.restored == {build.key_of(r) for r in plan.regenerated} + assert [upgrade.rechecked_value(r) for r in upgrade.rechecked] == [2900.0] + + +def test_a_later_record_that_moves_is_rechecked_and_keeps_its_value(tmp_path): + """A record decided after the 2026-09-22 audit (later law, here) that the + new engine moves is drafted as a recheck and keeps its value (rule 5); no + two lists may name one output.""" + computed = _unchanged() + computed[("scenario_005", S)] = 830.0 + drafted, _ = _draft(computed) + actions = {k: v for k, v in drafted.items() if k not in ("draft", "review")} + assert [build.key_of(e) for e in actions["excluded_rechecked"]] == [ + ("scenario_005", S) + ] + build.validate_actions(actions) + _, plan, written = _write(tmp_path, computed, actions) + assert [build.key_of(r) for r in plan.rechecked] == [("scenario_005", S)] + assert ( + build.parse_reference_csv(written.csv_text).values()[("scenario_005", S)] + == 820.35 + ) + for name in ("approved", "regenerated_exclusions", "new_exclusions"): + with pytest.raises(build.Refusal, match="is in both"): + build.validate_actions( + {**actions, name: [{"scenario_id": "scenario_005", "variable": S}]} + ) + + +def test_the_release_spec_keys_are_gone(): + """The 2026-10-12 builder drafted against a release spec; this one stages a + build with no release, so those keys are refused as unknown.""" + for key, value in ( + ("release_spec_sha256", "spec"), + ("kept_exclusions_from_release", []), + ): + with pytest.raises(build.Refusal, match="unknown actions keys"): + build.validate_actions({**_actions(), key: value}) + + +def test_the_written_date_must_be_the_actions_date(tmp_path): + computed, actions = _full() + base, plan = _plan(computed, actions) + with pytest.raises(build.Refusal, match="does not fall on the actions date"): + build.write_outputs( + tmp_path, + base, + plan, + actions, + bundle={}, + fix_modules=[], + provenance={}, + traces={}, + now="2026-10-24T00:00:01+00:00", + ) + + +# --- Refusals ------------------------------------------------------------------ + + +def _problems(computed, actions) -> list[str]: + return _plan(computed, actions)[1].problems + + +@SETTINGS +@given(delta=st.floats(min_value=1.01, max_value=1e5) | st.floats(-1e5, -1.01)) +def test_an_unexplained_scored_move_is_refused(delta): + computed = _unchanged() + computed[("scenario_001", S)] += delta + (problem,) = _problems(computed, _actions()) + assert problem.startswith("unreviewed move ('scenario_001'") + + +def test_a_flag_flip_is_a_move(): + computed = _unchanged() + computed[("scenario_005", FLAG)] = 0.0 + (problem,) = _problems(computed, _actions()) + assert "unreviewed move ('scenario_005', 'head_medicaid_eligible')" in problem + + +@SETTINGS +@given(delta=st.floats(min_value=1.01, max_value=1e4)) +def test_an_excluded_move_without_a_recheck_is_refused(delta): + computed = _unchanged() + computed[("scenario_006", "snap")] += delta + (problem,) = _problems(computed, _actions()) + assert problem.startswith("excluded output moved without a recheck") + + +@SETTINGS +@given(delta=st.floats(min_value=-1.0, max_value=1.0)) +def test_an_approved_output_that_does_not_move_is_refused(delta): + computed = _unchanged() + computed[("scenario_001", S)] += delta + approved = [ + { + "scenario_id": "scenario_001", + "variable": S, + "value": computed[("scenario_001", S)], + "cause": "c", + "basis": "b", + } + ] + (problem,) = _problems(computed, _actions(approved=approved)) + assert problem.startswith("approved ('scenario_001'") and "does not move" in problem + + +def test_an_approved_output_that_lands_elsewhere_is_refused(): + computed = _unchanged() + computed[("scenario_001", S)] = 1010.0 + approved = [ + { + "scenario_id": "scenario_001", + "variable": S, + "value": 1010.01, + "cause": "c", + "basis": "b", + } + ] + (problem,) = _problems(computed, _actions(approved=approved)) + assert "!= approved" in problem + + +@SETTINGS +@given( + miss=st.floats(min_value=0.0, max_value=50.0), + tolerance=st.floats(min_value=0.0, max_value=1.0), +) +def test_a_regenerated_output_must_land_within_its_tolerance(miss, tolerance): + computed = _unchanged() + computed[("scenario_002", F)] = 300.0 + miss + actions = _actions( + regenerated_exclusions=[_regenerate("scenario_002", F, 300.0, tolerance)] + ) + problems = _problems(computed, actions) + if abs(computed[("scenario_002", F)] - 300.0) <= tolerance: + assert problems == [] + else: + (problem,) = problems + assert "misses its audited target" in problem + + +def test_a_regeneration_must_name_the_records_target_and_a_small_tolerance(): + computed = _unchanged() + computed[("scenario_002", F)] = 300.0 + wrong_target = _actions( + regenerated_exclusions=[_regenerate("scenario_002", F, 301.0)] + ) + assert "is not the record's" in _problems(computed, wrong_target)[0] + wide = _actions(regenerated_exclusions=[_regenerate("scenario_002", F, 300.0, 1.5)]) + assert "tolerance 1.5 outside" in _problems(computed, wide)[0] + + +def test_only_an_engine_defect_is_regenerated(): + computed = _unchanged() + computed[("scenario_006", "snap")] = 0.0 + actions = _actions( + regenerated_exclusions=[_regenerate("scenario_006", "snap", 0.0)] + ) + (problem,) = _problems(computed, actions) + assert "not an engine defect" in problem + + +# --- A fix-modules target: a record decided on an older engine ---------------- +# +# scenario_003 snap's record was decided on 1.755.4 (frozen 3000, corrected +# 2500). Other engine changes have since moved the output, so its +# alternative_value is stale: the audited fix module, run on a pre-fix engine, +# gives the target instead. + +PRE_FIX = "policyengine-us 9.9.8" +MODULE = "r_fix_v2.py" +EVIDENCE = {"path": "evidence/pre_fix.json", "sha256": "e" * 64} + + +def _evidence(engine_value=3100.0, corrected=2600.3, engine=PRE_FIX, pin="p" * 64): + return { + "kind": build.EVIDENCE_KIND, + "engine": engine, + "modules": {MODULE: pin}, + "items": [ + { + "scenario_id": "scenario_003", + "variable": "snap", + "modules": [MODULE], + "engine_value": engine_value, + "corrected_value": corrected, + } + ], + } + + +def _module_target(**target): + entry = _regenerate("scenario_003", "snap", 2500.0) + entry["target"] = { + "kind": "fix_modules", + "modules": [MODULE], + "evidence": dict(EVIDENCE), + **target, + } + return entry + + +def _module_plan( + value=2600.0, after=2600.1, evidence=None, pins=None, entry=None, deps=None +): + computed = _unchanged() + computed[("scenario_003", "snap")] = value + base = _base() + actions = _actions(regenerated_exclusions=[entry or _module_target()]) + return build.plan_upgrade( + base, + actions, + computed, + evidence={EVIDENCE["path"]: evidence or _evidence()}, + module_pins={MODULE: "p" * 64} if pins is None else pins, + module_values={(("scenario_003", "snap"), (MODULE,)): after}, + module_deps=deps, + ) + + +def test_a_fix_modules_target_pins_the_siblings_its_modules_load(): + """r02_ira_219g_v2.py runs r02_ira_219g.py: the evidence must pin that + sibling at the bytes committed at the base, and the target records it.""" + sibling = "r_fix.py" + deps = {MODULE: [sibling]} + missing = _module_plan(deps=deps, pins={MODULE: "p" * 64, sibling: "s" * 64}) + assert any("does not pin the siblings" in p for p in missing.problems) + doc = _evidence() + doc["modules"][sibling] = "s" * 64 + plan = _module_plan( + deps=deps, evidence=doc, pins={MODULE: "p" * 64, sibling: "s" * 64} + ) + assert plan.problems == [] + (regenerated,) = plan.regenerated + assert regenerated["target"]["dependencies"] == [ + {"module": sibling, "sha256": "s" * 64} + ] + stale = _module_plan( + deps=deps, evidence=doc, pins={MODULE: "p" * 64, sibling: "t" * 64} + ) + assert any("does not pin the siblings" in p for p in stale.problems) + + +def test_module_dependencies_are_found_transitively(): + files = { + "a_v2.py": b"x = Path(__file__).with_name('a.py')", + "a.py": b'y = Path(__file__).with_name( "b.json" )', + "b.json": b"{}", + } + assert build.module_dependencies("a_v2.py", files.__getitem__) == ["a.py", "b.json"] + assert build.module_dependencies("b.json", files.__getitem__) == [] + + +def test_a_module_whose_closure_cannot_be_established_is_refused(): + """The delta review's case: c13v3_upstream_plus_r30.py loads six siblings + through _HERE / f"{name}.py"; pinning only the wrapper would let a loaded + sibling change unseen, so the builder refuses it.""" + with pytest.raises(build.Refusal, match="cannot be established"): + build.module_dependencies("c13v3_upstream_plus_r30.py", build.committed_fix) + with pytest.raises(build.Refusal, match="cannot be established"): + build.audit_module_pins(["c13v3_upstream_plus_r30.py"]) + + +def test_the_committed_modules_siblings_are_the_ones_they_load(): + """On the real fixes: r01, r02 and r03's v2 modules each load a sibling.""" + deps = { + m: build.module_dependencies(m, build.committed_fix) + for m in ( + "r01_ira_compensation_v2.py", + "r02_ira_219g_v2.py", + "r03_estate_income__qbi_false_v2.py", + "r07_idaho_health_premiums_v2.py", + ) + } + assert deps["r01_ira_compensation_v2.py"] == ["r01_ira_compensation.py"] + assert deps["r02_ira_219g_v2.py"] == ["r02_ira_219g.py"] + assert deps["r03_estate_income__qbi_false_v2.py"][0] == "r03_estate_income_v2.py" + assert deps["r07_idaho_health_premiums_v2.py"] == [] + + +@pytest.mark.parametrize( + "kwargs, message", + [ + ({"after": float("nan")}, "still moves"), + ({"evidence": _evidence(corrected=float("nan"))}, "not finite"), + ({"value": float("nan"), "after": 2600.0}, "non-finite"), + ], +) +def test_a_non_finite_value_is_refused(kwargs, message): + problems = _module_plan(**kwargs).problems + assert any(message in p for p in problems), problems + + +def test_a_record_target_misses_a_drifted_output(): + computed = _unchanged() + computed[("scenario_003", "snap")] = 2600.0 + actions = _actions( + regenerated_exclusions=[_regenerate("scenario_003", "snap", 2500.0)] + ) + (problem,) = _problems(computed, actions) + assert "misses its audited target" in problem and "(record)" in problem + + +def test_a_fix_modules_target_regenerates_a_drifted_output(tmp_path): + plan = _module_plan() + assert plan.problems == [] + (regenerated,) = plan.regenerated + target = regenerated["target"] + assert target == { + "kind": "fix_modules", + "value": 2600.3, + "engine": PRE_FIX, + "engine_value": 3100.0, + "modules": [{"module": MODULE, "sha256": "p" * 64}], + "dependencies": [], + "evidence": EVIDENCE["path"], + "evidence_sha256": EVIDENCE["sha256"], + "value_with_modules": 2600.1, + } + assert regenerated["audited_alternative_value"] == 2500.0 + assert regenerated["regenerated"] == 2600.0 + assert plan.new_values[("scenario_003", "snap")] == 2600.0 + + +def test_a_record_target_is_the_default_and_names_its_engine(): + computed = _unchanged() + computed[("scenario_002", F)] = 300.4 + actions = _actions(regenerated_exclusions=[_regenerate("scenario_002", F, 300.0)]) + (regenerated,) = _plan(computed, actions)[1].regenerated + assert regenerated["target"] == { + "kind": "record", + "value": 300.0, + "engine": "policyengine-us 1.755.4", + } + + +@pytest.mark.parametrize( + "kwargs, message", + [ + ({"evidence": _evidence(engine=ENGINE)}, "it must come from one"), + ( + {"evidence": _evidence(engine="policyengine-us 10.0.0")}, + "not an engine older", + ), + ({"pins": {MODULE: "q" * 64}}, "ran other bytes"), + ({"pins": {}}, "unknown fix modules"), + ({"evidence": _evidence(corrected=3100.5)}, "shows no defect"), + ({"after": 2590.0}, "still moves it"), + ({"value": 2610.0, "after": 2610.0}, "misses its audited target"), + ( + {"entry": _module_target(modules=["other.py"]), "pins": {"other.py": "0"}}, + "has 0 items", + ), + ({"entry": _module_target(modules=[])}, "names no modules"), + ({"entry": _module_target(extra=1)}, "takes kind, modules and evidence"), + ( + {"entry": _module_target(evidence={"path": "x", "sha256": "0"})}, + "evidence is not loaded", + ), + ({"entry": _module_target(kind="guess")}, "unknown target kind"), + ], +) +def test_a_fix_modules_target_refuses(kwargs, message): + problems = _module_plan(**kwargs).problems + assert problems and any(message in p for p in problems), problems + + +def test_a_record_target_takes_no_other_fields(): + computed = _unchanged() + computed[("scenario_002", F)] = 300.0 + entry = _regenerate("scenario_002", F, 300.0) + entry["target"] = {"kind": "record", "modules": [MODULE]} + (problem,) = _problems(computed, _actions(regenerated_exclusions=[entry])) + assert "takes no other fields" in problem + + +@SETTINGS +@given( + effect=st.floats(min_value=1.01, max_value=5e3) | st.floats(-5e3, -1.01), + drift=st.floats(min_value=-5e3, max_value=5e3), + landing=st.floats(min_value=-3.0, max_value=3.0), + leftover=st.floats(min_value=-3.0, max_value=3.0), +) +def test_a_fix_modules_regeneration_needs_a_landing_and_nothing_left_to_fix( + effect, drift, landing, leftover +): + """On the pre-fix engine the module moves the output by ``effect``; the new + engine lands ``landing`` from the corrected value, and the module, applied + again there, moves it by ``leftover``. It regenerates exactly when both + are within $1.""" + before = 3000.0 + drift + corrected = before + effect + value = corrected + landing + plan = _module_plan( + value=value, + after=value + leftover, + evidence=_evidence(engine_value=before, corrected=corrected), + ) + ok = abs(landing) <= 1.0 and abs(leftover) <= 1.0 + assert (plan.problems == []) == ok, plan.problems + if ok: + assert plan.new_values.get(("scenario_003", "snap"), 3000.0) in (value, 3000.0) + assert [r["target"]["value"] for r in plan.regenerated] == [corrected] + + +def test_the_derivation_names_the_audited_corrected_value(tmp_path): + computed, actions = _full() + _, _, written = _write(tmp_path, computed, actions) + derivation = written.exclusions["derivation"] + assert "within $1 of its audited corrected value" in derivation or ( + "each landing within $1 of its audited corrected value" in derivation + ) + assert "record's corrected value" not in derivation + + +@SETTINGS +@given(delta=st.floats(min_value=-1.0, max_value=1.0)) +def test_a_new_exclusion_on_an_output_that_does_not_move_is_refused(delta): + computed = _unchanged() + computed[("scenario_006", "local_income_tax")] = delta + actions = _actions(new_exclusions=[_new_exclusion("scenario_006", delta)]) + problems = _problems(computed, actions) + assert any("does not move" in p for p in problems) + + +def test_a_new_exclusion_must_carry_the_engine_value_and_date(): + computed = _unchanged() + computed[("scenario_006", "local_income_tax")] = 670.55 + record = _new_exclusion("scenario_006", 670.0) + record["decided_on"] = "2026-10-22" + problems = _problems(computed, _actions(new_exclusions=[record])) + assert len(problems) == 2 + assert "frozen_value 670.0 != engine 670.55" in problems[0] + assert "decided_on '2026-10-22' != '2026-10-23'" in problems[1] + + +def test_a_rechecked_output_that_does_not_move_is_refused(): + actions = _actions( + excluded_rechecked=[ + {"scenario_id": "scenario_006", "variable": "snap", "reason": "r"} + ] + ) + (problem,) = _problems(_unchanged(), actions) + assert problem.startswith("rechecked ('scenario_006', 'snap') does not move") + + +def test_actions_on_the_wrong_kind_of_output_are_refused(): + computed = _unchanged() + computed[("scenario_003", "snap")] = 0.0 + approved = [ + { + "scenario_id": "scenario_003", + "variable": "snap", + "value": 0.0, + "cause": "c", + "basis": "b", + } + ] + problems = _problems(computed, _actions(approved=approved)) + assert any( + "approved names ('scenario_003', 'snap'), which is excluded" in p + for p in problems + ) + rechecked = [{"scenario_id": "scenario_001", "variable": S, "reason": "r"}] + problems = _problems(_unchanged(), _actions(excluded_rechecked=rechecked)) + assert problems == [ + f"excluded_rechecked names ('scenario_001', '{S}'), which is scored" + ] + + +def test_the_actions_file_is_validated(): + with pytest.raises(build.Refusal, match="draft"): + build.validate_actions({**_actions(), "draft": True}) + build.validate_actions({**_actions(), "draft": True}, allow_draft=True) + with pytest.raises(build.Refusal, match="unknown actions keys"): + build.validate_actions({**_actions(), "approve": []}) + twice = _actions( + approved=[{"scenario_id": "scenario_001", "variable": S}], + excluded_rechecked=[{"scenario_id": "scenario_001", "variable": S}], + ) + with pytest.raises( + build.Refusal, match="is in both approved and excluded_rechecked" + ): + build.validate_actions(twice) + with pytest.raises(build.Refusal, match="policyengine-us X.Y.Z"): + build.validate_actions({**_actions(), "engine": "2.36.0"}) + + +def test_a_previous_engine_other_than_the_base_is_refused(): + problems = _problems( + _unchanged(), {**_actions(), "previous_engine": "policyengine-us 2.2.1"} + ) + assert problems == [ + "previous_engine is policyengine-us 2.2.1, not policyengine-us 2.41.0" + ] + + +# --- Properties -------------------------------------------------------------- + + +@SETTINGS +@given( + federal=st.floats(min_value=299.0, max_value=301.0), + later=st.floats(min_value=689.0, max_value=691.0), +) +def test_a_removed_record_is_scored_at_its_new_value(tmp_path, federal, later): + computed = _unchanged() + computed[("scenario_002", F)] = federal + computed[("scenario_004", S)] = later + actions = _actions( + regenerated_exclusions=[ + _regenerate("scenario_002", F, 300.0), + _regenerate("scenario_004", S, 690.0), + ] + ) + _, plan, written = _write(tmp_path, computed, actions) + values = build.parse_reference_csv(written.csv_text).values() + excluded = {build.key_of(r) for r in written.exclusions["exclusions"]} + for key, value in ((("scenario_002", F), federal), (("scenario_004", S), later)): + assert key not in excluded + assert values[key] == value + (change,) = [c for c in plan.changed if build.key_of(c) == key] + assert ( + change["regenerated"] == value + and change["cause"] == "regenerated_upstream_fix" + ) + (removed,) = [ + r + for r in written.meta["revisions"][-1]["regenerated_exclusions"] + if build.key_of(r) == ("scenario_002", F) + ] + assert removed["record"] == BASE_RECORDS[0] + assert removed["value_on_9_9_9"] == federal + + +@SETTINGS +@given( + moves=st.dictionaries( + st.sampled_from([(s, v) for s, v, _, _ in ROWS]), + st.floats(min_value=-1.0, max_value=1.0), + ) +) +def test_unchanged_outputs_keep_their_bytes(tmp_path, moves): + """Moves within the tolerance, anywhere: excluded outputs keep their values, + scored ones take the engine's and are listed; every other row keeps its + bytes; earlier revisions keep theirs.""" + computed = _unchanged() + for key, delta in moves.items(): + if key[1].endswith("_eligible"): # a 0/1 flag: any change is a move + continue + computed[key] += delta + base, plan, written = _write(tmp_path, computed, _actions()) + excluded = {build.key_of(r) for r in base.exclusions["exclusions"]} + rows = build.parse_reference_csv(written.csv_text).rows + listed = {build.key_of(c) for c in plan.within} + for old, new in zip(base.reference.rows, rows, strict=True): + if old.key in excluded or abs(computed[old.key] - old.value) <= build.EPS: + assert new.raw == old.raw + assert old.key not in listed + else: + assert new.value == computed[old.key] + assert old.key in listed + for before, after in zip(base.meta["revisions"], written.meta["revisions"]): + assert json.dumps(before) == json.dumps(after) + + +@SETTINGS +@given(seed=st.integers(min_value=0, max_value=2**32 - 1)) +def test_the_records_do_not_depend_on_the_actions_order(tmp_path, seed): + computed, actions = _full() + shuffled = copy.deepcopy(actions) + rng = random.Random(seed) + for name in ( + "approved", + "regenerated_exclusions", + "new_exclusions", + "excluded_rechecked", + ): + rng.shuffle(shuffled[name]) + shuffled["new_exclusions"].append(_new_exclusion("scenario_001", 50.0)) + computed = {**computed, ("scenario_001", "local_income_tax"): 50.0} + actions = { + **actions, + "new_exclusions": actions["new_exclusions"] + + [_new_exclusion("scenario_001", 50.0)], + } + rng.shuffle(shuffled["new_exclusions"]) + _, _, first = _write(tmp_path / "a", computed, actions) + _, _, second = _write(tmp_path / "b", computed, shuffled) + for name in ( + "reference_exclusions.json", + "reference_outputs.csv", + "reference_outputs.csv.meta.json", + ): + assert (tmp_path / "a" / name).read_bytes() == ( + tmp_path / "b" / name + ).read_bytes() + keys = [build.key_of(r) for r in first.exclusions["exclusions"]] + assert keys[-3:] == [ + ("scenario_001", "local_income_tax"), + ("scenario_006", "local_income_tax"), + ("scenario_023", FLAG), + ] + + +@SETTINGS +@given( + values=st.dictionaries( + st.sampled_from([(s, v) for s, v, _, _ in ROWS]), + st.floats(allow_nan=False, allow_infinity=False, width=32), + ) +) +def test_rendering_rewrites_only_the_named_rows(values): + reference = build.parse_reference_csv(_csv_text()) + text = build.render_reference_csv(reference, values) + rows = build.parse_reference_csv(text).rows + for old, new in zip(reference.rows, rows, strict=True): + if old.key in values: + assert new.value == float(values[old.key]) + assert new.fields[3] == old.fields[3] + else: + assert new.raw == old.raw + + +# --- The real base --------------------------------------------------------------- + + +@pytest.fixture(scope="module") +def real_base(): + return build.load_base() + + +def test_the_base_is_release_20261014(real_base): + assert len(real_base.reference.rows) == 1984 + assert len(real_base.exclusions["exclusions"]) == 49 + kinds = [r["kind"] for r in real_base.meta["revisions"]] + assert kinds.count("engine_upgrade") == 3 and kinds[-1] == "engine_upgrade" + assert real_base.meta["revisions"][-1]["engine_version"] == build.PREVIOUS_ENGINE + assert build.key_of(real_base.exclusions["exclusions"][-1]) == build.AUDIT_TAIL + # The base CSV round-trips byte for byte through the row parser. + raw = build.git_blob(build.BASE_COMMIT, f"{build.RUN}/reference_outputs.csv") + assert build.render_reference_csv(real_base.reference, {}) == raw.decode() + + +def test_the_base_commit_is_on_main_and_its_references_are_2_41_0s(): + """BASE_COMMIT (release 20261014, #221) is an ancestor of HEAD, and its four + reference files are release 20261013's (#217), which installed 2.41.0.""" + import subprocess + + ancestor = subprocess.run( + [ + "git", + "-C", + str(ROOT), + "merge-base", + "--is-ancestor", + build.BASE_COMMIT, + "HEAD", + ], + capture_output=True, + ) + assert ancestor.returncode == 0 + for name, pin in build.BASE_SHA256.items(): + blob = build.git_blob( + "bc305793c527531e7b3573dc789a436a7bc883d5", f"{build.RUN}/{name}" + ) + assert build.sha256_bytes(blob) == pin, name + + +def test_the_snapshot_holds_the_base_or_this_build(): + """Until a board release installs this build, the snapshot's reference + files are the base's; once one installs it, they are the build's. Either + way each file is one of the two, and the three move together.""" + names = ( + "reference_outputs.csv", + "reference_outputs.csv.meta.json", + "reference_exclusions.json", + ) + on_disk = [build.sha256(RUN_DIR / n) for n in names] + base = [build.BASE_SHA256[n] for n in names] + built = [build.sha256(BUILD / n) for n in names] + assert on_disk in (base, built) + + +def test_the_fix_modules_are_the_first_upgrades(real_base, tmp_path): + """In place, the conventions are the 2026-09-29 upgrade's; the sales tax + tables must sit beside them.""" + import shutil + + for path in build.FIXES.glob("*.py"): + shutil.copy(path, tmp_path / path.name) + with pytest.raises(build.Refusal, match="r19_irs_sales_tax_2025.json is missing"): + build.fix_module_pins(real_base.meta, tmp_path) + shutil.copy(build.SALES_TAX_SOURCE, tmp_path / build.SALES_TAX_TABLES) + pins = build.fix_module_pins(real_base.meta, tmp_path) + assert [p["module"] for p in pins][-2:] == [ + "latest_final.py", + build.SALES_TAX_TABLES, + ] + assert len(pins) == 13 + (tmp_path / "latest_c_md_2026.py").write_text("# edited\n") + with pytest.raises(build.Refusal, match="latest_c_md_2026.py is not the module"): + build.fix_module_pins(real_base.meta, tmp_path) + + +def test_the_fix_entry_tables_and_harness_are_pinned_in_place( + real_base, tmp_path, monkeypatch +): + """Imported in place, latest_final.py, the sales tax tables and sweep.py + are each checked against the bytes committed at the base commit, not + against themselves.""" + import shutil + + for path in build.FIXES.glob("*.py"): + shutil.copy(path, tmp_path / path.name) + shutil.copy(build.SALES_TAX_SOURCE, tmp_path / build.SALES_TAX_TABLES) + monkeypatch.setattr(build, "FIXES", tmp_path) + build.fix_module_pins(real_base.meta, tmp_path) + entry = tmp_path / "latest_final.py" + original = entry.read_bytes() + entry.write_bytes(original + b"# edited\n") + with pytest.raises(build.Refusal, match="latest_final.py is not"): + build.fix_module_pins(real_base.meta, tmp_path) + entry.write_bytes(original) + tables = tmp_path / build.SALES_TAX_TABLES + tables.write_text(tables.read_text() + " ") + monkeypatch.setattr(build, "SALES_TAX_SOURCE", tables) + with pytest.raises(build.Refusal, match="r19_irs_sales_tax_2025.json is not"): + build.fix_module_pins(real_base.meta, tmp_path) + + assert build.harness_pin()["sha256"] == build.sha256(build.HARNESS) + harness = tmp_path / "sweep.py" + harness.write_text(build.HARNESS.read_text() + "# edited\n") + with pytest.raises(build.Refusal, match="sweep.py is not"): + build.harness_pin(harness) + + +def test_the_real_base_on_its_own_values_plans_no_change(real_base): + """A stub engine that returns 20261014's values: the plan changes + nothing.""" + computed = real_base.reference.values() + plan = build.plan_upgrade(real_base, _actions(), computed) + assert plan.problems == [] and plan.changed == [] and plan.within == [] + + +# --- Narratives ---------------------------------------------------------------- + + +EXPLANATIONS = ( + "country,scenario_id,variable,reference_value,trace_lines,explanation,error\n" + f'us,scenario_001,{S},1000.0,3,"Old, text.",\n' + "us,scenario_001,local_income_tax,0.0,1,No local tax.,\n" + f'us,scenario_002,{S},500.25,2,"Said ""500.25"".",\n' + "us,scenario_002,federal_income_tax_before_refundable_credits,250.5,4,Fed.,\n" + 'us,scenario_003,snap,3000.0,9,"Multi\nline",\n' + "us,scenario_004,state_income_tax_before_refundable_credits,700.0,1,AZ.,\n" + "us,scenario_006,local_income_tax,0.0,1,No county.,\n" +) + + +class _Response: + def __init__(self, text): + self.choices = [ + types.SimpleNamespace(message=types.SimpleNamespace(content=text)) + ] + + +def _scenarios(): + import pandas as pd + + return pd.DataFrame( + [ + { + "scenario_id": f"scenario_00{i}", + "state": "IN", + "filing_status": "single", + "num_adults": 1, + "num_children": 0, + "total_income": 1000.0, + } + for i in range(1, 8) + ] + ) + + +def _narrate(tmp_path, completion, hand=None): + computed, actions = _full() + del actions["new_exclusions"][0] + computed[("scenario_006", "local_income_tax")] = 0.0 + _write(tmp_path, computed, actions) + return narratives.write_narratives( + tmp_path, EXPLANATIONS, _scenarios(), completion=completion, hand_corrected=hand + ) + + +def test_narratives_rewrite_only_the_changed_rows(tmp_path): + prompts = [] + + def completion(**kwargs): + prompts.append(kwargs) + value = float( + kwargs["messages"][0]["content"] + .split("REFERENCE VALUE: ")[1] + .split("\n")[0] + ) + return _Response(f"# Heading\nPolicyEngine gives ${narratives.money(value)}.") + + text, results = _narrate(tmp_path, completion) + assert {r[:2] for r in results} == { + ("scenario_001", S), + ("scenario_002", F), + ("scenario_004", S), + ("scenario_002", S), + } + assert all(p["model"] == "claude-haiku-4-5" for p in prompts) + assert all("policyengine-us 9.9.9" in p["messages"][0]["content"] for p in prompts) + old = narratives.parse_rows(EXPLANATIONS)[1] + new = narratives.parse_rows(text)[1] + changed = {r[:2] for r in results} + for (fields, raw), (new_fields, new_raw) in zip(old, new, strict=True): + if (fields[1], fields[2]) in changed: + assert new_fields[5].startswith("PolicyEngine gives $") + assert new_fields[4] == "2" and new_fields[6] == "" + else: + assert raw == new_raw + assert f"us,scenario_001,{S},1010.0,2,PolicyEngine gives $1,010." not in text + assert '1010.0,2,"PolicyEngine gives $1,010."' in text + + +def test_the_narratives_need_the_fourth_engine_upgrade(tmp_path): + computed, actions = _full() + del actions["new_exclusions"][0] + computed[("scenario_006", "local_income_tax")] = 0.0 + _write(tmp_path, computed, actions) + sidecar = tmp_path / "reference_outputs.csv.meta.json" + meta = json.loads(sidecar.read_text()) + meta["revisions"] = [r for r in meta["revisions"] if r["date"] != "2026-10-13"] + sidecar.write_text(json.dumps(meta)) + with pytest.raises(build.Refusal, match="fourth engine upgrade"): + narratives.write_narratives( + tmp_path, EXPLANATIONS, _scenarios(), completion=_value_narrator() + ) + + +def _value_narrator(mention: str = ""): + def completion(**kwargs): + value = float( + kwargs["messages"][0]["content"] + .split("REFERENCE VALUE: ")[1] + .split("\n")[0] + ) + return _Response(f"PolicyEngine gives ${narratives.money(value)}.{mention}") + + return completion + + +def test_a_rebuild_reuses_the_narratives_whose_writer_inputs_are_unchanged(tmp_path): + """Build A on 9.9.9, build B on 9.9.10 with one approved value moved: B + reuses A's narratives for every changed output whose value, cause, + grounding (the engine's name aside), variable and trace are A's, and only + those; a narrative that names A's engine is written again.""" + computed, actions = _full() + del actions["new_exclusions"][0] + computed[("scenario_006", "local_income_tax")] = 0.0 + _write(tmp_path / "a", computed, actions) + text_a, _ = narratives.write_narratives( + tmp_path / "a", EXPLANATIONS, _scenarios(), completion=_value_narrator() + ) + later = copy.deepcopy(actions) + later["engine"] = "policyengine-us 9.9.10" + later["approved"][0]["value"] = 1020.0 + moved = dict(computed) + moved[("scenario_001", S)] = 1020.0 + _write(tmp_path / "b", moved, later) + reuse = narratives.reusable_narratives(tmp_path / "b", tmp_path / "a", text_a) + assert set(reuse) == {("scenario_002", F), ("scenario_004", S), ("scenario_002", S)} + calls = [] + + def counting(**kwargs): + calls.append(kwargs) + return _value_narrator()(**kwargs) + + text_b, results = narratives.write_narratives( + tmp_path / "b", EXPLANATIONS, _scenarios(), completion=counting, reuse=reuse + ) + assert len(calls) == 1 and "1020.0" in calls[0]["messages"][0]["content"] + rows_a = {(f[1], f[2]): f for f, _ in narratives.parse_rows(text_a)[1]} + rows_b = {(f[1], f[2]): f for f, _ in narratives.parse_rows(text_b)[1]} + for key in reuse: + assert rows_b[key] == rows_a[key] + named, _ = narratives.write_narratives( + tmp_path / "a", + EXPLANATIONS, + _scenarios(), + completion=_value_narrator(" On policyengine-us 9.9.9."), + ) + assert narratives.reusable_narratives(tmp_path / "b", tmp_path / "a", named) == {} + same = narratives.reusable_narratives(tmp_path / "a", tmp_path / "a", named) + assert set(same) == { + ("scenario_001", S), + ("scenario_002", F), + ("scenario_004", S), + ("scenario_002", S), + } + + +@pytest.mark.parametrize( + "text, value, ok", + [ + ("Refundable credits are $0.00.", 0.0, True), + ("Refundable credits are $0.", 0.0, True), + ("In tax year 2026 the household gets nothing.", 0.0, False), + ("Tax is $1,916.61 after credits.", 1916.606201, True), + ("Tax is $1,916 after credits.", 1916.606201, False), + ("The refund is -$12.50.", -12.5, True), + ("It owes $2,116.61 before a $200 credit.", 1916.61, False), + ], +) +def test_a_narrative_states_its_amount_as_dollars_to_the_cent(text, value, ok): + assert narratives.states_amount(text, value) is ok + + +@SETTINGS +@given(cents=st.integers(min_value=0, max_value=10**9)) +def test_a_formatted_amount_is_always_recognized(cents): + value = cents / 100 + assert narratives.states_amount(f"PolicyEngine gives ${value:,.2f}.", value) + assert narratives.states_amount( + f"PolicyEngine gives ${narratives.money(value)}.", value + ) + + +def test_reuse_refuses_a_narratives_file_from_another_build(tmp_path): + computed, actions = _full() + del actions["new_exclusions"][0] + computed[("scenario_006", "local_income_tax")] = 0.0 + _write(tmp_path / "a", computed, actions) + text_a, _ = narratives.write_narratives( + tmp_path / "a", EXPLANATIONS, _scenarios(), completion=_value_narrator() + ) + assert narratives.reusable_narratives(tmp_path / "a", tmp_path / "a", text_a) + with pytest.raises(build.Refusal, match="is not --reuse-from's narratives"): + narratives.reusable_narratives(tmp_path / "a", tmp_path / "a", EXPLANATIONS) + + +@pytest.mark.parametrize("stated", ["nan", "inf", "-inf", "", "n/a"]) +def test_reuse_refuses_a_source_value_that_is_not_a_finite_number(tmp_path, stated): + computed, actions = _full() + del actions["new_exclusions"][0] + computed[("scenario_006", "local_income_tax")] = 0.0 + _write(tmp_path / "a", computed, actions) + text_a, _ = narratives.write_narratives( + tmp_path / "a", EXPLANATIONS, _scenarios(), completion=_value_narrator() + ) + rows = {(f[1], f[2]): (f, raw) for f, raw in narratives.parse_rows(text_a)[1]} + fields, raw = rows[("scenario_002", F)] + edited = raw.replace(f",{fields[3]},", f",{stated},", 1) + assert edited != raw + with pytest.raises(build.Refusal, match="is not --reuse-from's narratives"): + narratives.reusable_narratives( + tmp_path / "a", tmp_path / "a", text_a.replace(raw, edited) + ) + + +def test_a_narrative_that_omits_the_value_is_retried_then_refused(tmp_path): + calls = [] + + def stubborn(**kwargs): + calls.append(kwargs) + return _Response("No figure here.") + + with pytest.raises(build.Refusal, match="omits"): + _narrate(tmp_path, stubborn) + assert len(calls) == 1 + narratives.RETRIES + assert "must state the value" in calls[-1]["messages"][0]["content"] + + +def test_hand_corrected_narratives_must_state_the_value_and_be_changed(tmp_path): + def completion(**kwargs): + value = float( + kwargs["messages"][0]["content"] + .split("REFERENCE VALUE: ")[1] + .split("\n")[0] + ) + return _Response(f"Gives ${narratives.money(value)}.") + + hand = {f"scenario_001|{S}": "Corrected: $1,010 of tax."} + text, _ = _narrate(tmp_path / "a", completion, hand) + assert "Corrected: $1,010 of tax." in text + with pytest.raises(build.Refusal, match="did not change"): + _narrate(tmp_path / "b", completion, {"scenario_003|snap": "x"}) + with pytest.raises(build.Refusal, match="omits"): + _narrate(tmp_path / "c", completion, {f"scenario_001|{S}": "No value."}) + + +def test_a_new_exclusion_is_grounded_on_its_alternative_reading(): + item = { + "scenario_id": "s", + "variable": "v", + "cause": "excluded_reference_depends_on_unlisted_input", + "basis": "b", + } + record = { + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "Read so.", + } + text = narratives.grounding_for(item, {("s", "v"): record}) + assert text.endswith("an input the prompt does not state. Read so.") + assert narratives.grounding_for({**item, "cause": "a"}, {("s", "v"): record}) == "b" + + +def test_the_writer_is_anthropics(tmp_path, monkeypatch): + import policybench.case_reference_explanations as writer + + monkeypatch.setattr(writer, "REFERENCE_MODEL", "gpt-6-luna") + with pytest.raises(build.Refusal, match="Anthropic"): + _narrate(tmp_path, lambda **_: _Response("")) + + +def _narration_inputs(tmp_path): + computed, actions = _full() + del actions["new_exclusions"][0] + computed[("scenario_006", "local_income_tax")] = 0.0 + _, plan, _ = _write(tmp_path / "build", computed, actions) + explanations = tmp_path / "explanations.csv" + explanations.write_text(EXPLANATIONS) + hand = { + f"{c['scenario_id']}|{c['variable']}": ( + f"Hand: ${narratives.money(c['regenerated'])}." + ) + for c in plan.changed + plan.within + } + return explanations, hand + + +def test_the_narrative_run_never_uses_an_openai_key(tmp_path, monkeypatch): + """Without a key, a run that would call the writer is refused; a run whose + narratives are all hand-corrected needs none and never calls it. Neither + keeps an OpenAI key in its environment.""" + import os + + monkeypatch.setenv("OPENAI_API_KEY", "sk-test") + monkeypatch.delenv("ANTHROPIC_API_KEY", raising=False) + explanations, hand = _narration_inputs(tmp_path) + args = [ + "--references", + str(tmp_path / "build"), + "--explanations", + str(explanations), + "--out", + str(tmp_path / "out.csv"), + ] + with pytest.raises(build.Refusal, match="ANTHROPIC_API_KEY"): + narratives.main(args) + assert "OPENAI_API_KEY" not in os.environ + partial = dict(list(hand.items())[1:]) + (tmp_path / "partial.json").write_text(json.dumps(partial)) + with pytest.raises(build.Refusal, match="1 narratives need the writer"): + narratives.main([*args, "--hand-corrected", str(tmp_path / "partial.json")]) + (tmp_path / "hand.json").write_text(json.dumps(hand)) + narratives.main([*args, "--hand-corrected", str(tmp_path / "hand.json")]) + written = (tmp_path / "out.csv").read_text() + for text in hand.values(): + assert text in written + + +def test_the_committed_explanations_round_trip_byte_for_byte(): + path = ROOT / "annotations" / "us_full_run_20260612_policyengine_4_16_1_populace" + text = (path / "us_case_reference_explanations.csv").read_text() + assert narratives.rewrite_explanations(text, {}) == text + + +# --- Draft actions --------------------------------------------------------------- + + +def _cells(computed, states=None): + base = _base() + states = states or {} + return [ + drafting.Cell( + r.key[0], + states.get(r.key, "XX"), + r.key[1], + r.value, + computed[r.key], + "", + "", + ) + for r in base.reference.rows + ] + + +def _draft(computed, states=None, records=None, earlier=None, **kwargs): + base = _base() + records = records or {build.key_of(r): r for r in base.exclusions["exclusions"]} + return drafting.draft_actions( + _cells(computed, states), + records, + earlier or {}, + THIRD_REVISION, + engine_version="9.9.9", + date=DATE, + precise=True, + **kwargs, + ) + + +def test_the_draft_places_every_moved_output_and_prints_each_call(tmp_path): + computed, _ = _full() + computed[("scenario_001", "local_income_tax")] = 670.55 + computed[("scenario_006", "local_income_tax")] = 0.0 + computed[("scenario_007", "snap")] = 288.0 + computed[("scenario_007", "free_school_meals_eligible")] = 1.0 + states = { + ("scenario_001", "local_income_tax"): "IN", + ("scenario_001", S): "ZZ", + ("scenario_007", "snap"): "CA", + ("scenario_007", "free_school_meals_eligible"): "PA", + } + actions, calls = _draft(computed, states) + assert actions["draft"] is True + assert set(actions) == { + "engine", + "previous_engine", + "date", + "draft", + "approved", + "regenerated_exclusions", + "new_exclusions", + "excluded_rechecked", + "review", + } + placed = { + (c["scenario_id"], c["variable"]): (c["decision"], c["placed_in"]) + for c in calls + } + assert placed == { + ("scenario_001", S): ("UNDECIDED", "review only"), + ("scenario_001", "local_income_tax"): ("UNDECIDED", "review only"), + ("scenario_002", F): ("PROPOSED", "regenerated_exclusions"), + ("scenario_004", S): ("PROPOSED", "regenerated_exclusions"), + ("scenario_003", "snap"): ("PROPOSED", "excluded_rechecked"), + ("scenario_007", "snap"): ("PROPOSED", "approved"), + ("scenario_007", "free_school_meals_eligible"): ("PROPOSED", "approved"), + } + # The records name no upstream fix, so the builder refuses the regenerations + # until a reviewer names them; cleared, the draft builds except for the + # undecided moves. + base = _base() + cleared = {k: v for k, v in actions.items() if k not in ("draft", "review")} + build.validate_actions(cleared) + problems = build.plan_upgrade(base, cleared, computed).problems + assert problems == [ + f"unreviewed move ('scenario_001', '{S}'): 1000.0 -> 1010.0", + "unreviewed move ('scenario_001', 'local_income_tax'): 0.0 -> 670.55", + f"regenerated ('scenario_002', '{F}') names no upstream fix ('to be filed')", + f"regenerated ('scenario_004', '{S}') names no upstream fix ('to be filed')", + ] + for entry in cleared["regenerated_exclusions"]: + entry["upstream"] = "PolicyEngine/policyengine-us#1" + problems = build.plan_upgrade(base, cleared, computed).problems + assert problems == [ + f"unreviewed move ('scenario_001', '{S}'): 1000.0 -> 1010.0", + "unreviewed move ('scenario_001', 'local_income_tax'): 0.0 -> 670.55", + ] + + +def test_the_draft_keeps_an_on_target_record_that_names_a_second_reason(): + computed = _unchanged() + computed[("scenario_002", F)] = 300.0 + base = _base() + records = {build.key_of(r): copy.deepcopy(r) for r in base.exclusions["exclusions"]} + records[("scenario_002", F)]["note"] = ( + "The output also moves under r23 (unlisted input)." + ) + actions, calls = _draft(computed, records=records) + assert actions["regenerated_exclusions"] == [] + (entry,) = actions["excluded_rechecked"] + assert "names a second reason" in entry["reason"] + assert calls[0]["placed_in"] == "excluded_rechecked" + + +def test_an_unlisted_input_record_the_engine_lands_on_stays_excluded(): + """scenario_006 snap's record is an unlisted input with alternative $0; an + engine that now gives $0 takes that reading by a default, which does not + state the input: the draft rechecks it, and the builder refuses to + regenerate it (only an engine defect is regenerated).""" + computed = _unchanged() + computed[("scenario_006", "snap")] = 0.0 + actions, calls = _draft(computed) + assert actions["regenerated_exclusions"] == [] + (entry,) = actions["excluded_rechecked"] + assert "the record's alternative value" in entry["reason"] + assert "an engine default does not settle it" in entry["reason"] + assert entry["reason"].count("which") <= 1 + (call,) = calls + assert "lands on the alternative reading" in call["call"] + cleared = {k: v for k, v in actions.items() if k not in ("draft", "review")} + assert build.plan_upgrade(_base(), cleared, computed).problems == [] + regenerate = _actions( + regenerated_exclusions=[_regenerate("scenario_006", "snap", 0.0)] + ) + (problem,) = _problems(computed, regenerate) + assert "not an engine defect" in problem + + +def test_a_value_the_previous_upgrade_found_on_target_keeps_that_finding(): + """The 2026-10-13 recheck found scenario_003 snap on its corrected value and + kept it excluded for a second reason. The engine has not moved it since, + so it misses the record's older alternative value without the defect being + unfixed: the draft says so and keeps the second reason. A value that moved + since is drafted as off target, with the previous engine's value.""" + computed = _unchanged() + computed[("scenario_003", "snap")] = 2600.0 + base = _base() + records = {build.key_of(r): copy.deepcopy(r) for r in base.exclusions["exclusions"]} + records[("scenario_003", "snap")]["note"] = ( + "The output also moves under r23 (unlisted input)." + ) + earlier = { + ("scenario_003", "snap"): { + "value_on_2_41_0": 2600.0, + "reason": ( + "Stays excluded on policyengine-us 2.41.0: the engine gives " + "$2,600.00, the value policyengine-us 2.38.6 gave when release " + "20261010's recheck found it on its corrected value, but the " + "record names a second reason that a new engine does not settle." + ), + } + } + actions, _ = _draft(computed, records=records, earlier=earlier) + (entry,) = actions["excluded_rechecked"] + assert "is not fixed" not in entry["reason"] + assert ( + "the value policyengine-us 2.41.0 gave when the 2026-10-13 recheck found it " + "on its corrected value" in entry["reason"] + ) + assert "names a second reason" in entry["reason"] + assert entry["reason"].endswith( + "The value is 2.41.0's, rechecked on 2026-10-13 " + "(the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + ) + moved = { + ("scenario_003", "snap"): { + **earlier[("scenario_003", "snap")], + "value_on_2_41_0": 2550.0, + } + } + actions, _ = _draft(computed, records=records, earlier=moved) + (entry,) = actions["excluded_rechecked"] + assert "is not fixed in this release" in entry["reason"] + assert entry["reason"].endswith( + "policyengine-us 2.41.0 gave $2,550.00 when it was rechecked on 2026-10-13." + ) + + +def test_the_draft_aims_a_drifted_record_at_its_fix_modules_evidence(): + computed = _unchanged() + computed[("scenario_003", "snap")] = 2600.0 + without, _ = _draft(computed) + assert without["regenerated_exclusions"] == [] + assert "$100.00 from the record's" in without["excluded_rechecked"][0]["reason"] + doc = _evidence() + actions, calls = _draft(computed, evidence={"ref": dict(EVIDENCE), "doc": doc}) + (entry,) = actions["regenerated_exclusions"] + assert entry["target"] == { + "kind": "fix_modules", + "modules": [MODULE], + "evidence": EVIDENCE, + } + assert entry["alternative_value"] == 2500.0 + assert "$2,600.30 its fix modules (r_fix_v2.py) give on" in entry["basis"] + assert [c["placed_in"] for c in calls] == ["regenerated_exclusions"] + cleared = {k: v for k, v in actions.items() if k not in ("draft", "review")} + entry["upstream"] = "PolicyEngine/policyengine-us#1" + plan = build.plan_upgrade( + _base(), + cleared, + computed, + evidence={EVIDENCE["path"]: doc}, + module_pins={MODULE: "p" * 64}, + module_values={(("scenario_003", "snap"), (MODULE,)): 2600.0}, + ) + assert plan.problems == [] + assert [r["target"]["kind"] for r in plan.regenerated] == ["fix_modules"] + + +def test_a_regeneration_must_name_its_upstream_fix(): + computed = _unchanged() + computed[("scenario_002", F)] = 300.0 + for upstream in ("", "to be filed", "To be filed "): + entry = {**_regenerate("scenario_002", F, 300.0), "upstream": upstream} + (problem,) = _problems(computed, _actions(regenerated_exclusions=[entry])) + assert "names no upstream fix" in problem + + +def test_the_draft_rules_recognize_the_documented_scored_moves(): + """The two kinds of scored move 2.60.0 makes: California MCE's minimum + allotment (#10036) and a state's universal free breakfast (#10238). Each + rule matches only its own move.""" + fsm = "free_school_meals_eligible" + cells = { + "ca_mce": drafting.Cell("s1", "CA", "snap", 0.0, 288.0, "scored", ""), + "ca_other_amount": drafting.Cell("s1", "CA", "snap", 0.0, 300.0, "scored", ""), + "ca_from_positive": drafting.Cell( + "s1", "CA", "snap", 24.0, 288.0, "scored", "" + ), + "ny_minimum": drafting.Cell("s1", "NY", "snap", 0.0, 288.0, "scored", ""), + "pa_breakfast": drafting.Cell("s2", "PA", fsm, 0.0, 1.0, "scored", ""), + "ar_breakfast": drafting.Cell("s2", "AR", fsm, 0.0, 1.0, "scored", ""), + "sc_breakfast": drafting.Cell("s2", "SC", fsm, 0.0, 1.0, "scored", ""), + "pa_lost": drafting.Cell("s2", "PA", fsm, 1.0, 0.0, "scored", ""), + "pa_reduced": drafting.Cell( + "s2", "PA", "reduced_price_school_meals_eligible", 0.0, 1.0, "scored", "" + ), + } + rules = { + name: [ + propose(c, ENGINE, DATE)["rule"] + for matches, propose in drafting.RULES + if matches(c) + ] + for name, c in cells.items() + } + assert rules == { + "ca_mce": ["ca_snap_mce_no_net_income_test"], + "ca_other_amount": [], + "ca_from_positive": [], + "ny_minimum": [], + "pa_breakfast": ["state_universal_free_breakfast"], + "ar_breakfast": ["state_universal_free_breakfast"], + "sc_breakfast": [], + "pa_lost": [], + "pa_reduced": [], + } + snap = drafting._ca_mce_minimum_allotment(cells["ca_mce"], ENGINE, DATE)["entry"] + assert snap["value"] == 288.0 and snap["cause"].endswith("_10036") + assert "PolicyEngine/policyengine-us#10036" in snap["basis"] + assert "$24 a month" in snap["basis"] and "$288.00 for 2026" in snap["basis"] + for state, law in (("PA", "Act 33 of 2023"), ("AR", "Act 123 of 2025")): + cell = cells[f"{state.lower()}_breakfast"] + entry = drafting._state_universal_breakfast(cell, ENGINE, DATE)["entry"] + assert entry["value"] == 1.0 and entry["cause"].endswith("_10238") + assert law in entry["basis"] and "#10238" in entry["basis"] + assert "PolicyEngine returns positive annual free school meal" in entry["basis"] + + +def test_the_cells_table_must_be_against_20261014(tmp_path): + board = {("scenario_001", S): 1000.0} + path = tmp_path / "cells_pe2.60.0.csv" + path.write_text( + "scenario_id,state,variable,frozen_20261014,new,delta,moved,status,audited_target\n" + f"scenario_001,IN,{S},999.0,1000.0,1.0,False,scored,\n" + ) + with pytest.raises(build.Refusal, match="not 20261014's"): + drafting.read_cells(path, board, None) + assert drafting.engine_from_path(path) == "2.60.0" + path.write_text(path.read_text().replace("999.0", "1000.0")) + (cell,) = drafting.read_cells(path, board, None) + assert cell.new == 1000.0 and cell.state == "IN" + with pytest.raises(build.Refusal, match="not the table's"): + drafting.read_cells(path, board, {("scenario_001", S): 1000.5}) + + +def test_a_regeneration_names_the_upstream_fix_the_map_gives(): + upstreams = { + "outputs": {"scenario_064|state": "PolicyEngine/policyengine-us#9801"}, + "root_causes": {"r02": "#10032", "r11": "#10034"}, + } + record = {"root_cause": "r02+r11", "upstream": "to be filed"} + assert drafting.upstream_for(record, ("scenario_005", "state"), upstreams) == ( + "#10032; #10034" + ) + assert drafting.upstream_for(record, ("scenario_064", "state"), upstreams) == ( + "PolicyEngine/policyengine-us#9801" + ) + partial = {"root_cause": "r02+r99", "upstream": "PolicyEngine/policyengine-us#1"} + assert drafting.upstream_for(partial, ("s", "v"), upstreams) == ( + "PolicyEngine/policyengine-us#1" + ) + assert drafting.upstream_for(record, ("s", "v"), None) == "to be filed" + + +def test_an_output_found_indeterminate_earlier_is_rechecked_not_regenerated(): + computed = _unchanged() + computed[("scenario_003", "snap")] = 2600.0 + evidence = {"ref": dict(EVIDENCE), "doc": _evidence()} + plain, _ = _draft(computed, evidence=evidence) + assert [build.key_of(e) for e in plain["regenerated_exclusions"]] == [ + ("scenario_003", "snap") + ] + actions, calls = _draft( + computed, + evidence=evidence, + indeterminate={("scenario_003", "snap"): "2026-09-29"}, + ) + assert actions["regenerated_exclusions"] == [] + (entry,) = actions["excluded_rechecked"] + assert drafting.INDETERMINATE in entry["reason"] + assert "the 2026-09-29 recheck found" in entry["reason"] + assert "second reason" in entry["reason"] + (call,) = [c for c in calls if c["scenario_id"] == "scenario_003"] + assert call["placed_in"] == "excluded_rechecked" + + +def test_indeterminate_rechecks_reads_every_upgrade_revision(): + meta = { + "revisions": [ + {"kind": "convention", "date": "2026-09-22"}, + { + "kind": "engine_upgrade", + "date": "2026-09-29", + "excluded_outputs_rechecked": [ + { + "scenario_id": "scenario_001", + "variable": "snap", + "reason": f"... {drafting.INDETERMINATE}, and stays excluded.", + }, + {"scenario_id": "scenario_002", "variable": "ssi", "reason": "x"}, + ], + }, + { + "kind": "engine_upgrade", + "date": "2026-10-10", + "excluded_outputs_rechecked": [ + { + "scenario_id": "scenario_001", + "variable": "snap", + "reason": f"again {drafting.INDETERMINATE}", + } + ], + }, + ] + } + assert drafting.indeterminate_rechecks(meta) == { + ("scenario_001", "snap"): "2026-09-29" + } + sidecar = json.loads((RUN_DIR / "reference_outputs.csv.meta.json").read_text()) + assert drafting.indeterminate_rechecks(sidecar) == { + ("scenario_080", "snap"): "2026-09-29" + } + + +def test_the_previous_upgrade_is_the_bases_last(): + sidecar = json.loads( + build.git_blob( + build.BASE_COMMIT, f"{build.RUN}/reference_outputs.csv.meta.json" + ) + ) + last = drafting.last_upgrade(sidecar) + assert (last["date"], last["engine_version"]) == ( + "2026-10-13", + build.PREVIOUS_ENGINE, + ) + assert drafting.value_key(last["engine_version"]) == "value_on_2_41_0" + assert set(drafting.last_upgrade_rechecks(sidecar)) == { + build.key_of(r) for r in last["excluded_outputs_rechecked"] + } + + +# --- This audit's own fix modules ------------------------------------------------ + + +R33 = "r33_ca_educator_expense_addback.py" + + +def test_a_module_in_neither_fixes_folder_is_refused(): + """This audit adds no fix module of its own (no regeneration needs a + fix_modules target). The 2026-10-12 audit's r33 is in neither the + 2026-09-22 fixes at the base nor this audit's fixes/, so it is refused; a + 2026-09-22 module is found where it is committed.""" + assert not (build.LOCAL_FIXES).exists() or not any(build.LOCAL_FIXES.iterdir()) + with pytest.raises(build.Refusal, match="neither in"): + build.fix_location(R33) + rel, _ = build.fix_location("r02_ira_219g_v2.py") + assert rel == f"{build.AUDIT_FIXES_REL}/r02_ira_219g_v2.py" + assert not build.is_local_fix("r02_ira_219g_v2.py") + assert not build.is_local_fix(R33) + + +def _local_fixes(monkeypatch, tmp_path, local: dict): + """Stand ``local`` in as this audit's committed fixes/ and its checkout.""" + real = build.fix_location + + def located(name): + if name in local: + return f"{build.LOCAL_FIXES_REL}/{name}", local[name] + return real(name) + + monkeypatch.setattr(build, "fix_location", located) + copy_dir = tmp_path / "fixes" + copy_dir.mkdir() + for name, blob in local.items(): + (copy_dir / name).write_bytes(blob) + monkeypatch.setattr(build, "LOCAL_FIXES", copy_dir) + return copy_dir + + +def test_a_local_modules_pin_names_its_path(monkeypatch, tmp_path): + _local_fixes(monkeypatch, tmp_path, {"rx_local.py": b"reform = None\n"}) + pins = build.audit_module_pins(["r02_ira_219g_v2.py", "rx_local.py"]) + assert build.module_pin("rx_local.py", pins) == { + "module": "rx_local.py", + "sha256": build.sha256_bytes(b"reform = None\n"), + "path": f"{build.LOCAL_FIXES_REL}/rx_local.py", + } + assert set(build.module_pin("r02_ira_219g_v2.py", pins)) == {"module", "sha256"} + + +def test_a_local_module_edited_after_its_commit_is_refused(monkeypatch, tmp_path): + copy_dir = _local_fixes(monkeypatch, tmp_path, {"rx_local.py": b"X = 1\n"}) + (copy_dir / "rx_local.py").write_bytes(b"X = 2\n") + with pytest.raises(build.Refusal, match="as committed at HEAD"): + build.audit_module_pins(["rx_local.py"]) + + +def test_a_local_module_cannot_pin_a_sibling_from_the_audited_fixes( + tmp_path, monkeypatch +): + loads = b'from pathlib import Path\nSIBLING = Path(__file__).with_name("%s")\n' + _local_fixes( + monkeypatch, + tmp_path, + { + "rx_shadow.py": loads % b"r02_ira_219g_v2.py", + "rx_beside.py": loads % b"rx_helper.py", + "rx_helper.py": b"X = 1\n", + }, + ) + with pytest.raises(build.Refusal, match="rx_shadow.py loads r02_ira_219g_v2.py"): + build.audit_module_pins(["rx_shadow.py"]) + pins = build.audit_module_pins(["rx_beside.py"]) + assert set(pins) == {"rx_beside.py", "rx_helper.py"} + assert build.module_pin("rx_helper.py", pins)["path"] == ( + f"{build.LOCAL_FIXES_REL}/rx_helper.py" + ) + + +@SETTINGS +@given( + moved=st.dictionaries( + st.sampled_from([(s, v) for s, v, _, _ in ROWS]), + st.floats(min_value=1.5, max_value=5e3) | st.floats(-5e3, -1.5), + ) +) +def test_the_draft_places_every_moved_output_exactly_once(moved): + """Whatever moves, each output that moves beyond the tolerance gets exactly + one call, and lands in exactly one list (or review only); nothing else is + listed.""" + computed = _unchanged() + for key, delta in moved.items(): + computed[key] = ( + (1.0 - computed[key]) + if key[1].endswith("_eligible") + else (computed[key] + delta) + ) + actions, calls = _draft(computed) + beyond = {k for k, v in computed.items() if build.beyond(k[1], _unchanged()[k], v)} + assert sorted((c["scenario_id"], c["variable"]) for c in calls) == sorted(beyond) + listed = [ + build.key_of(e) + for name in ( + "approved", + "regenerated_exclusions", + "new_exclusions", + "excluded_rechecked", + ) + for e in actions[name] + ] + review_only = [ + (c["scenario_id"], c["variable"]) + for c in calls + if c["placed_in"] == "review only" + ] + assert sorted(listed + review_only) == sorted(beyond) + assert len(set(listed)) == len(listed) + + +# --- The committed build --------------------------------------------------------- +# +# The build this audit stages for the next board release. Its inputs are +# committed beside it, so the tests check it against them without an engine. + +FINAL = UPGRADE / "final_actions.json" +APPROVED = { + ("scenario_028", "free_school_meals_eligible"): 1.0, + ("scenario_031", "snap"): 288.0, + ("scenario_117", "free_school_meals_eligible"): 1.0, + ("scenario_123", "free_school_meals_eligible"): 1.0, +} +# The four outputs whose records cite r24 (who paid for the disability +# coverage); 2.60.0 lands each on its record's alternative value. +R24 = { + ("scenario_002", F), + ("scenario_107", F), + ("scenario_121", F), + ("scenario_121", S), +} +# narratives_upgrade.py with hand_corrected_narratives.json on this build and +# release 20261014's explanations (no writer call). +EXPLANATIONS_SHA256 = "a1691832890b9f6b9140ff1df199421cb7d8179b971cbb8cee19bc0333b682a4" +EXPLANATIONS_PATH = ( + "annotations/us_full_run_20260612_policyengine_4_16_1_populace/" + "us_case_reference_explanations.csv" +) + + +def _computed(path: Path) -> dict: + import csv + + with path.open(newline="") as source: + return { + (r["scenario_id"], r["variable"]): float(r["recomputed"]) + for r in csv.DictReader(source) + } + + +@pytest.fixture(scope="module") +def committed(): + meta = json.loads((BUILD / "reference_outputs.csv.meta.json").read_text()) + return types.SimpleNamespace( + csv_text=(BUILD / "reference_outputs.csv").read_text(), + meta=meta, + revision=meta["revisions"][-1], + exclusions=json.loads((BUILD / "reference_exclusions.json").read_text()), + traces=json.loads((BUILD / "reference_traces.json").read_text()), + actions=json.loads(FINAL.read_text()), + computed=_computed(BUILD / "computed.csv"), + ) + + +def test_the_committed_build_reproduces_from_its_inputs(real_base, committed, tmp_path): + """Differential: the base, the committed computed.csv and final_actions.json, + planned and written with the committed revision's provenance, bundle, fix + modules, traces and time, give the committed files byte for byte.""" + build.validate_actions(committed.actions) + plan = build.plan_upgrade(real_base, committed.actions, committed.computed) + assert plan.problems == [] + build.write_outputs( + tmp_path, + real_base, + plan, + committed.actions, + bundle=committed.meta["policyengine_bundles"]["us"], + fix_modules=committed.revision["fix_modules"], + provenance=committed.revision["provenance"], + traces=committed.traces, + now=committed.meta["regenerated_at_utc"], + ) + for name in ( + "reference_outputs.csv", + "reference_outputs.csv.meta.json", + "reference_exclusions.json", + "reference_traces.json", + ): + assert (tmp_path / name).read_bytes() == (BUILD / name).read_bytes(), name + + +def test_the_committed_revision_names_this_audits_inputs(real_base, committed): + revision = committed.revision + assert revision["kind"] == "engine_upgrade" + assert revision["engine_version"] == "policyengine-us 2.60.0" + assert revision["previous_engine_version"] == build.PREVIOUS_ENGINE + assert revision["date"] == committed.actions["date"] == "2026-10-23" + assert committed.meta["regenerated_at_utc"][:10] == revision["date"] + assert committed.meta["revisions"][:-1] == real_base.meta["revisions"] + provenance = revision["provenance"] + assert provenance["builder_sha256"] == build.sha256( + UPGRADE / "scripts" / "build_references_upgrade.py" + ) + assert provenance["actions_sha256"] == build.sha256(FINAL) + assert provenance["harness_sha256"] == build.sha256(build.HARNESS) + assert provenance["base_commit"] == build.BASE_COMMIT + assert committed.meta["reference_csv_sha256"] == build.sha256( + BUILD / "reference_outputs.csv" + ) + assert committed.meta["policyengine_bundles"]["us"]["model_version"] == "2.60.0" + assert {build.key_of(c): c["regenerated"] for c in revision["changed"]} == APPROVED + assert {build.key_of(c): c["cause"] for c in revision["changed"]} == { + k: ( + "ca_snap_mce_no_net_income_test_10036" + if k[1] == "snap" + else "state_universal_free_breakfast_10238" + ) + for k in APPROVED + } + assert revision["regenerated_exclusions"] == [] + assert revision["new_exclusions"] == [] + assert len(revision["excluded_outputs_rechecked"]) == 16 + assert set(committed.traces) == {f"{k[0]}|{k[1]}" for k in APPROVED} + + +def test_the_committed_csv_moves_only_the_approved_outputs(real_base, committed): + import pandas as pd + + from policybench.reference_exclusions import ( + load_reference_exclusions, + verify_exclusions_against_reference, + ) + + assert committed.csv_text == build.render_reference_csv( + real_base.reference, APPROVED + ) + verify_exclusions_against_reference( + pd.read_csv(BUILD / "reference_outputs.csv"), + load_reference_exclusions(BUILD / "reference_exclusions.json"), + ) + base_doc = real_base.exclusions + assert {k: v for k, v in committed.exclusions.items() if k != "derivation"} == { + k: v for k, v in base_doc.items() if k != "derivation" + } + added = committed.exclusions["derivation"].removeprefix(base_doc["derivation"]) + assert added == ( + " On 2026-10-23 the references moved from policyengine-us 2.41.0 to" + " policyengine-us 2.60.0 with the same pre-freeze conventions" + " (reference_audit/2026-10-22-engine-upgrade), and every output was" + " recomputed there. Of the excluded outputs that stay excluded, 16 moved;" + " each was re-reviewed and keeps the value it was decided on" + " (excluded_outputs_rechecked)." + ) + + +def test_the_committed_computed_values_are_every_scored_reference(committed): + references = build.parse_reference_csv(committed.csv_text).values() + excluded = {build.key_of(r) for r in committed.exclusions["exclusions"]} + assert set(committed.computed) == set(references) + for key, value in references.items(): + if key not in excluded: + assert abs(committed.computed[key] - value) <= build.EPS, key + for item in committed.revision["excluded_outputs_rechecked"]: + key = build.key_of(item) + assert key in excluded + assert item["kept_value"] == references[key] + assert item["value_on_2_60_0"] == committed.computed[key] + assert build.beyond(key[1], references[key], committed.computed[key]) + + +def test_the_r24_outputs_land_on_their_alternatives_and_stay_excluded(committed): + """2.60.0 counts employment disability benefits in gross income unless an + input it defaults to zero says the recipient paid for the coverage + (#10185), so the four r24 outputs land on their records' alternative + values. The records are unlisted-input exclusions (r24 is classed + unlisted_input) and the prompt still does not state who paid, so they stay + excluded at their decided $0.""" + root_causes = json.loads( + (ROOT / "reference_audit" / "2026-09-22" / "root_causes.json").read_text() + ) + root_causes = root_causes.get("root_causes", root_causes) + assert ( + root_causes["r24_disability_benefits_taxability"]["class"] == "unlisted_input" + ) + records = {build.key_of(r): r for r in committed.exclusions["exclusions"]} + references = build.parse_reference_csv(committed.csv_text).values() + rechecked = {build.key_of(r): r for r in committed.actions["excluded_rechecked"]} + for key in R24: + record = records[key] + assert record["reason_code"] == "reference_depends_on_unlisted_input" + assert "r24_disability_benefits_taxable" in record["note"] + assert references[key] == record["frozen_value"] == 0.0 + assert abs(committed.computed[key] - record["alternative_value"]) <= 1e-3 + assert "an engine default does not settle it" in rechecked[key]["reason"] + assert "policyengine-us#10185" in rechecked[key]["reason"] + + +def test_the_final_actions_are_the_reviewed_draft(real_base, committed): + """Drafted again from the committed computed.csv, the outputs land in the + same lists with the same values and causes; the review only adds figures + and upstream pull requests to a basis or a reason.""" + records = {build.key_of(r): r for r in real_base.exclusions["exclusions"]} + cells = drafting.cells_from_computed( + BUILD / "computed.csv", real_base.reference.values(), records + ) + drafted, calls = drafting.draft_actions( + cells, + records, + drafting.last_upgrade_rechecks(real_base.meta), + drafting.last_upgrade(real_base.meta), + engine_version="2.60.0", + date="2026-10-23", + precise=True, + indeterminate=drafting.indeterminate_rechecks(real_base.meta), + ) + final = committed.actions + assert drafted["draft"] is True and final["draft"] is False + for name in ( + "approved", + "regenerated_exclusions", + "new_exclusions", + "excluded_rechecked", + ): + assert [build.key_of(e) for e in final[name]] == [ + build.key_of(e) for e in drafted[name] + ], name + for d, f in zip(drafted["approved"], final["approved"], strict=True): + assert (d["value"], d["cause"]) == (f["value"], f["cause"]) + for d, f in zip( + drafted["excluded_rechecked"], final["excluded_rechecked"], strict=True + ): + assert f["reason"].startswith(d["reason"]) + assert final["review"] == drafted["review"] + assert {c["decision"] for c in calls} == {"PROPOSED"} + + +def test_the_hand_corrected_narratives_rebuild_the_explanations(committed): + """The four narratives replace the writer for every changed output (no + writer call), and on release 20261014's explanations they give the CSV + the next board release installs. Each states the trace's figures.""" + import hashlib + + import pandas as pd + + hand = json.loads((UPGRADE / "hand_corrected_narratives.json").read_text()) + assert set(hand) == {f"{k[0]}|{k[1]}" for k in APPROVED} + + def refuse(**_): + raise AssertionError("the narrative writer must not run") + + base_text = build.git_blob(build.BASE_COMMIT, EXPLANATIONS_PATH).decode() + text, results = narratives.write_narratives( + BUILD, + base_text, + pd.DataFrame(columns=["scenario_id"]), + completion=refuse, + hand_corrected=hand, + ) + assert hashlib.sha256(text.encode()).hexdigest() == EXPLANATIONS_SHA256 + assert {(r[0], r[1]) for r in results} == set(APPROVED) + figures = { + "scenario_031|snap": ( + ["$288", "$24", "$1,987.79", "$2,608.33", "$1,611", "$298", "$484"], + [ + "snap = 288", + "snap_min_allotment = 24", + "snap_net_income = 1611", + "tanf_non_cash_gross_income_limit = 2608.33", + "snap_expected_contribution = 484", + "snap_max_allotment = 298", + ], + ), + "scenario_028|free_school_meals_eligible": ( + ["$1,112.40", "$61,277", "1.86", "$33,000", "$2.90", "$0.84"], + [ + "free_school_meals = 1112.4", + "school_meal_countable_income = 61277", + "school_meal_fpg_ratio = 1.86", + "spm_unit_fpg = 33000", + "school_meal_daily_subsidy = 2.9", + "school_meal_paid_daily_subsidy = 0.84", + ], + ), + "scenario_117|free_school_meals_eligible": ( + ["$741.60", "$248,675", "6.43", "$38,680"], + [ + "free_school_meals = 741.6", + "school_meal_countable_income = 248675", + "school_meal_fpg_ratio = 6.43", + "spm_unit_fpg = 38680", + ], + ), + "scenario_123|free_school_meals_eligible": ( + ["$370.80", "$145,002", "5.31", "$27,320"], + [ + "free_school_meals = 370.8", + "school_meal_countable_income = 145002", + "school_meal_fpg_ratio = 5.31", + "spm_unit_fpg = 27320", + ], + ), + } + for key, (stated, traced) in figures.items(): + for figure in stated: + assert figure in hand[key], (key, figure) + for line in traced: + assert line in committed.traces[key]["trace"], (key, line) + # Free breakfast is $2.06 a school day over 180 days, per K-12 child. + assert round((2.90 - 0.84) * 180, 2) == 370.80 + assert round(3 * 370.80, 2) == 1112.40 and round(2 * 370.80, 2) == 741.60 + + +def test_the_timing_record_dates_the_sweep_on_the_newest_release(committed): + timing = json.loads((UPGRADE / "verification" / "sweep_timing.json").read_text()) + sweep = timing["reference_sweep"] + engine = committed.revision["engine_version"].removeprefix("policyengine-us ") + assert sweep["engine"] == engine == "2.60.0" + assert sweep["first_output_sha256"] == build.sha256(BUILD / "computed.csv") + uploads = timing["pypi"]["wheel_uploaded_at_utc"] + assert ( + uploads[engine][:19] + <= sweep["engine_installed_at_utc"][:19] + <= sweep["first_output_at_utc"][:19] + ) + + def key(version): + return tuple(int(p) for p in version.split(".")) + + assert [ + v + for v, at in uploads.items() + if key(v) > key(engine) and at[:19] < sweep["first_output_at_utc"][:19] + ] == [] + check = timing["publication_check"] + for name in ( + "computed.csv", + "reference_outputs.csv", + "reference_outputs.csv.meta.json", + "reference_exclusions.json", + ): + assert check["build_sha256"][name] == build.sha256(BUILD / name), name + assert ( + check["build_sha256"]["builder"] + == committed.revision["provenance"]["builder_sha256"] + ) + assert check["scored_outputs"] == 1984 - len(committed.exclusions["exclusions"]) + assert check.get("scored_differ", []) == [] + + +def test_the_superseded_sweep_differs_only_on_the_approved_school_meals(): + """The first sweep, on 2.59.0, was cut off before its build; 2.60.0 differs + from it on exactly the three school-meal flags #10238 moves.""" + doc = json.loads((UPGRADE / "verification" / "superseded_2_59_0.json").read_text()) + assert doc["sweep_timing_2_59_0"]["reference_sweep"]["engine"] == "2.59.0" + assert doc["first_pass_2_60_0_sha256"] == build.sha256(BUILD / "computed.csv") + assert { + (d["scenario_id"], d["variable"]) for d in doc["differ_2_59_0_vs_2_60_0"] + } == {k for k in APPROVED if k[1] == "free_school_meals_eligible"} + assert all(d["scored"] for d in doc["differ_2_59_0_vs_2_60_0"]) diff --git a/tests/test_sweep_timing_1022.py b/tests/test_sweep_timing_1022.py new file mode 100644 index 00000000..69af4476 --- /dev/null +++ b/tests/test_sweep_timing_1022.py @@ -0,0 +1,890 @@ +"""reference_audit/2026-10-22-engine-upgrade/scripts/sweep_timing.py: the +2026-10-22 engine move's timing record and publication check, on MOCK PyPI +data. A copy of tests/test_sweep_timing_1012.py, which tests the 2026-10-12 +audit's script, pointed at this audit's; the check also takes --snapshot, the +committed copy of the build it must equal (this audit's build/ while it is +staged).""" + +import importlib.util +import json +import math +import time +from pathlib import Path + +import pytest +from hypothesis import given +from hypothesis import strategies as st + +REPO = Path(__file__).resolve().parents[1] +_spec = importlib.util.spec_from_file_location( + "sweep_timing_1022", + REPO / "reference_audit/2026-10-22-engine-upgrade/scripts/sweep_timing.py", +) +timing = importlib.util.module_from_spec(_spec) +_spec.loader.exec_module(timing) + +# Linux's stat keeps no birth time, and the record's times are birth times. +BIRTH_TIMES = hasattr(Path(__file__).stat(), "st_birthtime") +REAL_BIRTH_TIME = timing.birth_time + + +@pytest.fixture(autouse=True) +def _birth_times(monkeypatch): + """MOCK, on a platform without birth times (Linux CI) only: date each file + by its modification time. These tests create every file they date once and + never rewrite it, so the two times agree; on macOS the real birth times + are read.""" + if not BIRTH_TIMES: + monkeypatch.setattr(timing, "birth_time", lambda path: path.stat().st_mtime) + + +def test_birth_time_refuses_a_platform_without_birth_times(tmp_path): + """Where stat keeps no birth time, the record refuses rather than date the + install or an output by a modification time.""" + path = tmp_path / "computed.csv" + path.write_text("x\n") + + class NoBirth: + def stat(self): + return type("Stat", (), {"st_mtime": 0.0})() + + def __str__(self): + return str(path) + + with pytest.raises(timing.Refusal, match="keeps no birth time"): + REAL_BIRTH_TIME(NoBirth()) + if BIRTH_TIMES: + assert REAL_BIRTH_TIME(path) == path.stat().st_birthtime + + +def _wheel(at, *, yanked=False, kind="bdist_wheel"): + return {"packagetype": kind, "upload_time_iso_8601": at, "yanked": yanked} + + +MOCK_PYPI = { + "releases": { + "2.38.4": [ + _wheel("2026-10-09T20:50:00.1Z"), + _wheel("2026-10-09T20:49:00Z", kind="sdist"), + ], + "2.39.0": [_wheel("2026-10-10T01:00:00.5Z")], + "2.39.1": [_wheel("2026-10-10T05:00:00Z", yanked=True)], + "2.40.0rc1": [_wheel("2026-10-10T06:00:00Z")], + "2.9.0": [_wheel("2026-08-01T00:00:00Z")], + "2.10.0": [], + } +} + + +def test_wheel_uploads_keep_released_wheels_only(): + """MOCK: sdists, yanked wheels, pre-releases and empty releases drop out; + versions order numerically, so 2.10 > 2.9.""" + uploads = timing.wheel_uploads(MOCK_PYPI) + assert uploads == { + "2.38.4": "2026-10-09T20:50:00.1Z", + "2.39.0": "2026-10-10T01:00:00.5Z", + "2.9.0": "2026-08-01T00:00:00Z", + } + assert timing.newest(uploads) == "2.39.0" + assert list(timing.from_engine(uploads, "2.38.4")) == ["2.38.4", "2.39.0"] + + +@pytest.mark.parametrize( + "moment, newer", + [ + ("2026-10-10T00:59:59Z", []), + ("2026-10-10T01:00:00Z", []), + ("2026-10-10T01:00:01Z", ["2.39.0"]), + ], +) +def test_a_newer_release_before_the_first_output_is_found(moment, newer): + uploads = timing.wheel_uploads(MOCK_PYPI) + assert timing.newer_before(uploads, "2.38.4", moment) == newer + + +def _computed(values: dict, path: Path) -> Path: + lines = ["fix,scenario_id,state,variable,frozen,recomputed,delta,moved"] + for (s, v), x in values.items(): + lines.append(f"latest_final,{s},TX,{v},0,{x!r},0,False") + path.write_text("\n".join(lines) + "\n") + return path + + +def test_compare_counts_the_outputs_that_differ(tmp_path): + a = _computed({("s1", "v"): 1.0, ("s2", "v"): 2.0}, tmp_path / "a.csv") + b = _computed({("s1", "v"): 1.0, ("s2", "v"): 2.5}, tmp_path / "b.csv") + rows, summary = timing.compare( + timing.read_computed(a), timing.read_computed(b), "2.38.4", "2.39.0" + ) + assert summary == { + "outputs": 2, + "same": 1, + "differ": ["s2|v"], + "scored_outputs": 2, + "scored_same": 1, + "scored_differ": ["s2|v"], + "excluded_differ": [], + "max_abs_delta": 0.5, + } + assert [r["same"] for r in rows] == [True, False] + # The same move on an output the release excludes touches no scored one. + _, excluded = timing.compare( + timing.read_computed(a), + timing.read_computed(b), + "2.38.4", + "2.39.0", + frozenset({("s2", "v")}), + ) + assert (excluded["scored_outputs"], excluded["scored_same"]) == (1, 1) + assert excluded["scored_differ"] == [] and excluded["excluded_differ"] == ["s2|v"] + with pytest.raises(timing.Refusal, match="do not cover"): + timing.compare( + timing.read_computed(a), + timing.read_computed(b), + "x", + "y", + frozenset({("s9", "v")}), + ) + + +def test_compare_refuses_other_outputs_or_non_finite_values(tmp_path): + a = timing.read_computed(_computed({("s1", "v"): 1.0}, tmp_path / "a.csv")) + b = timing.read_computed(_computed({("s2", "v"): 1.0}, tmp_path / "b.csv")) + with pytest.raises(timing.Refusal, match="different outputs"): + timing.compare(a, b, "x", "y") + nan = timing.read_computed(_computed({("s1", "v"): math.nan}, tmp_path / "n.csv")) + with pytest.raises(timing.Refusal, match="non-finite"): + timing.compare(a, nan, "x", "y") + + +@given( + st.dictionaries( + st.text("abc", min_size=1, max_size=3), st.floats(-1e9, 1e9), min_size=1 + ) +) +def test_a_sweep_compared_with_itself_is_all_the_same(values): + """Property: every output of a sweep is the same as itself.""" + computed = {(k, "v"): ("TX", x) for k, x in values.items()} + rows, summary = timing.compare(computed, computed, "a", "a") + assert summary["same"] == summary["outputs"] == len(values) + assert summary["differ"] == [] and summary["max_abs_delta"] == 0.0 + + +def _venv(root: Path, engine: str) -> Path: + (root / f"lib/python3.12/site-packages/policyengine_us-{engine}.dist-info").mkdir( + parents=True + ) + return root + + +def _pypi_around_now(offset_newer: float, offset_engine: float = -3600) -> dict: + """MOCK PyPI: the engine offset_engine seconds from now (an hour ago by + default), a newer release offset_newer seconds from now.""" + + def at(seconds): + return timing.utc(time.time() + seconds) + + return { + "releases": { + "2.38.4": [_wheel(at(offset_engine))], + "2.39.0": [_wheel(at(offset_newer))], + } + } + + +def _sweep_args(tmp_path: Path): + """MOCK sweep inputs, in a sweep's order: the engine is installed, then + the sweep writes its first output.""" + venv = _venv(tmp_path / "venv", "2.38.4") + first = tmp_path / "computed.csv" + first.write_text("x\n") + return type( + "Args", + (), + {"engine": "2.38.4", "venv": str(venv), "first_output": str(first)}, + ) + + +MOCK_INSTALL = {"version": "MOCK", "files_verified": 1, "editable": False} + + +@pytest.mark.parametrize("offset, ok", [(600, True), (-600, False)]) +def test_the_sweep_refuses_an_engine_that_was_not_the_newest( + tmp_path, monkeypatch, offset, ok +): + """MOCK: a release newer than the engine uploaded before the sweep's first + output means the engine was not the newest when the sweep began.""" + args = _sweep_args(tmp_path) + monkeypatch.setattr(timing, "engine_install", lambda venv, engine: MOCK_INSTALL) + monkeypatch.setattr(timing, "read_pypi", lambda url=None: _pypi_around_now(offset)) + if ok: + record = timing.sweep(args) + assert record["reference_sweep"]["engine"] == "2.38.4" + assert record["pypi"]["newest_at_read"] == "2.39.0" + assert ( + record["reference_sweep"]["first_output_at_utc"] + <= record["pypi"]["read_at_utc"] + ) + assert record["reference_sweep"]["first_output_sha256"] == ( + timing.sha256(Path(args.first_output)) + ) + else: + with pytest.raises(timing.Refusal, match="was not the newest"): + timing.sweep(args) + + +def test_the_sweep_refuses_an_engine_uploaded_after_its_output(tmp_path, monkeypatch): + """MOCK: an output older than its engine's wheel (an earlier rehearsal's + file, say) cannot date the sweep.""" + args = _sweep_args(tmp_path) + monkeypatch.setattr(timing, "engine_install", lambda venv, engine: MOCK_INSTALL) + monkeypatch.setattr( + timing, "read_pypi", lambda url=None: _pypi_around_now(7200, offset_engine=3600) + ) + with pytest.raises(timing.Refusal, match="must follow"): + timing.sweep(args) + + +_T = st.integers(0, 10).map(lambda n: f"2026-10-10T0{n // 10}:{n % 10}0:00Z") + + +@given(_T, _T, _T) +def test_a_sweep_follows_its_engines_upload_and_install(uploaded, installed, output): + """Property: the order check passes exactly when upload <= install <= output.""" + if uploaded <= installed <= output: + timing.sweep_order_problems(uploaded, installed, output, "2.38.4") + else: + with pytest.raises(timing.Refusal, match="must follow"): + timing.sweep_order_problems(uploaded, installed, output, "2.38.4") + + +def _write_build(root: Path, values: dict, excluded: set, engine: str = "2.38.4"): + """MOCK reference build and the committed snapshot it froze into: the + references are the computed values, every output scored but ``excluded``, + and the sidecar names the committed builder.""" + build, snapshot = root / "build", root / "snapshot" + build.mkdir(parents=True) + snapshot.mkdir(parents=True) + _computed(values, build / "computed.csv") + lines = ["scenario_id,variable,value,impact_weight"] + lines += [f"{s},{v},{x!r}," for (s, v), x in values.items()] + (build / "reference_outputs.csv").write_text("\n".join(lines) + "\n") + record = { + "exclusions": [{"scenario_id": s, "variable": v} for s, v in sorted(excluded)] + } + (build / "reference_exclusions.json").write_text(json.dumps(record)) + meta = { + "reference_csv_sha256": timing.sha256(build / "reference_outputs.csv"), + "revisions": [ + { + "kind": "engine_upgrade", + "engine_version": f"policyengine-us {engine}", + "provenance": {"builder_sha256": timing.sha256(timing.BUILDER)}, + } + ], + } + (build / "reference_outputs.csv.meta.json").write_text(json.dumps(meta)) + for name in ( + "reference_outputs.csv", + "reference_outputs.csv.meta.json", + "reference_exclusions.json", + ): + (snapshot / name).write_bytes((build / name).read_bytes()) + return build, snapshot + + +VALUES = {("s1", "v"): 1.0, ("s2", "v"): 2.0, ("s3", "v"): 3.0} + + +def _check_setup(tmp_path, monkeypatch, pypi, excluded=frozenset({("s3", "v")})): + path = tmp_path / "sweep_timing.json" + path.write_text(json.dumps({"reference_sweep": {"engine": "2.38.4"}, "pypi": {}})) + monkeypatch.setattr(timing, "TIMING", path) + monkeypatch.setattr(timing, "VERIFICATION", tmp_path / "verification") + monkeypatch.setattr(timing, "read_pypi", lambda url=None: pypi) + build, snapshot = _write_build(tmp_path, VALUES, set(excluded)) + return build, snapshot + + +def _check_args(build, snapshot, check_venv=None, work_dir=None): + return type( + "Args", + (), + { + "build": str(build), + "snapshot": str(snapshot), + "check_venv": check_venv and str(check_venv), + "work_dir": work_dir and str(work_dir), + }, + ) + + +def _MOCK_sweep(values: dict): + """MOCK check sweep: writes ``values`` as the computed.csv a first pass on + the venv's engine would, in place of running the builder.""" + + def run(venv, engine, out_dir): + out_dir.mkdir(parents=True) + path = _computed(values, out_dir / "computed.csv") + return path, { + "builder_sha256": timing.sha256(timing.BUILDER), + "MOCK": True, + "engine_install": MOCK_INSTALL, + } + + return run + + +ONLY_ENGINE = {"releases": {"2.38.4": [_wheel("2026-10-09T20:50:00Z")]}} + + +def test_the_check_records_a_still_newest_engine(tmp_path, monkeypatch): + """MOCK: with the reference engine still the newest, the record says so and + pins the build; a newer release needs a venv holding it.""" + build, snapshot = _check_setup(tmp_path, monkeypatch, ONLY_ENGINE) + out = timing.check(_check_args(build, snapshot)) + check = out["publication_check"] + assert check["engine"] == "2.38.4" and "was still the newest" in check["result"] + assert check["scored_outputs"] == 2 + assert set(check["build_sha256"]) == {*timing.BUILD_FILES, "builder"} + monkeypatch.setattr(timing, "read_pypi", lambda url=None: MOCK_PYPI) + with pytest.raises(timing.Refusal, match="newer than the reference engine"): + timing.check(_check_args(build, snapshot)) + + +def test_the_cli_check_takes_the_committed_copy_of_the_build(tmp_path, monkeypatch): + """MOCK: ``check --snapshot DIR`` holds the build to DIR (this audit's build/ + while the build is staged for the next board release); without it, the + build is held to the paper snapshot, which here it is not.""" + build, snapshot = _check_setup(tmp_path, monkeypatch, ONLY_ENGINE) + timing.main(["check", "--build", str(build), "--snapshot", str(snapshot)]) + record = json.loads(timing.TIMING.read_text()) + assert record["publication_check"]["engine"] == "2.38.4" + with pytest.raises(timing.Refusal, match="is not the committed snapshot's"): + timing.main(["check", "--build", str(build)]) + assert timing.STAGED_BUILD == timing.AUDIT / "build" + assert timing.BASE_ENGINE == "policyengine-us 2.41.0" + + +def test_the_check_holds_its_build_to_the_release(tmp_path, monkeypatch): + """MOCK: a build that is not the frozen release's is refused before PyPI + is read: another engine, a sidecar that does not pin its CSV, a missing or + other builder, a sidecar, CSV or record that is not the committed + snapshot's, a computed.csv that is not the scored references, and a + non-finite value anywhere.""" + build, snapshot = _check_setup(tmp_path, monkeypatch, ONLY_ENGINE) + meta_path = build / "reference_outputs.csv.meta.json" + meta = json.loads(meta_path.read_text()) + revision = meta["revisions"][0] + + def refused(match): + with pytest.raises(timing.Refusal, match=match): + timing.check(_check_args(build, snapshot)) + + def sidecar(**changes): + meta_path.write_text(json.dumps({**meta, **changes})) + + sidecar(revisions=[{**revision, "engine_version": "x"}]) + refused("not an engine upgrade to 2.38.4") + sidecar(reference_csv_sha256="0" * 64) + refused("does not pin its reference_outputs.csv") + for provenance in ({"builder_sha256": "f" * 64}, {}): + sidecar(revisions=[{**revision, "provenance": provenance}]) + refused("not the committed one") + sidecar(MOCK_extra=1) + refused("reference_outputs.csv.meta.json is not the committed snapshot's") + sidecar() + record = snapshot / "reference_exclusions.json" + original = record.read_bytes() + record.write_text(json.dumps({"exclusions": []})) + refused("reference_exclusions.json is not the committed snapshot's") + record.write_bytes(original) + _computed({**VALUES, ("s1", "v"): 1.5}, build / "computed.csv") + refused("not its scored references") + # Non-finite values are refused, scored or excluded, before any + # comparison: the still-newest branch never reaches compare. + for key in (("s1", "v"), ("s3", "v")): + _computed({**VALUES, key: math.nan}, build / "computed.csv") + refused("non-finite") + # A moved excluded output is the engine's value, not the reference's: fine. + _computed({**VALUES, ("s3", "v"): 9.0}, build / "computed.csv") + assert timing.check(_check_args(build, snapshot))["publication_check"] + + +@pytest.mark.parametrize( + "moved, publishes", + [({}, True), ({("s3", "v"): 3.5}, True), ({("s2", "v"): 2.5}, False)], +) +def test_the_check_stops_the_publish_when_a_scored_output_moves( + tmp_path, monkeypatch, moved, publishes +): + """MOCK: check runs the sweep on the newer release itself (here a MOCK + sweep); one that moves only excluded outputs passes, one that moves a + scored output writes the record and exits non-zero.""" + build, snapshot = _check_setup( + tmp_path, monkeypatch, _pypi_around_now(-1800, offset_engine=-7200) + ) + venv = _venv(tmp_path / "check-venv", "2.39.0") + monkeypatch.setattr(timing, "engine_install", lambda venv, engine: MOCK_INSTALL) + monkeypatch.setattr(timing, "run_check_sweep", _MOCK_sweep({**VALUES, **moved})) + monkeypatch.setattr(timing.tempfile, "mkdtemp", lambda **kw: str(tmp_path / "w")) + monkeypatch.setattr(timing, "SNAPSHOT", snapshot) + argv = ["check", "--build", str(build), "--check-venv", str(venv)] + if publishes: + timing.main(argv) + else: + with pytest.raises(timing.Refusal, match="do not publish"): + timing.main(argv) + check = json.loads(timing.TIMING.read_text())["publication_check"] + assert check["engine"] == "2.39.0" and check["scored_outputs"] == 2 + assert bool(check["scored_differ"]) is not publishes + assert check["check_sweep"]["MOCK"] is True + assert check["check_sweep"]["engine_install"] == MOCK_INSTALL + # A venv installed before the newer release's wheel was uploaded does not + # hold that release. + monkeypatch.setattr( + timing, + "read_pypi", + lambda url=None: _pypi_around_now(3600, offset_engine=-7200), + ) + with pytest.raises(timing.Refusal, match="must follow"): + timing.check(_check_args(build, snapshot, venv, tmp_path / "w2")) + + +def _fake_run_writing(receipt_problems=(), computed=True): + """MOCK subprocess.run for run_on_engine: writes the engine check's + receipt (and the sweep's computed.csv) where the real runner would.""" + calls = [] + + def run(command, env=None, **kw): + calls.append((command, env)) + Path(env["PB_ENGINE_RECEIPT"]).write_text( + json.dumps( + { + "version": env["PB_EXPECTED_ENGINE"], + "files_verified": 2, + "problems": list(receipt_problems), + } + ) + ) + if computed and "--out-dir" in command: + out = Path(command[command.index("--out-dir") + 1]) + out.mkdir(parents=True, exist_ok=True) # as the builder does + _computed(VALUES, out / "computed.csv") + return type("Ran", (), {"returncode": 1, "stdout": "", "stderr": "draft"})() + + return run, calls + + +def test_the_check_sweep_runs_the_builder_in_the_checked_process(tmp_path, monkeypatch): + """MOCK subprocess: one process, under the venv's interpreter with -P and a + fresh bytecode-cache prefix, checks the engine and then runs the builder + with empty actions naming the newer engine; a sweep that writes nothing, + or a failed check, is refused.""" + run, calls = _fake_run_writing() + monkeypatch.setattr(timing.subprocess, "run", run) + venv = tmp_path / "venv" + path, receipt = timing.run_check_sweep(venv, "2.39.0", tmp_path / "a") + assert path.is_file() and receipt["exit_code"] == 1 + assert receipt["engine_install"]["fresh_bytecode_cache"] is True + command, env = calls[0] + assert command[:4] == [str(venv / "bin/python"), "-P", "-c", timing.ENGINE_RUNNER] + assert command[4] == str(timing.BUILDER) and "--allow-draft" in command + assert env["PB_EXPECTED_ENGINE"] == "2.39.0" and env["PYTHONPYCACHEPREFIX"] + actions = json.loads((tmp_path / "a/actions.empty.json").read_text()) + assert actions["engine"] == "policyengine-us 2.39.0" and actions["draft"] is True + # The builder refuses any key it does not know, so the empty actions carry + # no release spec: this audit stages its build without one. + assert set(actions) == {"engine", "previous_engine", "date", "draft"} + assert actions["previous_engine"] == "policyengine-us 2.41.0" + run, _ = _fake_run_writing(computed=False) + monkeypatch.setattr(timing.subprocess, "run", run) + with pytest.raises(timing.Refusal, match="wrote no computed.csv"): + timing.run_check_sweep(venv, "2.39.0", tmp_path / "b") + run, _ = _fake_run_writing(receipt_problems=["an editable install"]) + monkeypatch.setattr(timing.subprocess, "run", run) + with pytest.raises(timing.Refusal, match="an editable install"): + timing.run_check_sweep(venv, "2.39.0", tmp_path / "c") + monkeypatch.setattr( + timing.subprocess, + "run", + lambda *a, **k: type( + "Ran", (), {"returncode": 2, "stdout": "", "stderr": "x"} + )(), + ) + with pytest.raises(timing.Refusal, match="did not run"): + timing.engine_install(venv, "2.39.0") + + +def test_a_relative_check_venv_is_the_one_found_and_run(tmp_path, monkeypatch): + """MOCK: --check-venv given relative to a caller outside the repository is + resolved once, so discovery, the install check and the sweep all use it.""" + build, snapshot = _check_setup( + tmp_path, monkeypatch, _pypi_around_now(-1800, offset_engine=-7200) + ) + venv = _venv(tmp_path / "check-venv", "2.39.0").resolve() + seen = [] + + def install(found, engine): + seen.append(found) + return MOCK_INSTALL + + def sweep(found, engine, out_dir): + seen.append(found) + return _MOCK_sweep(VALUES)(found, engine, out_dir) + + monkeypatch.setattr(timing, "engine_install", install) + monkeypatch.setattr(timing, "run_check_sweep", sweep) + elsewhere = tmp_path / "elsewhere" + elsewhere.mkdir() + monkeypatch.chdir(elsewhere) + timing.check(_check_args(build, snapshot, "../check-venv", tmp_path / "w")) + assert seen == [venv, venv] + + +def test_a_missing_scratch_parent_is_created(tmp_path, monkeypatch): + """MOCK: in a checkout without results/local, check creates it before + making the sweep's scratch directory.""" + build, snapshot = _check_setup( + tmp_path, monkeypatch, _pypi_around_now(-1800, offset_engine=-7200) + ) + root = tmp_path / "clean-checkout" + root.mkdir() + monkeypatch.setattr(timing, "ROOT", root) + monkeypatch.setattr(timing, "engine_install", lambda venv, engine: MOCK_INSTALL) + monkeypatch.setattr(timing, "run_check_sweep", _MOCK_sweep(VALUES)) + venv = _venv(tmp_path / "check-venv", "2.39.0") + timing.check(_check_args(build, snapshot, venv)) + assert (root / "results/local").is_dir() + assert any((root / "results/local").glob("check-sweep-2.39.0-*")) + + +def _fake_install( + root: Path, version: str, files: dict[str, str], algorithm: str = "sha256" +) -> Path: + """MOCK site-packages: a policyengine-us wheel's dist-info whose RECORD + pins ``files`` as written, with the given hash algorithm.""" + import base64 + import hashlib + + site = root / "site" + record = [] + for name, text in files.items(): + path = site / name + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(text) + digest = base64.urlsafe_b64encode( + hashlib.new(algorithm, text.encode()).digest() + ) + record.append(f"{name},{algorithm}={digest.rstrip(b'=').decode()},{len(text)}") + info = site / f"policyengine_us-{version}.dist-info" + info.mkdir() + (info / "METADATA").write_text( + f"Metadata-Version: 2.1\nName: policyengine-us\nVersion: {version}\n" + ) + (info / "RECORD").write_text("\n".join(record) + "\n") + return site + + +def _runner( + tmp_path: Path, *paths: Path, builder=None, fresh_cache=True, expected="9.9.9" +): + """Run ENGINE_RUNNER as run_on_engine does (-P, a fresh cache prefix), with + ``paths`` first on the import path, as a shadowing tree or a .pth redirect + would put them. Returns the receipt and the process.""" + import os + import subprocess + import sys + import tempfile + + receipt = Path(tempfile.mkdtemp(dir=tmp_path)) / "receipt.json" + env = { + **{k: v for k, v in os.environ.items() if k in ("PATH", "HOME", "LANG")}, + "PYTHONPATH": os.pathsep.join(str(p) for p in paths), + "PYTHONDONTWRITEBYTECODE": "1", + "PB_EXPECTED_ENGINE": expected, + "PB_ENGINE_RECEIPT": str(receipt), + } + if fresh_cache: + env["PYTHONPYCACHEPREFIX"] = tempfile.mkdtemp(dir=tmp_path) + command = [sys.executable, "-P", "-c", timing.ENGINE_RUNNER] + if builder is not None: + command.append(str(builder)) + ran = subprocess.run(command, env=env, capture_output=True, text=True, cwd=tmp_path) + return json.loads(receipt.read_text()), ran + + +PACKAGE = {"policyengine_us/__init__.py": "X = 1\n", "policyengine_us/m.py": "Y = 2\n"} + + +def _printer(directory: Path) -> Path: + """A MOCK builder that prints the engine module's X.""" + directory.mkdir(parents=True, exist_ok=True) + script = directory / "builder.py" + script.write_text("import policyengine_us\nprint('X', policyengine_us.X)\n") + return script + + +@pytest.mark.parametrize("algorithm", ["sha256", "sha384", "sha512"]) +def test_a_clean_wheel_passes_the_runner_and_runs_its_builder(tmp_path, algorithm): + """MOCK install, real runner: a clean wheel, with any hash RECORD permits, + passes and the builder runs in the same process on its code.""" + site = _fake_install(tmp_path / "clean", "9.9.9", PACKAGE, algorithm) + found, ran = _runner(tmp_path, site, builder=_printer(tmp_path / "b")) + assert found["problems"] == [] and found["files_verified"] == 2 + assert ran.returncode == 0 and "X 1" in ran.stdout + + +def test_the_runner_refuses_what_is_imported_not_the_label(tmp_path): + """MOCK installs, real runner: a source tree shadowing the wheel under the + same version label, an editable install, a file changed after install, an + unrecorded module, an unrecorded native extension, a wrong version and a + run without a fresh bytecode cache each stop it before any builder runs.""" + import importlib.machinery + + site = _fake_install(tmp_path / "clean", "9.9.9", PACKAGE) + shadow = tmp_path / "shadow" + (shadow / "policyengine_us").mkdir(parents=True) + (shadow / "policyengine_us" / "__init__.py").write_text("X = 0\n") + + def problems(*paths, **kw): + found, ran = _runner(tmp_path, *paths, builder=_printer(tmp_path / "p"), **kw) + assert ran.returncode == 3 and "X " not in ran.stdout, ran.stdout + return " ".join(found["problems"]) + + assert "imports policyengine_us from" in problems(shadow, site) + editable = _fake_install(tmp_path / "editable", "9.9.9", PACKAGE) + (editable / "policyengine_us-9.9.9.dist-info" / "direct_url.json").write_text( + json.dumps({"url": "file:///src", "dir_info": {"editable": True}}) + ) + assert "an editable install" in problems(editable) + changed = _fake_install(tmp_path / "changed", "9.9.9", PACKAGE) + (changed / "policyengine_us" / "m.py").write_text("Y = 3\n") + assert "policyengine_us/m.py" in problems(changed) + extra = _fake_install(tmp_path / "extra", "9.9.9", PACKAGE) + (extra / "policyengine_us" / "extra.py").write_text("Z = 4\n") + assert "importable files the wheel lacks" in problems(extra) + native = _fake_install(tmp_path / "native", "9.9.9", PACKAGE) + suffix = importlib.machinery.EXTENSION_SUFFIXES[0] + (native / "policyengine_us" / f"m{suffix}").write_bytes(b"\0") + assert f"policyengine_us/m{suffix}" in problems(native) + assert "version 9.9.9, not 9.9.8" in problems(site, expected="9.9.8") + assert "no fresh bytecode-cache prefix" in problems(site, fresh_cache=False) + + +def test_stale_bytecode_cannot_run_in_place_of_the_verified_source(tmp_path): + """MOCK install, real runner: an unchecked-hash .pyc compiled from older + code sits in __pycache__ beside a source that matches RECORD. A plain + interpreter runs the stale bytecode; the runner's fresh cache prefix makes + the builder run the verified source.""" + import importlib.util + import os + import py_compile + import subprocess + import sys + + site = _fake_install(tmp_path / "stale", "9.9.9", PACKAGE) + source = site / "policyengine_us" / "__init__.py" + old = tmp_path / "old" / "__init__.py" + old.parent.mkdir() + old.write_text("X = 0\n") + py_compile.compile( + str(old), + cfile=importlib.util.cache_from_source(str(source)), + invalidation_mode=py_compile.PycInvalidationMode.UNCHECKED_HASH, + ) + plain = subprocess.run( + [sys.executable, "-c", "import policyengine_us; print('X', policyengine_us.X)"], + env={**os.environ, "PYTHONPATH": str(site), "PYTHONDONTWRITEBYTECODE": "1"}, + capture_output=True, + text=True, + cwd=tmp_path, + ) + assert "X 0" in plain.stdout # the stale bytecode is what a plain import runs + found, ran = _runner(tmp_path, site, builder=_printer(tmp_path / "b")) + assert found["problems"] == [] and "X 1" in ran.stdout + + +def test_a_package_beside_the_builder_cannot_shadow_the_engine(tmp_path): + """MOCK install, real runner: a policyengine_us package in the builder's + own directory is not on the import path (-P, and runpy adds no script + directory), so the builder runs the wheel's code.""" + site = _fake_install(tmp_path / "clean", "9.9.9", PACKAGE) + beside = tmp_path / "scripts" + (beside / "policyengine_us").mkdir(parents=True) + (beside / "policyengine_us" / "__init__.py").write_text("X = -1\n") + found, ran = _runner(tmp_path, site, builder=_printer(beside)) + assert found["problems"] == [] and "X 1" in ran.stdout + + +def test_a_symlink_in_the_package_is_refused(tmp_path): + """MOCK installs, real runner: a symlinked directory (a package that would + shadow a recorded module, its files hidden from the scan) and a symlinked + file each stop the runner before the builder runs; installs must be + copies, not links (so uv's symlink link mode is not supported).""" + outside = tmp_path / "outside" / "spm" + outside.mkdir(parents=True) + (outside / "__init__.py").write_text("X = 99\n") + linked_dir = _fake_install( + tmp_path / "dir", "9.9.9", {**PACKAGE, "policyengine_us/spm.py": "S = 1\n"} + ) + (linked_dir / "policyengine_us" / "spm").symlink_to( + outside, target_is_directory=True + ) + found, ran = _runner(tmp_path, linked_dir, builder=_printer(tmp_path / "b1")) + assert ran.returncode == 3 and "policyengine_us/spm" in " ".join(found["problems"]) + linked_file = _fake_install(tmp_path / "file", "9.9.9", PACKAGE) + target = tmp_path / "outside" / "m.py" + target.write_text("Y = 2\n") + (linked_file / "policyengine_us" / "m.py").unlink() + (linked_file / "policyengine_us" / "m.py").symlink_to(target) + found, ran = _runner(tmp_path, linked_file, builder=_printer(tmp_path / "b2")) + assert ran.returncode == 3 and "symlinks in the package" in " ".join( + found["problems"] + ) + + +def test_run_takes_only_fresh_receipts_and_outputs(tmp_path, monkeypatch): + """MOCK subprocess: an existing receipt, or an out-dir already holding a + computed.csv, is refused before anything runs; a run whose builder writes + nothing new is refused after it; and a relative receipt given outside the + repository is the file the child writes and the parent reads.""" + run, calls = _fake_run_writing() + monkeypatch.setattr(timing.subprocess, "run", run) + venv = _venv(tmp_path / "venv", "9.9.9") + out = tmp_path / "pass1" + out.mkdir() + receipt = tmp_path / "receipt.json" + receipt.write_text("{}") + with pytest.raises(timing.Refusal, match="each run writes a fresh receipt"): + timing.run_on_engine(venv, "9.9.9", receipt, ["--out-dir", str(out)]) + receipt.unlink() + _computed(VALUES, out / "computed.csv") + argv = ["run", "--venv", str(venv), "--engine", "9.9.9", "--receipt", str(receipt)] + with pytest.raises(timing.Refusal, match="fresh out-dir"): + timing.main([*argv, "--", "--out-dir", str(out)]) + (out / "computed.csv").unlink() + silent, _ = _fake_run_writing(computed=False) + monkeypatch.setattr(timing.subprocess, "run", silent) + with pytest.raises(timing.Refusal, match="wrote no new"): + timing.main([*argv, "--", "--out-dir", str(out)]) + # Outside the repository, a relative receipt and out-dir are resolved once. + monkeypatch.setattr(timing.subprocess, "run", run) + elsewhere = tmp_path / "elsewhere" + elsewhere.mkdir() + monkeypatch.chdir(elsewhere) + with pytest.raises(SystemExit) as stopped: + timing.main( + [ + "run", + "--venv", + str(venv), + "--engine", + "9.9.9", + "--receipt", + "r.json", + "--", + "--out-dir", + "fresh", + ] + ) + assert stopped.value.code == 1 # the MOCK builder's draft refusal + assert calls[-1][1]["PB_ENGINE_RECEIPT"] == str(elsewhere / "r.json") + assert (elsewhere / "r.json").is_file() and ( + elsewhere / "fresh/computed.csv" + ).is_file() + + +def test_builder_arguments_are_read_as_the_builder_reads_them(tmp_path, monkeypatch): + """The equals form, an abbreviation and a repeated flag (last wins) name + the same out-dir the builder would use; --computed-csv names the file the + run must write; paths are resolved here; an unknown argument is refused.""" + monkeypatch.chdir(tmp_path) + out = str(tmp_path / "b") + for argv in ( + ["--out-dir", "b"], + ["--out-dir=b"], + ["--out-d", "b"], + ["--out-dir", "a", "--out-dir=b"], + ): + canonical, computed = timing.builder_arguments([*argv, "--allow-draft"]) + assert canonical == ["--out-dir", out, "--allow-draft"], argv + assert computed == tmp_path / "b" / "computed.csv" + canonical, computed = timing.builder_arguments( + ["--actions=x.json", "--out-dir", "b", "--computed-csv", "c.csv"] + ) + assert canonical == [ + "--actions", + str(tmp_path / "x.json"), + "--out-dir", + out, + "--computed-csv", + str(tmp_path / "c.csv"), + ] + assert computed == tmp_path / "c.csv" + assert timing.builder_arguments(["--evidence-request", "r.json"])[1] is None + with pytest.raises(timing.Refusal, match="cannot take these arguments"): + timing.builder_arguments(["--out-dir", "b", "--unknown"]) + + +def test_the_replica_takes_exactly_the_builders_flags(): + """builder_arguments' parser has the builder's own flags, so argparse + resolves equals forms and abbreviations the same way in both.""" + import ast + + tree = ast.parse(timing.BUILDER.read_text()) + (main,) = [ + n for n in tree.body if isinstance(n, ast.FunctionDef) and n.name == "main" + ] + flags = { + call.args[0].value: any( + k.arg == "action" and getattr(k.value, "value", None) == "store_true" + for k in call.keywords + ) + for call in ast.walk(main) + if isinstance(call, ast.Call) + and getattr(call.func, "attr", None) == "add_argument" + } + assert {f for f, switch in flags.items() if switch} == set(timing.BUILDER_SWITCHES) + assert {f for f, switch in flags.items() if not switch} == set( + timing.BUILDER_VALUE_FLAGS + ) + + +def test_run_checks_the_file_the_builder_actually_writes(tmp_path, monkeypatch): + """MOCK subprocess: with the equals form an old computed.csv is still + refused, and with --computed-csv the run checks that file, not the + out-dir's.""" + + def run(command, env=None, **kw): + Path(env["PB_ENGINE_RECEIPT"]).write_text( + json.dumps({"version": "9.9.9", "files_verified": 2, "problems": []}) + ) + target = Path(command[command.index("--computed-csv") + 1]) + _computed(VALUES, target) + return type("Ran", (), {"returncode": 1, "stdout": "", "stderr": ""})() + + monkeypatch.setattr(timing.subprocess, "run", run) + venv = _venv(tmp_path / "venv", "9.9.9") + old = tmp_path / "old" + old.mkdir() + _computed(VALUES, old / "computed.csv") + base = ["run", "--venv", str(venv), "--engine", "9.9.9"] + with pytest.raises(timing.Refusal, match="fresh out-dir"): + timing.main( + [*base, "--receipt", str(tmp_path / "r1.json"), "--", f"--out-dir={old}"] + ) + with pytest.raises(SystemExit) as stopped: + timing.main( + [ + *base, + "--receipt", + str(tmp_path / "r2.json"), + "--", + "--out-dir", + str(tmp_path / "new"), + "--computed-csv", + str(tmp_path / "c.csv"), + ] + ) + assert stopped.value.code == 1 and (tmp_path / "c.csv").is_file() From 196a867212dd8d2d5bafd91fa5da65d2e1ca7841 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Thu, 22 Oct 2026 22:16:52 -0400 Subject: [PATCH 2/4] Commit the staged build as reference-build/, which .gitignore does not hide .gitignore excludes every build/ directory, so the first commit left the staged reference files out. The copy is now reference-build/, the name the release drivers give an installed build's copy. The builder's docstring names the directory, so the build was run again on 2.60.0: every file is byte-identical except the sidecar's builder sha256 and time, and the publication check was rerun (2.60.0 still the newest release). Co-Authored-By: Claude Opus 5.5 --- .../2026-10-22-engine-upgrade/README.md | 14 +- .../hand_corrected_narratives.md | 2 +- .../reference-build/computed.csv | 1985 +++++++++++ .../reference-build/reference_exclusions.json | 689 ++++ .../reference-build/reference_outputs.csv | 1985 +++++++++++ .../reference_outputs.csv.meta.json | 3132 +++++++++++++++++ .../reference-build/reference_traces.json | 18 + .../scripts/build_references_upgrade.py | 2 +- .../scripts/sweep_timing.py | 4 +- .../verification/sweep_timing.json | 8 +- tests/test_build_references_upgrade_1022.py | 2 +- tests/test_sweep_timing_1022.py | 11 +- 12 files changed, 7831 insertions(+), 21 deletions(-) create mode 100644 reference_audit/2026-10-22-engine-upgrade/reference-build/computed.csv create mode 100644 reference_audit/2026-10-22-engine-upgrade/reference-build/reference_exclusions.json create mode 100644 reference_audit/2026-10-22-engine-upgrade/reference-build/reference_outputs.csv create mode 100644 reference_audit/2026-10-22-engine-upgrade/reference-build/reference_outputs.csv.meta.json create mode 100644 reference_audit/2026-10-22-engine-upgrade/reference-build/reference_traces.json diff --git a/reference_audit/2026-10-22-engine-upgrade/README.md b/reference_audit/2026-10-22-engine-upgrade/README.md index 6fa1bda3..6169da8a 100644 --- a/reference_audit/2026-10-22-engine-upgrade/README.md +++ b/reference_audit/2026-10-22-engine-upgrade/README.md @@ -7,7 +7,7 @@ uploaded at 22:47:49 UTC on 2026-10-22 and installed at 01:44:20 UTC on 2026-10- sweep wrote its first output at 01:45:50. The directory is named for the day the audit began (2026-10-22); the records date the upgrade by its UTC day, 2026-10-23. -The build is staged, not installed. `build/` holds the reference CSV, sidecar and exclusion +The build is staged, not installed. `reference-build/` holds the reference CSV, sidecar and exclusion record that the next board release installs into `paper/snapshot/20260501/runs/us_full_run_20260612_policyengine_4_16_1_populace/`. Until then the published board, release 20261014, stays on 2.41.0. @@ -37,7 +37,7 @@ and Arkansas's applies from the 2025-26 school year. Both are standing statutes. The school-meal output asks "whether PolicyEngine returns positive annual free school meal support". Each of these households is in the paid tier for lunch, but its K-12 children now get a free breakfast. `final_actions.json` gives each change's basis, with the figures from -`build/reference_traces.json`. +`reference-build/reference_traces.json`. Each named pull request (#10036, #10158, #10185 and #10238) is an ancestor of 2.60.0's release commit, 2bc4ccc970. #10238 is not in 2.59.0's, 05813807e1. @@ -99,20 +99,20 @@ At 02:11 UTC on 2026-10-23, PolicyBench read PyPI again, and 2.60.0 was still th before it publishes. After installing the build, it runs: ``` -scripts/sweep_timing.py check --build build --snapshot +scripts/sweep_timing.py check --build reference-build --snapshot ``` with `--check-venv` if a newer release is out. ## Installing the build (the next board release) -1. Copy `build/reference_outputs.csv`, `reference_outputs.csv.meta.json` and +1. Copy `reference-build/reference_outputs.csv`, `reference_outputs.csv.meta.json` and `reference_exclusions.json` into the run directory, and move pyproject's policyengine-us pin (and `uv.lock`) to 2.60.0. 2. Rebuild the reference narratives of the four changed outputs. No writer call is needed: ``` - scripts/narratives_upgrade.py --references build \ + scripts/narratives_upgrade.py --references reference-build \ --explanations annotations/us_full_run_20260612_policyengine_4_16_1_populace/us_case_reference_explanations.csv \ --hand-corrected hand_corrected_narratives.json --out ``` @@ -132,13 +132,13 @@ files or this build's. upstream pull requests added to four bases and five reasons; no placement changed. - `actions_from_cells.py`: drafts the actions from a first pass. Its rules recognize the two kinds of scored move this upgrade makes. -- `scripts/build_references_upgrade.py`: the builder (sha256 `2aa0a6b1…`, which the sidecar +- `scripts/build_references_upgrade.py`: the builder (sha256 `d4b00204…`, which the sidecar pins). It is the 2026-10-12 builder on release 20261014's references, without a release spec. - `scripts/sweep_timing.py`: the timing record and the publication check. The check takes `--snapshot`, the committed copy the build must equal. - `scripts/narratives_upgrade.py`: the reference narratives. A run whose narratives are all hand-corrected needs no API key. -- `build/`: the build. `computed.csv` is every output on 2.60.0, byte-identical to the sweep's +- `reference-build/`: the build. `computed.csv` is every output on 2.60.0, byte-identical to the sweep's first output. - `hand_corrected_narratives.json` and `.md`: the four changed outputs' reference narratives. - `verification/sweep_timing.json` and `verification/superseded_2_59_0.json`. diff --git a/reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.md b/reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.md index 2b7e691e..c370e4e9 100644 --- a/reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.md +++ b/reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.md @@ -5,7 +5,7 @@ `scripts/narratives_upgrade.py --hand-corrected`, so the narrative writer (claude-haiku-4-5) is not called. The 2026-10-12 upgrade's writer misstated the change behind six of its nine outputs. -Each text states figures from the 2.60.0 build's traces (`build/reference_traces.json`). +Each text states figures from the 2.60.0 build's traces (`reference-build/reference_traces.json`). `tests/test_build_references_upgrade_1022.py` checks each figure against the trace and recomputes every sum the texts state. Each rule a text names is the one the upstream pull request encodes, with its law: #10036 for California's MCE, and #10238 for the Pennsylvania and diff --git a/reference_audit/2026-10-22-engine-upgrade/reference-build/computed.csv b/reference_audit/2026-10-22-engine-upgrade/reference-build/computed.csv new file mode 100644 index 00000000..67542582 --- /dev/null +++ b/reference_audit/2026-10-22-engine-upgrade/reference-build/computed.csv @@ -0,0 +1,1985 @@ +fix,scenario_id,state,variable,frozen,recomputed,delta,moved +latest_final,scenario_000,TX,federal_income_tax_before_refundable_credits,2906.45361328125,2906.45361328125,0.0,False +latest_final,scenario_000,TX,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_000,TX,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_000,TX,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_000,TX,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_000,TX,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_000,TX,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_000,TX,snap,0.0,0.0,0.0,False +latest_final,scenario_000,TX,ssi,0.0,0.0,0.0,False +latest_final,scenario_000,TX,tanf,0.0,0.0,0.0,False +latest_final,scenario_000,TX,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_000,TX,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_000,TX,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_000,TX,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_000,TX,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_000,TX,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_001,VA,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_001,VA,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_001,VA,payroll_tax,2223.393798828125,2223.393798828125,0.0,False +latest_final,scenario_001,VA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_001,VA,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_001,VA,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_001,VA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_001,VA,snap,0.0,0.0,0.0,False +latest_final,scenario_001,VA,ssi,0.0,0.0,0.0,False +latest_final,scenario_001,VA,tanf,0.0,0.0,0.0,False +latest_final,scenario_001,VA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_001,VA,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_001,VA,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_001,VA,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_001,VA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_001,VA,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_001,VA,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_001,VA,spouse_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_001,VA,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_001,VA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_002,WA,federal_income_tax_before_refundable_credits,0.0,1890.300048828125,1890.300048828125,True +latest_final,scenario_002,WA,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_002,WA,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_002,WA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_002,WA,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_002,WA,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_002,WA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_002,WA,snap,0.0,0.0,0.0,False +latest_final,scenario_002,WA,ssi,0.0,0.0,0.0,False +latest_final,scenario_002,WA,tanf,0.0,0.0,0.0,False +latest_final,scenario_002,WA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_002,WA,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_002,WA,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_002,WA,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_002,WA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_002,WA,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_002,WA,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_002,WA,spouse_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_002,WA,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_002,WA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_003,TX,federal_income_tax_before_refundable_credits,22400.654296875,22400.654296875,0.0,False +latest_final,scenario_003,TX,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_003,TX,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_003,TX,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_003,TX,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_003,TX,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_003,TX,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_003,TX,snap,0.0,0.0,0.0,False +latest_final,scenario_003,TX,ssi,0.0,0.0,0.0,False +latest_final,scenario_003,TX,tanf,0.0,0.0,0.0,False +latest_final,scenario_003,TX,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_003,TX,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_003,TX,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_003,TX,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_003,TX,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_003,TX,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_003,TX,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_003,TX,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_003,TX,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_003,TX,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_004,NY,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_004,NY,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_004,NY,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_004,NY,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_004,NY,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_004,NY,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_004,NY,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_004,NY,snap,0.0,0.0,0.0,False +latest_final,scenario_004,NY,ssi,0.0,0.0,0.0,False +latest_final,scenario_004,NY,tanf,0.0,0.0,0.0,False +latest_final,scenario_004,NY,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_004,NY,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_004,NY,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_004,NY,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_004,NY,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_004,NY,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_004,NY,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_004,NY,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_004,NY,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_004,NY,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_005,CA,federal_income_tax_before_refundable_credits,106505.8984375,108525.578125,2019.6796875,True +latest_final,scenario_005,CA,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_005,CA,payroll_tax,36044.0,36044.0,0.0,False +latest_final,scenario_005,CA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_005,CA,state_income_tax_before_refundable_credits,40975.25390625,40975.25390625,0.0,False +latest_final,scenario_005,CA,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_005,CA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_005,CA,snap,0.0,0.0,0.0,False +latest_final,scenario_005,CA,ssi,0.0,0.0,0.0,False +latest_final,scenario_005,CA,tanf,0.0,0.0,0.0,False +latest_final,scenario_005,CA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_005,CA,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_005,CA,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_005,CA,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_005,CA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_005,CA,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_005,CA,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_005,CA,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_005,CA,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_005,CA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_007,ID,federal_income_tax_before_refundable_credits,3707.695068359375,3707.695068359375,0.0,False +latest_final,scenario_007,ID,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_007,ID,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_007,ID,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_007,ID,state_income_tax_before_refundable_credits,661.3170166015625,661.3170166015625,0.0,False +latest_final,scenario_007,ID,state_refundable_credits,155.0,155.0,0.0,False +latest_final,scenario_007,ID,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_007,ID,snap,0.0,0.0,0.0,False +latest_final,scenario_007,ID,ssi,0.0,0.0,0.0,False +latest_final,scenario_007,ID,tanf,0.0,0.0,0.0,False +latest_final,scenario_007,ID,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_007,ID,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_007,ID,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_007,ID,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_007,ID,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_007,ID,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,federal_refundable_credits,12433.611328125,12433.611328125,0.0,False +latest_final,scenario_008,NJ,payroll_tax,2276.659912109375,2276.659912109375,0.0,False +latest_final,scenario_008,NJ,self_employment_tax,565.1820068359375,565.1820068359375,0.0,False +latest_final,scenario_008,NJ,state_income_tax_before_refundable_credits,264.80999755859375,264.80999755859375,0.0,False +latest_final,scenario_008,NJ,state_refundable_credits,5842.39990234375,5842.39990234375,0.0,False +latest_final,scenario_008,NJ,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,snap,15108.0,15108.0,0.0,False +latest_final,scenario_008,NJ,ssi,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,tanf,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child2_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child3_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child4_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child5_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child6_wic_eligible,1.0,1.0,0.0,False +latest_final,scenario_008,NJ,head_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_008,NJ,spouse_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_008,NJ,child1_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_008,NJ,child2_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_008,NJ,child3_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_008,NJ,child4_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_008,NJ,child5_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_008,NJ,child6_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_008,NJ,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child2_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child3_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child4_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child5_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child6_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child2_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child3_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child4_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child5_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child6_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child1_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child2_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child3_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child4_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child5_head_start_eligible,1.0,1.0,0.0,False +latest_final,scenario_008,NJ,child6_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child1_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child2_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child3_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child4_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child5_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_008,NJ,child6_early_head_start_eligible,1.0,1.0,0.0,False +latest_final,scenario_008,NJ,free_school_meals_eligible,1.0,1.0,0.0,False +latest_final,scenario_008,NJ,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_009,NC,federal_income_tax_before_refundable_credits,8348.0,8348.0,0.0,False +latest_final,scenario_009,NC,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_009,NC,payroll_tax,4590.0,4590.0,0.0,False +latest_final,scenario_009,NC,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_009,NC,state_income_tax_before_refundable_credits,2190.510009765625,2190.510009765625,0.0,False +latest_final,scenario_009,NC,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_009,NC,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_009,NC,snap,0.0,0.0,0.0,False +latest_final,scenario_009,NC,ssi,0.0,0.0,0.0,False +latest_final,scenario_009,NC,tanf,0.0,0.0,0.0,False +latest_final,scenario_009,NC,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_009,NC,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_009,NC,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_009,NC,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_009,NC,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_009,NC,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_009,NC,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_009,NC,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_009,NC,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_009,NC,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_012,MS,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_012,MS,federal_refundable_credits,6127.0,6127.0,0.0,False +latest_final,scenario_012,MS,payroll_tax,1683.0,1683.0,0.0,False +latest_final,scenario_012,MS,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_012,MS,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_012,MS,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_012,MS,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_012,MS,snap,4884.0,4884.0,0.0,False +latest_final,scenario_012,MS,ssi,0.0,0.0,0.0,False +latest_final,scenario_012,MS,tanf,0.0,0.0,0.0,False +latest_final,scenario_012,MS,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_012,MS,spouse_wic_eligible,1.0,1.0,0.0,False +latest_final,scenario_012,MS,child1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_012,MS,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_012,MS,spouse_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_012,MS,child1_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_012,MS,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_012,MS,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_012,MS,child1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_012,MS,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_012,MS,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_012,MS,child1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_012,MS,child1_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_012,MS,child1_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_012,MS,free_school_meals_eligible,1.0,1.0,0.0,False +latest_final,scenario_012,MS,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_013,AZ,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_013,AZ,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_013,AZ,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_013,AZ,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_013,AZ,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_013,AZ,state_refundable_credits,25.0,25.0,0.0,False +latest_final,scenario_013,AZ,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_013,AZ,snap,240.0,240.0,0.0,False +latest_final,scenario_013,AZ,ssi,0.0,0.0,0.0,False +latest_final,scenario_013,AZ,tanf,0.0,0.0,0.0,False +latest_final,scenario_013,AZ,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_013,AZ,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_013,AZ,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_013,AZ,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_013,AZ,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_013,AZ,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_014,WV,federal_income_tax_before_refundable_credits,6311.31787109375,6311.31787109375,0.0,False +latest_final,scenario_014,WV,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_014,WV,payroll_tax,6802.96484375,6802.96484375,0.0,False +latest_final,scenario_014,WV,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_014,WV,state_income_tax_before_refundable_credits,3092.186279296875,3092.186279296875,0.0,False +latest_final,scenario_014,WV,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_014,WV,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_014,WV,snap,0.0,0.0,0.0,False +latest_final,scenario_014,WV,ssi,0.0,0.0,0.0,False +latest_final,scenario_014,WV,tanf,0.0,0.0,0.0,False +latest_final,scenario_014,WV,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_014,WV,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_014,WV,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_014,WV,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_014,WV,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_014,WV,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_014,WV,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_014,WV,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_014,WV,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_014,WV,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_015,IN,federal_income_tax_before_refundable_credits,2969.1259765625,2969.1259765625,0.0,False +latest_final,scenario_015,IN,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_015,IN,payroll_tax,3442.5,3442.5,0.0,False +latest_final,scenario_015,IN,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_015,IN,state_income_tax_before_refundable_credits,1236.3267822265625,1236.3267822265625,0.0,False +latest_final,scenario_015,IN,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_015,IN,local_income_tax,670.5501098632812,670.5501098632812,0.0,False +latest_final,scenario_015,IN,snap,0.0,0.0,0.0,False +latest_final,scenario_015,IN,ssi,0.0,0.0,0.0,False +latest_final,scenario_015,IN,tanf,0.0,0.0,0.0,False +latest_final,scenario_015,IN,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_015,IN,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_015,IN,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_015,IN,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_015,IN,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_015,IN,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_016,FL,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_016,FL,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_016,FL,payroll_tax,2649.80224609375,2649.80224609375,0.0,False +latest_final,scenario_016,FL,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_016,FL,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_016,FL,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_016,FL,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_016,FL,snap,0.0,0.0,0.0,False +latest_final,scenario_016,FL,ssi,0.0,0.0,0.0,False +latest_final,scenario_016,FL,tanf,0.0,0.0,0.0,False +latest_final,scenario_016,FL,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_016,FL,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_016,FL,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_016,FL,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_016,FL,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_016,FL,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_018,AZ,federal_income_tax_before_refundable_credits,5211.05078125,5211.05078125,0.0,False +latest_final,scenario_018,AZ,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_018,AZ,payroll_tax,5202.38232421875,5202.38232421875,0.0,False +latest_final,scenario_018,AZ,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_018,AZ,state_income_tax_before_refundable_credits,1137.30224609375,1137.30224609375,0.0,False +latest_final,scenario_018,AZ,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_018,AZ,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_018,AZ,snap,0.0,0.0,0.0,False +latest_final,scenario_018,AZ,ssi,0.0,0.0,0.0,False +latest_final,scenario_018,AZ,tanf,0.0,0.0,0.0,False +latest_final,scenario_018,AZ,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_018,AZ,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_018,AZ,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_018,AZ,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_018,AZ,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_018,AZ,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_020,TX,federal_income_tax_before_refundable_credits,68056.7109375,68334.734375,278.0234375,True +latest_final,scenario_020,TX,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_020,TX,payroll_tax,16689.0,16689.0,0.0,False +latest_final,scenario_020,TX,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_020,TX,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_020,TX,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_020,TX,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_020,TX,snap,0.0,0.0,0.0,False +latest_final,scenario_020,TX,ssi,0.0,0.0,0.0,False +latest_final,scenario_020,TX,tanf,0.0,0.0,0.0,False +latest_final,scenario_020,TX,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_020,TX,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_020,TX,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_020,TX,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_020,TX,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_020,TX,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_021,MO,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_021,MO,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_021,MO,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_021,MO,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_021,MO,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_021,MO,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_021,MO,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_021,MO,snap,0.0,0.0,0.0,False +latest_final,scenario_021,MO,ssi,0.0,0.0,0.0,False +latest_final,scenario_021,MO,tanf,0.0,0.0,0.0,False +latest_final,scenario_021,MO,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_021,MO,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_021,MO,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_021,MO,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_021,MO,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_021,MO,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_022,CA,federal_income_tax_before_refundable_credits,11113.5703125,11113.5703125,0.0,False +latest_final,scenario_022,CA,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_022,CA,payroll_tax,4710.83251953125,4710.83251953125,0.0,False +latest_final,scenario_022,CA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_022,CA,state_income_tax_before_refundable_credits,1968.805419921875,1968.805419921875,0.0,False +latest_final,scenario_022,CA,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_022,CA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_022,CA,snap,0.0,0.0,0.0,False +latest_final,scenario_022,CA,ssi,0.0,0.0,0.0,False +latest_final,scenario_022,CA,tanf,0.0,0.0,0.0,False +latest_final,scenario_022,CA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_022,CA,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_022,CA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_022,CA,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_022,CA,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_022,CA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_023,CA,federal_income_tax_before_refundable_credits,643.43359375,643.43359375,0.0,False +latest_final,scenario_023,CA,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_023,CA,payroll_tax,1561.1168212890625,1561.1168212890625,0.0,False +latest_final,scenario_023,CA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_023,CA,state_income_tax_before_refundable_credits,12.776718139648438,12.776718139648438,0.0,False +latest_final,scenario_023,CA,state_refundable_credits,95.15400695800781,95.15400695800781,0.0,False +latest_final,scenario_023,CA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_023,CA,snap,461.3397216796875,408.0,-53.3397216796875,True +latest_final,scenario_023,CA,ssi,0.0,0.0,0.0,False +latest_final,scenario_023,CA,tanf,0.0,0.0,0.0,False +latest_final,scenario_023,CA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_023,CA,head_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_023,CA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_023,CA,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_023,CA,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_023,CA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_025,OH,federal_income_tax_before_refundable_credits,7031.03564453125,7031.03564453125,0.0,False +latest_final,scenario_025,OH,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_025,OH,payroll_tax,4798.48486328125,4798.48486328125,0.0,False +latest_final,scenario_025,OH,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_025,OH,state_income_tax_before_refundable_credits,1916.606201171875,1916.606201171875,0.0,False +latest_final,scenario_025,OH,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_025,OH,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_025,OH,snap,0.0,0.0,0.0,False +latest_final,scenario_025,OH,ssi,0.0,0.0,0.0,False +latest_final,scenario_025,OH,tanf,0.0,0.0,0.0,False +latest_final,scenario_025,OH,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_025,OH,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_025,OH,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_025,OH,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_025,OH,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_025,OH,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_025,OH,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_025,OH,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_025,OH,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_025,OH,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_026,NC,federal_refundable_credits,2013.4892578125,2013.4892578125,0.0,False +latest_final,scenario_026,NC,payroll_tax,6518.474609375,6518.474609375,0.0,False +latest_final,scenario_026,NC,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_026,NC,state_income_tax_before_refundable_credits,2086.79052734375,2086.79052734375,0.0,False +latest_final,scenario_026,NC,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_026,NC,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_026,NC,snap,0.0,0.0,0.0,False +latest_final,scenario_026,NC,ssi,0.0,0.0,0.0,False +latest_final,scenario_026,NC,tanf,0.0,0.0,0.0,False +latest_final,scenario_026,NC,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,child1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,child2_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,child3_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,child1_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_026,NC,child2_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_026,NC,child3_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_026,NC,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,child1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,child2_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,child3_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,child1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,child2_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,child3_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,child1_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,child2_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,child3_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,child1_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,child2_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,child3_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_026,NC,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_027,CT,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_027,CT,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_027,CT,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_027,CT,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_027,CT,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_027,CT,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_027,CT,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_027,CT,snap,288.0,288.0,0.0,False +latest_final,scenario_027,CT,ssi,0.0,0.0,0.0,False +latest_final,scenario_027,CT,tanf,0.0,0.0,0.0,False +latest_final,scenario_027,CT,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_027,CT,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_027,CT,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_027,CT,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_027,CT,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_027,CT,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_027,CT,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_027,CT,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_027,CT,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_027,CT,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_028,PA,federal_refundable_credits,3274.927978515625,3274.927978515625,0.0,False +latest_final,scenario_028,PA,payroll_tax,4632.0,4632.0,0.0,False +latest_final,scenario_028,PA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_028,PA,state_income_tax_before_refundable_credits,1842.3070068359375,1842.3070068359375,0.0,False +latest_final,scenario_028,PA,state_refundable_credits,62.41279220581055,62.41279220581055,0.0,False +latest_final,scenario_028,PA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_028,PA,snap,0.0,0.0,0.0,False +latest_final,scenario_028,PA,ssi,0.0,0.0,0.0,False +latest_final,scenario_028,PA,tanf,0.0,0.0,0.0,False +latest_final,scenario_028,PA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,child1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,child2_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,child3_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,child1_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,child2_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,child3_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,child1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,child2_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,child3_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,child1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,child2_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,child3_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,child1_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,child2_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,child3_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,child1_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,child2_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,child3_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_028,PA,free_school_meals_eligible,0.0,1.0,1.0,True +latest_final,scenario_028,PA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_029,OK,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_029,OK,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_029,OK,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_029,OK,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_029,OK,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_029,OK,state_refundable_credits,40.0,40.0,0.0,False +latest_final,scenario_029,OK,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_029,OK,snap,0.0,0.0,0.0,False +latest_final,scenario_029,OK,ssi,0.0,0.0,0.0,False +latest_final,scenario_029,OK,tanf,0.0,0.0,0.0,False +latest_final,scenario_029,OK,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_029,OK,head_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_029,OK,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_029,OK,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_029,OK,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_029,OK,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_030,TX,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_030,TX,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_030,TX,payroll_tax,994.5,994.5,0.0,False +latest_final,scenario_030,TX,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_030,TX,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_030,TX,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_030,TX,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_030,TX,snap,288.0,288.0,0.0,False +latest_final,scenario_030,TX,ssi,0.0,0.0,0.0,False +latest_final,scenario_030,TX,tanf,0.0,0.0,0.0,False +latest_final,scenario_030,TX,head_wic_eligible,1.0,1.0,0.0,False +latest_final,scenario_030,TX,head_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_030,TX,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_030,TX,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_030,TX,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_030,TX,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_031,CA,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_031,CA,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_031,CA,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_031,CA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_031,CA,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_031,CA,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_031,CA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_031,CA,snap,0.0,288.0,288.0,True +latest_final,scenario_031,CA,ssi,0.0,0.0,0.0,False +latest_final,scenario_031,CA,tanf,0.0,0.0,0.0,False +latest_final,scenario_031,CA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_031,CA,head_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_031,CA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_031,CA,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_031,CA,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_031,CA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_032,MN,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_032,MN,federal_refundable_credits,6127.0,6127.0,0.0,False +latest_final,scenario_032,MN,payroll_tax,2346.10009765625,2346.10009765625,0.0,False +latest_final,scenario_032,MN,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_032,MN,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_032,MN,state_refundable_credits,2187.60009765625,2187.60009765625,0.0,False +latest_final,scenario_032,MN,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_032,MN,snap,0.0,0.0,0.0,False +latest_final,scenario_032,MN,ssi,0.0,0.0,0.0,False +latest_final,scenario_032,MN,tanf,0.0,0.0,0.0,False +latest_final,scenario_032,MN,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_032,MN,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_032,MN,child1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_032,MN,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_032,MN,spouse_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_032,MN,child1_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_032,MN,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_032,MN,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_032,MN,child1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_032,MN,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_032,MN,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_032,MN,child1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_032,MN,child1_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_032,MN,child1_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_032,MN,free_school_meals_eligible,1.0,1.0,0.0,False +latest_final,scenario_032,MN,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_033,SD,federal_income_tax_before_refundable_credits,3818.148193359375,3818.148193359375,0.0,False +latest_final,scenario_033,SD,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_033,SD,payroll_tax,6043.5,6043.5,0.0,False +latest_final,scenario_033,SD,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_033,SD,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_033,SD,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_033,SD,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_033,SD,snap,0.0,0.0,0.0,False +latest_final,scenario_033,SD,ssi,0.0,0.0,0.0,False +latest_final,scenario_033,SD,tanf,0.0,0.0,0.0,False +latest_final,scenario_033,SD,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_033,SD,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_033,SD,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_033,SD,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_033,SD,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_033,SD,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_033,SD,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_033,SD,spouse_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_033,SD,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_033,SD,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_036,NJ,federal_income_tax_before_refundable_credits,4926.39990234375,4926.39990234375,0.0,False +latest_final,scenario_036,NJ,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_036,NJ,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_036,NJ,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_036,NJ,state_income_tax_before_refundable_credits,1724.155029296875,1724.155029296875,0.0,False +latest_final,scenario_036,NJ,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_036,NJ,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_036,NJ,snap,0.0,0.0,0.0,False +latest_final,scenario_036,NJ,ssi,0.0,0.0,0.0,False +latest_final,scenario_036,NJ,tanf,0.0,0.0,0.0,False +latest_final,scenario_036,NJ,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_036,NJ,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_036,NJ,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_036,NJ,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_036,NJ,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_036,NJ,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_037,NC,federal_income_tax_before_refundable_credits,1649.2513427734375,1649.2513427734375,0.0,False +latest_final,scenario_037,NC,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_037,NC,payroll_tax,3208.668701171875,3208.668701171875,0.0,False +latest_final,scenario_037,NC,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_037,NC,state_income_tax_before_refundable_credits,1148.69921875,1148.69921875,0.0,False +latest_final,scenario_037,NC,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_037,NC,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_037,NC,snap,0.0,0.0,0.0,False +latest_final,scenario_037,NC,ssi,0.0,0.0,0.0,False +latest_final,scenario_037,NC,tanf,0.0,0.0,0.0,False +latest_final,scenario_037,NC,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_037,NC,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_037,NC,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_037,NC,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_037,NC,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_037,NC,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_038,LA,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_038,LA,federal_refundable_credits,10225.353515625,10225.353515625,0.0,False +latest_final,scenario_038,LA,payroll_tax,571.2637329101562,571.2637329101562,0.0,False +latest_final,scenario_038,LA,self_employment_tax,2193.612548828125,2193.612548828125,0.0,False +latest_final,scenario_038,LA,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_038,LA,state_refundable_credits,365.8000183105469,365.8000183105469,0.0,False +latest_final,scenario_038,LA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_038,LA,snap,7212.0,7212.0,0.0,False +latest_final,scenario_038,LA,ssi,0.0,0.0,0.0,False +latest_final,scenario_038,LA,tanf,0.0,0.0,0.0,False +latest_final,scenario_038,LA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_038,LA,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_038,LA,child1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_038,LA,child2_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_038,LA,head_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_038,LA,spouse_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_038,LA,child1_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_038,LA,child2_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_038,LA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_038,LA,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_038,LA,child1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_038,LA,child2_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_038,LA,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_038,LA,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_038,LA,child1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_038,LA,child2_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_038,LA,child1_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_038,LA,child2_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_038,LA,child1_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_038,LA,child2_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_038,LA,free_school_meals_eligible,1.0,1.0,0.0,False +latest_final,scenario_038,LA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_039,VA,federal_income_tax_before_refundable_credits,8596.0283203125,8596.0283203125,0.0,False +latest_final,scenario_039,VA,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_039,VA,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_039,VA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_039,VA,state_income_tax_before_refundable_credits,1975.7982177734375,1975.7982177734375,0.0,False +latest_final,scenario_039,VA,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_039,VA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_039,VA,snap,0.0,0.0,0.0,False +latest_final,scenario_039,VA,ssi,0.0,0.0,0.0,False +latest_final,scenario_039,VA,tanf,0.0,0.0,0.0,False +latest_final,scenario_039,VA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_039,VA,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_039,VA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_039,VA,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_039,VA,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_039,VA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_040,AZ,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_040,AZ,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_040,AZ,payroll_tax,2142.0,2142.0,0.0,False +latest_final,scenario_040,AZ,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_040,AZ,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_040,AZ,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_040,AZ,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_040,AZ,snap,0.0,0.0,0.0,False +latest_final,scenario_040,AZ,ssi,0.0,0.0,0.0,False +latest_final,scenario_040,AZ,tanf,0.0,0.0,0.0,False +latest_final,scenario_040,AZ,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_040,AZ,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_040,AZ,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_040,AZ,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_040,AZ,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_040,AZ,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_040,AZ,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_040,AZ,spouse_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_040,AZ,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_040,AZ,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_042,WI,federal_income_tax_before_refundable_credits,2361.96484375,2361.96484375,0.0,False +latest_final,scenario_042,WI,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_042,WI,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_042,WI,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_042,WI,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_042,WI,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_042,WI,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_042,WI,snap,0.0,0.0,0.0,False +latest_final,scenario_042,WI,ssi,0.0,0.0,0.0,False +latest_final,scenario_042,WI,tanf,0.0,0.0,0.0,False +latest_final,scenario_042,WI,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_042,WI,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_042,WI,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_042,WI,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_042,WI,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_042,WI,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_043,CO,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_043,CO,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_043,CO,payroll_tax,330.7310791015625,330.7310791015625,0.0,False +latest_final,scenario_043,CO,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_043,CO,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_043,CO,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_043,CO,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_043,CO,snap,3576.0,3576.0,0.0,False +latest_final,scenario_043,CO,ssi,0.0,0.0,0.0,False +latest_final,scenario_043,CO,tanf,0.0,0.0,0.0,False +latest_final,scenario_043,CO,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_043,CO,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_043,CO,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_043,CO,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_043,CO,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_043,CO,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_044,KS,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_044,KS,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_044,KS,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_044,KS,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_044,KS,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_044,KS,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_044,KS,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_044,KS,snap,0.0,0.0,0.0,False +latest_final,scenario_044,KS,ssi,0.0,0.0,0.0,False +latest_final,scenario_044,KS,tanf,0.0,0.0,0.0,False +latest_final,scenario_044,KS,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_044,KS,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_044,KS,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_044,KS,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_044,KS,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_044,KS,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_044,KS,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_044,KS,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_044,KS,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_044,KS,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_045,MI,federal_income_tax_before_refundable_credits,2173.07080078125,2173.07080078125,0.0,False +latest_final,scenario_045,MI,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_045,MI,payroll_tax,2775.08251953125,2775.08251953125,0.0,False +latest_final,scenario_045,MI,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_045,MI,state_income_tax_before_refundable_credits,1290.9625244140625,1290.9625244140625,0.0,False +latest_final,scenario_045,MI,state_refundable_credits,760.7887573242188,760.7887573242188,0.0,False +latest_final,scenario_045,MI,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_045,MI,snap,0.0,0.0,0.0,False +latest_final,scenario_045,MI,ssi,0.0,0.0,0.0,False +latest_final,scenario_045,MI,tanf,0.0,0.0,0.0,False +latest_final,scenario_045,MI,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_045,MI,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_045,MI,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_045,MI,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_045,MI,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_045,MI,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,federal_income_tax_before_refundable_credits,499.71484375,499.71484375,0.0,False +latest_final,scenario_046,OK,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_046,OK,payroll_tax,7038.0,7038.0,0.0,False +latest_final,scenario_046,OK,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_046,OK,state_income_tax_before_refundable_credits,2739.135009765625,2739.135009765625,0.0,False +latest_final,scenario_046,OK,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_046,OK,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_046,OK,snap,0.0,0.0,0.0,False +latest_final,scenario_046,OK,ssi,0.0,0.0,0.0,False +latest_final,scenario_046,OK,tanf,0.0,0.0,0.0,False +latest_final,scenario_046,OK,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,child1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,child2_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,child1_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,child2_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,child1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,child2_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,child1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,child2_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,child1_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,child2_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,child1_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,child2_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_046,OK,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_048,OH,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_048,OH,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_048,OH,payroll_tax,585.6839599609375,585.6839599609375,0.0,False +latest_final,scenario_048,OH,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_048,OH,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_048,OH,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_048,OH,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_048,OH,snap,0.0,0.0,0.0,False +latest_final,scenario_048,OH,ssi,0.0,0.0,0.0,False +latest_final,scenario_048,OH,tanf,0.0,0.0,0.0,False +latest_final,scenario_048,OH,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_048,OH,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_048,OH,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_048,OH,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_048,OH,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_048,OH,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_049,NH,federal_income_tax_before_refundable_credits,30702.58984375,30702.58984375,0.0,False +latest_final,scenario_049,NH,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_049,NH,payroll_tax,15134.5,15134.5,0.0,False +latest_final,scenario_049,NH,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_049,NH,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_049,NH,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_049,NH,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_049,NH,snap,0.0,0.0,0.0,False +latest_final,scenario_049,NH,ssi,0.0,0.0,0.0,False +latest_final,scenario_049,NH,tanf,0.0,0.0,0.0,False +latest_final,scenario_049,NH,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_049,NH,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_049,NH,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_049,NH,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_049,NH,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_049,NH,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_049,NH,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_049,NH,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_049,NH,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_049,NH,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_051,LA,federal_income_tax_before_refundable_credits,2620.0,2620.0,0.0,False +latest_final,scenario_051,LA,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_051,LA,payroll_tax,3060.0,3060.0,0.0,False +latest_final,scenario_051,LA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_051,LA,state_income_tax_before_refundable_credits,820.3499755859375,820.260009765625,-0.0899658203125,False +latest_final,scenario_051,LA,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_051,LA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_051,LA,snap,0.0,0.0,0.0,False +latest_final,scenario_051,LA,ssi,0.0,0.0,0.0,False +latest_final,scenario_051,LA,tanf,0.0,0.0,0.0,False +latest_final,scenario_051,LA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_051,LA,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_051,LA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_051,LA,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_051,LA,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_051,LA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_052,TX,federal_income_tax_before_refundable_credits,104211.40625,104225.2578125,13.8515625,True +latest_final,scenario_052,TX,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_052,TX,payroll_tax,20939.0,20939.0,0.0,False +latest_final,scenario_052,TX,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_052,TX,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_052,TX,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_052,TX,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_052,TX,snap,0.0,0.0,0.0,False +latest_final,scenario_052,TX,ssi,0.0,0.0,0.0,False +latest_final,scenario_052,TX,tanf,0.0,0.0,0.0,False +latest_final,scenario_052,TX,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_052,TX,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_052,TX,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_052,TX,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_052,TX,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_052,TX,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_052,TX,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_052,TX,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_052,TX,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_052,TX,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_053,ID,federal_income_tax_before_refundable_credits,5903.109375,5903.109375,0.0,False +latest_final,scenario_053,ID,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_053,ID,payroll_tax,5123.10400390625,5123.10400390625,0.0,False +latest_final,scenario_053,ID,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_053,ID,state_income_tax_before_refundable_credits,2186.05712890625,2186.05712890625,0.0,False +latest_final,scenario_053,ID,state_refundable_credits,155.0,155.0,0.0,False +latest_final,scenario_053,ID,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_053,ID,snap,0.0,0.0,0.0,False +latest_final,scenario_053,ID,ssi,0.0,0.0,0.0,False +latest_final,scenario_053,ID,tanf,0.0,0.0,0.0,False +latest_final,scenario_053,ID,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_053,ID,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_053,ID,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_053,ID,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_053,ID,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_053,ID,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_054,NC,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_054,NC,federal_refundable_credits,8365.55859375,8365.55859375,0.0,False +latest_final,scenario_054,NC,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_054,NC,self_employment_tax,2416.15283203125,2416.15283203125,0.0,False +latest_final,scenario_054,NC,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_054,NC,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_054,NC,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_054,NC,snap,6060.0,6060.0,0.0,False +latest_final,scenario_054,NC,ssi,0.0,0.0,0.0,False +latest_final,scenario_054,NC,tanf,0.0,0.0,0.0,False +latest_final,scenario_054,NC,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_054,NC,child1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_054,NC,child2_wic_eligible,1.0,1.0,0.0,False +latest_final,scenario_054,NC,head_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_054,NC,child1_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_054,NC,child2_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_054,NC,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_054,NC,child1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_054,NC,child2_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_054,NC,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_054,NC,child1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_054,NC,child2_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_054,NC,child1_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_054,NC,child2_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_054,NC,child1_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_054,NC,child2_early_head_start_eligible,1.0,1.0,0.0,False +latest_final,scenario_054,NC,free_school_meals_eligible,1.0,1.0,0.0,False +latest_final,scenario_054,NC,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_055,FL,federal_income_tax_before_refundable_credits,25238.578125,25238.578125,0.0,False +latest_final,scenario_055,FL,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_055,FL,payroll_tax,6398.08837890625,6398.08837890625,0.0,False +latest_final,scenario_055,FL,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_055,FL,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_055,FL,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_055,FL,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_055,FL,snap,0.0,0.0,0.0,False +latest_final,scenario_055,FL,ssi,0.0,0.0,0.0,False +latest_final,scenario_055,FL,tanf,0.0,0.0,0.0,False +latest_final,scenario_055,FL,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_055,FL,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_055,FL,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_055,FL,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_055,FL,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_055,FL,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_056,NJ,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_056,NJ,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_056,NJ,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_056,NJ,self_employment_tax,613.2224731445312,613.2224731445312,0.0,False +latest_final,scenario_056,NJ,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_056,NJ,state_refundable_credits,265.6000061035156,265.6000061035156,0.0,False +latest_final,scenario_056,NJ,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_056,NJ,snap,1140.0,95.0,-1045.0,True +latest_final,scenario_056,NJ,ssi,0.0,0.0,0.0,False +latest_final,scenario_056,NJ,tanf,0.0,0.0,0.0,False +latest_final,scenario_056,NJ,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_056,NJ,head_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_056,NJ,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_056,NJ,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_056,NJ,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_056,NJ,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_057,LA,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_057,LA,federal_refundable_credits,664.0,664.0,0.0,False +latest_final,scenario_057,LA,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_057,LA,self_employment_tax,1469.4732666015625,1469.4732666015625,0.0,False +latest_final,scenario_057,LA,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_057,LA,state_refundable_credits,33.20000076293945,33.20000076293945,0.0,False +latest_final,scenario_057,LA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_057,LA,snap,2669.217041015625,2628.0,-41.217041015625,True +latest_final,scenario_057,LA,ssi,7231.00146484375,7231.00146484375,0.0,False +latest_final,scenario_057,LA,tanf,0.0,0.0,0.0,False +latest_final,scenario_057,LA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_057,LA,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_057,LA,head_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_057,LA,spouse_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_057,LA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_057,LA,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_057,LA,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_057,LA,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_057,LA,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_057,LA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_059,FL,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_059,FL,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_059,FL,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_059,FL,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_059,FL,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_059,FL,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_059,FL,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_059,FL,snap,0.0,0.0,0.0,False +latest_final,scenario_059,FL,ssi,0.0,0.0,0.0,False +latest_final,scenario_059,FL,tanf,0.0,0.0,0.0,False +latest_final,scenario_059,FL,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_059,FL,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_059,FL,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_059,FL,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_059,FL,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_059,FL,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_059,FL,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_059,FL,spouse_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_059,FL,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_059,FL,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_060,TX,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_060,TX,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_060,TX,payroll_tax,229.5,229.5,0.0,False +latest_final,scenario_060,TX,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_060,TX,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_060,TX,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_060,TX,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_060,TX,snap,0.0,0.0,0.0,False +latest_final,scenario_060,TX,ssi,0.0,0.0,0.0,False +latest_final,scenario_060,TX,tanf,0.0,0.0,0.0,False +latest_final,scenario_060,TX,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_060,TX,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_060,TX,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_060,TX,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_060,TX,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_060,TX,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_062,FL,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_062,FL,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_062,FL,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_062,FL,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_062,FL,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_062,FL,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_062,FL,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_062,FL,snap,0.0,0.0,0.0,False +latest_final,scenario_062,FL,ssi,0.0,0.0,0.0,False +latest_final,scenario_062,FL,tanf,0.0,0.0,0.0,False +latest_final,scenario_062,FL,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_062,FL,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_062,FL,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_062,FL,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_062,FL,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_062,FL,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,federal_income_tax_before_refundable_credits,4441.455078125,4441.455078125,0.0,False +latest_final,scenario_064,WI,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_064,WI,payroll_tax,7443.0673828125,7443.0673828125,0.0,False +latest_final,scenario_064,WI,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_064,WI,state_income_tax_before_refundable_credits,4599.62158203125,4599.62158203125,0.0,False +latest_final,scenario_064,WI,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_064,WI,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_064,WI,snap,0.0,0.0,0.0,False +latest_final,scenario_064,WI,ssi,0.0,0.0,0.0,False +latest_final,scenario_064,WI,tanf,0.0,0.0,0.0,False +latest_final,scenario_064,WI,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,dependent1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,dependent2_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,child1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,dependent1_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_064,WI,dependent2_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,child1_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,dependent1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,dependent2_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,child1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,dependent1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,dependent2_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,child1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,child1_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,child1_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_064,WI,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_066,VA,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_066,VA,federal_refundable_credits,39.779998779296875,39.779998779296875,0.0,False +latest_final,scenario_066,VA,payroll_tax,39.779998779296875,39.779998779296875,0.0,False +latest_final,scenario_066,VA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_066,VA,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_066,VA,state_refundable_credits,7.955999851226807,7.955999851226807,0.0,False +latest_final,scenario_066,VA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_066,VA,snap,3576.0,3576.0,0.0,False +latest_final,scenario_066,VA,ssi,0.0,0.0,0.0,False +latest_final,scenario_066,VA,tanf,0.0,0.0,0.0,False +latest_final,scenario_066,VA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_066,VA,head_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_066,VA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_066,VA,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_066,VA,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_066,VA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_067,IN,federal_income_tax_before_refundable_credits,5616.240234375,5616.240234375,0.0,False +latest_final,scenario_067,IN,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_067,IN,payroll_tax,6300.5400390625,6300.5400390625,0.0,False +latest_final,scenario_067,IN,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_067,IN,state_income_tax_before_refundable_credits,2486.908935546875,2486.908935546875,0.0,False +latest_final,scenario_067,IN,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_067,IN,local_income_tax,1348.83203125,1348.83203125,0.0,False +latest_final,scenario_067,IN,snap,0.0,0.0,0.0,False +latest_final,scenario_067,IN,ssi,0.0,0.0,0.0,False +latest_final,scenario_067,IN,tanf,0.0,0.0,0.0,False +latest_final,scenario_067,IN,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_067,IN,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_067,IN,dependent1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_067,IN,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_067,IN,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_067,IN,dependent1_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_067,IN,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_067,IN,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_067,IN,dependent1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_067,IN,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_067,IN,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_067,IN,dependent1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_067,IN,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_067,IN,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_068,MD,federal_income_tax_before_refundable_credits,1910.0238037109375,1910.0238037109375,0.0,False +latest_final,scenario_068,MD,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_068,MD,payroll_tax,2607.39013671875,2607.39013671875,0.0,False +latest_final,scenario_068,MD,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_068,MD,state_income_tax_before_refundable_credits,1255.3427734375,1255.3427734375,0.0,False +latest_final,scenario_068,MD,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_068,MD,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_068,MD,snap,0.0,0.0,0.0,False +latest_final,scenario_068,MD,ssi,0.0,0.0,0.0,False +latest_final,scenario_068,MD,tanf,0.0,0.0,0.0,False +latest_final,scenario_068,MD,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_068,MD,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_068,MD,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_068,MD,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_068,MD,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_068,MD,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_070,IL,federal_income_tax_before_refundable_credits,1979.9605712890625,1979.9605712890625,0.0,False +latest_final,scenario_070,IL,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_070,IL,payroll_tax,2907.0,2907.0,0.0,False +latest_final,scenario_070,IL,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_070,IL,state_income_tax_before_refundable_credits,1650.561279296875,1650.561279296875,0.0,False +latest_final,scenario_070,IL,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_070,IL,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_070,IL,snap,0.0,0.0,0.0,False +latest_final,scenario_070,IL,ssi,0.0,0.0,0.0,False +latest_final,scenario_070,IL,tanf,0.0,0.0,0.0,False +latest_final,scenario_070,IL,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_070,IL,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_070,IL,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_070,IL,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_070,IL,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_070,IL,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_071,NY,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_071,NY,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_071,NY,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_071,NY,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_071,NY,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_071,NY,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_071,NY,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_071,NY,snap,0.0,0.0,0.0,False +latest_final,scenario_071,NY,ssi,0.0,0.0,0.0,False +latest_final,scenario_071,NY,tanf,0.0,0.0,0.0,False +latest_final,scenario_071,NY,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_071,NY,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_071,NY,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_071,NY,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_071,NY,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_071,NY,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_072,MI,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_072,MI,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_072,MI,payroll_tax,1530.0,1530.0,0.0,False +latest_final,scenario_072,MI,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_072,MI,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_072,MI,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_072,MI,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_072,MI,snap,0.0,0.0,0.0,False +latest_final,scenario_072,MI,ssi,0.0,0.0,0.0,False +latest_final,scenario_072,MI,tanf,0.0,0.0,0.0,False +latest_final,scenario_072,MI,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_072,MI,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_072,MI,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_072,MI,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_072,MI,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_072,MI,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_072,MI,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_072,MI,spouse_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_072,MI,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_072,MI,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_073,MI,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_073,MI,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_073,MI,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_073,MI,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_073,MI,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_073,MI,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_073,MI,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_073,MI,snap,288.0,288.0,0.0,False +latest_final,scenario_073,MI,ssi,0.0,0.0,0.0,False +latest_final,scenario_073,MI,tanf,0.0,0.0,0.0,False +latest_final,scenario_073,MI,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_073,MI,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_073,MI,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_073,MI,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_073,MI,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_073,MI,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_074,LA,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_074,LA,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_074,LA,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_074,LA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_074,LA,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_074,LA,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_074,LA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_074,LA,snap,0.0,0.0,0.0,False +latest_final,scenario_074,LA,ssi,0.0,0.0,0.0,False +latest_final,scenario_074,LA,tanf,0.0,0.0,0.0,False +latest_final,scenario_074,LA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_074,LA,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_074,LA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_074,LA,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_074,LA,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_074,LA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_075,FL,federal_income_tax_before_refundable_credits,14777.1455078125,14777.1455078125,0.0,False +latest_final,scenario_075,FL,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_075,FL,payroll_tax,968.2120971679688,968.2120971679688,0.0,False +latest_final,scenario_075,FL,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_075,FL,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_075,FL,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_075,FL,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_075,FL,snap,0.0,0.0,0.0,False +latest_final,scenario_075,FL,ssi,0.0,0.0,0.0,False +latest_final,scenario_075,FL,tanf,0.0,0.0,0.0,False +latest_final,scenario_075,FL,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_075,FL,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_075,FL,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_075,FL,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_075,FL,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_075,FL,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_076,ID,federal_income_tax_before_refundable_credits,19611.80078125,19611.80078125,0.0,False +latest_final,scenario_076,ID,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_076,ID,payroll_tax,12240.0,12240.0,0.0,False +latest_final,scenario_076,ID,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_076,ID,state_income_tax_before_refundable_credits,6828.34423828125,6828.34423828125,0.0,False +latest_final,scenario_076,ID,state_refundable_credits,465.0,465.0,0.0,False +latest_final,scenario_076,ID,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_076,ID,snap,0.0,0.0,0.0,False +latest_final,scenario_076,ID,ssi,0.0,0.0,0.0,False +latest_final,scenario_076,ID,tanf,0.0,0.0,0.0,False +latest_final,scenario_076,ID,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_076,ID,child1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_076,ID,child2_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_076,ID,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_076,ID,child1_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_076,ID,child2_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_076,ID,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_076,ID,child1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_076,ID,child2_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_076,ID,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_076,ID,child1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_076,ID,child2_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_076,ID,child1_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_076,ID,child2_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_076,ID,child1_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_076,ID,child2_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_076,ID,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_076,ID,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_077,LA,federal_income_tax_before_refundable_credits,690.6175537109375,690.6175537109375,0.0,False +latest_final,scenario_077,LA,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_077,LA,payroll_tax,1989.472412109375,1989.472412109375,0.0,False +latest_final,scenario_077,LA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_077,LA,state_income_tax_before_refundable_credits,305.13525390625,305.0452575683594,-0.089996337890625,False +latest_final,scenario_077,LA,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_077,LA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_077,LA,snap,0.0,0.0,0.0,False +latest_final,scenario_077,LA,ssi,0.0,0.0,0.0,False +latest_final,scenario_077,LA,tanf,0.0,0.0,0.0,False +latest_final,scenario_077,LA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_077,LA,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_077,LA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_077,LA,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_077,LA,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_077,LA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_078,MD,federal_income_tax_before_refundable_credits,24164.45703125,24164.45703125,0.0,False +latest_final,scenario_078,MD,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_078,MD,payroll_tax,14317.322265625,14317.322265625,0.0,False +latest_final,scenario_078,MD,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_078,MD,state_income_tax_before_refundable_credits,6936.87646484375,6936.87646484375,0.0,False +latest_final,scenario_078,MD,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_078,MD,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_078,MD,snap,0.0,0.0,0.0,False +latest_final,scenario_078,MD,ssi,0.0,0.0,0.0,False +latest_final,scenario_078,MD,tanf,0.0,0.0,0.0,False +latest_final,scenario_078,MD,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_078,MD,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_078,MD,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_078,MD,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_078,MD,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_078,MD,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_079,AZ,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_079,AZ,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_079,AZ,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_079,AZ,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_079,AZ,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_079,AZ,state_refundable_credits,50.0,50.0,0.0,False +latest_final,scenario_079,AZ,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_079,AZ,snap,2376.0,2376.0,0.0,False +latest_final,scenario_079,AZ,ssi,10572.0,10572.0,0.0,False +latest_final,scenario_079,AZ,tanf,0.0,0.0,0.0,False +latest_final,scenario_079,AZ,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_079,AZ,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_079,AZ,head_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_079,AZ,spouse_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_079,AZ,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_079,AZ,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_079,AZ,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_079,AZ,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_079,AZ,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_079,AZ,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_080,PA,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_080,PA,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_080,PA,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_080,PA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_080,PA,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_080,PA,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_080,PA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_080,PA,snap,3596.039794921875,3240.0,-356.039794921875,True +latest_final,scenario_080,PA,ssi,0.0,0.0,0.0,False +latest_final,scenario_080,PA,tanf,0.0,0.0,0.0,False +latest_final,scenario_080,PA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_080,PA,head_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_080,PA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_080,PA,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_080,PA,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_080,PA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_081,MA,federal_income_tax_before_refundable_credits,26932.2734375,26932.2734375,0.0,False +latest_final,scenario_081,MA,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_081,MA,payroll_tax,14192.662109375,14192.662109375,0.0,False +latest_final,scenario_081,MA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_081,MA,state_income_tax_before_refundable_credits,8238.40625,8232.900390625,-5.505859375,True +latest_final,scenario_081,MA,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_081,MA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_081,MA,snap,0.0,0.0,0.0,False +latest_final,scenario_081,MA,ssi,0.0,0.0,0.0,False +latest_final,scenario_081,MA,tanf,0.0,0.0,0.0,False +latest_final,scenario_081,MA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_081,MA,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_081,MA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_081,MA,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_081,MA,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_081,MA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_082,NY,federal_income_tax_before_refundable_credits,9579.767578125,9579.767578125,0.0,False +latest_final,scenario_082,NY,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_082,NY,payroll_tax,8108.02734375,8108.02734375,0.0,False +latest_final,scenario_082,NY,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_082,NY,state_income_tax_before_refundable_credits,5599.1435546875,5599.1435546875,0.0,False +latest_final,scenario_082,NY,state_refundable_credits,1187.5478515625,1187.5478515625,0.0,False +latest_final,scenario_082,NY,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_082,NY,snap,0.0,0.0,0.0,False +latest_final,scenario_082,NY,ssi,0.0,0.0,0.0,False +latest_final,scenario_082,NY,tanf,0.0,0.0,0.0,False +latest_final,scenario_082,NY,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_082,NY,child1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_082,NY,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_082,NY,child1_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_082,NY,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_082,NY,child1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_082,NY,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_082,NY,child1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_082,NY,child1_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_082,NY,child1_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_082,NY,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_082,NY,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_083,TX,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_083,TX,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_083,TX,payroll_tax,539.3250122070312,539.3250122070312,0.0,False +latest_final,scenario_083,TX,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_083,TX,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_083,TX,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_083,TX,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_083,TX,snap,0.0,0.0,0.0,False +latest_final,scenario_083,TX,ssi,0.0,0.0,0.0,False +latest_final,scenario_083,TX,tanf,0.0,0.0,0.0,False +latest_final,scenario_083,TX,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_083,TX,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_083,TX,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_083,TX,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_083,TX,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_083,TX,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_084,NC,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_084,NC,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_084,NC,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_084,NC,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_084,NC,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_084,NC,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_084,NC,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_084,NC,snap,0.0,0.0,0.0,False +latest_final,scenario_084,NC,ssi,0.0,0.0,0.0,False +latest_final,scenario_084,NC,tanf,0.0,0.0,0.0,False +latest_final,scenario_084,NC,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_084,NC,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_084,NC,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_084,NC,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_084,NC,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_084,NC,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_085,PA,federal_income_tax_before_refundable_credits,2322.8486328125,2322.8486328125,0.0,False +latest_final,scenario_085,PA,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_085,PA,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_085,PA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_085,PA,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_085,PA,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_085,PA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_085,PA,snap,0.0,0.0,0.0,False +latest_final,scenario_085,PA,ssi,0.0,0.0,0.0,False +latest_final,scenario_085,PA,tanf,0.0,0.0,0.0,False +latest_final,scenario_085,PA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_085,PA,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_085,PA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_085,PA,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_085,PA,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_085,PA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_086,GA,federal_income_tax_before_refundable_credits,3255.5478515625,3255.5478515625,0.0,False +latest_final,scenario_086,GA,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_086,GA,payroll_tax,4743.0,4743.0,0.0,False +latest_final,scenario_086,GA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_086,GA,state_income_tax_before_refundable_credits,2078.958740234375,2078.958740234375,0.0,False +latest_final,scenario_086,GA,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_086,GA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_086,GA,snap,0.0,0.0,0.0,False +latest_final,scenario_086,GA,ssi,0.0,0.0,0.0,False +latest_final,scenario_086,GA,tanf,0.0,0.0,0.0,False +latest_final,scenario_086,GA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_086,GA,child1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_086,GA,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_086,GA,child1_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_086,GA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_086,GA,child1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_086,GA,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_086,GA,child1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_086,GA,child1_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_086,GA,child1_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_086,GA,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_086,GA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_088,TX,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_088,TX,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_088,TX,payroll_tax,1421.1448974609375,1421.1448974609375,0.0,False +latest_final,scenario_088,TX,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_088,TX,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_088,TX,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_088,TX,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_088,TX,snap,0.0,0.0,0.0,False +latest_final,scenario_088,TX,ssi,0.0,0.0,0.0,False +latest_final,scenario_088,TX,tanf,0.0,0.0,0.0,False +latest_final,scenario_088,TX,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_088,TX,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_088,TX,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_088,TX,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_088,TX,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_088,TX,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_089,NC,federal_income_tax_before_refundable_credits,6819.7119140625,6819.7119140625,0.0,False +latest_final,scenario_089,NC,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_089,NC,payroll_tax,5039.91015625,5039.91015625,0.0,False +latest_final,scenario_089,NC,self_employment_tax,4286.24072265625,4286.24072265625,0.0,False +latest_final,scenario_089,NC,state_income_tax_before_refundable_credits,3219.935302734375,3219.935302734375,0.0,False +latest_final,scenario_089,NC,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_089,NC,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_089,NC,snap,0.0,0.0,0.0,False +latest_final,scenario_089,NC,ssi,0.0,0.0,0.0,False +latest_final,scenario_089,NC,tanf,0.0,0.0,0.0,False +latest_final,scenario_089,NC,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_089,NC,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_089,NC,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_089,NC,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_089,NC,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_089,NC,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_089,NC,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_089,NC,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_089,NC,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_089,NC,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_090,KS,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_090,KS,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_090,KS,payroll_tax,535.5,535.5,0.0,False +latest_final,scenario_090,KS,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_090,KS,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_090,KS,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_090,KS,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_090,KS,snap,0.0,0.0,0.0,False +latest_final,scenario_090,KS,ssi,0.0,0.0,0.0,False +latest_final,scenario_090,KS,tanf,0.0,0.0,0.0,False +latest_final,scenario_090,KS,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_090,KS,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_090,KS,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_090,KS,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_090,KS,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_090,KS,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_091,WI,federal_income_tax_before_refundable_credits,1349.998779296875,1349.998779296875,0.0,False +latest_final,scenario_091,WI,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_091,WI,payroll_tax,2065.5,2065.5,0.0,False +latest_final,scenario_091,WI,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_091,WI,state_income_tax_before_refundable_credits,878.5157470703125,878.5157470703125,0.0,False +latest_final,scenario_091,WI,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_091,WI,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_091,WI,snap,0.0,0.0,0.0,False +latest_final,scenario_091,WI,ssi,0.0,0.0,0.0,False +latest_final,scenario_091,WI,tanf,0.0,0.0,0.0,False +latest_final,scenario_091,WI,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_091,WI,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_091,WI,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_091,WI,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_091,WI,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_091,WI,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_092,AL,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_092,AL,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_092,AL,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_092,AL,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_092,AL,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_092,AL,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_092,AL,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_092,AL,snap,0.0,0.0,0.0,False +latest_final,scenario_092,AL,ssi,0.0,0.0,0.0,False +latest_final,scenario_092,AL,tanf,0.0,0.0,0.0,False +latest_final,scenario_092,AL,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_092,AL,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_092,AL,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_092,AL,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_092,AL,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_092,AL,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_093,MO,federal_income_tax_before_refundable_credits,8628.990234375,8628.990234375,0.0,False +latest_final,scenario_093,MO,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_093,MO,payroll_tax,12469.5,12469.5,0.0,False +latest_final,scenario_093,MO,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_093,MO,state_income_tax_before_refundable_credits,3388.24560546875,3388.24560546875,0.0,False +latest_final,scenario_093,MO,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_093,MO,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_093,MO,snap,0.0,0.0,0.0,False +latest_final,scenario_093,MO,ssi,0.0,0.0,0.0,False +latest_final,scenario_093,MO,tanf,0.0,0.0,0.0,False +latest_final,scenario_093,MO,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_093,MO,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_093,MO,dependent1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_093,MO,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_093,MO,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_093,MO,dependent1_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_093,MO,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_093,MO,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_093,MO,dependent1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_093,MO,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_093,MO,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_093,MO,dependent1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_093,MO,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_093,MO,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_095,NJ,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_095,NJ,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_095,NJ,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_095,NJ,self_employment_tax,593.2291259765625,593.2291259765625,0.0,False +latest_final,scenario_095,NJ,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_095,NJ,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_095,NJ,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_095,NJ,snap,0.0,0.0,0.0,False +latest_final,scenario_095,NJ,ssi,0.0,0.0,0.0,False +latest_final,scenario_095,NJ,tanf,0.0,0.0,0.0,False +latest_final,scenario_095,NJ,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_095,NJ,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_095,NJ,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_095,NJ,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_095,NJ,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_095,NJ,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_098,IL,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_098,IL,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_098,IL,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_098,IL,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_098,IL,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_098,IL,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_098,IL,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_098,IL,snap,0.0,0.0,0.0,False +latest_final,scenario_098,IL,ssi,0.0,0.0,0.0,False +latest_final,scenario_098,IL,tanf,0.0,0.0,0.0,False +latest_final,scenario_098,IL,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_098,IL,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_098,IL,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_098,IL,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_098,IL,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_098,IL,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,federal_income_tax_before_refundable_credits,10711.484375,10711.484375,0.0,False +latest_final,scenario_099,CA,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_099,CA,payroll_tax,14767.5,14767.5,0.0,False +latest_final,scenario_099,CA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_099,CA,state_income_tax_before_refundable_credits,4615.48388671875,4615.48388671875,0.0,False +latest_final,scenario_099,CA,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_099,CA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_099,CA,snap,0.0,0.0,0.0,False +latest_final,scenario_099,CA,ssi,0.0,0.0,0.0,False +latest_final,scenario_099,CA,tanf,0.0,0.0,0.0,False +latest_final,scenario_099,CA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,child1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,child2_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,child1_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,child2_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,child1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,child2_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,child1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,child2_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,child1_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,child2_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,child1_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,child2_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_099,CA,free_school_meals_eligible,1.0,1.0,0.0,False +latest_final,scenario_099,CA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_100,MT,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_100,MT,federal_refundable_credits,822.2882690429688,822.2882690429688,0.0,False +latest_final,scenario_100,MT,payroll_tax,452.47613525390625,452.47613525390625,0.0,False +latest_final,scenario_100,MT,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_100,MT,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_100,MT,state_refundable_credits,164.45765686035156,164.45765686035156,0.0,False +latest_final,scenario_100,MT,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_100,MT,snap,8625.8896484375,6924.0,-1701.8896484375,True +latest_final,scenario_100,MT,ssi,0.0,0.0,0.0,False +latest_final,scenario_100,MT,tanf,6064.958984375,6064.958984375,0.0,False +latest_final,scenario_100,MT,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_100,MT,child1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_100,MT,child2_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_100,MT,head_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_100,MT,child1_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_100,MT,child2_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_100,MT,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_100,MT,child1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_100,MT,child2_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_100,MT,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_100,MT,child1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_100,MT,child2_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_100,MT,child1_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_100,MT,child2_head_start_eligible,1.0,1.0,0.0,False +latest_final,scenario_100,MT,child1_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_100,MT,child2_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_100,MT,free_school_meals_eligible,1.0,1.0,0.0,False +latest_final,scenario_100,MT,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_101,TX,federal_income_tax_before_refundable_credits,13418.599609375,13418.599609375,0.0,False +latest_final,scenario_101,TX,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_101,TX,payroll_tax,7879.5,7879.5,0.0,False +latest_final,scenario_101,TX,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_101,TX,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_101,TX,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_101,TX,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_101,TX,snap,0.0,0.0,0.0,False +latest_final,scenario_101,TX,ssi,0.0,0.0,0.0,False +latest_final,scenario_101,TX,tanf,0.0,0.0,0.0,False +latest_final,scenario_101,TX,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_101,TX,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_101,TX,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_101,TX,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_101,TX,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_101,TX,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_102,NC,federal_income_tax_before_refundable_credits,6104.09619140625,6104.09619140625,0.0,False +latest_final,scenario_102,NC,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_102,NC,payroll_tax,6670.7998046875,6670.7998046875,0.0,False +latest_final,scenario_102,NC,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_102,NC,state_income_tax_before_refundable_credits,2461.869873046875,2461.869873046875,0.0,False +latest_final,scenario_102,NC,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_102,NC,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_102,NC,snap,0.0,0.0,0.0,False +latest_final,scenario_102,NC,ssi,0.0,0.0,0.0,False +latest_final,scenario_102,NC,tanf,0.0,0.0,0.0,False +latest_final,scenario_102,NC,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_102,NC,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_102,NC,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_102,NC,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_102,NC,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_102,NC,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_102,NC,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_102,NC,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_102,NC,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_102,NC,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_104,NY,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_104,NY,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_104,NY,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_104,NY,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_104,NY,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_104,NY,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_104,NY,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_104,NY,snap,0.0,0.0,0.0,False +latest_final,scenario_104,NY,ssi,0.0,0.0,0.0,False +latest_final,scenario_104,NY,tanf,0.0,0.0,0.0,False +latest_final,scenario_104,NY,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_104,NY,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_104,NY,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_104,NY,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_104,NY,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_104,NY,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_107,OH,federal_income_tax_before_refundable_credits,0.0,211.232421875,211.232421875,True +latest_final,scenario_107,OH,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_107,OH,payroll_tax,486.9607238769531,486.9607238769531,0.0,False +latest_final,scenario_107,OH,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_107,OH,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_107,OH,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_107,OH,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_107,OH,snap,0.0,0.0,0.0,False +latest_final,scenario_107,OH,ssi,0.0,0.0,0.0,False +latest_final,scenario_107,OH,tanf,0.0,0.0,0.0,False +latest_final,scenario_107,OH,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_107,OH,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_107,OH,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_107,OH,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_107,OH,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_107,OH,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_108,WI,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_108,WI,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_108,WI,payroll_tax,585.6839599609375,585.6839599609375,0.0,False +latest_final,scenario_108,WI,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_108,WI,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_108,WI,state_refundable_credits,271.3916015625,271.3916015625,0.0,False +latest_final,scenario_108,WI,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_108,WI,snap,288.0,288.0,0.0,False +latest_final,scenario_108,WI,ssi,0.0,0.0,0.0,False +latest_final,scenario_108,WI,tanf,0.0,0.0,0.0,False +latest_final,scenario_108,WI,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_108,WI,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_108,WI,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_108,WI,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_108,WI,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_108,WI,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_109,FL,federal_refundable_credits,12038.0859375,12038.0859375,0.0,False +latest_final,scenario_109,FL,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_109,FL,self_employment_tax,4238.86474609375,4238.86474609375,0.0,False +latest_final,scenario_109,FL,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_109,FL,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_109,FL,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_109,FL,snap,7932.0,7932.0,0.0,False +latest_final,scenario_109,FL,ssi,0.0,0.0,0.0,False +latest_final,scenario_109,FL,tanf,0.0,0.0,0.0,False +latest_final,scenario_109,FL,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,child1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,child2_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,child3_wic_eligible,1.0,1.0,0.0,False +latest_final,scenario_109,FL,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,child1_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_109,FL,child2_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_109,FL,child3_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_109,FL,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,child1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,child2_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,child3_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,child1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,child2_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,child3_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,child1_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,child2_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,child3_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,child1_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,child2_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_109,FL,child3_early_head_start_eligible,1.0,1.0,0.0,False +latest_final,scenario_109,FL,free_school_meals_eligible,1.0,1.0,0.0,False +latest_final,scenario_109,FL,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_110,OH,federal_income_tax_before_refundable_credits,25747.7734375,25747.7734375,0.0,False +latest_final,scenario_110,OH,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_110,OH,payroll_tax,7650.0,7650.0,0.0,False +latest_final,scenario_110,OH,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_110,OH,state_income_tax_before_refundable_credits,4236.8076171875,4236.8076171875,0.0,False +latest_final,scenario_110,OH,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_110,OH,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_110,OH,snap,0.0,0.0,0.0,False +latest_final,scenario_110,OH,ssi,0.0,0.0,0.0,False +latest_final,scenario_110,OH,tanf,0.0,0.0,0.0,False +latest_final,scenario_110,OH,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_110,OH,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_110,OH,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_110,OH,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_110,OH,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_110,OH,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_111,WA,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_111,WA,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_111,WA,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_111,WA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_111,WA,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_111,WA,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_111,WA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_111,WA,snap,0.0,0.0,0.0,False +latest_final,scenario_111,WA,ssi,0.0,0.0,0.0,False +latest_final,scenario_111,WA,tanf,0.0,0.0,0.0,False +latest_final,scenario_111,WA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_111,WA,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_111,WA,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_111,WA,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_111,WA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_111,WA,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_111,WA,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_111,WA,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_111,WA,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_111,WA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_112,TX,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_112,TX,federal_refundable_credits,453.09600830078125,453.09600830078125,0.0,False +latest_final,scenario_112,TX,payroll_tax,453.09600830078125,453.09600830078125,0.0,False +latest_final,scenario_112,TX,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_112,TX,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_112,TX,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_112,TX,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_112,TX,snap,287.68316650390625,0.0,-287.68316650390625,True +latest_final,scenario_112,TX,ssi,0.0,0.0,0.0,False +latest_final,scenario_112,TX,tanf,0.0,0.0,0.0,False +latest_final,scenario_112,TX,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_112,TX,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_112,TX,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_112,TX,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_112,TX,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_112,TX,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_114,VA,federal_income_tax_before_refundable_credits,10729.6123046875,10729.6123046875,0.0,False +latest_final,scenario_114,VA,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_114,VA,payroll_tax,1736.550048828125,1736.550048828125,0.0,False +latest_final,scenario_114,VA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_114,VA,state_income_tax_before_refundable_credits,3514.14501953125,3514.14501953125,0.0,False +latest_final,scenario_114,VA,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_114,VA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_114,VA,snap,0.0,0.0,0.0,False +latest_final,scenario_114,VA,ssi,0.0,0.0,0.0,False +latest_final,scenario_114,VA,tanf,0.0,0.0,0.0,False +latest_final,scenario_114,VA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_114,VA,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_114,VA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_114,VA,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_114,VA,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_114,VA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_115,AL,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_115,AL,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_115,AL,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_115,AL,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_115,AL,state_income_tax_before_refundable_credits,4.679999828338623,4.679999828338623,0.0,False +latest_final,scenario_115,AL,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_115,AL,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_115,AL,snap,0.0,0.0,0.0,False +latest_final,scenario_115,AL,ssi,0.0,0.0,0.0,False +latest_final,scenario_115,AL,tanf,0.0,0.0,0.0,False +latest_final,scenario_115,AL,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_115,AL,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_115,AL,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_115,AL,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_115,AL,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_115,AL,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_116,FL,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_116,FL,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_116,FL,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_116,FL,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_116,FL,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_116,FL,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_116,FL,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_116,FL,snap,0.0,0.0,0.0,False +latest_final,scenario_116,FL,ssi,0.0,0.0,0.0,False +latest_final,scenario_116,FL,tanf,0.0,0.0,0.0,False +latest_final,scenario_116,FL,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_116,FL,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_116,FL,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_116,FL,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_116,FL,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_116,FL,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_116,FL,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_116,FL,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_116,FL,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_116,FL,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,federal_income_tax_before_refundable_credits,24961.33984375,24961.33984375,0.0,False +latest_final,scenario_117,AR,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_117,AR,payroll_tax,15044.787109375,15044.787109375,0.0,False +latest_final,scenario_117,AR,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_117,AR,state_income_tax_before_refundable_credits,7984.53369140625,7984.53369140625,0.0,False +latest_final,scenario_117,AR,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_117,AR,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_117,AR,snap,0.0,0.0,0.0,False +latest_final,scenario_117,AR,ssi,0.0,0.0,0.0,False +latest_final,scenario_117,AR,tanf,0.0,0.0,0.0,False +latest_final,scenario_117,AR,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,child1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,child2_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,child3_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,child1_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,child2_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,child3_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,child1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,child2_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,child3_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,child1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,child2_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,child3_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,child1_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,child2_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,child3_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,child1_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,child2_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,child3_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_117,AR,free_school_meals_eligible,0.0,1.0,1.0,True +latest_final,scenario_117,AR,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_118,NY,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_118,NY,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_118,NY,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_118,NY,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_118,NY,state_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_118,NY,state_refundable_credits,375.0,375.0,0.0,False +latest_final,scenario_118,NY,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_118,NY,snap,2903.9404296875,2400.0,-503.9404296875,True +latest_final,scenario_118,NY,ssi,9368.0,9368.0,0.0,False +latest_final,scenario_118,NY,tanf,0.0,0.0,0.0,False +latest_final,scenario_118,NY,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_118,NY,head_medicaid_eligible,1.0,1.0,0.0,False +latest_final,scenario_118,NY,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_118,NY,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_118,NY,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_118,NY,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_119,VA,federal_income_tax_before_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_119,VA,federal_refundable_credits,3366.07373046875,3366.07373046875,0.0,False +latest_final,scenario_119,VA,payroll_tax,4207.5,4207.5,0.0,False +latest_final,scenario_119,VA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_119,VA,state_income_tax_before_refundable_credits,1756.681396484375,1756.681396484375,0.0,False +latest_final,scenario_119,VA,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_119,VA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_119,VA,snap,0.0,0.0,0.0,False +latest_final,scenario_119,VA,ssi,0.0,0.0,0.0,False +latest_final,scenario_119,VA,tanf,0.0,0.0,0.0,False +latest_final,scenario_119,VA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_119,VA,child1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_119,VA,child2_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_119,VA,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_119,VA,child1_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_119,VA,child2_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_119,VA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_119,VA,child1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_119,VA,child2_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_119,VA,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_119,VA,child1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_119,VA,child2_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_119,VA,child1_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_119,VA,child2_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_119,VA,child1_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_119,VA,child2_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_119,VA,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_119,VA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_120,CT,federal_income_tax_before_refundable_credits,40021.81640625,40423.17578125,401.359375,True +latest_final,scenario_120,CT,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_120,CT,payroll_tax,13496.1552734375,13496.1552734375,0.0,False +latest_final,scenario_120,CT,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_120,CT,state_income_tax_before_refundable_credits,11919.0576171875,11919.0576171875,0.0,False +latest_final,scenario_120,CT,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_120,CT,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_120,CT,snap,0.0,0.0,0.0,False +latest_final,scenario_120,CT,ssi,0.0,0.0,0.0,False +latest_final,scenario_120,CT,tanf,0.0,0.0,0.0,False +latest_final,scenario_120,CT,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_120,CT,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_120,CT,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_120,CT,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_120,CT,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_120,CT,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_121,SC,federal_income_tax_before_refundable_credits,0.0,875.3375244140625,875.3375244140625,True +latest_final,scenario_121,SC,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_121,SC,payroll_tax,1963.3724365234375,1963.3724365234375,0.0,False +latest_final,scenario_121,SC,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_121,SC,state_income_tax_before_refundable_credits,0.0,212.23350524902344,212.23350524902344,True +latest_final,scenario_121,SC,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_121,SC,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_121,SC,snap,0.0,0.0,0.0,False +latest_final,scenario_121,SC,ssi,0.0,0.0,0.0,False +latest_final,scenario_121,SC,tanf,0.0,0.0,0.0,False +latest_final,scenario_121,SC,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_121,SC,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_121,SC,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_121,SC,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_121,SC,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_121,SC,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_122,MN,federal_income_tax_before_refundable_credits,4746.66162109375,4746.66162109375,0.0,False +latest_final,scenario_122,MN,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_122,MN,payroll_tax,0.0,0.0,0.0,False +latest_final,scenario_122,MN,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_122,MN,state_income_tax_before_refundable_credits,1025.54150390625,1025.54150390625,0.0,False +latest_final,scenario_122,MN,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_122,MN,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_122,MN,snap,0.0,0.0,0.0,False +latest_final,scenario_122,MN,ssi,0.0,0.0,0.0,False +latest_final,scenario_122,MN,tanf,0.0,0.0,0.0,False +latest_final,scenario_122,MN,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_122,MN,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_122,MN,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_122,MN,head_medicare_eligible,1.0,1.0,0.0,False +latest_final,scenario_122,MN,free_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_122,MN,reduced_price_school_meals_eligible,0.0,0.0,0.0,False +latest_final,scenario_123,PA,federal_income_tax_before_refundable_credits,5200.240234375,5200.240234375,0.0,False +latest_final,scenario_123,PA,federal_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_123,PA,payroll_tax,11194.0,11194.0,0.0,False +latest_final,scenario_123,PA,self_employment_tax,0.0,0.0,0.0,False +latest_final,scenario_123,PA,state_income_tax_before_refundable_credits,3070.061279296875,3070.061279296875,0.0,False +latest_final,scenario_123,PA,state_refundable_credits,0.0,0.0,0.0,False +latest_final,scenario_123,PA,local_income_tax,0.0,0.0,0.0,False +latest_final,scenario_123,PA,snap,0.0,0.0,0.0,False +latest_final,scenario_123,PA,ssi,0.0,0.0,0.0,False +latest_final,scenario_123,PA,tanf,0.0,0.0,0.0,False +latest_final,scenario_123,PA,head_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_123,PA,spouse_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_123,PA,child1_wic_eligible,0.0,0.0,0.0,False +latest_final,scenario_123,PA,head_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_123,PA,spouse_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_123,PA,child1_medicaid_eligible,0.0,0.0,0.0,False +latest_final,scenario_123,PA,head_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_123,PA,spouse_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_123,PA,child1_chip_eligible,0.0,0.0,0.0,False +latest_final,scenario_123,PA,head_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_123,PA,spouse_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_123,PA,child1_medicare_eligible,0.0,0.0,0.0,False +latest_final,scenario_123,PA,child1_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_123,PA,child1_early_head_start_eligible,0.0,0.0,0.0,False +latest_final,scenario_123,PA,free_school_meals_eligible,0.0,1.0,1.0,True +latest_final,scenario_123,PA,reduced_price_school_meals_eligible,0.0,0.0,0.0,False diff --git a/reference_audit/2026-10-22-engine-upgrade/reference-build/reference_exclusions.json b/reference_audit/2026-10-22-engine-upgrade/reference-build/reference_exclusions.json new file mode 100644 index 00000000..575beed9 --- /dev/null +++ b/reference_audit/2026-10-22-engine-upgrade/reference-build/reference_exclusions.json @@ -0,0 +1,689 @@ +{ + "schema_version": 1, + "rule": "An output is excluded from scoring for every model when its reference depends on an input or definition that the certified household data never carried and the prompt therefore never stated, and a careful reader could take the stated facts the other way. Excluded outputs stay in the published payload, marked scored=false, so every prompt and response remains inspectable.", + "derivation": "All 1,984 references were recomputed with policyengine-us 1.755.4 (the version that produced them; base recompute matched the frozen CSV on every row) under each alternative reading; every output whose value moved is listed. 2026-09-05. On 2026-10-05 eight more outputs were excluded on review of release dashboard-data-20260930 (reference_audit/2026-10-05, reference_audit/2026-10-05-medicare-part-b and reference_audit/2026-10-05-payroll); their records are computed on policyengine-us 2.15.17, whose values are the references, and each sweep's baseline reproduced every scored reference. On 2026-10-06 ten more outputs were excluded on review of release dashboard-data-20261006 (reference_audit/2026-10-05-reference-adversary and reference_audit/2026-10-05-louisiana); their records are computed on policyengine-us 2.15.17, whose values are the references. On 2026-09-29 the references moved to policyengine-us 2.15.17 with the pre-freeze conventions. Every excluded output was recomputed there, and each one that moved was re-reviewed and stays excluded (the reference sidecar's engine_upgrade revision lists them). Records decided before that date keep the values they were decided on; the four records decided that day were computed on 2.15.17. The audit excluded one of them on review of the release. Its reference did not move, so the engine_upgrade revision does not list it (final_actions.json audit_exclusions). On 2026-10-10 the references moved from policyengine-us 2.15.17 to policyengine-us 2.38.6 with the same pre-freeze conventions (reference_audit/2026-10-09-engine-upgrade), and every output was recomputed there. The new engine fixes the defects behind 18 excluded outputs, each landing within $1 of its audited corrected value, so their records were removed and the outputs are scored again (the reference sidecar's second engine_upgrade revision lists them under regenerated_exclusions). Two scored outputs the new engine moved were excluded that day; their records are computed on 2.38.6. Of the excluded outputs that stay excluded, 17 moved; each was re-reviewed and keeps the value it was decided on (excluded_outputs_rechecked). On 2026-10-13 the references moved from policyengine-us 2.38.6 to policyengine-us 2.41.0 with the same pre-freeze conventions (reference_audit/2026-10-12-engine-upgrade), and every output was recomputed there. The new engine fixes the defects behind nine excluded outputs, each landing within $1 of its audited corrected value, so their records were removed and the outputs are scored again (the reference sidecar's third engine_upgrade revision lists them under regenerated_exclusions). Of the excluded outputs that stay excluded, 12 moved; each was re-reviewed and keeps the value it was decided on (excluded_outputs_rechecked). On 2026-10-23 the references moved from policyengine-us 2.41.0 to policyengine-us 2.60.0 with the same pre-freeze conventions (reference_audit/2026-10-22-engine-upgrade), and every output was recomputed there. Of the excluded outputs that stay excluded, 16 moved; each was re-reviewed and keeps the value it was decided on (excluded_outputs_rechecked).", + "exclusions": [ + { + "scenario_id": "scenario_007", + "variable": "head_medicare_eligible", + "reason_code": "reference_depends_on_unlisted_input", + "unlisted_input": "months_receiving_social_security_disability", + "alternative_reading": "The person's listed Social Security disability income is read as 24 or more months of SSDI receipt (the engine input months_receiving_social_security_disability, integer-typed, never carried by the data and never promptable). Recomputed with policyengine-us 1.755.4.", + "frozen_value": 0.0, + "alternative_value": 1.0, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-05", + "decided_by": "developer", + "judge_verdict": "llm_error (age_disability) where any row was judged", + "note": "In law the under-65 route needs 24 months of SSDI entitlement; a year-round recipient has at least 12. The facts do not settle it." + }, + { + "scenario_id": "scenario_073", + "variable": "head_medicare_eligible", + "reason_code": "reference_depends_on_unlisted_input", + "unlisted_input": "months_receiving_social_security_disability", + "alternative_reading": "The person's listed Social Security disability income is read as 24 or more months of SSDI receipt (the engine input months_receiving_social_security_disability, integer-typed, never carried by the data and never promptable). Recomputed with policyengine-us 1.755.4.", + "frozen_value": 0.0, + "alternative_value": 1.0, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-05", + "decided_by": "developer", + "judge_verdict": "llm_error (age_disability) where any row was judged", + "note": "In law the under-65 route needs 24 months of SSDI entitlement; a year-round recipient has at least 12. The facts do not settle it." + }, + { + "scenario_id": "scenario_074", + "variable": "head_medicare_eligible", + "reason_code": "reference_depends_on_unlisted_input", + "unlisted_input": "months_receiving_social_security_disability", + "alternative_reading": "The person's listed Social Security disability income is read as 24 or more months of SSDI receipt (the engine input months_receiving_social_security_disability, integer-typed, never carried by the data and never promptable). Recomputed with policyengine-us 1.755.4.", + "frozen_value": 0.0, + "alternative_value": 1.0, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-05", + "decided_by": "developer", + "judge_verdict": "llm_error (age_disability) where any row was judged", + "note": "In law the under-65 route needs 24 months of SSDI entitlement; a year-round recipient has at least 12. The facts do not settle it." + }, + { + "scenario_id": "scenario_079", + "variable": "head_medicare_eligible", + "reason_code": "reference_depends_on_unlisted_input", + "unlisted_input": "months_receiving_social_security_disability", + "alternative_reading": "The person's listed Social Security disability income is read as 24 or more months of SSDI receipt (the engine input months_receiving_social_security_disability, integer-typed, never carried by the data and never promptable). Recomputed with policyengine-us 1.755.4.", + "frozen_value": 0.0, + "alternative_value": 1.0, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-05", + "decided_by": "developer", + "judge_verdict": "llm_error (age_disability) where any row was judged", + "note": "In law the under-65 route needs 24 months of SSDI entitlement; a year-round recipient has at least 12. The facts do not settle it." + }, + { + "scenario_id": "scenario_084", + "variable": "head_medicare_eligible", + "reason_code": "reference_depends_on_unlisted_input", + "unlisted_input": "months_receiving_social_security_disability", + "alternative_reading": "The person's listed Social Security disability income is read as 24 or more months of SSDI receipt (the engine input months_receiving_social_security_disability, integer-typed, never carried by the data and never promptable). Recomputed with policyengine-us 1.755.4.", + "frozen_value": 0.0, + "alternative_value": 1.0, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-05", + "decided_by": "developer", + "judge_verdict": "llm_error (age_disability) where any row was judged", + "note": "In law the under-65 route needs 24 months of SSDI entitlement; a year-round recipient has at least 12. The facts do not settle it." + }, + { + "scenario_id": "scenario_023", + "variable": "snap", + "reason_code": "reference_depends_on_unlisted_input", + "unlisted_input": "meets_ssi_disability_criteria", + "alternative_reading": "The household fact 'is disabled' is read as satisfying SSI's disability criterion (the engine input meets_ssi_disability_criteria, which the certified microdata never sets and the prompt never lists). Recomputed with policyengine-us 1.755.4 with each person in a correctly built marital unit; the run's own situation placed every household member in one marital unit, which deems the whole household's income to the adult and masks the change.", + "frozen_value": 461.339722, + "alternative_value": 3576.0, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-05", + "decided_by": "developer", + "judge_verdict": "llm_error where any row was judged", + "note": "SSI itself stays $0 under either reading (the head's countable income exceeds the federal benefit rate); SNAP moves because SSI-disabled status switches on the elderly-or-disabled SNAP rules. The 2026-09-05 record gave 3,596.04 under that reading on the frozen engine; the 2026-09-22 audit recomputes it with every publication convention and upstream fix." + }, + { + "scenario_id": "scenario_057", + "variable": "snap", + "reason_code": "reference_depends_on_unlisted_input", + "unlisted_input": "meets_ssi_disability_criteria", + "alternative_reading": "The household fact 'is disabled' is read as satisfying SSI's disability criterion (the engine input meets_ssi_disability_criteria, which the certified microdata never sets and the prompt never lists). Recomputed with policyengine-us 1.755.4 with each person in a correctly built marital unit; the run's own situation placed every household member in one marital unit, which deems the whole household's income to the adult and masks the change.", + "frozen_value": 2669.217041, + "alternative_value": 840.0, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-05", + "decided_by": "developer", + "judge_verdict": "llm_error where any row was judged", + "note": "Moves with the additional SSI counted as household income. The 2026-09-05 record gave 883.62 under that reading on the frozen engine; the 2026-09-22 audit recomputes it with every publication convention and upstream fix." + }, + { + "scenario_id": "scenario_100", + "variable": "snap", + "reason_code": "reference_depends_on_unlisted_input", + "unlisted_input": "meets_ssi_disability_criteria", + "alternative_reading": "The household fact 'is disabled' is read as satisfying SSI's disability criterion (the engine input meets_ssi_disability_criteria, which the certified microdata never sets and the prompt never lists). Recomputed with policyengine-us 1.755.4 with each person in a correctly built marital unit; the run's own situation placed every household member in one marital unit, which deems the whole household's income to the adult and masks the change.", + "frozen_value": 8625.889648, + "alternative_value": 8844.0, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-05", + "decided_by": "developer", + "judge_verdict": "llm_error where any row was judged", + "note": "SSI stays $0 under either reading ($2,800 in the bank exceeds the $2,000 resource limit); SNAP moves through the elderly-or-disabled SNAP rules. The 2026-09-05 record gave 8,917.49 under that reading on the frozen engine; the 2026-09-22 audit recomputes it with every publication convention and upstream fix. r30_snap_heat_and_eat_sua (engine defect, not fixed upstream) also moves this output on the stated facts, from 8,556.00 to 6,924.00; the record keeps its 2026-09-05 classification." + }, + { + "scenario_id": "scenario_057", + "variable": "ssi", + "reason_code": "reference_depends_on_unlisted_input", + "unlisted_input": "meets_ssi_disability_criteria", + "alternative_reading": "The household fact 'is disabled' is read as satisfying SSI's disability criterion (the engine input meets_ssi_disability_criteria, which the certified microdata never sets and the prompt never lists). Recomputed with policyengine-us 1.755.4 with each person in a correctly built marital unit; the run's own situation placed every household member in one marital unit, which deems the whole household's income to the adult and masks the change.", + "frozen_value": 7231.001465, + "alternative_value": 13182.999023, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-05", + "decided_by": "developer", + "judge_verdict": "llm_error where any row was judged", + "note": "An aged or blind member already receives SSI; the disabled 20-year-old would add a second federal benefit under the alternative reading." + }, + { + "scenario_id": "scenario_064", + "variable": "ssi", + "reason_code": "reference_depends_on_unlisted_input", + "unlisted_input": "meets_ssi_disability_criteria", + "alternative_reading": "The household fact 'is disabled' is read as satisfying SSI's disability criterion (the engine input meets_ssi_disability_criteria, which the certified microdata never sets and the prompt never lists). Recomputed with policyengine-us 1.755.4 with each person in a correctly built marital unit; the run's own situation placed every household member in one marital unit, which deems the whole household's income to the adult and masks the change.", + "frozen_value": 0.0, + "alternative_value": 11928.0, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-05", + "decided_by": "developer", + "judge_verdict": "prompt_ambiguity (claude-opus-5, 2026-09-05)", + "note": "Under the alternative reading nine of the twelve models that paid SSI land within 10% of the $11,928 federal benefit (five exactly); deepseek-v4-pro, deepseek-v4-pro-0813 and inkling also applied a one-third in-kind reduction the facts do not support." + }, + { + "scenario_id": "scenario_067", + "variable": "ssi", + "reason_code": "reference_depends_on_unlisted_input", + "unlisted_input": "meets_ssi_disability_criteria", + "alternative_reading": "The household fact 'is disabled' is read as satisfying SSI's disability criterion (the engine input meets_ssi_disability_criteria, which the certified microdata never sets and the prompt never lists). Recomputed with policyengine-us 1.755.4 with each person in a correctly built marital unit; the run's own situation placed every household member in one marital unit, which deems the whole household's income to the adult and masks the change.", + "frozen_value": 0.0, + "alternative_value": 1368.0, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-05", + "decided_by": "developer", + "judge_verdict": "llm_error (gpt-5.6-sol, 2026-09-01 board)", + "note": "Under the alternative reading nine of the twelve models that paid SSI land within 10% of $1,368 (six exactly); glm-5.2, grok-build-0.1 and minimax-m3 used wrong rates or annualised the monthly exclusion." + }, + { + "scenario_id": "scenario_002", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt lists disability benefits from employment without saying who paid for the coverage. Benefits from employer-paid coverage are included in gross income (26 U.S.C. 105(a)); benefits from coverage the employee paid for with after-tax money are excluded (26 U.S.C. 104(a)(3)). The reference excludes them; the alternative value includes them.", + "frozen_value": 0.0, + "alternative_value": 1890.300049, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "unlisted_input": "who paid for the coverage behind listed employment disability benefits, which decides whether they are taxable", + "note": "Corrected value applies r24_disability_benefits_taxable with every publication convention and upstream fix." + }, + { + "scenario_id": "scenario_005", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r02_ira_219g", + "alternative_reading": "A filer who defers wages into a 401(k) or 403(b) is an active participant, and above the 2026 phase-out range ($81,000 to $91,000 single or head of household, $129,000 to $149,000 joint) deducts nothing.", + "frozen_value": 106505.8984375, + "alternative_value": 107198.335938, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine deducts traditional IRA contributions without the active-participant phase-out", + "law": "26 U.S.C. 219(g); IRS Notice 2025-67 (2026 ranges)", + "upstream": "to be filed", + "note": "Corrected value applies r02_ira_219g_v2 with every publication convention and upstream fix. The output also moves under r25_niit_in_federal_output (unlisted input)." + }, + { + "scenario_id": "scenario_020", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt defines the output as federal individual income tax after nonrefundable credits and before refundable credits. The reference adds the net investment income tax (26 U.S.C. 1411), which Form 1040 reports on Schedule 2, Part II with self-employment tax, after line 22's tax after nonrefundable credits; read as line 22, the output excludes it.", + "frozen_value": 68056.7109375, + "alternative_value": 68112.09375, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "unlisted_input": "whether federal income tax before refundable credits includes the net investment income tax, which the output's definition does not say", + "note": "Corrected value applies r25_niit_excluded with every publication convention and upstream fix." + }, + { + "scenario_id": "scenario_052", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r02_ira_219g", + "alternative_reading": "A filer who defers wages into a 401(k) or 403(b) is an active participant, and above the 2026 phase-out range ($81,000 to $91,000 single or head of household, $129,000 to $149,000 joint) deducts nothing.", + "frozen_value": 104211.40625, + "alternative_value": 104225.257812, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine deducts traditional IRA contributions without the active-participant phase-out", + "law": "26 U.S.C. 219(g); IRS Notice 2025-67 (2026 ranges)", + "upstream": "to be filed", + "note": "Corrected value applies r02_ira_219g_v2 with every publication convention and upstream fix. The output also moves under r25_niit_in_federal_output (unlisted input)." + }, + { + "scenario_id": "scenario_056", + "variable": "snap", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt lists no hours worked and says to treat unlisted numeric inputs as 0; the reference assumed 40 hours a week, which clears the SNAP work requirement for able-bodied adults without dependents. Under the zero-hours reading the time limit applies, which ends benefits after three countable months unless an exemption or area waiver applies; the alternative value is the engine's zero-hours result, not a certified entitlement. The prompt lists home mortgage interest without saying the mortgaged home is the household's residence; if it is, SNAP counts the mortgage payment, interest included, as a shelter cost (7 CFR 273.9(d)(6)(ii)(A)), which is the reading under the alternative value.", + "frozen_value": 1140.0, + "alternative_value": 0.0, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "unlisted_input": "weekly_hours_worked_before_lsr and whether the listed home mortgage interest is on the home the SNAP household occupies", + "note": "Corrected value applies r14_unlisted_weekly_hours_v2_v2 and r15_snap_mortgage_interest_v2 together with every publication convention and upstream fix." + }, + { + "scenario_id": "scenario_062", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt lists survivor benefits other than Social Security without saying whether they are taxable; the reference treats them as nontaxable, while a survivor pension or annuity is taxable under 26 U.S.C. 72.", + "frozen_value": 0.0, + "alternative_value": 4328.386719, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "unlisted_input": "taxability of survivor_benefits", + "note": "Corrected value applies r16_survivor_benefits_federal_v2 with every publication convention and upstream fix." + }, + { + "scenario_id": "scenario_064", + "variable": "dependent1_medicaid_eligible", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt lists an adult 'Dependent' without saying whether that person is the claiming filers' child. If the dependent is their child, 42 CFR 435.603(f)(2) puts the dependent in the parents' Medicaid household, whose combined MAGI decides eligibility; the reference treats the dependent as a non-child whose household is their own (42 CFR 435.603(f)(2)(i), (f)(3)).", + "frozen_value": 1.0, + "alternative_value": 0.0, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "unlisted_input": "the relationship of an adult tax dependent to the filers who claim them", + "note": "Corrected value applies r067_adult_dependent_relationship with every publication convention and upstream fix." + }, + { + "scenario_id": "scenario_064", + "variable": "dependent2_medicaid_eligible", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt lists an 18-year-old 'Dependent' separately from the household's children without saying whose child they are. Read as a non-child tax dependent, the dependent's Medicaid household is their own under 42 CFR 435.603(f)(2)(i), with $0 of MAGI; the reference places them in the claiming filers' household.", + "frozen_value": 0.0, + "alternative_value": 1.0, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "unlisted_input": "the relationship of an adult tax dependent to the filers who claim them", + "note": "Corrected value applies r067_adult_dependent_nonchild with every publication convention and upstream fix." + }, + { + "scenario_id": "scenario_067", + "variable": "dependent1_medicaid_eligible", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt lists an adult 'Dependent' without saying whether that person is the claiming filers' child. If the dependent is their child, 42 CFR 435.603(f)(2) puts the dependent in the parents' Medicaid household, whose combined MAGI decides eligibility; the reference treats the dependent as a non-child whose household is their own (42 CFR 435.603(f)(2)(i), (f)(3)).", + "frozen_value": 1.0, + "alternative_value": 0.0, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "unlisted_input": "the relationship of an adult tax dependent to the filers who claim them", + "note": "Corrected value applies r067_adult_dependent_relationship with every publication convention and upstream fix." + }, + { + "scenario_id": "scenario_080", + "variable": "snap", + "reason_code": "reference_engine_defect", + "root_cause": "r30_snap_heat_and_eat_sua", + "alternative_reading": "A LIHEAP payment makes a household eligible for the standard utility allowance only if the household has an elderly or disabled member; other households take the allowance only if they incur heating or cooling costs.", + "frozen_value": 3596.039794921875, + "alternative_value": 3240.0, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine grants the heat-and-eat standard utility allowance to households without an elderly or disabled member, which P.L. 119-21 sec. 10103 ended", + "law": "7 U.S.C. 2014(e)(6)(C)(iv)(I), as amended by P.L. 119-21 sec. 10103(a) (approved 2025-07-04)", + "upstream": "to be filed", + "note": "Corrected value applies r30_snap_heat_and_eat_sua with every publication convention and upstream fix. The prompt says the head is disabled but states none of the routes 7 U.S.C. 2012(j) lists for a disabled member, such as receipt of SSI or Social Security disability benefits, so the engine and this record treat the household as having no elderly or disabled member (verification/v9_axiom_us-2014-sua.md). Read the other way, the LIHEAP payment would still confer the standard utility allowance, and the value the publication conventions and upstream SNAP fixes give, 3,576.00 (the reference it would carry if scored), would stand; the output is excluded either way." + }, + { + "scenario_id": "scenario_081", + "variable": "state_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r22_ma_part_a_loss_offset", + "alternative_reading": "Massachusetts applies excess short-term capital losses against Part A interest and dividends, up to $2,000 of combined losses, before taxing Part A income.", + "frozen_value": 8238.40625, + "alternative_value": 8232.900391, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine taxes Massachusetts Part A dividends gross, without the short-term capital loss offset its own Part A AGI computes", + "law": "M.G.L. c. 62 sec. 2(b), 2(c)(2)(a), 2(c)(4), 2(f); DOR TIR 02-21", + "upstream": "to be filed", + "note": "Corrected value applies ma_part_a_loss_offset with every publication convention and upstream fix. The output also moves under r23_ma_interest_source (unlisted input)." + }, + { + "scenario_id": "scenario_107", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt lists disability benefits from employment without saying who paid for the coverage. Benefits from employer-paid coverage are included in gross income (26 U.S.C. 105(a)); benefits from coverage the employee paid for with after-tax money are excluded (26 U.S.C. 104(a)(3)). The reference excludes them; the alternative value includes them.", + "frozen_value": 0.0, + "alternative_value": 211.232422, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "unlisted_input": "who paid for the coverage behind listed employment disability benefits, which decides whether they are taxable", + "note": "Corrected value applies r24_disability_benefits_taxable with every publication convention and upstream fix." + }, + { + "scenario_id": "scenario_108", + "variable": "state_refundable_credits", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt lists survivor benefits other than Social Security without saying what they are. Wisconsin homestead household income counts the gross amount of a survivor pension or annuity (Wis. Stat. 71.52(6); Schedule H line 9d), which is the reading under the alternative value; the reference leaves them out. The prompt lists survivor benefits other than Social Security without saying whether they are taxable; the reference treats them as nontaxable, while a survivor pension or annuity is taxable under 26 U.S.C. 72.", + "frozen_value": 271.3916015625, + "alternative_value": 0.0, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "unlisted_input": "source of survivor_benefits (pension or annuity, or another survivor payment) and taxability of survivor_benefits", + "note": "Corrected value applies r10_wi_homestead_income and r16_survivor_benefits_federal_v2 together with every publication convention and upstream fix." + }, + { + "scenario_id": "scenario_112", + "variable": "snap", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt lists no hours worked and says to treat unlisted numeric inputs as 0; the reference assumed 40 hours a week, which clears the SNAP work requirement for able-bodied adults without dependents. Under the zero-hours reading the time limit applies, which ends benefits after three countable months unless an exemption or area waiver applies; the alternative value is the engine's zero-hours result, not a certified entitlement.", + "frozen_value": 287.68316650390625, + "alternative_value": 0.0, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "unlisted_input": "weekly_hours_worked_before_lsr", + "note": "Corrected value applies r14_unlisted_weekly_hours_v2_v2 with every publication convention and upstream fix. The output also moves under r28_snap_min_allotment_rounding (engine defect, fixed upstream)." + }, + { + "scenario_id": "scenario_118", + "variable": "snap", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt lists home mortgage interest without saying the mortgaged home is the household's residence; if it is, SNAP counts the mortgage payment, interest included, as a shelter cost (7 CFR 273.9(d)(6)(ii)(A)), which is the reading under the alternative value.", + "frozen_value": 2903.9404296875, + "alternative_value": 3576.0, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "unlisted_input": "whether the listed home mortgage interest is on the home the SNAP household occupies", + "note": "Corrected value applies r15_snap_mortgage_interest_v2 with every publication convention and upstream fix. The output also moves under r26_snap_contribution_rounding (engine defect, fixed upstream)." + }, + { + "scenario_id": "scenario_120", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r02_ira_219g", + "alternative_reading": "A filer who defers wages into a 401(k) or 403(b) is an active participant, and above the 2026 phase-out range ($81,000 to $91,000 single or head of household, $129,000 to $149,000 joint) deducts nothing.", + "frozen_value": 40021.81640625, + "alternative_value": 40028.320312, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine deducts traditional IRA contributions without the active-participant phase-out", + "law": "26 U.S.C. 219(g); IRS Notice 2025-67 (2026 ranges)", + "upstream": "to be filed", + "note": "Corrected value applies r02_ira_219g_v2 with every publication convention and upstream fix. The output also moves under r25_niit_in_federal_output (unlisted input). The output also moves under the state income tax withheld reading (unlisted input): the reference's SALT uses the Connecticut withholding estimate ($12,010.05); with the engine's own liability ($11,917.18) the 2.15.17 value is $40,438.95, and with no state income tax paid it is $43,619.93. With r02's IRA fix on 2.15.17 the value is $40,423.18 under the withholding estimate, $40,445.46 under the liability and $43,629.21 with no state income tax paid. policyengine-us 2.15.17 also leaves the household's Connecticut paid leave contributions ($827.98) out of SALT (Rev. Rul. 2025-4); with them the 2.15.17 value is $40,217.95." + }, + { + "scenario_id": "scenario_121", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt lists disability benefits from employment without saying who paid for the coverage. Benefits from employer-paid coverage are included in gross income (26 U.S.C. 105(a)); benefits from coverage the employee paid for with after-tax money are excluded (26 U.S.C. 104(a)(3)). The reference excludes them; the alternative value includes them.", + "frozen_value": 0.0, + "alternative_value": 875.337524, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "unlisted_input": "who paid for the coverage behind listed employment disability benefits, which decides whether they are taxable", + "note": "Corrected value applies r24_disability_benefits_taxable with every publication convention and upstream fix." + }, + { + "scenario_id": "scenario_121", + "variable": "state_income_tax_before_refundable_credits", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt lists disability benefits from employment without saying who paid for the coverage. Benefits from employer-paid coverage are included in gross income (26 U.S.C. 105(a)); benefits from coverage the employee paid for with after-tax money are excluded (26 U.S.C. 104(a)(3)). The reference excludes them; the alternative value includes them.", + "frozen_value": 0.0, + "alternative_value": 212.233505, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "unlisted_input": "who paid for the coverage behind listed employment disability benefits, which decides whether they are taxable", + "note": "Corrected value applies r24_disability_benefits_taxable with every publication convention and upstream fix." + }, + { + "scenario_id": "scenario_033", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt lists state and local tax refund income without saying whether the refunded tax reduced federal tax when it was deducted in the prior year (it labels already-taxable inputs 'taxable'). policyengine-us 2.15.17 counts the whole refund in gross income (policyengine-us#9422, which fixed issue #9122); under 26 U.S.C. 111(a) none of it is income if the household did not itemize, or took no tax benefit, in the year it paid the tax.", + "frozen_value": 3818.148193, + "alternative_value": 3788.988037, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-09-29", + "decided_by": "developer", + "unlisted_input": "whether the prior-year deduction of the refunded state and local tax reduced federal tax (prior-year itemization, the income-versus-sales-tax election, SALT-cap headroom)", + "note": "Found in the 2026-09-29 engine upgrade (cluster salt_refund_gross_income_9122); investigator and an independent reviewer. Alternative computed on 2.15.17 with the refund left out of gross income (sweep/fixes/latest_alt_salt_refund_no_prior_benefit.py)." + }, + { + "scenario_id": "scenario_078", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt lists state and local tax refund income without saying whether the refunded tax reduced federal tax when it was deducted in the prior year (it labels already-taxable inputs 'taxable'). policyengine-us 2.15.17 counts the whole refund in gross income (policyengine-us#9422, which fixed issue #9122); under 26 U.S.C. 111(a) none of it is income if the household did not itemize, or took no tax benefit, in the year it paid the tax.", + "frozen_value": 24164.457031, + "alternative_value": 23772.800781, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-09-29", + "decided_by": "developer", + "unlisted_input": "whether the prior-year deduction of the refunded state and local tax reduced federal tax (prior-year itemization, the income-versus-sales-tax election, SALT-cap headroom)", + "note": "Found in the 2026-09-29 engine upgrade (cluster salt_refund_gross_income_9122); investigator and an independent reviewer. Alternative computed on 2.15.17 with the refund left out of gross income (sweep/fixes/latest_alt_salt_refund_no_prior_benefit.py). The frozen value also counts Maryland county income tax, at the rate policyengine-us 2.15.17 assigns an unlisted county, in the federal SALT deduction through the Maryland withholding proxy (c_md_2026); the SALT cap binds at every 2026 county rate. The output also moves under the state income tax withheld reading (unlisted input): the reference's SALT uses the Maryland withholding estimate ($15,791.66); with the engine's own liability ($11,295.39) the 2.15.17 value is $24,799.16, and with no state income tax paid it is $27,290.70. The $40,400 cap that binds in the reference does not bind under the liability, so the liability value depends on the county, which the prompt does not state: $24,705.95 to $25,068.44 across Maryland's 24 county rates (the engine's default, Allegany, gives $24,799.16)." + }, + { + "scenario_id": "scenario_117", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt lists state and local tax refund income without saying whether the refunded tax reduced federal tax when it was deducted in the prior year (it labels already-taxable inputs 'taxable'). policyengine-us 2.15.17 counts the whole refund in gross income (policyengine-us#9422, which fixed issue #9122); under 26 U.S.C. 111(a) none of it is income if the household did not itemize, or took no tax benefit, in the year it paid the tax.", + "frozen_value": 24961.339844, + "alternative_value": 24391.796875, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-09-29", + "decided_by": "developer", + "unlisted_input": "whether the prior-year deduction of the refunded state and local tax reduced federal tax (prior-year itemization, the income-versus-sales-tax election, SALT-cap headroom)", + "note": "Found in the 2026-09-29 engine upgrade (cluster salt_refund_gross_income_9122); investigator and an independent reviewer. Alternative computed on 2.15.17 with the refund left out of gross income (sweep/fixes/latest_alt_salt_refund_no_prior_benefit.py)." + }, + { + "scenario_id": "scenario_022", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt lists no state income tax withheld or paid during 2026. The reference fills the state income tax part of the federal state and local tax deduction (26 U.S.C. 164(a)(3), (b)(5)) with policyengine-us's formula estimate of California income tax withheld: California's single rate schedule applied to the person's whole federal AGI (including $17,624.75 of taxable Social Security, which California exempts) less California's single standard deduction, at California's 2025 amounts (ca_withheld_income_tax, under the c_ca_hold_2025 convention), $6,058.85. The same engine computes the household's California income tax before refundable credits as $2,505.87. Read as the household paying its 2026 California income tax during the year, the deduction takes that liability and the output is the alternative value. The prompt's rule that unlisted numeric inputs are 0 gives a third reading, no state income tax paid, under which SALT takes the general sales tax (the note gives that value).", + "frozen_value": 11113.5703125, + "alternative_value": 11895.2275390625, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-10-05", + "decided_by": "developer", + "unlisted_input": "state income tax withheld or paid during 2026, which the federal state and local tax deduction takes as its state income tax part; policyengine-us fills it with state_withheld_income_tax, a formula estimate on federal AGI that the household data never set", + "note": "Found 2026-10-05 by sweeping every reference with the state income tax in SALT read three ways (reference_audit/2026-10-05/scripts/sweep_salt_withholding.py, on policyengine-us 2.15.17 with latest_final; its baseline reproduces all 1,928 scored references, and an independent re-implementation agreed on all 1,984 outputs). SALT is $14,887.85 in the reference and $11,334.87 under the alternative; the household itemizes under both, and the $40,400 cap binds under neither. Under the zero reading SALT takes the general sales tax, $1,155.60, and the output is $12,192.29; that sales tax includes the engine's local component of $192.60 (20% of the state table amount, an estimate for an unlisted locality), and without it the output is $12,234.66. The alternative uses the engine's California liability ($2,505.87), which this household's state output carries as an engine-defect exclusion; with the corrected liability ($1,968.81, recorded on policyengine-us 1.755.4) the output is $12,013.38. The output also moves under an engine defect: policyengine-us 2.15.17 leaves the household's California SDI contributions ($684.26) out of SALT, though they are deductible state income taxes (Trujillo v. Commissioner, 68 T.C. 670 (1977)). With them the output is $10,963.04 under the withholding estimate and $11,744.69 under the liability." + }, + { + "scenario_id": "scenario_032", + "variable": "payroll_tax", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt defines payroll_tax as employee Social Security, Medicare and Additional Medicare Tax plus mandatory employee state payroll taxes, and says to exclude employer payroll taxes. Minnesota Paid Leave premiums \"accrue and become payable by each employer\" (Minn. Stat. 268B.14, subd. 1); the employer must pay at least 50 percent (small employers: at least a quarter of the full rate, subd. 5a), and employees pay through wage deductions only \"the remaining portion, if any, of the premium not paid by the employer\" (subd. 3), so the employee share runs from 0 to 0.44% of wages at the employer's choice. The reference reads 'mandatory' as the employee share the statute sets, withheld unless the employer elects to pay it, and counts the largest share the employer may deduct (mn_employee_paid_leave_contribution $127.60), as policyengine-us assumes. Read as the amount the law requires of the employee whatever the employer does, which is $0, the output is employee federal payroll tax alone: the alternative value (policyengine-us 2.15.17 with latest_final and payroll_mandatory_scope).", + "frozen_value": 2346.10009765625, + "alternative_value": 2218.5, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-10-05", + "decided_by": "developer", + "unlisted_input": "whether the employer deducts the employee share of a state paid-leave or disability premium that the law lets it deduct but does not require, which decides whether that share is a mandatory employee state payroll tax", + "note": "Found 2026-10-05 by classifying every state program in the payroll references from primary law (reference_audit/2026-10-05-payroll/program_classification.json) and sweeping all 1,984 outputs with the programs classified as optional employer pass-through left out of employee state payroll tax; that moves this output alone in its household and no other output. The law: Minn. Stat. 268B.14, subds. 1, 3 and 5a. The frozen value has been the reference since the first run (references generated 2026-06-12)." + }, + { + "scenario_id": "scenario_043", + "variable": "payroll_tax", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt defines payroll_tax as employee Social Security, Medicare and Additional Medicare Tax plus mandatory employee state payroll taxes, and says to exclude employer payroll taxes. Colorado FAMLI premiums are remitted by the employer (C.R.S. 8-13.3-507(2)), which \"may deduct up to 50 percent of the premium\" from wages (507(5)); an employer that deducts less is considered to have elected to pay the rest (7 CCR 1107-1 s. 1.4(6)(A)). The reference reads 'mandatory' as the employee share the statute sets, withheld unless the employer elects to pay it, and counts the largest share the employer may deduct (co_employee_famli_contribution $17.99), as policyengine-us assumes. Read as the amount the law requires of the employee whatever the employer does, which is $0, the output is employee federal payroll tax alone: the alternative value (policyengine-us 2.15.17 with latest_final and payroll_mandatory_scope).", + "frozen_value": 330.7310791015625, + "alternative_value": 312.74322509765625, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-10-05", + "decided_by": "developer", + "unlisted_input": "whether the employer deducts the employee share of a state paid-leave or disability premium that the law lets it deduct but does not require, which decides whether that share is a mandatory employee state payroll tax", + "note": "Found 2026-10-05 by classifying every state program in the payroll references from primary law (reference_audit/2026-10-05-payroll/program_classification.json) and sweeping all 1,984 outputs with the programs classified as optional employer pass-through left out of employee state payroll tax; that moves this output alone in its household and no other output. The law: C.R.S. 8-13.3-507(2), (3)(b) and (5); 7 CCR 1107-1 s. 1.4(6)(A). The frozen value has been the reference since the first run (references generated 2026-06-12)." + }, + { + "scenario_id": "scenario_081", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt lists no state income tax withheld or paid during 2026. The reference fills the state income tax part of the federal state and local tax deduction (26 U.S.C. 164(a)(3), (b)(5)) with policyengine-us's formula estimate of Massachusetts income tax withheld: 5% of the person's whole federal AGI above the $4,400 single personal exemption (ma_withheld_income_tax), $8,484.41. The same engine computes the household's Massachusetts income tax before refundable credits as $8,238.41. Read as the household paying its 2026 Massachusetts income tax during the year, the deduction takes that liability and the output is the alternative value. The prompt's rule that unlisted numeric inputs are 0 gives a third reading, no state income tax paid, under which SALT takes the general sales tax (the note gives that value).", + "frozen_value": 26932.2734375, + "alternative_value": 26991.3125, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-10-05", + "decided_by": "developer", + "unlisted_input": "state income tax withheld or paid during 2026, which the federal state and local tax deduction takes as its state income tax part; policyengine-us fills it with state_withheld_income_tax, a formula estimate on federal AGI that the household data never set", + "note": "Found 2026-10-05 by sweeping every reference with the state income tax in SALT read three ways (reference_audit/2026-10-05/scripts/sweep_salt_withholding.py, on policyengine-us 2.15.17 with latest_final; its baseline reproduces all 1,928 scored references, and an independent re-implementation agreed on all 1,984 outputs). SALT is $14,127.41 in the reference and $13,881.41 under the alternative; the household itemizes under both, and the $40,400 cap binds under neither. Under the zero reading SALT takes the general sales tax, $853.00, and the output is $28,763.81. The alternative uses the engine's Massachusetts liability ($8,238.41), which this household's state output carries as an engine-defect exclusion; with the corrected liability ($8,232.90) the output is $26,992.64. The output would also move if the employer deducted the employee share of the household's Massachusetts paid family and medical leave premium, which the law allows but does not require (this household's payroll tax output is excluded on that ground; reference_audit/2026-10-05-payroll): policyengine-us 2.15.17 leaves any such contributions out of SALT, though Rev. Rul. 2025-4 treats them as deductible state income taxes. With the largest share Massachusetts's published 2026 rates let the employer deduct ($805.01), the output is $26,739.07 under the withholding estimate and $26,798.11 under the liability." + }, + { + "scenario_id": "scenario_081", + "variable": "payroll_tax", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt defines payroll_tax as employee Social Security, Medicare and Additional Medicare Tax plus mandatory employee state payroll taxes, and says to exclude employer payroll taxes. Massachusetts PFML contributions are remitted by the employer (M.G.L. c. 175M, s. 6(a)), which may deduct part of the contribution from wages (s. 6(c)): under the Department of Family and Medical Leave's published 2026 rates, up to 100 percent of the family and 40 percent of the medical contribution, though Acts 2026 c. 101 ss. 25-26 and 45 can be read to swap those caps for 2026 and may choose to deduct less (458 CMR 2.05(5)(c)). The reference reads 'mandatory' as the employee share the statute sets, withheld unless the employer elects to pay it, and counts the largest share Massachusetts's published 2026 rates let the employer deduct (ma_employee_paid_leave_contribution $805.01), as policyengine-us assumes. Read as the amount the law requires of the employee whatever the employer does, which is $0, the output is employee federal payroll tax alone: the alternative value (policyengine-us 2.15.17 with latest_final and payroll_mandatory_scope).", + "frozen_value": 14192.662109375, + "alternative_value": 13387.65234375, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-10-05", + "decided_by": "developer", + "unlisted_input": "whether the employer deducts the employee share of a state paid-leave or disability premium that the law lets it deduct but does not require, which decides whether that share is a mandatory employee state payroll tax", + "note": "Found 2026-10-05 by classifying every state program in the payroll references from primary law (reference_audit/2026-10-05-payroll/program_classification.json) and sweeping all 1,984 outputs with the programs classified as optional employer pass-through left out of employee state payroll tax; that moves this output alone in its household and no other output. The law: M.G.L. c. 175M, s. 6(a), (c) and (d); 458 CMR 2.05(5). The frozen value has been the reference since the first run (references generated 2026-06-12)." + }, + { + "scenario_id": "scenario_082", + "variable": "payroll_tax", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt defines payroll_tax as employee Social Security, Medicare and Additional Medicare Tax plus mandatory employee state payroll taxes, and says to exclude employer payroll taxes. New York's covered employer must provide disability and Paid Family Leave coverage; it pays the disability cost beyond what it collects (N.Y. Workers' Compensation Law s. 210(1)), no employer is required to fund Paid Family Leave (s. 209(3)(b)), and the employer \"is authorized to collect\" employee contributions up to the statutory caps by payroll deduction (s. 209(4)). The Workers' Compensation Board says an employer \"is allowed, but not required\" to collect them. The reference reads 'mandatory' as the employee share the statute sets, withheld unless the employer elects to pay it, and counts the largest share the employer may deduct (ny_employee_disability_benefits_contribution $31.20, ny_employee_paid_family_leave_contribution $411.91), as policyengine-us assumes. Read as the amount the law requires of the employee whatever the employer does, which is $0, the output is employee federal payroll tax alone: the alternative value (policyengine-us 2.15.17 with latest_final and payroll_mandatory_scope).", + "frozen_value": 8108.02734375, + "alternative_value": 7664.91748046875, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-10-05", + "decided_by": "developer", + "unlisted_input": "whether the employer deducts the employee share of a state paid-leave or disability premium that the law lets it deduct but does not require, which decides whether that share is a mandatory employee state payroll tax", + "note": "Found 2026-10-05 by classifying every state program in the payroll references from primary law (reference_audit/2026-10-05-payroll/program_classification.json) and sweeping all 1,984 outputs with the programs classified as optional employer pass-through left out of employee state payroll tax; that moves this output alone in its household and no other output. The law: N.Y. Workers' Compensation Law ss. 209(3)-(4) and 210(1). The frozen value has been the reference since the first run (references generated 2026-06-12)." + }, + { + "scenario_id": "scenario_114", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt lists no state income tax withheld or paid during 2026. The reference fills the state income tax part of the federal state and local tax deduction (26 U.S.C. 164(a)(3), (b)(5)) with policyengine-us's formula estimate of Virginia income tax withheld: Virginia's rate schedule applied to the person's whole federal AGI (including $19,828.80 of taxable Social Security, which Virginia exempts) less Virginia's single standard deduction (va_withheld_income_tax), $5,367.30. The same engine computes the household's Virginia income tax before refundable credits as $3,514.15. Read as the household paying its 2026 Virginia income tax during the year, the deduction takes that liability and the output is the alternative value. The prompt's rule that unlisted numeric inputs are 0 gives a third reading, no state income tax paid, under which SALT takes the general sales tax (the note gives that value).", + "frozen_value": 10729.6123046875, + "alternative_value": 11137.306640625, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-10-05", + "decided_by": "developer", + "unlisted_input": "state income tax withheld or paid during 2026, which the federal state and local tax deduction takes as its state income tax part; policyengine-us fills it with state_withheld_income_tax, a formula estimate on federal AGI that the household data never set; also Medicare enrollment and a Medicare Part B premium paid during 2026, which the medical expense deductions count; policyengine-us treats every Medicare-eligible person as enrolled (takes_up_medicare_if_eligible defaults to true, so medicare_enrolled follows is_medicare_eligible) and adds the modeled premium (medicare_part_b_premium) to medical expenses, and the household data never set either", + "note": "Found 2026-10-05 by sweeping every reference with the state income tax in SALT read three ways (reference_audit/2026-10-05/scripts/sweep_salt_withholding.py, on policyengine-us 2.15.17 with latest_final; its baseline reproduces all 1,928 scored references, and an independent re-implementation agreed on all 1,984 outputs). SALT is $9,431.59 in the reference and $7,578.44 under the alternative; the household itemizes under both, and the $40,400 cap binds under neither. Under the zero reading SALT takes the general sales tax, $692.40, and the output is $11,758.09; that sales tax includes the engine's local component of $115.40 (20% of the state table amount, an estimate for an unlisted locality), and without it the output is $11,783.48. The reference's medical deduction also includes a modeled Medicare Part B premium of $2,434.80, which the prompt does not list. Without it the output is $11,265.27 under the withholding estimate and $11,642.16 under the liability, and with no withholding, local sales tax or Part B premium it is $11,969.80 (the household then takes the standard deduction)." + }, + { + "scenario_id": "scenario_114", + "variable": "state_income_tax_before_refundable_credits", + "reason_code": "reference_depends_on_unlisted_input", + "alternative_reading": "The prompt lists no Medicare enrollment and no Medicare Part B premium, and its rules say to treat any unlisted numeric input as 0 and not to infer unlisted expenses or health coverage. The reference counts a modeled Part B premium as a medical expense: policyengine-us treats the head (age 69, so Medicare-eligible) as enrolled because takes_up_medicare_if_eligible defaults to true, and medical_expense_health_insurance_premiums adds medicare_part_b_premium, the 2026 standard premium of $202.90 a month, $2,434.80, to the listed $10,000 of other medical expenses. The household itemizes, so the federal medical expense deduction (26 U.S.C. 213(a): expenses above 7.5% of AGI) counts it, and Virginia's itemized deductions, which start from the federal itemized deductions (va_itemized_deductions), carry it too. The prompt also says to assume program take-up when required, and a reader who takes a 69-year-old with Social Security retirement income to be enrolled in Part B and paying the standard premium gets the frozen value. But the benchmark sets take-up only for the programs its household data list (Medicaid, SSI, the ACA credit, the DC property tax credit, the EITC, SNAP and tax filing; policybench.scenarios.DEFAULT_TAKEUP_INPUTS), and Medicare is not among them; the Medicare request asks only whether the head is eligible; and the more specific rules against inferring unlisted expenses or health coverage point the other way. Read with no Part B premium paid, the deduction falls by $2,434.80 and the output is the alternative value.", + "frozen_value": 3514.14501953125, + "alternative_value": 3654.14599609375, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-10-05", + "decided_by": "developer", + "unlisted_input": "Medicare enrollment and a Medicare Part B premium paid during 2026, which the medical expense deductions count; policyengine-us treats every Medicare-eligible person as enrolled (takes_up_medicare_if_eligible defaults to true, so medicare_enrolled follows is_medicare_eligible) and adds the modeled premium (medicare_part_b_premium) to medical expenses, and the household data never set either", + "note": "Found 2026-10-05 by sweeping every reference with each person's Medicare Part B premium at 0, and again with Medicare enrollment off (reference_audit/2026-10-05-medicare-part-b/scripts/sweep_part_b.py, on policyengine-us 2.15.17 with latest_final; its baseline reproduces all 1,928 scored references). Of 39 Medicare-eligible people in 33 households, the engine charges the premium in 30 (Medicare Savings Program coverage pays it for the 4 eligible people in the other 3); only this household's two tax outputs move, under either reading. The federal medical expense deduction is $4,441.86 in the reference ($12,434.80 of expenses less 7.5% of $106,572.56 AGI) and $2,007.06 without the premium; the household itemizes under both. The output also depends on the state income tax in the federal SALT deduction, which PolicyEngine/policybench#191 proposes to treat as an unlisted input (decision d963), through the federal itemization election, which Virginia follows (va_deductions reads tax_unit_itemizes). Without the premium the output is $3,654.15 under both the withholding estimate and the liability; with no state income tax paid it is $4,127.67, with or without the local sales tax estimate, because the household then takes the federal and Virginia standard deductions. With the premium it is $3,514.15 under all four readings. The premium is the standard premium: the engine reads the income-related adjustment from MAGI two years earlier, which no household sets, and at this household's 2026 MAGI ($106,572.56) none would apply. GPT-6 Astra ($3,654.16) and GPT-6.1 Sol ($3,654.66) answered within $1 of the alternative value, and no model within $1 of the frozen value." + }, + { + "scenario_id": "scenario_051", + "variable": "state_income_tax_before_refundable_credits", + "reason_code": "reference_law_published_after_freeze", + "alternative_reading": "R.S. 47:294(B) multiplies 2025's $12,500 by the calendar-2025 CPI-U increase but sets no rounding rule and gives the Department no duty to publish the result. Before the 2026-07-03 freeze Louisiana published only its withholding and estimated-tax amount, $12,875, and said the amount allowed on 2026 returns would differ; its first 2026 return amount, $12,838, came in RIB 26-019 on 2026-09-28, after the freeze. policyengine-us carries $12,835, which PolicyEngine/policyengine-us#8411 computed on 2026-05-24 from published CPI-U values ($12,500 x 324.054 / 315.605, rounded to the dollar): a computation under the statute, not a forecast, but a figure no Louisiana publication stated before the freeze. The reference is 3% of this single filer's Louisiana AGI ($40,180) less $12,835. Both Louisiana outputs that rest on the amount are excluded, and the published-amounts convention stays in force for every other reference (decision d994).", + "frozen_value": 820.3499755859375, + "alternative_value": 820.260009765625, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-10-06", + "decided_by": "developer", + "decision": "d994", + "root_cause": "la_2026_standard_deduction_unpublished", + "published": "Louisiana Department of Revenue, Revenue Information Bulletin 26-019, dated 2026-09-28: Louisiana's 2026 standard deduction is $12,838 for single and separate filers and $25,676 for the other statuses, the first 2026 return amount Louisiana published", + "law": "La. R.S. 47:294(A)-(B) (Act 11 of the 2024 Third Extraordinary Session); BLS CPI-U, series CUUR0000SA0, December 2024 and December 2025 (released 2026-01-13); Louisiana Department of Revenue, Revenue Information Bulletin 26-019 (2026-09-28)", + "note": "Found 2026-10-05 while preparing an interview on the board, and audited in reference_audit/2026-10-05-louisiana (PolicyEngine/policybench#192): the sweep (scripts/sweep_la_standard_deduction.py, policyengine-us 2.15.17 with latest_final) reproduces all 1,928 scored references at $12,835 and moves only these two outputs under every candidate amount (verification/sweep_la_standard_deduction.log). Values under the candidates: $12,500 (2025's amount, the last return amount published) $830.40; $12,875 (the withholding amount) $819.15; $12,838 (RIB 26-019) $820.26. Of release dashboard-data-20260930's 46 models, none answered within $1 of the frozen value or of $820.26, and 21 answered within $1 of $830.40 (verification/leaderboard_impact.json)." + }, + { + "scenario_id": "scenario_077", + "variable": "state_income_tax_before_refundable_credits", + "reason_code": "reference_law_published_after_freeze", + "alternative_reading": "R.S. 47:294(B) multiplies 2025's $12,500 by the calendar-2025 CPI-U increase but sets no rounding rule and gives the Department no duty to publish the result. Before the 2026-07-03 freeze Louisiana published only its withholding and estimated-tax amount, $12,875, and said the amount allowed on 2026 returns would differ; its first 2026 return amount, $12,838, came in RIB 26-019 on 2026-09-28, after the freeze. policyengine-us carries $12,835, which PolicyEngine/policyengine-us#8411 computed on 2026-05-24 from published CPI-U values ($12,500 x 324.054 / 315.605, rounded to the dollar): a computation under the statute, not a forecast, but a figure no Louisiana publication stated before the freeze. The reference is 3% of this single filer's Louisiana AGI ($23,006.18) less $12,835. Both Louisiana outputs that rest on the amount are excluded, and the published-amounts convention stays in force for every other reference (decision d994).", + "frozen_value": 305.13525390625, + "alternative_value": 305.0452575683594, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-10-06", + "decided_by": "developer", + "decision": "d994", + "root_cause": "la_2026_standard_deduction_unpublished", + "published": "Louisiana Department of Revenue, Revenue Information Bulletin 26-019, dated 2026-09-28: Louisiana's 2026 standard deduction is $12,838 for single and separate filers and $25,676 for the other statuses, the first 2026 return amount Louisiana published", + "law": "La. R.S. 47:294(A)-(B) (Act 11 of the 2024 Third Extraordinary Session); BLS CPI-U, series CUUR0000SA0, December 2024 and December 2025 (released 2026-01-13); Louisiana Department of Revenue, Revenue Information Bulletin 26-019 (2026-09-28)", + "note": "Found 2026-10-05 while preparing an interview on the board, and audited in reference_audit/2026-10-05-louisiana (PolicyEngine/policybench#192): the sweep (scripts/sweep_la_standard_deduction.py, policyengine-us 2.15.17 with latest_final) reproduces all 1,928 scored references at $12,835 and moves only these two outputs under every candidate amount (verification/sweep_la_standard_deduction.log). Values under the candidates: $12,500 (2025's amount, the last return amount published) $315.19; $12,875 (the withholding amount) $303.94; $12,838 (RIB 26-019) $305.05. Of release dashboard-data-20260930's 46 models, none answered within $1 of the frozen value or of $305.05, and 19 answered within $1 of $315.19 (verification/leaderboard_impact.json)." + }, + { + "scenario_id": "scenario_093", + "variable": "federal_income_tax_before_refundable_credits", + "frozen_value": 8628.990234375, + "alternative_value": 11848.990234375, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-10-06", + "decided_by": "developer", + "decision": "d1022", + "law": "72 P.S. 7302(a); 2025 PA-40 instructions p. 3 (a minor with PA income over $33 must file); 26 U.S.C. 73(a); RSMo 143.011", + "note": "Found 2026-10-05 by the reference adversary (runs/claude/cases/us__scenario_093__federal_income_tax_before_refundable_credits) and verified independently on 2026-10-06 (verification/independent/pa_123.md; verification/definition_conformance.md (household scope)). Alternative value: head and spouse return plus the dependent's own federal return ($3,220.00), verification/definition_conformance.json.", + "reason_code": "reference_depends_on_unlisted_input", + "root_cause": "household_scope_dependent_returns", + "unlisted_input": "whether the income tax outputs cover only the head and spouse's return or every return the household's members must file; the definitions name no return, and a dependent here must file their own", + "alternative_reading": "A dependent with $45,000 of wages must file their own federal and state return. The engine computes only the head and spouse's return. The output definitions name no return, tax unit or household, the prompt shows one 'Tax unit' block, and the request asks for quantities 'for this household' and says to assume filing when required. Careful readers split both ways (pa_123.md section 3)." + }, + { + "scenario_id": "scenario_093", + "variable": "state_income_tax_before_refundable_credits", + "frozen_value": 3388.24560546875, + "alternative_value": 4528.07861328125, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-10-06", + "decided_by": "developer", + "decision": "d1022", + "law": "72 P.S. 7302(a); 2025 PA-40 instructions p. 3 (a minor with PA income over $33 must file); 26 U.S.C. 73(a); RSMo 143.011", + "note": "Found 2026-10-05 by the reference adversary (runs/claude/cases/us__scenario_093__state_income_tax_before_refundable_credits) and verified independently on 2026-10-06 (verification/independent/pa_123.md; verification/definition_conformance.md (household scope)). Alternative value: head and spouse return plus the dependent's own MO-1040, verification/definition_conformance.json.", + "reason_code": "reference_depends_on_unlisted_input", + "root_cause": "household_scope_dependent_returns", + "unlisted_input": "whether the income tax outputs cover only the head and spouse's return or every return the household's members must file; the definitions name no return, and a dependent here must file their own", + "alternative_reading": "A dependent with $45,000 of wages must file their own federal and state return. The engine computes only the head and spouse's return. The output definitions name no return, tax unit or household, the prompt shows one 'Tax unit' block, and the request asks for quantities 'for this household' and says to assume filing when required. Careful readers split both ways (pa_123.md section 3)." + }, + { + "scenario_id": "scenario_123", + "variable": "federal_income_tax_before_refundable_credits", + "frozen_value": 5200.240234375, + "alternative_value": 8420.240234375, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-10-06", + "decided_by": "developer", + "decision": "d1022", + "law": "72 P.S. 7302(a); 2025 PA-40 instructions p. 3 (a minor with PA income over $33 must file); 26 U.S.C. 73(a); RSMo 143.011", + "note": "Found 2026-10-05 by the reference adversary (runs/claude/cases/us__scenario_123__federal_income_tax_before_refundable_credits) and verified independently on 2026-10-06 (verification/independent/pa_123.md; verification/definition_conformance.md (household scope)). Alternative value: head and spouse return plus the child's own federal return ($3,220.00), verification/definition_conformance.json.", + "reason_code": "reference_depends_on_unlisted_input", + "root_cause": "household_scope_dependent_returns", + "unlisted_input": "whether the income tax outputs cover only the head and spouse's return or every return the household's members must file; the definitions name no return, and a dependent here must file their own", + "alternative_reading": "A dependent with $45,000 of wages must file their own federal and state return. The engine computes only the head and spouse's return. The output definitions name no return, tax unit or household, the prompt shows one 'Tax unit' block, and the request asks for quantities 'for this household' and says to assume filing when required. Careful readers split both ways (pa_123.md section 3)." + }, + { + "scenario_id": "scenario_123", + "variable": "state_income_tax_before_refundable_credits", + "frozen_value": 3070.061279296875, + "alternative_value": 4451.561279296875, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-10-06", + "decided_by": "developer", + "decision": "d1022", + "law": "72 P.S. 7302(a); 2025 PA-40 instructions p. 3 (a minor with PA income over $33 must file); 26 U.S.C. 73(a); RSMo 143.011", + "note": "Found 2026-10-05 by the reference adversary (runs/claude/cases/us__scenario_123__state_income_tax_before_refundable_credits) and verified independently on 2026-10-06 (verification/independent/pa_123.md; verification/definition_conformance.md (household scope)). Alternative value: head and spouse return plus the child's own PA-40 ($1,381.50), verification/definition_conformance.json.", + "reason_code": "reference_depends_on_unlisted_input", + "root_cause": "household_scope_dependent_returns", + "unlisted_input": "whether the income tax outputs cover only the head and spouse's return or every return the household's members must file; the definitions name no return, and a dependent here must file their own", + "alternative_reading": "A dependent with $45,000 of wages must file their own federal and state return. The engine computes only the head and spouse's return. The output definitions name no return, tax unit or household, the prompt shows one 'Tax unit' block, and the request asks for quantities 'for this household' and says to assume filing when required. Careful readers split both ways (pa_123.md section 3)." + }, + { + "scenario_id": "scenario_015", + "variable": "local_income_tax", + "reason_code": "reference_depends_on_unlisted_input", + "unlisted_input": "county of residence (Indiana county income tax)", + "alternative_reading": "The prompt places the household in Indiana but states no county, and Indiana's county income taxes (IC 6-3.6) differ by county. policyengine-us 2.38.6 computes Indiana county tax (in_county_tax) in local_income_tax at the rate of the county it assigns a household with no stated county (Adams County on policyengine-us 2.38.6). Read without a county, as policyengine-us 2.15.17 did, the household owes no county tax.", + "frozen_value": 670.5501098632812, + "alternative_value": 0.0, + "engine_version": "policyengine-us 2.38.6", + "decided_on": "2026-10-10", + "decided_by": "developer", + "note": "Found in the 2026-10-10 engine upgrade (the US hub's sweep, cells_pe.md: local-tax standardization wires Indiana county income tax into local_income_tax). The alternative is the policyengine-us 2.15.17 reference." + }, + { + "scenario_id": "scenario_067", + "variable": "local_income_tax", + "reason_code": "reference_depends_on_unlisted_input", + "unlisted_input": "county of residence (Indiana county income tax)", + "alternative_reading": "The prompt places the household in Indiana but states no county, and Indiana's county income taxes (IC 6-3.6) differ by county. policyengine-us 2.38.6 computes Indiana county tax (in_county_tax) in local_income_tax at the rate of the county it assigns a household with no stated county (Adams County on policyengine-us 2.38.6). Read without a county, as policyengine-us 2.15.17 did, the household owes no county tax.", + "frozen_value": 1348.83203125, + "alternative_value": 0.0, + "engine_version": "policyengine-us 2.38.6", + "decided_on": "2026-10-10", + "decided_by": "developer", + "note": "Found in the 2026-10-10 engine upgrade (the US hub's sweep, cells_pe.md: local-tax standardization wires Indiana county income tax into local_income_tax). The alternative is the policyengine-us 2.15.17 reference." + }, + { + "scenario_id": "scenario_023", + "variable": "head_medicaid_eligible", + "reason_code": "reference_depends_on_unlisted_input", + "unlisted_input": "meets_ssi_disability_criteria", + "alternative_reading": "The household fact 'is disabled' is read as not meeting the Social Security definition of disability (the engine input meets_ssi_disability_criteria, which the prompt does not list). The head's MAGI is 141.2% of the federal poverty guideline, above the 138% limit for the adult expansion group, so only a disability pathway leads to Medi-Cal. California's 250% Working Disabled Program requires the Social Security definition (42 CFR 435.540(a)); policyengine-us 2.15.17 tests the broad is_disabled flag instead and places the head in that program (medicaid_category WORKING_DISABLED_BUY_IN).", + "frozen_value": 1.0, + "alternative_value": 0.0, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-09-29", + "decided_by": "developer", + "judge_verdict": "llm_error (claude-opus-5-5, 2026-09-29)", + "note": "Flagged in the 2026-09-29 engine upgrade by the investigation of cluster excl_snap_ssi_disability and its independent review, and excluded on review of the release (reference_audit/2026-09-28/final_actions.json, audit_exclusions). Alternative computed on 2.15.17 with the publication conventions and the Working Disabled Program's disability test reading meets_ssi_disability_criteria (reference_audit/2026-09-28/scripts/probe_023_medicaid.py); unmodified, 2.15.17 gives 1 under either reading. The same unlisted input excludes this household's SNAP." + } + ] +} diff --git a/reference_audit/2026-10-22-engine-upgrade/reference-build/reference_outputs.csv b/reference_audit/2026-10-22-engine-upgrade/reference-build/reference_outputs.csv new file mode 100644 index 00000000..daffbdeb --- /dev/null +++ b/reference_audit/2026-10-22-engine-upgrade/reference-build/reference_outputs.csv @@ -0,0 +1,1985 @@ +scenario_id,variable,value,impact_weight +scenario_000,federal_income_tax_before_refundable_credits,2906.45361328125, +scenario_000,federal_refundable_credits,0.0, +scenario_000,payroll_tax,0.0, +scenario_000,self_employment_tax,0.0, +scenario_000,state_income_tax_before_refundable_credits,0.0, +scenario_000,state_refundable_credits,0.0, +scenario_000,local_income_tax,0.0, +scenario_000,snap,0.0, +scenario_000,ssi,0.0, +scenario_000,tanf,0.0, +scenario_000,head_wic_eligible,0.0,0.0 +scenario_000,head_medicaid_eligible,0.0,0.0 +scenario_000,head_chip_eligible,0.0,0.0 +scenario_000,head_medicare_eligible,1.0,5285.2001953125 +scenario_000,free_school_meals_eligible,0.0,0.0 +scenario_000,reduced_price_school_meals_eligible,0.0,0.0 +scenario_001,federal_income_tax_before_refundable_credits,0.0, +scenario_001,federal_refundable_credits,0.0, +scenario_001,payroll_tax,2223.393798828125, +scenario_001,self_employment_tax,0.0, +scenario_001,state_income_tax_before_refundable_credits,0.0, +scenario_001,state_refundable_credits,0.0, +scenario_001,local_income_tax,0.0, +scenario_001,snap,0.0, +scenario_001,ssi,0.0, +scenario_001,tanf,0.0, +scenario_001,head_wic_eligible,0.0,0.0 +scenario_001,spouse_wic_eligible,0.0,0.0 +scenario_001,head_medicaid_eligible,0.0,0.0 +scenario_001,spouse_medicaid_eligible,0.0,0.0 +scenario_001,head_chip_eligible,0.0,0.0 +scenario_001,spouse_chip_eligible,0.0,0.0 +scenario_001,head_medicare_eligible,1.0,5285.2001953125 +scenario_001,spouse_medicare_eligible,1.0,5285.2001953125 +scenario_001,free_school_meals_eligible,0.0,0.0 +scenario_001,reduced_price_school_meals_eligible,0.0,0.0 +scenario_002,federal_income_tax_before_refundable_credits,0.0, +scenario_002,federal_refundable_credits,0.0, +scenario_002,payroll_tax,0.0, +scenario_002,self_employment_tax,0.0, +scenario_002,state_income_tax_before_refundable_credits,0.0, +scenario_002,state_refundable_credits,0.0, +scenario_002,local_income_tax,0.0, +scenario_002,snap,0.0, +scenario_002,ssi,0.0, +scenario_002,tanf,0.0, +scenario_002,head_wic_eligible,0.0,0.0 +scenario_002,spouse_wic_eligible,0.0,0.0 +scenario_002,head_medicaid_eligible,0.0,0.0 +scenario_002,spouse_medicaid_eligible,0.0,0.0 +scenario_002,head_chip_eligible,0.0,0.0 +scenario_002,spouse_chip_eligible,0.0,0.0 +scenario_002,head_medicare_eligible,1.0,5285.2001953125 +scenario_002,spouse_medicare_eligible,1.0,5285.2001953125 +scenario_002,free_school_meals_eligible,0.0,0.0 +scenario_002,reduced_price_school_meals_eligible,0.0,0.0 +scenario_003,federal_income_tax_before_refundable_credits,22400.654296875, +scenario_003,federal_refundable_credits,0.0, +scenario_003,payroll_tax,0.0, +scenario_003,self_employment_tax,0.0, +scenario_003,state_income_tax_before_refundable_credits,0.0, +scenario_003,state_refundable_credits,0.0, +scenario_003,local_income_tax,0.0, +scenario_003,snap,0.0, +scenario_003,ssi,0.0, +scenario_003,tanf,0.0, +scenario_003,head_wic_eligible,0.0,0.0 +scenario_003,spouse_wic_eligible,0.0,0.0 +scenario_003,head_medicaid_eligible,0.0,0.0 +scenario_003,spouse_medicaid_eligible,0.0,0.0 +scenario_003,head_chip_eligible,0.0,0.0 +scenario_003,spouse_chip_eligible,0.0,0.0 +scenario_003,head_medicare_eligible,0.0,0.0 +scenario_003,spouse_medicare_eligible,0.0,0.0 +scenario_003,free_school_meals_eligible,0.0,0.0 +scenario_003,reduced_price_school_meals_eligible,0.0,0.0 +scenario_004,federal_income_tax_before_refundable_credits,0.0, +scenario_004,federal_refundable_credits,0.0, +scenario_004,payroll_tax,0.0, +scenario_004,self_employment_tax,0.0, +scenario_004,state_income_tax_before_refundable_credits,0.0, +scenario_004,state_refundable_credits,0.0, +scenario_004,local_income_tax,0.0, +scenario_004,snap,0.0, +scenario_004,ssi,0.0, +scenario_004,tanf,0.0, +scenario_004,head_wic_eligible,0.0,0.0 +scenario_004,spouse_wic_eligible,0.0,0.0 +scenario_004,head_medicaid_eligible,0.0,0.0 +scenario_004,spouse_medicaid_eligible,0.0,0.0 +scenario_004,head_chip_eligible,0.0,0.0 +scenario_004,spouse_chip_eligible,0.0,0.0 +scenario_004,head_medicare_eligible,0.0,0.0 +scenario_004,spouse_medicare_eligible,0.0,0.0 +scenario_004,free_school_meals_eligible,0.0,0.0 +scenario_004,reduced_price_school_meals_eligible,0.0,0.0 +scenario_005,federal_income_tax_before_refundable_credits,106505.8984375, +scenario_005,federal_refundable_credits,0.0, +scenario_005,payroll_tax,36044.0, +scenario_005,self_employment_tax,0.0, +scenario_005,state_income_tax_before_refundable_credits,40975.25390625, +scenario_005,state_refundable_credits,0.0, +scenario_005,local_income_tax,0.0, +scenario_005,snap,0.0, +scenario_005,ssi,0.0, +scenario_005,tanf,0.0, +scenario_005,head_wic_eligible,0.0,0.0 +scenario_005,spouse_wic_eligible,0.0,0.0 +scenario_005,head_medicaid_eligible,0.0,0.0 +scenario_005,spouse_medicaid_eligible,0.0,0.0 +scenario_005,head_chip_eligible,0.0,0.0 +scenario_005,spouse_chip_eligible,0.0,0.0 +scenario_005,head_medicare_eligible,0.0,0.0 +scenario_005,spouse_medicare_eligible,0.0,0.0 +scenario_005,free_school_meals_eligible,0.0,0.0 +scenario_005,reduced_price_school_meals_eligible,0.0,0.0 +scenario_007,federal_income_tax_before_refundable_credits,3707.695068359375, +scenario_007,federal_refundable_credits,0.0, +scenario_007,payroll_tax,0.0, +scenario_007,self_employment_tax,0.0, +scenario_007,state_income_tax_before_refundable_credits,661.3170166015625, +scenario_007,state_refundable_credits,155.0, +scenario_007,local_income_tax,0.0, +scenario_007,snap,0.0, +scenario_007,ssi,0.0, +scenario_007,tanf,0.0, +scenario_007,head_wic_eligible,0.0,0.0 +scenario_007,head_medicaid_eligible,0.0,0.0 +scenario_007,head_chip_eligible,0.0,0.0 +scenario_007,head_medicare_eligible,0.0,0.0 +scenario_007,free_school_meals_eligible,0.0,0.0 +scenario_007,reduced_price_school_meals_eligible,0.0,0.0 +scenario_008,federal_income_tax_before_refundable_credits,0.0, +scenario_008,federal_refundable_credits,12433.611328125, +scenario_008,payroll_tax,2276.659912109375, +scenario_008,self_employment_tax,565.1820068359375, +scenario_008,state_income_tax_before_refundable_credits,264.80999755859375, +scenario_008,state_refundable_credits,5842.39990234375, +scenario_008,local_income_tax,0.0, +scenario_008,snap,15108.0, +scenario_008,ssi,0.0, +scenario_008,tanf,0.0, +scenario_008,head_wic_eligible,0.0,0.0 +scenario_008,spouse_wic_eligible,0.0,0.0 +scenario_008,child1_wic_eligible,0.0,0.0 +scenario_008,child2_wic_eligible,0.0,0.0 +scenario_008,child3_wic_eligible,0.0,0.0 +scenario_008,child4_wic_eligible,0.0,0.0 +scenario_008,child5_wic_eligible,0.0,0.0 +scenario_008,child6_wic_eligible,1.0,722.9943237304688 +scenario_008,head_medicaid_eligible,1.0,13804.8798828125 +scenario_008,spouse_medicaid_eligible,1.0,13565.7646484375 +scenario_008,child1_medicaid_eligible,1.0,9221.0537109375 +scenario_008,child2_medicaid_eligible,1.0,7970.48486328125 +scenario_008,child3_medicaid_eligible,1.0,7970.48486328125 +scenario_008,child4_medicaid_eligible,1.0,7970.48486328125 +scenario_008,child5_medicaid_eligible,1.0,7970.48486328125 +scenario_008,child6_medicaid_eligible,1.0,7970.48486328125 +scenario_008,head_chip_eligible,0.0,0.0 +scenario_008,spouse_chip_eligible,0.0,0.0 +scenario_008,child1_chip_eligible,0.0,0.0 +scenario_008,child2_chip_eligible,0.0,0.0 +scenario_008,child3_chip_eligible,0.0,0.0 +scenario_008,child4_chip_eligible,0.0,0.0 +scenario_008,child5_chip_eligible,0.0,0.0 +scenario_008,child6_chip_eligible,0.0,0.0 +scenario_008,head_medicare_eligible,0.0,0.0 +scenario_008,spouse_medicare_eligible,0.0,0.0 +scenario_008,child1_medicare_eligible,0.0,0.0 +scenario_008,child2_medicare_eligible,0.0,0.0 +scenario_008,child3_medicare_eligible,0.0,0.0 +scenario_008,child4_medicare_eligible,0.0,0.0 +scenario_008,child5_medicare_eligible,0.0,0.0 +scenario_008,child6_medicare_eligible,0.0,0.0 +scenario_008,child1_head_start_eligible,0.0,0.0 +scenario_008,child2_head_start_eligible,0.0,0.0 +scenario_008,child3_head_start_eligible,0.0,0.0 +scenario_008,child4_head_start_eligible,0.0,0.0 +scenario_008,child5_head_start_eligible,1.0,15394.83984375 +scenario_008,child6_head_start_eligible,0.0,0.0 +scenario_008,child1_early_head_start_eligible,0.0,0.0 +scenario_008,child2_early_head_start_eligible,0.0,0.0 +scenario_008,child3_early_head_start_eligible,0.0,0.0 +scenario_008,child4_early_head_start_eligible,0.0,0.0 +scenario_008,child5_early_head_start_eligible,0.0,0.0 +scenario_008,child6_early_head_start_eligible,1.0,20705.59765625 +scenario_008,free_school_meals_eligible,1.0,5654.81103515625 +scenario_008,reduced_price_school_meals_eligible,0.0,0.0 +scenario_009,federal_income_tax_before_refundable_credits,8348.0, +scenario_009,federal_refundable_credits,0.0, +scenario_009,payroll_tax,4590.0, +scenario_009,self_employment_tax,0.0, +scenario_009,state_income_tax_before_refundable_credits,2190.510009765625, +scenario_009,state_refundable_credits,0.0, +scenario_009,local_income_tax,0.0, +scenario_009,snap,0.0, +scenario_009,ssi,0.0, +scenario_009,tanf,0.0, +scenario_009,head_wic_eligible,0.0,0.0 +scenario_009,spouse_wic_eligible,0.0,0.0 +scenario_009,head_medicaid_eligible,0.0,0.0 +scenario_009,spouse_medicaid_eligible,0.0,0.0 +scenario_009,head_chip_eligible,0.0,0.0 +scenario_009,spouse_chip_eligible,0.0,0.0 +scenario_009,head_medicare_eligible,0.0,0.0 +scenario_009,spouse_medicare_eligible,0.0,0.0 +scenario_009,free_school_meals_eligible,0.0,0.0 +scenario_009,reduced_price_school_meals_eligible,0.0,0.0 +scenario_012,federal_income_tax_before_refundable_credits,0.0, +scenario_012,federal_refundable_credits,6127.0, +scenario_012,payroll_tax,1683.0, +scenario_012,self_employment_tax,0.0, +scenario_012,state_income_tax_before_refundable_credits,0.0, +scenario_012,state_refundable_credits,0.0, +scenario_012,local_income_tax,0.0, +scenario_012,snap,4884.0, +scenario_012,ssi,0.0, +scenario_012,tanf,0.0, +scenario_012,head_wic_eligible,0.0,0.0 +scenario_012,spouse_wic_eligible,1.0,1026.747314453125 +scenario_012,child1_wic_eligible,0.0,0.0 +scenario_012,head_medicaid_eligible,0.0,0.0 +scenario_012,spouse_medicaid_eligible,1.0,7871.869140625 +scenario_012,child1_medicaid_eligible,1.0,7871.869140625 +scenario_012,head_chip_eligible,0.0,0.0 +scenario_012,spouse_chip_eligible,0.0,0.0 +scenario_012,child1_chip_eligible,0.0,0.0 +scenario_012,head_medicare_eligible,0.0,0.0 +scenario_012,spouse_medicare_eligible,0.0,0.0 +scenario_012,child1_medicare_eligible,0.0,0.0 +scenario_012,child1_head_start_eligible,0.0,0.0 +scenario_012,child1_early_head_start_eligible,0.0,0.0 +scenario_012,free_school_meals_eligible,1.0,1130.9622802734375 +scenario_012,reduced_price_school_meals_eligible,0.0,0.0 +scenario_013,federal_income_tax_before_refundable_credits,0.0, +scenario_013,federal_refundable_credits,0.0, +scenario_013,payroll_tax,0.0, +scenario_013,self_employment_tax,0.0, +scenario_013,state_income_tax_before_refundable_credits,0.0, +scenario_013,state_refundable_credits,25.0, +scenario_013,local_income_tax,0.0, +scenario_013,snap,240.0, +scenario_013,ssi,0.0, +scenario_013,tanf,0.0, +scenario_013,head_wic_eligible,0.0,0.0 +scenario_013,head_medicaid_eligible,0.0,0.0 +scenario_013,head_chip_eligible,0.0,0.0 +scenario_013,head_medicare_eligible,1.0,5285.2001953125 +scenario_013,free_school_meals_eligible,0.0,0.0 +scenario_013,reduced_price_school_meals_eligible,0.0,0.0 +scenario_014,federal_income_tax_before_refundable_credits,6311.31787109375, +scenario_014,federal_refundable_credits,0.0, +scenario_014,payroll_tax,6802.96484375, +scenario_014,self_employment_tax,0.0, +scenario_014,state_income_tax_before_refundable_credits,3092.186279296875, +scenario_014,state_refundable_credits,0.0, +scenario_014,local_income_tax,0.0, +scenario_014,snap,0.0, +scenario_014,ssi,0.0, +scenario_014,tanf,0.0, +scenario_014,head_wic_eligible,0.0,0.0 +scenario_014,spouse_wic_eligible,0.0,0.0 +scenario_014,head_medicaid_eligible,0.0,0.0 +scenario_014,spouse_medicaid_eligible,0.0,0.0 +scenario_014,head_chip_eligible,0.0,0.0 +scenario_014,spouse_chip_eligible,0.0,0.0 +scenario_014,head_medicare_eligible,0.0,0.0 +scenario_014,spouse_medicare_eligible,0.0,0.0 +scenario_014,free_school_meals_eligible,0.0,0.0 +scenario_014,reduced_price_school_meals_eligible,0.0,0.0 +scenario_015,federal_income_tax_before_refundable_credits,2969.1259765625, +scenario_015,federal_refundable_credits,0.0, +scenario_015,payroll_tax,3442.5, +scenario_015,self_employment_tax,0.0, +scenario_015,state_income_tax_before_refundable_credits,1236.3267822265625, +scenario_015,state_refundable_credits,0.0, +scenario_015,local_income_tax,670.5501098632812, +scenario_015,snap,0.0, +scenario_015,ssi,0.0, +scenario_015,tanf,0.0, +scenario_015,head_wic_eligible,0.0,0.0 +scenario_015,head_medicaid_eligible,0.0,0.0 +scenario_015,head_chip_eligible,0.0,0.0 +scenario_015,head_medicare_eligible,0.0,0.0 +scenario_015,free_school_meals_eligible,0.0,0.0 +scenario_015,reduced_price_school_meals_eligible,0.0,0.0 +scenario_016,federal_income_tax_before_refundable_credits,0.0, +scenario_016,federal_refundable_credits,0.0, +scenario_016,payroll_tax,2649.80224609375, +scenario_016,self_employment_tax,0.0, +scenario_016,state_income_tax_before_refundable_credits,0.0, +scenario_016,state_refundable_credits,0.0, +scenario_016,local_income_tax,0.0, +scenario_016,snap,0.0, +scenario_016,ssi,0.0, +scenario_016,tanf,0.0, +scenario_016,head_wic_eligible,0.0,0.0 +scenario_016,head_medicaid_eligible,0.0,0.0 +scenario_016,head_chip_eligible,0.0,0.0 +scenario_016,head_medicare_eligible,0.0,0.0 +scenario_016,free_school_meals_eligible,0.0,0.0 +scenario_016,reduced_price_school_meals_eligible,0.0,0.0 +scenario_018,federal_income_tax_before_refundable_credits,5211.05078125, +scenario_018,federal_refundable_credits,0.0, +scenario_018,payroll_tax,5202.38232421875, +scenario_018,self_employment_tax,0.0, +scenario_018,state_income_tax_before_refundable_credits,1137.30224609375, +scenario_018,state_refundable_credits,0.0, +scenario_018,local_income_tax,0.0, +scenario_018,snap,0.0, +scenario_018,ssi,0.0, +scenario_018,tanf,0.0, +scenario_018,head_wic_eligible,0.0,0.0 +scenario_018,head_medicaid_eligible,0.0,0.0 +scenario_018,head_chip_eligible,0.0,0.0 +scenario_018,head_medicare_eligible,0.0,0.0 +scenario_018,free_school_meals_eligible,0.0,0.0 +scenario_018,reduced_price_school_meals_eligible,0.0,0.0 +scenario_020,federal_income_tax_before_refundable_credits,68056.7109375, +scenario_020,federal_refundable_credits,0.0, +scenario_020,payroll_tax,16689.0, +scenario_020,self_employment_tax,0.0, +scenario_020,state_income_tax_before_refundable_credits,0.0, +scenario_020,state_refundable_credits,0.0, +scenario_020,local_income_tax,0.0, +scenario_020,snap,0.0, +scenario_020,ssi,0.0, +scenario_020,tanf,0.0, +scenario_020,head_wic_eligible,0.0,0.0 +scenario_020,head_medicaid_eligible,0.0,0.0 +scenario_020,head_chip_eligible,0.0,0.0 +scenario_020,head_medicare_eligible,0.0,0.0 +scenario_020,free_school_meals_eligible,0.0,0.0 +scenario_020,reduced_price_school_meals_eligible,0.0,0.0 +scenario_021,federal_income_tax_before_refundable_credits,0.0, +scenario_021,federal_refundable_credits,0.0, +scenario_021,payroll_tax,0.0, +scenario_021,self_employment_tax,0.0, +scenario_021,state_income_tax_before_refundable_credits,0.0, +scenario_021,state_refundable_credits,0.0, +scenario_021,local_income_tax,0.0, +scenario_021,snap,0.0, +scenario_021,ssi,0.0, +scenario_021,tanf,0.0, +scenario_021,head_wic_eligible,0.0,0.0 +scenario_021,head_medicaid_eligible,0.0,0.0 +scenario_021,head_chip_eligible,0.0,0.0 +scenario_021,head_medicare_eligible,1.0,5285.2001953125 +scenario_021,free_school_meals_eligible,0.0,0.0 +scenario_021,reduced_price_school_meals_eligible,0.0,0.0 +scenario_022,federal_income_tax_before_refundable_credits,11113.5703125, +scenario_022,federal_refundable_credits,0.0, +scenario_022,payroll_tax,4710.83251953125, +scenario_022,self_employment_tax,0.0, +scenario_022,state_income_tax_before_refundable_credits,1968.805419921875, +scenario_022,state_refundable_credits,0.0, +scenario_022,local_income_tax,0.0, +scenario_022,snap,0.0, +scenario_022,ssi,0.0, +scenario_022,tanf,0.0, +scenario_022,head_wic_eligible,0.0,0.0 +scenario_022,head_medicaid_eligible,0.0,0.0 +scenario_022,head_chip_eligible,0.0,0.0 +scenario_022,head_medicare_eligible,1.0,5285.2001953125 +scenario_022,free_school_meals_eligible,0.0,0.0 +scenario_022,reduced_price_school_meals_eligible,0.0,0.0 +scenario_023,federal_income_tax_before_refundable_credits,643.43359375, +scenario_023,federal_refundable_credits,0.0, +scenario_023,payroll_tax,1561.1168212890625, +scenario_023,self_employment_tax,0.0, +scenario_023,state_income_tax_before_refundable_credits,12.776718139648438, +scenario_023,state_refundable_credits,95.15400695800781, +scenario_023,local_income_tax,0.0, +scenario_023,snap,461.3397216796875, +scenario_023,ssi,0.0, +scenario_023,tanf,0.0, +scenario_023,head_wic_eligible,0.0,0.0 +scenario_023,head_medicaid_eligible,1.0,6612.93994140625 +scenario_023,head_chip_eligible,0.0,0.0 +scenario_023,head_medicare_eligible,0.0,0.0 +scenario_023,free_school_meals_eligible,0.0,0.0 +scenario_023,reduced_price_school_meals_eligible,0.0,0.0 +scenario_025,federal_income_tax_before_refundable_credits,7031.03564453125, +scenario_025,federal_refundable_credits,0.0, +scenario_025,payroll_tax,4798.48486328125, +scenario_025,self_employment_tax,0.0, +scenario_025,state_income_tax_before_refundable_credits,1916.606201171875, +scenario_025,state_refundable_credits,0.0, +scenario_025,local_income_tax,0.0, +scenario_025,snap,0.0, +scenario_025,ssi,0.0, +scenario_025,tanf,0.0, +scenario_025,head_wic_eligible,0.0,0.0 +scenario_025,spouse_wic_eligible,0.0,0.0 +scenario_025,head_medicaid_eligible,0.0,0.0 +scenario_025,spouse_medicaid_eligible,0.0,0.0 +scenario_025,head_chip_eligible,0.0,0.0 +scenario_025,spouse_chip_eligible,0.0,0.0 +scenario_025,head_medicare_eligible,0.0,0.0 +scenario_025,spouse_medicare_eligible,0.0,0.0 +scenario_025,free_school_meals_eligible,0.0,0.0 +scenario_025,reduced_price_school_meals_eligible,0.0,0.0 +scenario_026,federal_income_tax_before_refundable_credits,0.0, +scenario_026,federal_refundable_credits,2013.4892578125, +scenario_026,payroll_tax,6518.474609375, +scenario_026,self_employment_tax,0.0, +scenario_026,state_income_tax_before_refundable_credits,2086.79052734375, +scenario_026,state_refundable_credits,0.0, +scenario_026,local_income_tax,0.0, +scenario_026,snap,0.0, +scenario_026,ssi,0.0, +scenario_026,tanf,0.0, +scenario_026,head_wic_eligible,0.0,0.0 +scenario_026,spouse_wic_eligible,0.0,0.0 +scenario_026,child1_wic_eligible,0.0,0.0 +scenario_026,child2_wic_eligible,0.0,0.0 +scenario_026,child3_wic_eligible,0.0,0.0 +scenario_026,head_medicaid_eligible,0.0,0.0 +scenario_026,spouse_medicaid_eligible,0.0,0.0 +scenario_026,child1_medicaid_eligible,1.0,3820.046875 +scenario_026,child2_medicaid_eligible,1.0,3820.046875 +scenario_026,child3_medicaid_eligible,1.0,3820.046875 +scenario_026,head_chip_eligible,0.0,0.0 +scenario_026,spouse_chip_eligible,0.0,0.0 +scenario_026,child1_chip_eligible,0.0,0.0 +scenario_026,child2_chip_eligible,0.0,0.0 +scenario_026,child3_chip_eligible,0.0,0.0 +scenario_026,head_medicare_eligible,0.0,0.0 +scenario_026,spouse_medicare_eligible,0.0,0.0 +scenario_026,child1_medicare_eligible,0.0,0.0 +scenario_026,child2_medicare_eligible,0.0,0.0 +scenario_026,child3_medicare_eligible,0.0,0.0 +scenario_026,child1_head_start_eligible,0.0,0.0 +scenario_026,child2_head_start_eligible,0.0,0.0 +scenario_026,child3_head_start_eligible,0.0,0.0 +scenario_026,child1_early_head_start_eligible,0.0,0.0 +scenario_026,child2_early_head_start_eligible,0.0,0.0 +scenario_026,child3_early_head_start_eligible,0.0,0.0 +scenario_026,free_school_meals_eligible,0.0,0.0 +scenario_026,reduced_price_school_meals_eligible,0.0,0.0 +scenario_027,federal_income_tax_before_refundable_credits,0.0, +scenario_027,federal_refundable_credits,0.0, +scenario_027,payroll_tax,0.0, +scenario_027,self_employment_tax,0.0, +scenario_027,state_income_tax_before_refundable_credits,0.0, +scenario_027,state_refundable_credits,0.0, +scenario_027,local_income_tax,0.0, +scenario_027,snap,288.0, +scenario_027,ssi,0.0, +scenario_027,tanf,0.0, +scenario_027,head_wic_eligible,0.0,0.0 +scenario_027,spouse_wic_eligible,0.0,0.0 +scenario_027,head_medicaid_eligible,0.0,0.0 +scenario_027,spouse_medicaid_eligible,0.0,0.0 +scenario_027,head_chip_eligible,0.0,0.0 +scenario_027,spouse_chip_eligible,0.0,0.0 +scenario_027,head_medicare_eligible,1.0,5285.2001953125 +scenario_027,spouse_medicare_eligible,0.0,0.0 +scenario_027,free_school_meals_eligible,0.0,0.0 +scenario_027,reduced_price_school_meals_eligible,0.0,0.0 +scenario_028,federal_income_tax_before_refundable_credits,0.0, +scenario_028,federal_refundable_credits,3274.927978515625, +scenario_028,payroll_tax,4632.0, +scenario_028,self_employment_tax,0.0, +scenario_028,state_income_tax_before_refundable_credits,1842.3070068359375, +scenario_028,state_refundable_credits,62.41279220581055, +scenario_028,local_income_tax,0.0, +scenario_028,snap,0.0, +scenario_028,ssi,0.0, +scenario_028,tanf,0.0, +scenario_028,head_wic_eligible,0.0,0.0 +scenario_028,child1_wic_eligible,0.0,0.0 +scenario_028,child2_wic_eligible,0.0,0.0 +scenario_028,child3_wic_eligible,0.0,0.0 +scenario_028,head_medicaid_eligible,0.0,0.0 +scenario_028,child1_medicaid_eligible,0.0,0.0 +scenario_028,child2_medicaid_eligible,0.0,0.0 +scenario_028,child3_medicaid_eligible,0.0,0.0 +scenario_028,head_chip_eligible,0.0,0.0 +scenario_028,child1_chip_eligible,0.0,0.0 +scenario_028,child2_chip_eligible,0.0,0.0 +scenario_028,child3_chip_eligible,0.0,0.0 +scenario_028,head_medicare_eligible,0.0,0.0 +scenario_028,child1_medicare_eligible,0.0,0.0 +scenario_028,child2_medicare_eligible,0.0,0.0 +scenario_028,child3_medicare_eligible,0.0,0.0 +scenario_028,child1_head_start_eligible,0.0,0.0 +scenario_028,child2_head_start_eligible,0.0,0.0 +scenario_028,child3_head_start_eligible,0.0,0.0 +scenario_028,child1_early_head_start_eligible,0.0,0.0 +scenario_028,child2_early_head_start_eligible,0.0,0.0 +scenario_028,child3_early_head_start_eligible,0.0,0.0 +scenario_028,free_school_meals_eligible,1.0,0.0 +scenario_028,reduced_price_school_meals_eligible,0.0,3009.81884765625 +scenario_029,federal_income_tax_before_refundable_credits,0.0, +scenario_029,federal_refundable_credits,0.0, +scenario_029,payroll_tax,0.0, +scenario_029,self_employment_tax,0.0, +scenario_029,state_income_tax_before_refundable_credits,0.0, +scenario_029,state_refundable_credits,40.0, +scenario_029,local_income_tax,0.0, +scenario_029,snap,0.0, +scenario_029,ssi,0.0, +scenario_029,tanf,0.0, +scenario_029,head_wic_eligible,0.0,0.0 +scenario_029,head_medicaid_eligible,1.0,9609.619140625 +scenario_029,head_chip_eligible,0.0,0.0 +scenario_029,head_medicare_eligible,0.0,0.0 +scenario_029,free_school_meals_eligible,0.0,0.0 +scenario_029,reduced_price_school_meals_eligible,0.0,0.0 +scenario_030,federal_income_tax_before_refundable_credits,0.0, +scenario_030,federal_refundable_credits,0.0, +scenario_030,payroll_tax,994.5, +scenario_030,self_employment_tax,0.0, +scenario_030,state_income_tax_before_refundable_credits,0.0, +scenario_030,state_refundable_credits,0.0, +scenario_030,local_income_tax,0.0, +scenario_030,snap,288.0, +scenario_030,ssi,0.0, +scenario_030,tanf,0.0, +scenario_030,head_wic_eligible,1.0,1026.747314453125 +scenario_030,head_medicaid_eligible,1.0,6607.0888671875 +scenario_030,head_chip_eligible,0.0,0.0 +scenario_030,head_medicare_eligible,0.0,0.0 +scenario_030,free_school_meals_eligible,0.0,0.0 +scenario_030,reduced_price_school_meals_eligible,0.0,0.0 +scenario_031,federal_income_tax_before_refundable_credits,0.0, +scenario_031,federal_refundable_credits,0.0, +scenario_031,payroll_tax,0.0, +scenario_031,self_employment_tax,0.0, +scenario_031,state_income_tax_before_refundable_credits,0.0, +scenario_031,state_refundable_credits,0.0, +scenario_031,local_income_tax,0.0, +scenario_031,snap,288.0, +scenario_031,ssi,0.0, +scenario_031,tanf,0.0, +scenario_031,head_wic_eligible,0.0,0.0 +scenario_031,head_medicaid_eligible,1.0,18251.322265625 +scenario_031,head_chip_eligible,0.0,0.0 +scenario_031,head_medicare_eligible,1.0,5285.2001953125 +scenario_031,free_school_meals_eligible,0.0,0.0 +scenario_031,reduced_price_school_meals_eligible,0.0,0.0 +scenario_032,federal_income_tax_before_refundable_credits,0.0, +scenario_032,federal_refundable_credits,6127.0, +scenario_032,payroll_tax,2346.10009765625, +scenario_032,self_employment_tax,0.0, +scenario_032,state_income_tax_before_refundable_credits,0.0, +scenario_032,state_refundable_credits,2187.60009765625, +scenario_032,local_income_tax,0.0, +scenario_032,snap,0.0, +scenario_032,ssi,0.0, +scenario_032,tanf,0.0, +scenario_032,head_wic_eligible,0.0,0.0 +scenario_032,spouse_wic_eligible,0.0,0.0 +scenario_032,child1_wic_eligible,0.0,0.0 +scenario_032,head_medicaid_eligible,0.0,0.0 +scenario_032,spouse_medicaid_eligible,1.0,8593.0478515625 +scenario_032,child1_medicaid_eligible,1.0,8593.0478515625 +scenario_032,head_chip_eligible,0.0,0.0 +scenario_032,spouse_chip_eligible,0.0,0.0 +scenario_032,child1_chip_eligible,0.0,0.0 +scenario_032,head_medicare_eligible,0.0,0.0 +scenario_032,spouse_medicare_eligible,0.0,0.0 +scenario_032,child1_medicare_eligible,0.0,0.0 +scenario_032,child1_head_start_eligible,0.0,0.0 +scenario_032,child1_early_head_start_eligible,0.0,0.0 +scenario_032,free_school_meals_eligible,1.0,1130.9622802734375 +scenario_032,reduced_price_school_meals_eligible,0.0,0.0 +scenario_033,federal_income_tax_before_refundable_credits,3818.148193359375, +scenario_033,federal_refundable_credits,0.0, +scenario_033,payroll_tax,6043.5, +scenario_033,self_employment_tax,0.0, +scenario_033,state_income_tax_before_refundable_credits,0.0, +scenario_033,state_refundable_credits,0.0, +scenario_033,local_income_tax,0.0, +scenario_033,snap,0.0, +scenario_033,ssi,0.0, +scenario_033,tanf,0.0, +scenario_033,head_wic_eligible,0.0,0.0 +scenario_033,spouse_wic_eligible,0.0,0.0 +scenario_033,head_medicaid_eligible,0.0,0.0 +scenario_033,spouse_medicaid_eligible,0.0,0.0 +scenario_033,head_chip_eligible,0.0,0.0 +scenario_033,spouse_chip_eligible,0.0,0.0 +scenario_033,head_medicare_eligible,1.0,5285.2001953125 +scenario_033,spouse_medicare_eligible,1.0,5285.2001953125 +scenario_033,free_school_meals_eligible,0.0,0.0 +scenario_033,reduced_price_school_meals_eligible,0.0,0.0 +scenario_036,federal_income_tax_before_refundable_credits,4926.39990234375, +scenario_036,federal_refundable_credits,0.0, +scenario_036,payroll_tax,0.0, +scenario_036,self_employment_tax,0.0, +scenario_036,state_income_tax_before_refundable_credits,1724.155029296875, +scenario_036,state_refundable_credits,0.0, +scenario_036,local_income_tax,0.0, +scenario_036,snap,0.0, +scenario_036,ssi,0.0, +scenario_036,tanf,0.0, +scenario_036,head_wic_eligible,0.0,0.0 +scenario_036,head_medicaid_eligible,0.0,0.0 +scenario_036,head_chip_eligible,0.0,0.0 +scenario_036,head_medicare_eligible,0.0,0.0 +scenario_036,free_school_meals_eligible,0.0,0.0 +scenario_036,reduced_price_school_meals_eligible,0.0,0.0 +scenario_037,federal_income_tax_before_refundable_credits,1649.2513427734375, +scenario_037,federal_refundable_credits,0.0, +scenario_037,payroll_tax,3208.668701171875, +scenario_037,self_employment_tax,0.0, +scenario_037,state_income_tax_before_refundable_credits,1148.69921875, +scenario_037,state_refundable_credits,0.0, +scenario_037,local_income_tax,0.0, +scenario_037,snap,0.0, +scenario_037,ssi,0.0, +scenario_037,tanf,0.0, +scenario_037,head_wic_eligible,0.0,0.0 +scenario_037,head_medicaid_eligible,0.0,0.0 +scenario_037,head_chip_eligible,0.0,0.0 +scenario_037,head_medicare_eligible,0.0,0.0 +scenario_037,free_school_meals_eligible,0.0,0.0 +scenario_037,reduced_price_school_meals_eligible,0.0,0.0 +scenario_038,federal_income_tax_before_refundable_credits,0.0, +scenario_038,federal_refundable_credits,10225.353515625, +scenario_038,payroll_tax,571.2637329101562, +scenario_038,self_employment_tax,2193.612548828125, +scenario_038,state_income_tax_before_refundable_credits,0.0, +scenario_038,state_refundable_credits,365.8000183105469, +scenario_038,local_income_tax,0.0, +scenario_038,snap,7212.0, +scenario_038,ssi,0.0, +scenario_038,tanf,0.0, +scenario_038,head_wic_eligible,0.0,0.0 +scenario_038,spouse_wic_eligible,0.0,0.0 +scenario_038,child1_wic_eligible,0.0,0.0 +scenario_038,child2_wic_eligible,0.0,0.0 +scenario_038,head_medicaid_eligible,1.0,9648.587890625 +scenario_038,spouse_medicaid_eligible,1.0,8774.4521484375 +scenario_038,child1_medicaid_eligible,1.0,7351.86572265625 +scenario_038,child2_medicaid_eligible,1.0,7351.86572265625 +scenario_038,head_chip_eligible,0.0,0.0 +scenario_038,spouse_chip_eligible,0.0,0.0 +scenario_038,child1_chip_eligible,0.0,0.0 +scenario_038,child2_chip_eligible,0.0,0.0 +scenario_038,head_medicare_eligible,0.0,0.0 +scenario_038,spouse_medicare_eligible,0.0,0.0 +scenario_038,child1_medicare_eligible,0.0,0.0 +scenario_038,child2_medicare_eligible,0.0,0.0 +scenario_038,child1_head_start_eligible,0.0,0.0 +scenario_038,child2_head_start_eligible,0.0,0.0 +scenario_038,child1_early_head_start_eligible,0.0,0.0 +scenario_038,child2_early_head_start_eligible,0.0,0.0 +scenario_038,free_school_meals_eligible,1.0,2261.924560546875 +scenario_038,reduced_price_school_meals_eligible,0.0,0.0 +scenario_039,federal_income_tax_before_refundable_credits,8596.0283203125, +scenario_039,federal_refundable_credits,0.0, +scenario_039,payroll_tax,0.0, +scenario_039,self_employment_tax,0.0, +scenario_039,state_income_tax_before_refundable_credits,1975.7982177734375, +scenario_039,state_refundable_credits,0.0, +scenario_039,local_income_tax,0.0, +scenario_039,snap,0.0, +scenario_039,ssi,0.0, +scenario_039,tanf,0.0, +scenario_039,head_wic_eligible,0.0,0.0 +scenario_039,head_medicaid_eligible,0.0,0.0 +scenario_039,head_chip_eligible,0.0,0.0 +scenario_039,head_medicare_eligible,0.0,0.0 +scenario_039,free_school_meals_eligible,0.0,0.0 +scenario_039,reduced_price_school_meals_eligible,0.0,0.0 +scenario_040,federal_income_tax_before_refundable_credits,0.0, +scenario_040,federal_refundable_credits,0.0, +scenario_040,payroll_tax,2142.0, +scenario_040,self_employment_tax,0.0, +scenario_040,state_income_tax_before_refundable_credits,0.0, +scenario_040,state_refundable_credits,0.0, +scenario_040,local_income_tax,0.0, +scenario_040,snap,0.0, +scenario_040,ssi,0.0, +scenario_040,tanf,0.0, +scenario_040,head_wic_eligible,0.0,0.0 +scenario_040,spouse_wic_eligible,0.0,0.0 +scenario_040,head_medicaid_eligible,0.0,0.0 +scenario_040,spouse_medicaid_eligible,0.0,0.0 +scenario_040,head_chip_eligible,0.0,0.0 +scenario_040,spouse_chip_eligible,0.0,0.0 +scenario_040,head_medicare_eligible,1.0,5285.2001953125 +scenario_040,spouse_medicare_eligible,1.0,5285.2001953125 +scenario_040,free_school_meals_eligible,0.0,0.0 +scenario_040,reduced_price_school_meals_eligible,0.0,0.0 +scenario_042,federal_income_tax_before_refundable_credits,2361.96484375, +scenario_042,federal_refundable_credits,0.0, +scenario_042,payroll_tax,0.0, +scenario_042,self_employment_tax,0.0, +scenario_042,state_income_tax_before_refundable_credits,0.0, +scenario_042,state_refundable_credits,0.0, +scenario_042,local_income_tax,0.0, +scenario_042,snap,0.0, +scenario_042,ssi,0.0, +scenario_042,tanf,0.0, +scenario_042,head_wic_eligible,0.0,0.0 +scenario_042,head_medicaid_eligible,0.0,0.0 +scenario_042,head_chip_eligible,0.0,0.0 +scenario_042,head_medicare_eligible,1.0,5285.2001953125 +scenario_042,free_school_meals_eligible,0.0,0.0 +scenario_042,reduced_price_school_meals_eligible,0.0,0.0 +scenario_043,federal_income_tax_before_refundable_credits,0.0, +scenario_043,federal_refundable_credits,0.0, +scenario_043,payroll_tax,330.7310791015625, +scenario_043,self_employment_tax,0.0, +scenario_043,state_income_tax_before_refundable_credits,0.0, +scenario_043,state_refundable_credits,0.0, +scenario_043,local_income_tax,0.0, +scenario_043,snap,3576.0, +scenario_043,ssi,0.0, +scenario_043,tanf,0.0, +scenario_043,head_wic_eligible,0.0,0.0 +scenario_043,head_medicaid_eligible,0.0,0.0 +scenario_043,head_chip_eligible,0.0,0.0 +scenario_043,head_medicare_eligible,1.0,5285.2001953125 +scenario_043,free_school_meals_eligible,0.0,0.0 +scenario_043,reduced_price_school_meals_eligible,0.0,0.0 +scenario_044,federal_income_tax_before_refundable_credits,0.0, +scenario_044,federal_refundable_credits,0.0, +scenario_044,payroll_tax,0.0, +scenario_044,self_employment_tax,0.0, +scenario_044,state_income_tax_before_refundable_credits,0.0, +scenario_044,state_refundable_credits,0.0, +scenario_044,local_income_tax,0.0, +scenario_044,snap,0.0, +scenario_044,ssi,0.0, +scenario_044,tanf,0.0, +scenario_044,head_wic_eligible,0.0,0.0 +scenario_044,spouse_wic_eligible,0.0,0.0 +scenario_044,head_medicaid_eligible,0.0,0.0 +scenario_044,spouse_medicaid_eligible,0.0,0.0 +scenario_044,head_chip_eligible,0.0,0.0 +scenario_044,spouse_chip_eligible,0.0,0.0 +scenario_044,head_medicare_eligible,1.0,5285.2001953125 +scenario_044,spouse_medicare_eligible,0.0,0.0 +scenario_044,free_school_meals_eligible,0.0,0.0 +scenario_044,reduced_price_school_meals_eligible,0.0,0.0 +scenario_045,federal_income_tax_before_refundable_credits,2173.07080078125, +scenario_045,federal_refundable_credits,0.0, +scenario_045,payroll_tax,2775.08251953125, +scenario_045,self_employment_tax,0.0, +scenario_045,state_income_tax_before_refundable_credits,1290.9625244140625, +scenario_045,state_refundable_credits,760.7887573242188, +scenario_045,local_income_tax,0.0, +scenario_045,snap,0.0, +scenario_045,ssi,0.0, +scenario_045,tanf,0.0, +scenario_045,head_wic_eligible,0.0,0.0 +scenario_045,head_medicaid_eligible,0.0,0.0 +scenario_045,head_chip_eligible,0.0,0.0 +scenario_045,head_medicare_eligible,0.0,0.0 +scenario_045,free_school_meals_eligible,0.0,0.0 +scenario_045,reduced_price_school_meals_eligible,0.0,0.0 +scenario_046,federal_income_tax_before_refundable_credits,499.71484375, +scenario_046,federal_refundable_credits,0.0, +scenario_046,payroll_tax,7038.0, +scenario_046,self_employment_tax,0.0, +scenario_046,state_income_tax_before_refundable_credits,2739.135009765625, +scenario_046,state_refundable_credits,0.0, +scenario_046,local_income_tax,0.0, +scenario_046,snap,0.0, +scenario_046,ssi,0.0, +scenario_046,tanf,0.0, +scenario_046,head_wic_eligible,0.0,0.0 +scenario_046,spouse_wic_eligible,0.0,0.0 +scenario_046,child1_wic_eligible,0.0,0.0 +scenario_046,child2_wic_eligible,0.0,0.0 +scenario_046,head_medicaid_eligible,0.0,0.0 +scenario_046,spouse_medicaid_eligible,0.0,0.0 +scenario_046,child1_medicaid_eligible,0.0,0.0 +scenario_046,child2_medicaid_eligible,0.0,0.0 +scenario_046,head_chip_eligible,0.0,0.0 +scenario_046,spouse_chip_eligible,0.0,0.0 +scenario_046,child1_chip_eligible,0.0,0.0 +scenario_046,child2_chip_eligible,0.0,0.0 +scenario_046,head_medicare_eligible,0.0,0.0 +scenario_046,spouse_medicare_eligible,0.0,0.0 +scenario_046,child1_medicare_eligible,0.0,0.0 +scenario_046,child2_medicare_eligible,0.0,0.0 +scenario_046,child1_head_start_eligible,0.0,0.0 +scenario_046,child2_head_start_eligible,0.0,0.0 +scenario_046,child1_early_head_start_eligible,0.0,0.0 +scenario_046,child2_early_head_start_eligible,0.0,0.0 +scenario_046,free_school_meals_eligible,0.0,0.0 +scenario_046,reduced_price_school_meals_eligible,0.0,0.0 +scenario_048,federal_income_tax_before_refundable_credits,0.0, +scenario_048,federal_refundable_credits,0.0, +scenario_048,payroll_tax,585.6839599609375, +scenario_048,self_employment_tax,0.0, +scenario_048,state_income_tax_before_refundable_credits,0.0, +scenario_048,state_refundable_credits,0.0, +scenario_048,local_income_tax,0.0, +scenario_048,snap,0.0, +scenario_048,ssi,0.0, +scenario_048,tanf,0.0, +scenario_048,head_wic_eligible,0.0,0.0 +scenario_048,head_medicaid_eligible,0.0,0.0 +scenario_048,head_chip_eligible,0.0,0.0 +scenario_048,head_medicare_eligible,1.0,5285.2001953125 +scenario_048,free_school_meals_eligible,0.0,0.0 +scenario_048,reduced_price_school_meals_eligible,0.0,0.0 +scenario_049,federal_income_tax_before_refundable_credits,30702.58984375, +scenario_049,federal_refundable_credits,0.0, +scenario_049,payroll_tax,15134.5, +scenario_049,self_employment_tax,0.0, +scenario_049,state_income_tax_before_refundable_credits,0.0, +scenario_049,state_refundable_credits,0.0, +scenario_049,local_income_tax,0.0, +scenario_049,snap,0.0, +scenario_049,ssi,0.0, +scenario_049,tanf,0.0, +scenario_049,head_wic_eligible,0.0,0.0 +scenario_049,spouse_wic_eligible,0.0,0.0 +scenario_049,head_medicaid_eligible,0.0,0.0 +scenario_049,spouse_medicaid_eligible,0.0,0.0 +scenario_049,head_chip_eligible,0.0,0.0 +scenario_049,spouse_chip_eligible,0.0,0.0 +scenario_049,head_medicare_eligible,0.0,0.0 +scenario_049,spouse_medicare_eligible,0.0,0.0 +scenario_049,free_school_meals_eligible,0.0,0.0 +scenario_049,reduced_price_school_meals_eligible,0.0,0.0 +scenario_051,federal_income_tax_before_refundable_credits,2620.0, +scenario_051,federal_refundable_credits,0.0, +scenario_051,payroll_tax,3060.0, +scenario_051,self_employment_tax,0.0, +scenario_051,state_income_tax_before_refundable_credits,820.3499755859375, +scenario_051,state_refundable_credits,0.0, +scenario_051,local_income_tax,0.0, +scenario_051,snap,0.0, +scenario_051,ssi,0.0, +scenario_051,tanf,0.0, +scenario_051,head_wic_eligible,0.0,0.0 +scenario_051,head_medicaid_eligible,0.0,0.0 +scenario_051,head_chip_eligible,0.0,0.0 +scenario_051,head_medicare_eligible,0.0,0.0 +scenario_051,free_school_meals_eligible,0.0,0.0 +scenario_051,reduced_price_school_meals_eligible,0.0,0.0 +scenario_052,federal_income_tax_before_refundable_credits,104211.40625, +scenario_052,federal_refundable_credits,0.0, +scenario_052,payroll_tax,20939.0, +scenario_052,self_employment_tax,0.0, +scenario_052,state_income_tax_before_refundable_credits,0.0, +scenario_052,state_refundable_credits,0.0, +scenario_052,local_income_tax,0.0, +scenario_052,snap,0.0, +scenario_052,ssi,0.0, +scenario_052,tanf,0.0, +scenario_052,head_wic_eligible,0.0,0.0 +scenario_052,spouse_wic_eligible,0.0,0.0 +scenario_052,head_medicaid_eligible,0.0,0.0 +scenario_052,spouse_medicaid_eligible,0.0,0.0 +scenario_052,head_chip_eligible,0.0,0.0 +scenario_052,spouse_chip_eligible,0.0,0.0 +scenario_052,head_medicare_eligible,0.0,0.0 +scenario_052,spouse_medicare_eligible,0.0,0.0 +scenario_052,free_school_meals_eligible,0.0,0.0 +scenario_052,reduced_price_school_meals_eligible,0.0,0.0 +scenario_053,federal_income_tax_before_refundable_credits,5903.109375, +scenario_053,federal_refundable_credits,0.0, +scenario_053,payroll_tax,5123.10400390625, +scenario_053,self_employment_tax,0.0, +scenario_053,state_income_tax_before_refundable_credits,2186.05712890625, +scenario_053,state_refundable_credits,155.0, +scenario_053,local_income_tax,0.0, +scenario_053,snap,0.0, +scenario_053,ssi,0.0, +scenario_053,tanf,0.0, +scenario_053,head_wic_eligible,0.0,0.0 +scenario_053,head_medicaid_eligible,0.0,0.0 +scenario_053,head_chip_eligible,0.0,0.0 +scenario_053,head_medicare_eligible,0.0,0.0 +scenario_053,free_school_meals_eligible,0.0,0.0 +scenario_053,reduced_price_school_meals_eligible,0.0,0.0 +scenario_054,federal_income_tax_before_refundable_credits,0.0, +scenario_054,federal_refundable_credits,8365.55859375, +scenario_054,payroll_tax,0.0, +scenario_054,self_employment_tax,2416.15283203125, +scenario_054,state_income_tax_before_refundable_credits,0.0, +scenario_054,state_refundable_credits,0.0, +scenario_054,local_income_tax,0.0, +scenario_054,snap,6060.0, +scenario_054,ssi,0.0, +scenario_054,tanf,0.0, +scenario_054,head_wic_eligible,0.0,0.0 +scenario_054,child1_wic_eligible,0.0,0.0 +scenario_054,child2_wic_eligible,1.0,723.1546020507812 +scenario_054,head_medicaid_eligible,1.0,6381.77099609375 +scenario_054,child1_medicaid_eligible,1.0,3820.046875 +scenario_054,child2_medicaid_eligible,1.0,3820.046875 +scenario_054,head_chip_eligible,0.0,0.0 +scenario_054,child1_chip_eligible,0.0,0.0 +scenario_054,child2_chip_eligible,0.0,0.0 +scenario_054,head_medicare_eligible,0.0,0.0 +scenario_054,child1_medicare_eligible,0.0,0.0 +scenario_054,child2_medicare_eligible,0.0,0.0 +scenario_054,child1_head_start_eligible,0.0,0.0 +scenario_054,child2_head_start_eligible,0.0,0.0 +scenario_054,child1_early_head_start_eligible,0.0,0.0 +scenario_054,child2_early_head_start_eligible,1.0,26084.623046875 +scenario_054,free_school_meals_eligible,1.0,1130.9622802734375 +scenario_054,reduced_price_school_meals_eligible,0.0,0.0 +scenario_055,federal_income_tax_before_refundable_credits,25238.578125, +scenario_055,federal_refundable_credits,0.0, +scenario_055,payroll_tax,6398.08837890625, +scenario_055,self_employment_tax,0.0, +scenario_055,state_income_tax_before_refundable_credits,0.0, +scenario_055,state_refundable_credits,0.0, +scenario_055,local_income_tax,0.0, +scenario_055,snap,0.0, +scenario_055,ssi,0.0, +scenario_055,tanf,0.0, +scenario_055,head_wic_eligible,0.0,0.0 +scenario_055,head_medicaid_eligible,0.0,0.0 +scenario_055,head_chip_eligible,0.0,0.0 +scenario_055,head_medicare_eligible,1.0,5285.2001953125 +scenario_055,free_school_meals_eligible,0.0,0.0 +scenario_055,reduced_price_school_meals_eligible,0.0,0.0 +scenario_056,federal_income_tax_before_refundable_credits,0.0, +scenario_056,federal_refundable_credits,0.0, +scenario_056,payroll_tax,0.0, +scenario_056,self_employment_tax,613.2224731445312, +scenario_056,state_income_tax_before_refundable_credits,0.0, +scenario_056,state_refundable_credits,265.6000061035156, +scenario_056,local_income_tax,0.0, +scenario_056,snap,1140.0, +scenario_056,ssi,0.0, +scenario_056,tanf,0.0, +scenario_056,head_wic_eligible,0.0,0.0 +scenario_056,head_medicaid_eligible,1.0,10106.5751953125 +scenario_056,head_chip_eligible,0.0,0.0 +scenario_056,head_medicare_eligible,0.0,0.0 +scenario_056,free_school_meals_eligible,0.0,0.0 +scenario_056,reduced_price_school_meals_eligible,0.0,0.0 +scenario_057,federal_income_tax_before_refundable_credits,0.0, +scenario_057,federal_refundable_credits,664.0, +scenario_057,payroll_tax,0.0, +scenario_057,self_employment_tax,1469.4732666015625, +scenario_057,state_income_tax_before_refundable_credits,0.0, +scenario_057,state_refundable_credits,33.20000076293945, +scenario_057,local_income_tax,0.0, +scenario_057,snap,2669.217041015625, +scenario_057,ssi,7231.00146484375, +scenario_057,tanf,0.0, +scenario_057,head_wic_eligible,0.0,0.0 +scenario_057,spouse_wic_eligible,0.0,0.0 +scenario_057,head_medicaid_eligible,1.0,13041.474609375 +scenario_057,spouse_medicaid_eligible,1.0,9322.166015625 +scenario_057,head_chip_eligible,0.0,0.0 +scenario_057,spouse_chip_eligible,0.0,0.0 +scenario_057,head_medicare_eligible,0.0,0.0 +scenario_057,spouse_medicare_eligible,0.0,0.0 +scenario_057,free_school_meals_eligible,0.0,0.0 +scenario_057,reduced_price_school_meals_eligible,0.0,0.0 +scenario_059,federal_income_tax_before_refundable_credits,0.0, +scenario_059,federal_refundable_credits,0.0, +scenario_059,payroll_tax,0.0, +scenario_059,self_employment_tax,0.0, +scenario_059,state_income_tax_before_refundable_credits,0.0, +scenario_059,state_refundable_credits,0.0, +scenario_059,local_income_tax,0.0, +scenario_059,snap,0.0, +scenario_059,ssi,0.0, +scenario_059,tanf,0.0, +scenario_059,head_wic_eligible,0.0,0.0 +scenario_059,spouse_wic_eligible,0.0,0.0 +scenario_059,head_medicaid_eligible,0.0,0.0 +scenario_059,spouse_medicaid_eligible,0.0,0.0 +scenario_059,head_chip_eligible,0.0,0.0 +scenario_059,spouse_chip_eligible,0.0,0.0 +scenario_059,head_medicare_eligible,1.0,5285.2001953125 +scenario_059,spouse_medicare_eligible,1.0,5285.2001953125 +scenario_059,free_school_meals_eligible,0.0,0.0 +scenario_059,reduced_price_school_meals_eligible,0.0,0.0 +scenario_060,federal_income_tax_before_refundable_credits,0.0, +scenario_060,federal_refundable_credits,0.0, +scenario_060,payroll_tax,229.5, +scenario_060,self_employment_tax,0.0, +scenario_060,state_income_tax_before_refundable_credits,0.0, +scenario_060,state_refundable_credits,0.0, +scenario_060,local_income_tax,0.0, +scenario_060,snap,0.0, +scenario_060,ssi,0.0, +scenario_060,tanf,0.0, +scenario_060,head_wic_eligible,0.0,0.0 +scenario_060,head_medicaid_eligible,0.0,0.0 +scenario_060,head_chip_eligible,0.0,0.0 +scenario_060,head_medicare_eligible,1.0,5285.2001953125 +scenario_060,free_school_meals_eligible,0.0,0.0 +scenario_060,reduced_price_school_meals_eligible,0.0,0.0 +scenario_062,federal_income_tax_before_refundable_credits,0.0, +scenario_062,federal_refundable_credits,0.0, +scenario_062,payroll_tax,0.0, +scenario_062,self_employment_tax,0.0, +scenario_062,state_income_tax_before_refundable_credits,0.0, +scenario_062,state_refundable_credits,0.0, +scenario_062,local_income_tax,0.0, +scenario_062,snap,0.0, +scenario_062,ssi,0.0, +scenario_062,tanf,0.0, +scenario_062,head_wic_eligible,0.0,0.0 +scenario_062,head_medicaid_eligible,0.0,0.0 +scenario_062,head_chip_eligible,0.0,0.0 +scenario_062,head_medicare_eligible,1.0,5285.2001953125 +scenario_062,free_school_meals_eligible,0.0,0.0 +scenario_062,reduced_price_school_meals_eligible,0.0,0.0 +scenario_064,federal_income_tax_before_refundable_credits,4441.455078125, +scenario_064,federal_refundable_credits,0.0, +scenario_064,payroll_tax,7443.0673828125, +scenario_064,self_employment_tax,0.0, +scenario_064,state_income_tax_before_refundable_credits,4599.62158203125, +scenario_064,state_refundable_credits,0.0, +scenario_064,local_income_tax,0.0, +scenario_064,snap,0.0, +scenario_064,ssi,0.0, +scenario_064,tanf,0.0, +scenario_064,head_wic_eligible,0.0,0.0 +scenario_064,spouse_wic_eligible,0.0,0.0 +scenario_064,dependent1_wic_eligible,0.0,0.0 +scenario_064,dependent2_wic_eligible,0.0,0.0 +scenario_064,child1_wic_eligible,0.0,0.0 +scenario_064,head_medicaid_eligible,0.0,0.0 +scenario_064,spouse_medicaid_eligible,0.0,0.0 +scenario_064,dependent1_medicaid_eligible,1.0,6584.33984375 +scenario_064,dependent2_medicaid_eligible,0.0,0.0 +scenario_064,child1_medicaid_eligible,0.0,0.0 +scenario_064,head_chip_eligible,0.0,0.0 +scenario_064,spouse_chip_eligible,0.0,0.0 +scenario_064,dependent1_chip_eligible,0.0,0.0 +scenario_064,dependent2_chip_eligible,0.0,0.0 +scenario_064,child1_chip_eligible,0.0,0.0 +scenario_064,head_medicare_eligible,0.0,0.0 +scenario_064,spouse_medicare_eligible,0.0,0.0 +scenario_064,dependent1_medicare_eligible,0.0,0.0 +scenario_064,dependent2_medicare_eligible,0.0,0.0 +scenario_064,child1_medicare_eligible,0.0,0.0 +scenario_064,child1_head_start_eligible,0.0,0.0 +scenario_064,child1_early_head_start_eligible,0.0,0.0 +scenario_064,free_school_meals_eligible,0.0,0.0 +scenario_064,reduced_price_school_meals_eligible,0.0,0.0 +scenario_066,federal_income_tax_before_refundable_credits,0.0, +scenario_066,federal_refundable_credits,39.779998779296875, +scenario_066,payroll_tax,39.779998779296875, +scenario_066,self_employment_tax,0.0, +scenario_066,state_income_tax_before_refundable_credits,0.0, +scenario_066,state_refundable_credits,7.955999851226807, +scenario_066,local_income_tax,0.0, +scenario_066,snap,3576.0, +scenario_066,ssi,0.0, +scenario_066,tanf,0.0, +scenario_066,head_wic_eligible,0.0,0.0 +scenario_066,head_medicaid_eligible,1.0,7680.8876953125 +scenario_066,head_chip_eligible,0.0,0.0 +scenario_066,head_medicare_eligible,0.0,0.0 +scenario_066,free_school_meals_eligible,0.0,0.0 +scenario_066,reduced_price_school_meals_eligible,0.0,0.0 +scenario_067,federal_income_tax_before_refundable_credits,5616.240234375, +scenario_067,federal_refundable_credits,0.0, +scenario_067,payroll_tax,6300.5400390625, +scenario_067,self_employment_tax,0.0, +scenario_067,state_income_tax_before_refundable_credits,2486.908935546875, +scenario_067,state_refundable_credits,0.0, +scenario_067,local_income_tax,1348.83203125, +scenario_067,snap,0.0, +scenario_067,ssi,0.0, +scenario_067,tanf,0.0, +scenario_067,head_wic_eligible,0.0,0.0 +scenario_067,spouse_wic_eligible,0.0,0.0 +scenario_067,dependent1_wic_eligible,0.0,0.0 +scenario_067,head_medicaid_eligible,0.0,0.0 +scenario_067,spouse_medicaid_eligible,0.0,0.0 +scenario_067,dependent1_medicaid_eligible,1.0,5132.95166015625 +scenario_067,head_chip_eligible,0.0,0.0 +scenario_067,spouse_chip_eligible,0.0,0.0 +scenario_067,dependent1_chip_eligible,0.0,0.0 +scenario_067,head_medicare_eligible,0.0,0.0 +scenario_067,spouse_medicare_eligible,0.0,0.0 +scenario_067,dependent1_medicare_eligible,0.0,0.0 +scenario_067,free_school_meals_eligible,0.0,0.0 +scenario_067,reduced_price_school_meals_eligible,0.0,0.0 +scenario_068,federal_income_tax_before_refundable_credits,1910.0238037109375, +scenario_068,federal_refundable_credits,0.0, +scenario_068,payroll_tax,2607.39013671875, +scenario_068,self_employment_tax,0.0, +scenario_068,state_income_tax_before_refundable_credits,1255.3427734375, +scenario_068,state_refundable_credits,0.0, +scenario_068,local_income_tax,0.0, +scenario_068,snap,0.0, +scenario_068,ssi,0.0, +scenario_068,tanf,0.0, +scenario_068,head_wic_eligible,0.0,0.0 +scenario_068,head_medicaid_eligible,0.0,0.0 +scenario_068,head_chip_eligible,0.0,0.0 +scenario_068,head_medicare_eligible,0.0,0.0 +scenario_068,free_school_meals_eligible,0.0,0.0 +scenario_068,reduced_price_school_meals_eligible,0.0,0.0 +scenario_070,federal_income_tax_before_refundable_credits,1979.9605712890625, +scenario_070,federal_refundable_credits,0.0, +scenario_070,payroll_tax,2907.0, +scenario_070,self_employment_tax,0.0, +scenario_070,state_income_tax_before_refundable_credits,1650.561279296875, +scenario_070,state_refundable_credits,0.0, +scenario_070,local_income_tax,0.0, +scenario_070,snap,0.0, +scenario_070,ssi,0.0, +scenario_070,tanf,0.0, +scenario_070,head_wic_eligible,0.0,0.0 +scenario_070,head_medicaid_eligible,0.0,0.0 +scenario_070,head_chip_eligible,0.0,0.0 +scenario_070,head_medicare_eligible,0.0,0.0 +scenario_070,free_school_meals_eligible,0.0,0.0 +scenario_070,reduced_price_school_meals_eligible,0.0,0.0 +scenario_071,federal_income_tax_before_refundable_credits,0.0, +scenario_071,federal_refundable_credits,0.0, +scenario_071,payroll_tax,0.0, +scenario_071,self_employment_tax,0.0, +scenario_071,state_income_tax_before_refundable_credits,0.0, +scenario_071,state_refundable_credits,0.0, +scenario_071,local_income_tax,0.0, +scenario_071,snap,0.0, +scenario_071,ssi,0.0, +scenario_071,tanf,0.0, +scenario_071,head_wic_eligible,0.0,0.0 +scenario_071,head_medicaid_eligible,0.0,0.0 +scenario_071,head_chip_eligible,0.0,0.0 +scenario_071,head_medicare_eligible,1.0,5285.2001953125 +scenario_071,free_school_meals_eligible,0.0,0.0 +scenario_071,reduced_price_school_meals_eligible,0.0,0.0 +scenario_072,federal_income_tax_before_refundable_credits,0.0, +scenario_072,federal_refundable_credits,0.0, +scenario_072,payroll_tax,1530.0, +scenario_072,self_employment_tax,0.0, +scenario_072,state_income_tax_before_refundable_credits,0.0, +scenario_072,state_refundable_credits,0.0, +scenario_072,local_income_tax,0.0, +scenario_072,snap,0.0, +scenario_072,ssi,0.0, +scenario_072,tanf,0.0, +scenario_072,head_wic_eligible,0.0,0.0 +scenario_072,spouse_wic_eligible,0.0,0.0 +scenario_072,head_medicaid_eligible,0.0,0.0 +scenario_072,spouse_medicaid_eligible,0.0,0.0 +scenario_072,head_chip_eligible,0.0,0.0 +scenario_072,spouse_chip_eligible,0.0,0.0 +scenario_072,head_medicare_eligible,1.0,5285.2001953125 +scenario_072,spouse_medicare_eligible,1.0,5285.2001953125 +scenario_072,free_school_meals_eligible,0.0,0.0 +scenario_072,reduced_price_school_meals_eligible,0.0,0.0 +scenario_073,federal_income_tax_before_refundable_credits,0.0, +scenario_073,federal_refundable_credits,0.0, +scenario_073,payroll_tax,0.0, +scenario_073,self_employment_tax,0.0, +scenario_073,state_income_tax_before_refundable_credits,0.0, +scenario_073,state_refundable_credits,0.0, +scenario_073,local_income_tax,0.0, +scenario_073,snap,288.0, +scenario_073,ssi,0.0, +scenario_073,tanf,0.0, +scenario_073,head_wic_eligible,0.0,0.0 +scenario_073,head_medicaid_eligible,0.0,0.0 +scenario_073,head_chip_eligible,0.0,0.0 +scenario_073,head_medicare_eligible,0.0,0.0 +scenario_073,free_school_meals_eligible,0.0,0.0 +scenario_073,reduced_price_school_meals_eligible,0.0,0.0 +scenario_074,federal_income_tax_before_refundable_credits,0.0, +scenario_074,federal_refundable_credits,0.0, +scenario_074,payroll_tax,0.0, +scenario_074,self_employment_tax,0.0, +scenario_074,state_income_tax_before_refundable_credits,0.0, +scenario_074,state_refundable_credits,0.0, +scenario_074,local_income_tax,0.0, +scenario_074,snap,0.0, +scenario_074,ssi,0.0, +scenario_074,tanf,0.0, +scenario_074,head_wic_eligible,0.0,0.0 +scenario_074,head_medicaid_eligible,0.0,0.0 +scenario_074,head_chip_eligible,0.0,0.0 +scenario_074,head_medicare_eligible,0.0,0.0 +scenario_074,free_school_meals_eligible,0.0,0.0 +scenario_074,reduced_price_school_meals_eligible,0.0,0.0 +scenario_075,federal_income_tax_before_refundable_credits,14777.1455078125, +scenario_075,federal_refundable_credits,0.0, +scenario_075,payroll_tax,968.2120971679688, +scenario_075,self_employment_tax,0.0, +scenario_075,state_income_tax_before_refundable_credits,0.0, +scenario_075,state_refundable_credits,0.0, +scenario_075,local_income_tax,0.0, +scenario_075,snap,0.0, +scenario_075,ssi,0.0, +scenario_075,tanf,0.0, +scenario_075,head_wic_eligible,0.0,0.0 +scenario_075,head_medicaid_eligible,0.0,0.0 +scenario_075,head_chip_eligible,0.0,0.0 +scenario_075,head_medicare_eligible,0.0,0.0 +scenario_075,free_school_meals_eligible,0.0,0.0 +scenario_075,reduced_price_school_meals_eligible,0.0,0.0 +scenario_076,federal_income_tax_before_refundable_credits,19611.80078125, +scenario_076,federal_refundable_credits,0.0, +scenario_076,payroll_tax,12240.0, +scenario_076,self_employment_tax,0.0, +scenario_076,state_income_tax_before_refundable_credits,6828.34423828125, +scenario_076,state_refundable_credits,465.0, +scenario_076,local_income_tax,0.0, +scenario_076,snap,0.0, +scenario_076,ssi,0.0, +scenario_076,tanf,0.0, +scenario_076,head_wic_eligible,0.0,0.0 +scenario_076,child1_wic_eligible,0.0,0.0 +scenario_076,child2_wic_eligible,0.0,0.0 +scenario_076,head_medicaid_eligible,0.0,0.0 +scenario_076,child1_medicaid_eligible,0.0,0.0 +scenario_076,child2_medicaid_eligible,0.0,0.0 +scenario_076,head_chip_eligible,0.0,0.0 +scenario_076,child1_chip_eligible,0.0,0.0 +scenario_076,child2_chip_eligible,0.0,0.0 +scenario_076,head_medicare_eligible,0.0,0.0 +scenario_076,child1_medicare_eligible,0.0,0.0 +scenario_076,child2_medicare_eligible,0.0,0.0 +scenario_076,child1_head_start_eligible,0.0,0.0 +scenario_076,child2_head_start_eligible,0.0,0.0 +scenario_076,child1_early_head_start_eligible,0.0,0.0 +scenario_076,child2_early_head_start_eligible,0.0,0.0 +scenario_076,free_school_meals_eligible,0.0,0.0 +scenario_076,reduced_price_school_meals_eligible,0.0,0.0 +scenario_077,federal_income_tax_before_refundable_credits,690.6175537109375, +scenario_077,federal_refundable_credits,0.0, +scenario_077,payroll_tax,1989.472412109375, +scenario_077,self_employment_tax,0.0, +scenario_077,state_income_tax_before_refundable_credits,305.13525390625, +scenario_077,state_refundable_credits,0.0, +scenario_077,local_income_tax,0.0, +scenario_077,snap,0.0, +scenario_077,ssi,0.0, +scenario_077,tanf,0.0, +scenario_077,head_wic_eligible,0.0,0.0 +scenario_077,head_medicaid_eligible,0.0,0.0 +scenario_077,head_chip_eligible,0.0,0.0 +scenario_077,head_medicare_eligible,0.0,0.0 +scenario_077,free_school_meals_eligible,0.0,0.0 +scenario_077,reduced_price_school_meals_eligible,0.0,0.0 +scenario_078,federal_income_tax_before_refundable_credits,24164.45703125, +scenario_078,federal_refundable_credits,0.0, +scenario_078,payroll_tax,14317.322265625, +scenario_078,self_employment_tax,0.0, +scenario_078,state_income_tax_before_refundable_credits,6936.87646484375, +scenario_078,state_refundable_credits,0.0, +scenario_078,local_income_tax,0.0, +scenario_078,snap,0.0, +scenario_078,ssi,0.0, +scenario_078,tanf,0.0, +scenario_078,head_wic_eligible,0.0,0.0 +scenario_078,head_medicaid_eligible,0.0,0.0 +scenario_078,head_chip_eligible,0.0,0.0 +scenario_078,head_medicare_eligible,0.0,0.0 +scenario_078,free_school_meals_eligible,0.0,0.0 +scenario_078,reduced_price_school_meals_eligible,0.0,0.0 +scenario_079,federal_income_tax_before_refundable_credits,0.0, +scenario_079,federal_refundable_credits,0.0, +scenario_079,payroll_tax,0.0, +scenario_079,self_employment_tax,0.0, +scenario_079,state_income_tax_before_refundable_credits,0.0, +scenario_079,state_refundable_credits,50.0, +scenario_079,local_income_tax,0.0, +scenario_079,snap,2376.0, +scenario_079,ssi,10572.0, +scenario_079,tanf,0.0, +scenario_079,head_wic_eligible,0.0,0.0 +scenario_079,spouse_wic_eligible,0.0,0.0 +scenario_079,head_medicaid_eligible,1.0,10921.8173828125 +scenario_079,spouse_medicaid_eligible,1.0,9558.6806640625 +scenario_079,head_chip_eligible,0.0,0.0 +scenario_079,spouse_chip_eligible,0.0,0.0 +scenario_079,head_medicare_eligible,0.0,0.0 +scenario_079,spouse_medicare_eligible,0.0,0.0 +scenario_079,free_school_meals_eligible,0.0,0.0 +scenario_079,reduced_price_school_meals_eligible,0.0,0.0 +scenario_080,federal_income_tax_before_refundable_credits,0.0, +scenario_080,federal_refundable_credits,0.0, +scenario_080,payroll_tax,0.0, +scenario_080,self_employment_tax,0.0, +scenario_080,state_income_tax_before_refundable_credits,0.0, +scenario_080,state_refundable_credits,0.0, +scenario_080,local_income_tax,0.0, +scenario_080,snap,3596.039794921875, +scenario_080,ssi,0.0, +scenario_080,tanf,0.0, +scenario_080,head_wic_eligible,0.0,0.0 +scenario_080,head_medicaid_eligible,1.0,14526.80078125 +scenario_080,head_chip_eligible,0.0,0.0 +scenario_080,head_medicare_eligible,0.0,0.0 +scenario_080,free_school_meals_eligible,0.0,0.0 +scenario_080,reduced_price_school_meals_eligible,0.0,0.0 +scenario_081,federal_income_tax_before_refundable_credits,26932.2734375, +scenario_081,federal_refundable_credits,0.0, +scenario_081,payroll_tax,14192.662109375, +scenario_081,self_employment_tax,0.0, +scenario_081,state_income_tax_before_refundable_credits,8238.40625, +scenario_081,state_refundable_credits,0.0, +scenario_081,local_income_tax,0.0, +scenario_081,snap,0.0, +scenario_081,ssi,0.0, +scenario_081,tanf,0.0, +scenario_081,head_wic_eligible,0.0,0.0 +scenario_081,head_medicaid_eligible,0.0,0.0 +scenario_081,head_chip_eligible,0.0,0.0 +scenario_081,head_medicare_eligible,0.0,0.0 +scenario_081,free_school_meals_eligible,0.0,0.0 +scenario_081,reduced_price_school_meals_eligible,0.0,0.0 +scenario_082,federal_income_tax_before_refundable_credits,9579.767578125, +scenario_082,federal_refundable_credits,0.0, +scenario_082,payroll_tax,8108.02734375, +scenario_082,self_employment_tax,0.0, +scenario_082,state_income_tax_before_refundable_credits,5599.1435546875, +scenario_082,state_refundable_credits,1187.5478515625, +scenario_082,local_income_tax,0.0, +scenario_082,snap,0.0, +scenario_082,ssi,0.0, +scenario_082,tanf,0.0, +scenario_082,head_wic_eligible,0.0,0.0 +scenario_082,child1_wic_eligible,0.0,0.0 +scenario_082,head_medicaid_eligible,0.0,0.0 +scenario_082,child1_medicaid_eligible,0.0,0.0 +scenario_082,head_chip_eligible,0.0,0.0 +scenario_082,child1_chip_eligible,0.0,0.0 +scenario_082,head_medicare_eligible,0.0,0.0 +scenario_082,child1_medicare_eligible,0.0,0.0 +scenario_082,child1_head_start_eligible,0.0,0.0 +scenario_082,child1_early_head_start_eligible,0.0,0.0 +scenario_082,free_school_meals_eligible,0.0,0.0 +scenario_082,reduced_price_school_meals_eligible,0.0,0.0 +scenario_083,federal_income_tax_before_refundable_credits,0.0, +scenario_083,federal_refundable_credits,0.0, +scenario_083,payroll_tax,539.3250122070312, +scenario_083,self_employment_tax,0.0, +scenario_083,state_income_tax_before_refundable_credits,0.0, +scenario_083,state_refundable_credits,0.0, +scenario_083,local_income_tax,0.0, +scenario_083,snap,0.0, +scenario_083,ssi,0.0, +scenario_083,tanf,0.0, +scenario_083,head_wic_eligible,0.0,0.0 +scenario_083,head_medicaid_eligible,0.0,0.0 +scenario_083,head_chip_eligible,0.0,0.0 +scenario_083,head_medicare_eligible,0.0,0.0 +scenario_083,free_school_meals_eligible,0.0,0.0 +scenario_083,reduced_price_school_meals_eligible,0.0,0.0 +scenario_084,federal_income_tax_before_refundable_credits,0.0, +scenario_084,federal_refundable_credits,0.0, +scenario_084,payroll_tax,0.0, +scenario_084,self_employment_tax,0.0, +scenario_084,state_income_tax_before_refundable_credits,0.0, +scenario_084,state_refundable_credits,0.0, +scenario_084,local_income_tax,0.0, +scenario_084,snap,0.0, +scenario_084,ssi,0.0, +scenario_084,tanf,0.0, +scenario_084,head_wic_eligible,0.0,0.0 +scenario_084,head_medicaid_eligible,0.0,0.0 +scenario_084,head_chip_eligible,0.0,0.0 +scenario_084,head_medicare_eligible,0.0,0.0 +scenario_084,free_school_meals_eligible,0.0,0.0 +scenario_084,reduced_price_school_meals_eligible,0.0,0.0 +scenario_085,federal_income_tax_before_refundable_credits,2322.8486328125, +scenario_085,federal_refundable_credits,0.0, +scenario_085,payroll_tax,0.0, +scenario_085,self_employment_tax,0.0, +scenario_085,state_income_tax_before_refundable_credits,0.0, +scenario_085,state_refundable_credits,0.0, +scenario_085,local_income_tax,0.0, +scenario_085,snap,0.0, +scenario_085,ssi,0.0, +scenario_085,tanf,0.0, +scenario_085,head_wic_eligible,0.0,0.0 +scenario_085,head_medicaid_eligible,0.0,0.0 +scenario_085,head_chip_eligible,0.0,0.0 +scenario_085,head_medicare_eligible,1.0,5285.2001953125 +scenario_085,free_school_meals_eligible,0.0,0.0 +scenario_085,reduced_price_school_meals_eligible,0.0,0.0 +scenario_086,federal_income_tax_before_refundable_credits,3255.5478515625, +scenario_086,federal_refundable_credits,0.0, +scenario_086,payroll_tax,4743.0, +scenario_086,self_employment_tax,0.0, +scenario_086,state_income_tax_before_refundable_credits,2078.958740234375, +scenario_086,state_refundable_credits,0.0, +scenario_086,local_income_tax,0.0, +scenario_086,snap,0.0, +scenario_086,ssi,0.0, +scenario_086,tanf,0.0, +scenario_086,head_wic_eligible,0.0,0.0 +scenario_086,child1_wic_eligible,0.0,0.0 +scenario_086,head_medicaid_eligible,0.0,0.0 +scenario_086,child1_medicaid_eligible,0.0,0.0 +scenario_086,head_chip_eligible,0.0,0.0 +scenario_086,child1_chip_eligible,0.0,0.0 +scenario_086,head_medicare_eligible,0.0,0.0 +scenario_086,child1_medicare_eligible,0.0,0.0 +scenario_086,child1_head_start_eligible,0.0,0.0 +scenario_086,child1_early_head_start_eligible,0.0,0.0 +scenario_086,free_school_meals_eligible,0.0,0.0 +scenario_086,reduced_price_school_meals_eligible,0.0,0.0 +scenario_088,federal_income_tax_before_refundable_credits,0.0, +scenario_088,federal_refundable_credits,0.0, +scenario_088,payroll_tax,1421.1448974609375, +scenario_088,self_employment_tax,0.0, +scenario_088,state_income_tax_before_refundable_credits,0.0, +scenario_088,state_refundable_credits,0.0, +scenario_088,local_income_tax,0.0, +scenario_088,snap,0.0, +scenario_088,ssi,0.0, +scenario_088,tanf,0.0, +scenario_088,head_wic_eligible,0.0,0.0 +scenario_088,head_medicaid_eligible,0.0,0.0 +scenario_088,head_chip_eligible,0.0,0.0 +scenario_088,head_medicare_eligible,0.0,0.0 +scenario_088,free_school_meals_eligible,0.0,0.0 +scenario_088,reduced_price_school_meals_eligible,0.0,0.0 +scenario_089,federal_income_tax_before_refundable_credits,6819.7119140625, +scenario_089,federal_refundable_credits,0.0, +scenario_089,payroll_tax,5039.91015625, +scenario_089,self_employment_tax,4286.24072265625, +scenario_089,state_income_tax_before_refundable_credits,3219.935302734375, +scenario_089,state_refundable_credits,0.0, +scenario_089,local_income_tax,0.0, +scenario_089,snap,0.0, +scenario_089,ssi,0.0, +scenario_089,tanf,0.0, +scenario_089,head_wic_eligible,0.0,0.0 +scenario_089,spouse_wic_eligible,0.0,0.0 +scenario_089,head_medicaid_eligible,0.0,0.0 +scenario_089,spouse_medicaid_eligible,0.0,0.0 +scenario_089,head_chip_eligible,0.0,0.0 +scenario_089,spouse_chip_eligible,0.0,0.0 +scenario_089,head_medicare_eligible,0.0,0.0 +scenario_089,spouse_medicare_eligible,0.0,0.0 +scenario_089,free_school_meals_eligible,0.0,0.0 +scenario_089,reduced_price_school_meals_eligible,0.0,0.0 +scenario_090,federal_income_tax_before_refundable_credits,0.0, +scenario_090,federal_refundable_credits,0.0, +scenario_090,payroll_tax,535.5, +scenario_090,self_employment_tax,0.0, +scenario_090,state_income_tax_before_refundable_credits,0.0, +scenario_090,state_refundable_credits,0.0, +scenario_090,local_income_tax,0.0, +scenario_090,snap,0.0, +scenario_090,ssi,0.0, +scenario_090,tanf,0.0, +scenario_090,head_wic_eligible,0.0,0.0 +scenario_090,head_medicaid_eligible,0.0,0.0 +scenario_090,head_chip_eligible,0.0,0.0 +scenario_090,head_medicare_eligible,0.0,0.0 +scenario_090,free_school_meals_eligible,0.0,0.0 +scenario_090,reduced_price_school_meals_eligible,0.0,0.0 +scenario_091,federal_income_tax_before_refundable_credits,1349.998779296875, +scenario_091,federal_refundable_credits,0.0, +scenario_091,payroll_tax,2065.5, +scenario_091,self_employment_tax,0.0, +scenario_091,state_income_tax_before_refundable_credits,878.5157470703125, +scenario_091,state_refundable_credits,0.0, +scenario_091,local_income_tax,0.0, +scenario_091,snap,0.0, +scenario_091,ssi,0.0, +scenario_091,tanf,0.0, +scenario_091,head_wic_eligible,0.0,0.0 +scenario_091,head_medicaid_eligible,0.0,0.0 +scenario_091,head_chip_eligible,0.0,0.0 +scenario_091,head_medicare_eligible,0.0,0.0 +scenario_091,free_school_meals_eligible,0.0,0.0 +scenario_091,reduced_price_school_meals_eligible,0.0,0.0 +scenario_092,federal_income_tax_before_refundable_credits,0.0, +scenario_092,federal_refundable_credits,0.0, +scenario_092,payroll_tax,0.0, +scenario_092,self_employment_tax,0.0, +scenario_092,state_income_tax_before_refundable_credits,0.0, +scenario_092,state_refundable_credits,0.0, +scenario_092,local_income_tax,0.0, +scenario_092,snap,0.0, +scenario_092,ssi,0.0, +scenario_092,tanf,0.0, +scenario_092,head_wic_eligible,0.0,0.0 +scenario_092,head_medicaid_eligible,0.0,0.0 +scenario_092,head_chip_eligible,0.0,0.0 +scenario_092,head_medicare_eligible,1.0,5285.2001953125 +scenario_092,free_school_meals_eligible,0.0,0.0 +scenario_092,reduced_price_school_meals_eligible,0.0,0.0 +scenario_093,federal_income_tax_before_refundable_credits,8628.990234375, +scenario_093,federal_refundable_credits,0.0, +scenario_093,payroll_tax,12469.5, +scenario_093,self_employment_tax,0.0, +scenario_093,state_income_tax_before_refundable_credits,3388.24560546875, +scenario_093,state_refundable_credits,0.0, +scenario_093,local_income_tax,0.0, +scenario_093,snap,0.0, +scenario_093,ssi,0.0, +scenario_093,tanf,0.0, +scenario_093,head_wic_eligible,0.0,0.0 +scenario_093,spouse_wic_eligible,0.0,0.0 +scenario_093,dependent1_wic_eligible,0.0,0.0 +scenario_093,head_medicaid_eligible,0.0,0.0 +scenario_093,spouse_medicaid_eligible,0.0,0.0 +scenario_093,dependent1_medicaid_eligible,0.0,0.0 +scenario_093,head_chip_eligible,0.0,0.0 +scenario_093,spouse_chip_eligible,0.0,0.0 +scenario_093,dependent1_chip_eligible,0.0,0.0 +scenario_093,head_medicare_eligible,0.0,0.0 +scenario_093,spouse_medicare_eligible,0.0,0.0 +scenario_093,dependent1_medicare_eligible,0.0,0.0 +scenario_093,free_school_meals_eligible,0.0,0.0 +scenario_093,reduced_price_school_meals_eligible,0.0,0.0 +scenario_095,federal_income_tax_before_refundable_credits,0.0, +scenario_095,federal_refundable_credits,0.0, +scenario_095,payroll_tax,0.0, +scenario_095,self_employment_tax,593.2291259765625, +scenario_095,state_income_tax_before_refundable_credits,0.0, +scenario_095,state_refundable_credits,0.0, +scenario_095,local_income_tax,0.0, +scenario_095,snap,0.0, +scenario_095,ssi,0.0, +scenario_095,tanf,0.0, +scenario_095,head_wic_eligible,0.0,0.0 +scenario_095,head_medicaid_eligible,0.0,0.0 +scenario_095,head_chip_eligible,0.0,0.0 +scenario_095,head_medicare_eligible,1.0,5285.2001953125 +scenario_095,free_school_meals_eligible,0.0,0.0 +scenario_095,reduced_price_school_meals_eligible,0.0,0.0 +scenario_098,federal_income_tax_before_refundable_credits,0.0, +scenario_098,federal_refundable_credits,0.0, +scenario_098,payroll_tax,0.0, +scenario_098,self_employment_tax,0.0, +scenario_098,state_income_tax_before_refundable_credits,0.0, +scenario_098,state_refundable_credits,0.0, +scenario_098,local_income_tax,0.0, +scenario_098,snap,0.0, +scenario_098,ssi,0.0, +scenario_098,tanf,0.0, +scenario_098,head_wic_eligible,0.0,0.0 +scenario_098,head_medicaid_eligible,0.0,0.0 +scenario_098,head_chip_eligible,0.0,0.0 +scenario_098,head_medicare_eligible,1.0,5285.2001953125 +scenario_098,free_school_meals_eligible,0.0,0.0 +scenario_098,reduced_price_school_meals_eligible,0.0,0.0 +scenario_099,federal_income_tax_before_refundable_credits,10711.484375, +scenario_099,federal_refundable_credits,0.0, +scenario_099,payroll_tax,14767.5, +scenario_099,self_employment_tax,0.0, +scenario_099,state_income_tax_before_refundable_credits,4615.48388671875, +scenario_099,state_refundable_credits,0.0, +scenario_099,local_income_tax,0.0, +scenario_099,snap,0.0, +scenario_099,ssi,0.0, +scenario_099,tanf,0.0, +scenario_099,head_wic_eligible,0.0,0.0 +scenario_099,spouse_wic_eligible,0.0,0.0 +scenario_099,child1_wic_eligible,0.0,0.0 +scenario_099,child2_wic_eligible,0.0,0.0 +scenario_099,head_medicaid_eligible,0.0,0.0 +scenario_099,spouse_medicaid_eligible,0.0,0.0 +scenario_099,child1_medicaid_eligible,0.0,0.0 +scenario_099,child2_medicaid_eligible,0.0,0.0 +scenario_099,head_chip_eligible,0.0,0.0 +scenario_099,spouse_chip_eligible,0.0,0.0 +scenario_099,child1_chip_eligible,0.0,0.0 +scenario_099,child2_chip_eligible,0.0,0.0 +scenario_099,head_medicare_eligible,0.0,0.0 +scenario_099,spouse_medicare_eligible,0.0,0.0 +scenario_099,child1_medicare_eligible,0.0,0.0 +scenario_099,child2_medicare_eligible,0.0,0.0 +scenario_099,child1_head_start_eligible,0.0,0.0 +scenario_099,child2_head_start_eligible,0.0,0.0 +scenario_099,child1_early_head_start_eligible,0.0,0.0 +scenario_099,child2_early_head_start_eligible,0.0,0.0 +scenario_099,free_school_meals_eligible,1.0,1130.9622802734375 +scenario_099,reduced_price_school_meals_eligible,0.0,0.0 +scenario_100,federal_income_tax_before_refundable_credits,0.0, +scenario_100,federal_refundable_credits,822.2882690429688, +scenario_100,payroll_tax,452.47613525390625, +scenario_100,self_employment_tax,0.0, +scenario_100,state_income_tax_before_refundable_credits,0.0, +scenario_100,state_refundable_credits,164.45765686035156, +scenario_100,local_income_tax,0.0, +scenario_100,snap,8625.8896484375, +scenario_100,ssi,0.0, +scenario_100,tanf,6064.958984375, +scenario_100,head_wic_eligible,0.0,0.0 +scenario_100,child1_wic_eligible,0.0,0.0 +scenario_100,child2_wic_eligible,0.0,0.0 +scenario_100,head_medicaid_eligible,1.0,16038.5244140625 +scenario_100,child1_medicaid_eligible,1.0,8179.58154296875 +scenario_100,child2_medicaid_eligible,1.0,8179.58154296875 +scenario_100,head_chip_eligible,0.0,0.0 +scenario_100,child1_chip_eligible,0.0,0.0 +scenario_100,child2_chip_eligible,0.0,0.0 +scenario_100,head_medicare_eligible,0.0,0.0 +scenario_100,child1_medicare_eligible,0.0,0.0 +scenario_100,child2_medicare_eligible,0.0,0.0 +scenario_100,child1_head_start_eligible,0.0,0.0 +scenario_100,child2_head_start_eligible,1.0,19273.044921875 +scenario_100,child1_early_head_start_eligible,0.0,0.0 +scenario_100,child2_early_head_start_eligible,0.0,0.0 +scenario_100,free_school_meals_eligible,1.0,2261.924560546875 +scenario_100,reduced_price_school_meals_eligible,0.0,0.0 +scenario_101,federal_income_tax_before_refundable_credits,13418.599609375, +scenario_101,federal_refundable_credits,0.0, +scenario_101,payroll_tax,7879.5, +scenario_101,self_employment_tax,0.0, +scenario_101,state_income_tax_before_refundable_credits,0.0, +scenario_101,state_refundable_credits,0.0, +scenario_101,local_income_tax,0.0, +scenario_101,snap,0.0, +scenario_101,ssi,0.0, +scenario_101,tanf,0.0, +scenario_101,head_wic_eligible,0.0,0.0 +scenario_101,head_medicaid_eligible,0.0,0.0 +scenario_101,head_chip_eligible,0.0,0.0 +scenario_101,head_medicare_eligible,0.0,0.0 +scenario_101,free_school_meals_eligible,0.0,0.0 +scenario_101,reduced_price_school_meals_eligible,0.0,0.0 +scenario_102,federal_income_tax_before_refundable_credits,6104.09619140625, +scenario_102,federal_refundable_credits,0.0, +scenario_102,payroll_tax,6670.7998046875, +scenario_102,self_employment_tax,0.0, +scenario_102,state_income_tax_before_refundable_credits,2461.869873046875, +scenario_102,state_refundable_credits,0.0, +scenario_102,local_income_tax,0.0, +scenario_102,snap,0.0, +scenario_102,ssi,0.0, +scenario_102,tanf,0.0, +scenario_102,head_wic_eligible,0.0,0.0 +scenario_102,spouse_wic_eligible,0.0,0.0 +scenario_102,head_medicaid_eligible,0.0,0.0 +scenario_102,spouse_medicaid_eligible,0.0,0.0 +scenario_102,head_chip_eligible,0.0,0.0 +scenario_102,spouse_chip_eligible,0.0,0.0 +scenario_102,head_medicare_eligible,0.0,0.0 +scenario_102,spouse_medicare_eligible,0.0,0.0 +scenario_102,free_school_meals_eligible,0.0,0.0 +scenario_102,reduced_price_school_meals_eligible,0.0,0.0 +scenario_104,federal_income_tax_before_refundable_credits,0.0, +scenario_104,federal_refundable_credits,0.0, +scenario_104,payroll_tax,0.0, +scenario_104,self_employment_tax,0.0, +scenario_104,state_income_tax_before_refundable_credits,0.0, +scenario_104,state_refundable_credits,0.0, +scenario_104,local_income_tax,0.0, +scenario_104,snap,0.0, +scenario_104,ssi,0.0, +scenario_104,tanf,0.0, +scenario_104,head_wic_eligible,0.0,0.0 +scenario_104,head_medicaid_eligible,0.0,0.0 +scenario_104,head_chip_eligible,0.0,0.0 +scenario_104,head_medicare_eligible,1.0,5285.2001953125 +scenario_104,free_school_meals_eligible,0.0,0.0 +scenario_104,reduced_price_school_meals_eligible,0.0,0.0 +scenario_107,federal_income_tax_before_refundable_credits,0.0, +scenario_107,federal_refundable_credits,0.0, +scenario_107,payroll_tax,486.9607238769531, +scenario_107,self_employment_tax,0.0, +scenario_107,state_income_tax_before_refundable_credits,0.0, +scenario_107,state_refundable_credits,0.0, +scenario_107,local_income_tax,0.0, +scenario_107,snap,0.0, +scenario_107,ssi,0.0, +scenario_107,tanf,0.0, +scenario_107,head_wic_eligible,0.0,0.0 +scenario_107,head_medicaid_eligible,0.0,0.0 +scenario_107,head_chip_eligible,0.0,0.0 +scenario_107,head_medicare_eligible,1.0,5285.2001953125 +scenario_107,free_school_meals_eligible,0.0,0.0 +scenario_107,reduced_price_school_meals_eligible,0.0,0.0 +scenario_108,federal_income_tax_before_refundable_credits,0.0, +scenario_108,federal_refundable_credits,0.0, +scenario_108,payroll_tax,585.6839599609375, +scenario_108,self_employment_tax,0.0, +scenario_108,state_income_tax_before_refundable_credits,0.0, +scenario_108,state_refundable_credits,271.3916015625, +scenario_108,local_income_tax,0.0, +scenario_108,snap,288.0, +scenario_108,ssi,0.0, +scenario_108,tanf,0.0, +scenario_108,head_wic_eligible,0.0,0.0 +scenario_108,head_medicaid_eligible,0.0,0.0 +scenario_108,head_chip_eligible,0.0,0.0 +scenario_108,head_medicare_eligible,1.0,5285.2001953125 +scenario_108,free_school_meals_eligible,0.0,0.0 +scenario_108,reduced_price_school_meals_eligible,0.0,0.0 +scenario_109,federal_income_tax_before_refundable_credits,0.0, +scenario_109,federal_refundable_credits,12038.0859375, +scenario_109,payroll_tax,0.0, +scenario_109,self_employment_tax,4238.86474609375, +scenario_109,state_income_tax_before_refundable_credits,0.0, +scenario_109,state_refundable_credits,0.0, +scenario_109,local_income_tax,0.0, +scenario_109,snap,7932.0, +scenario_109,ssi,0.0, +scenario_109,tanf,0.0, +scenario_109,head_wic_eligible,0.0,0.0 +scenario_109,spouse_wic_eligible,0.0,0.0 +scenario_109,child1_wic_eligible,0.0,0.0 +scenario_109,child2_wic_eligible,0.0,0.0 +scenario_109,child3_wic_eligible,1.0,2222.318603515625 +scenario_109,head_medicaid_eligible,0.0,0.0 +scenario_109,spouse_medicaid_eligible,0.0,0.0 +scenario_109,child1_medicaid_eligible,1.0,3836.309814453125 +scenario_109,child2_medicaid_eligible,1.0,3836.309814453125 +scenario_109,child3_medicaid_eligible,1.0,3836.309814453125 +scenario_109,head_chip_eligible,0.0,0.0 +scenario_109,spouse_chip_eligible,0.0,0.0 +scenario_109,child1_chip_eligible,0.0,0.0 +scenario_109,child2_chip_eligible,0.0,0.0 +scenario_109,child3_chip_eligible,0.0,0.0 +scenario_109,head_medicare_eligible,0.0,0.0 +scenario_109,spouse_medicare_eligible,0.0,0.0 +scenario_109,child1_medicare_eligible,0.0,0.0 +scenario_109,child2_medicare_eligible,0.0,0.0 +scenario_109,child3_medicare_eligible,0.0,0.0 +scenario_109,child1_head_start_eligible,0.0,0.0 +scenario_109,child2_head_start_eligible,0.0,0.0 +scenario_109,child3_head_start_eligible,0.0,0.0 +scenario_109,child1_early_head_start_eligible,0.0,0.0 +scenario_109,child2_early_head_start_eligible,0.0,0.0 +scenario_109,child3_early_head_start_eligible,1.0,21977.013671875 +scenario_109,free_school_meals_eligible,1.0,2261.924560546875 +scenario_109,reduced_price_school_meals_eligible,0.0,0.0 +scenario_110,federal_income_tax_before_refundable_credits,25747.7734375, +scenario_110,federal_refundable_credits,0.0, +scenario_110,payroll_tax,7650.0, +scenario_110,self_employment_tax,0.0, +scenario_110,state_income_tax_before_refundable_credits,4236.8076171875, +scenario_110,state_refundable_credits,0.0, +scenario_110,local_income_tax,0.0, +scenario_110,snap,0.0, +scenario_110,ssi,0.0, +scenario_110,tanf,0.0, +scenario_110,head_wic_eligible,0.0,0.0 +scenario_110,head_medicaid_eligible,0.0,0.0 +scenario_110,head_chip_eligible,0.0,0.0 +scenario_110,head_medicare_eligible,0.0,0.0 +scenario_110,free_school_meals_eligible,0.0,0.0 +scenario_110,reduced_price_school_meals_eligible,0.0,0.0 +scenario_111,federal_income_tax_before_refundable_credits,0.0, +scenario_111,federal_refundable_credits,0.0, +scenario_111,payroll_tax,0.0, +scenario_111,self_employment_tax,0.0, +scenario_111,state_income_tax_before_refundable_credits,0.0, +scenario_111,state_refundable_credits,0.0, +scenario_111,local_income_tax,0.0, +scenario_111,snap,0.0, +scenario_111,ssi,0.0, +scenario_111,tanf,0.0, +scenario_111,head_wic_eligible,0.0,0.0 +scenario_111,spouse_wic_eligible,0.0,0.0 +scenario_111,head_medicaid_eligible,0.0,0.0 +scenario_111,spouse_medicaid_eligible,0.0,0.0 +scenario_111,head_chip_eligible,0.0,0.0 +scenario_111,spouse_chip_eligible,0.0,0.0 +scenario_111,head_medicare_eligible,1.0,5285.2001953125 +scenario_111,spouse_medicare_eligible,0.0,0.0 +scenario_111,free_school_meals_eligible,0.0,0.0 +scenario_111,reduced_price_school_meals_eligible,0.0,0.0 +scenario_112,federal_income_tax_before_refundable_credits,0.0, +scenario_112,federal_refundable_credits,453.09600830078125, +scenario_112,payroll_tax,453.09600830078125, +scenario_112,self_employment_tax,0.0, +scenario_112,state_income_tax_before_refundable_credits,0.0, +scenario_112,state_refundable_credits,0.0, +scenario_112,local_income_tax,0.0, +scenario_112,snap,287.68316650390625, +scenario_112,ssi,0.0, +scenario_112,tanf,0.0, +scenario_112,head_wic_eligible,0.0,0.0 +scenario_112,head_medicaid_eligible,0.0,0.0 +scenario_112,head_chip_eligible,0.0,0.0 +scenario_112,head_medicare_eligible,0.0,0.0 +scenario_112,free_school_meals_eligible,0.0,0.0 +scenario_112,reduced_price_school_meals_eligible,0.0,0.0 +scenario_114,federal_income_tax_before_refundable_credits,10729.6123046875, +scenario_114,federal_refundable_credits,0.0, +scenario_114,payroll_tax,1736.550048828125, +scenario_114,self_employment_tax,0.0, +scenario_114,state_income_tax_before_refundable_credits,3514.14501953125, +scenario_114,state_refundable_credits,0.0, +scenario_114,local_income_tax,0.0, +scenario_114,snap,0.0, +scenario_114,ssi,0.0, +scenario_114,tanf,0.0, +scenario_114,head_wic_eligible,0.0,0.0 +scenario_114,head_medicaid_eligible,0.0,0.0 +scenario_114,head_chip_eligible,0.0,0.0 +scenario_114,head_medicare_eligible,1.0,5285.2001953125 +scenario_114,free_school_meals_eligible,0.0,0.0 +scenario_114,reduced_price_school_meals_eligible,0.0,0.0 +scenario_115,federal_income_tax_before_refundable_credits,0.0, +scenario_115,federal_refundable_credits,0.0, +scenario_115,payroll_tax,0.0, +scenario_115,self_employment_tax,0.0, +scenario_115,state_income_tax_before_refundable_credits,4.679999828338623, +scenario_115,state_refundable_credits,0.0, +scenario_115,local_income_tax,0.0, +scenario_115,snap,0.0, +scenario_115,ssi,0.0, +scenario_115,tanf,0.0, +scenario_115,head_wic_eligible,0.0,0.0 +scenario_115,head_medicaid_eligible,0.0,0.0 +scenario_115,head_chip_eligible,0.0,0.0 +scenario_115,head_medicare_eligible,1.0,5285.2001953125 +scenario_115,free_school_meals_eligible,0.0,0.0 +scenario_115,reduced_price_school_meals_eligible,0.0,0.0 +scenario_116,federal_income_tax_before_refundable_credits,0.0, +scenario_116,federal_refundable_credits,0.0, +scenario_116,payroll_tax,0.0, +scenario_116,self_employment_tax,0.0, +scenario_116,state_income_tax_before_refundable_credits,0.0, +scenario_116,state_refundable_credits,0.0, +scenario_116,local_income_tax,0.0, +scenario_116,snap,0.0, +scenario_116,ssi,0.0, +scenario_116,tanf,0.0, +scenario_116,head_wic_eligible,0.0,0.0 +scenario_116,spouse_wic_eligible,0.0,0.0 +scenario_116,head_medicaid_eligible,0.0,0.0 +scenario_116,spouse_medicaid_eligible,0.0,0.0 +scenario_116,head_chip_eligible,0.0,0.0 +scenario_116,spouse_chip_eligible,0.0,0.0 +scenario_116,head_medicare_eligible,0.0,0.0 +scenario_116,spouse_medicare_eligible,0.0,0.0 +scenario_116,free_school_meals_eligible,0.0,0.0 +scenario_116,reduced_price_school_meals_eligible,0.0,0.0 +scenario_117,federal_income_tax_before_refundable_credits,24961.33984375, +scenario_117,federal_refundable_credits,0.0, +scenario_117,payroll_tax,15044.787109375, +scenario_117,self_employment_tax,0.0, +scenario_117,state_income_tax_before_refundable_credits,7984.53369140625, +scenario_117,state_refundable_credits,0.0, +scenario_117,local_income_tax,0.0, +scenario_117,snap,0.0, +scenario_117,ssi,0.0, +scenario_117,tanf,0.0, +scenario_117,head_wic_eligible,0.0,0.0 +scenario_117,spouse_wic_eligible,0.0,0.0 +scenario_117,child1_wic_eligible,0.0,0.0 +scenario_117,child2_wic_eligible,0.0,0.0 +scenario_117,child3_wic_eligible,0.0,0.0 +scenario_117,head_medicaid_eligible,0.0,0.0 +scenario_117,spouse_medicaid_eligible,0.0,0.0 +scenario_117,child1_medicaid_eligible,0.0,0.0 +scenario_117,child2_medicaid_eligible,0.0,0.0 +scenario_117,child3_medicaid_eligible,0.0,0.0 +scenario_117,head_chip_eligible,0.0,0.0 +scenario_117,spouse_chip_eligible,0.0,0.0 +scenario_117,child1_chip_eligible,0.0,0.0 +scenario_117,child2_chip_eligible,0.0,0.0 +scenario_117,child3_chip_eligible,0.0,0.0 +scenario_117,head_medicare_eligible,0.0,0.0 +scenario_117,spouse_medicare_eligible,0.0,0.0 +scenario_117,child1_medicare_eligible,0.0,0.0 +scenario_117,child2_medicare_eligible,0.0,0.0 +scenario_117,child3_medicare_eligible,0.0,0.0 +scenario_117,child1_head_start_eligible,0.0,0.0 +scenario_117,child2_head_start_eligible,0.0,0.0 +scenario_117,child3_head_start_eligible,0.0,0.0 +scenario_117,child1_early_head_start_eligible,0.0,0.0 +scenario_117,child2_early_head_start_eligible,0.0,0.0 +scenario_117,child3_early_head_start_eligible,0.0,0.0 +scenario_117,free_school_meals_eligible,1.0,0.0 +scenario_117,reduced_price_school_meals_eligible,0.0,0.0 +scenario_118,federal_income_tax_before_refundable_credits,0.0, +scenario_118,federal_refundable_credits,0.0, +scenario_118,payroll_tax,0.0, +scenario_118,self_employment_tax,0.0, +scenario_118,state_income_tax_before_refundable_credits,0.0, +scenario_118,state_refundable_credits,375.0, +scenario_118,local_income_tax,0.0, +scenario_118,snap,2903.9404296875, +scenario_118,ssi,9368.0, +scenario_118,tanf,0.0, +scenario_118,head_wic_eligible,0.0,0.0 +scenario_118,head_medicaid_eligible,1.0,16059.89453125 +scenario_118,head_chip_eligible,0.0,0.0 +scenario_118,head_medicare_eligible,1.0,5285.2001953125 +scenario_118,free_school_meals_eligible,0.0,0.0 +scenario_118,reduced_price_school_meals_eligible,0.0,0.0 +scenario_119,federal_income_tax_before_refundable_credits,0.0, +scenario_119,federal_refundable_credits,3366.07373046875, +scenario_119,payroll_tax,4207.5, +scenario_119,self_employment_tax,0.0, +scenario_119,state_income_tax_before_refundable_credits,1756.681396484375, +scenario_119,state_refundable_credits,0.0, +scenario_119,local_income_tax,0.0, +scenario_119,snap,0.0, +scenario_119,ssi,0.0, +scenario_119,tanf,0.0, +scenario_119,head_wic_eligible,0.0,0.0 +scenario_119,child1_wic_eligible,0.0,0.0 +scenario_119,child2_wic_eligible,0.0,0.0 +scenario_119,head_medicaid_eligible,0.0,0.0 +scenario_119,child1_medicaid_eligible,0.0,0.0 +scenario_119,child2_medicaid_eligible,0.0,0.0 +scenario_119,head_chip_eligible,0.0,0.0 +scenario_119,child1_chip_eligible,0.0,0.0 +scenario_119,child2_chip_eligible,0.0,0.0 +scenario_119,head_medicare_eligible,0.0,0.0 +scenario_119,child1_medicare_eligible,0.0,0.0 +scenario_119,child2_medicare_eligible,0.0,0.0 +scenario_119,child1_head_start_eligible,0.0,0.0 +scenario_119,child2_head_start_eligible,0.0,0.0 +scenario_119,child1_early_head_start_eligible,0.0,0.0 +scenario_119,child2_early_head_start_eligible,0.0,0.0 +scenario_119,free_school_meals_eligible,0.0,0.0 +scenario_119,reduced_price_school_meals_eligible,0.0,0.0 +scenario_120,federal_income_tax_before_refundable_credits,40021.81640625, +scenario_120,federal_refundable_credits,0.0, +scenario_120,payroll_tax,13496.1552734375, +scenario_120,self_employment_tax,0.0, +scenario_120,state_income_tax_before_refundable_credits,11919.0576171875, +scenario_120,state_refundable_credits,0.0, +scenario_120,local_income_tax,0.0, +scenario_120,snap,0.0, +scenario_120,ssi,0.0, +scenario_120,tanf,0.0, +scenario_120,head_wic_eligible,0.0,0.0 +scenario_120,head_medicaid_eligible,0.0,0.0 +scenario_120,head_chip_eligible,0.0,0.0 +scenario_120,head_medicare_eligible,1.0,5285.2001953125 +scenario_120,free_school_meals_eligible,0.0,0.0 +scenario_120,reduced_price_school_meals_eligible,0.0,0.0 +scenario_121,federal_income_tax_before_refundable_credits,0.0, +scenario_121,federal_refundable_credits,0.0, +scenario_121,payroll_tax,1963.3724365234375, +scenario_121,self_employment_tax,0.0, +scenario_121,state_income_tax_before_refundable_credits,0.0, +scenario_121,state_refundable_credits,0.0, +scenario_121,local_income_tax,0.0, +scenario_121,snap,0.0, +scenario_121,ssi,0.0, +scenario_121,tanf,0.0, +scenario_121,head_wic_eligible,0.0,0.0 +scenario_121,head_medicaid_eligible,0.0,0.0 +scenario_121,head_chip_eligible,0.0,0.0 +scenario_121,head_medicare_eligible,0.0,0.0 +scenario_121,free_school_meals_eligible,0.0,0.0 +scenario_121,reduced_price_school_meals_eligible,0.0,0.0 +scenario_122,federal_income_tax_before_refundable_credits,4746.66162109375, +scenario_122,federal_refundable_credits,0.0, +scenario_122,payroll_tax,0.0, +scenario_122,self_employment_tax,0.0, +scenario_122,state_income_tax_before_refundable_credits,1025.54150390625, +scenario_122,state_refundable_credits,0.0, +scenario_122,local_income_tax,0.0, +scenario_122,snap,0.0, +scenario_122,ssi,0.0, +scenario_122,tanf,0.0, +scenario_122,head_wic_eligible,0.0,0.0 +scenario_122,head_medicaid_eligible,0.0,0.0 +scenario_122,head_chip_eligible,0.0,0.0 +scenario_122,head_medicare_eligible,1.0,5285.2001953125 +scenario_122,free_school_meals_eligible,0.0,0.0 +scenario_122,reduced_price_school_meals_eligible,0.0,0.0 +scenario_123,federal_income_tax_before_refundable_credits,5200.240234375, +scenario_123,federal_refundable_credits,0.0, +scenario_123,payroll_tax,11194.0, +scenario_123,self_employment_tax,0.0, +scenario_123,state_income_tax_before_refundable_credits,3070.061279296875, +scenario_123,state_refundable_credits,0.0, +scenario_123,local_income_tax,0.0, +scenario_123,snap,0.0, +scenario_123,ssi,0.0, +scenario_123,tanf,0.0, +scenario_123,head_wic_eligible,0.0,0.0 +scenario_123,spouse_wic_eligible,0.0,0.0 +scenario_123,child1_wic_eligible,0.0,0.0 +scenario_123,head_medicaid_eligible,0.0,0.0 +scenario_123,spouse_medicaid_eligible,0.0,0.0 +scenario_123,child1_medicaid_eligible,0.0,0.0 +scenario_123,head_chip_eligible,0.0,0.0 +scenario_123,spouse_chip_eligible,0.0,0.0 +scenario_123,child1_chip_eligible,0.0,0.0 +scenario_123,head_medicare_eligible,0.0,0.0 +scenario_123,spouse_medicare_eligible,0.0,0.0 +scenario_123,child1_medicare_eligible,0.0,0.0 +scenario_123,child1_head_start_eligible,0.0,0.0 +scenario_123,child1_early_head_start_eligible,0.0,0.0 +scenario_123,free_school_meals_eligible,1.0,0.0 +scenario_123,reduced_price_school_meals_eligible,0.0,0.0 diff --git a/reference_audit/2026-10-22-engine-upgrade/reference-build/reference_outputs.csv.meta.json b/reference_audit/2026-10-22-engine-upgrade/reference-build/reference_outputs.csv.meta.json new file mode 100644 index 00000000..e01a24a2 --- /dev/null +++ b/reference_audit/2026-10-22-engine-upgrade/reference-build/reference_outputs.csv.meta.json @@ -0,0 +1,3132 @@ +{ + "country": "us", + "generated_at_utc": "2026-07-03T04:21:31.815629+00:00", + "metadata_version": 1, + "num_scenarios": 100, + "output": "results/local/v1_1/us/reference_outputs.csv", + "policyengine_bundles": { + "us": { + "bundle_id": "us-6.1.2", + "country_id": "us", + "policyengine_version": "6.1.2", + "bundled_policyengine_version": "6.1.2", + "model_package": "policyengine-us", + "model_version": "2.60.0", + "model_direct_url": null, + "bundled_model_version": "2.2.1", + "model_version_source": "installed package", + "model_matches_policyengine_bundle": false, + "data_package": "microcosm-data", + "data_version": "0.1.0", + "default_dataset": "populace_us_2024", + "default_dataset_uri": "hf://policyengine/populace-us/populace_us_2024.h5@populace-us-2024-spm-20260915", + "certified_data_build_id": "populace-us-2024-spm-20260915", + "certified_data_artifact_sha256": "6496cc4393d4d3c6574f76eca231de5898c803b9067645591fd5c4d3e65aee84", + "data_build_model_version": "2.2.1", + "data_build_model_git_sha": null, + "data_build_fingerprint": null, + "compatibility_basis": "installed_model_package_not_policyengine_py_bundle", + "bundled_compatibility_basis": "built_with_model_package", + "certified_by": "installed model package; no matching policyengine.py bundle manifest", + "bundled_certified_by": "policyengine.py bundle certification" + } + }, + "private_fraction": 0.0, + "program_set": "headline", + "programs": [ + "federal_income_tax_before_refundable_credits", + "federal_refundable_credits", + "free_school_meals_eligible", + "local_income_tax", + "payroll_tax", + "person_chip_eligible", + "person_early_head_start_eligible", + "person_head_start_eligible", + "person_medicaid_eligible", + "person_medicare_eligible", + "person_wic_eligible", + "reduced_price_school_meals_eligible", + "self_employment_tax", + "snap", + "ssi", + "state_income_tax_before_refundable_credits", + "state_refundable_credits", + "tanf" + ], + "requested_num_scenarios": 100, + "scenario_manifest_input": "results/local/v1_1/us/scenarios_patched.csv", + "scenario_manifest_output": "results/local/v1_1/us/scenarios_out.csv", + "seed": 42, + "split": "public", + "split_seed": 1042, + "task": "reference_outputs", + "reference_csv_sha256": "eab09a0c184c14b0c33679d9ac132d6f1de720c439ac30685a67ca38655184cb", + "revisions": [ + { + "date": "2026-09-22", + "kind": "convention", + "convention": "c_snap_hold_fy2026", + "outputs": "snap", + "rule": "A scored reference follows from the stated facts and from law published before the 2026-07-03 reference freeze. SNAP October-December 2026 hold the FY2026 schedule (the SNAP uprating index behind the maximum allotments, deductions, shelter cap and utility allowances), the last USDA published before the 2026-07-03 reference freeze; USDA published FY2027 on 2026-08-21. The poverty guideline is the 2026 HHS guideline, published in January 2026. The engine's SNAP rounding defects are root causes r26, r27, r28 and r31, fixed upstream and applied with the convention.", + "basis": "7 U.S.C. 2012(u), 2017(a); USDA FY2026 SNAP COLA memorandum (signed 2025-08-14)", + "engine_version": "policyengine-us 1.755.4", + "fix_module": "r13_hold_fy2026_v3.py", + "fix_module_sha256": "7de931064360e7ff68ab4ca72144f6239f79baffa73ffb49b67caa4e26739d70", + "applied_together_with": [ + "c_ca_hold_2025", + "c_id_hold_2025", + "c_irs_sales_tax_2025", + "c_md_2026", + "c_mi_published_2026", + "c_mn_published_2026", + "c_mo_published_2026", + "c_wi_published_2026", + "r04_capital_gain_distributions", + "r09_ny_rptc_rent_cap", + "r17_caleitc_agi_comparison", + "r26_snap_contribution_rounding", + "r27_snap_net_income_rounding", + "r28_snap_min_allotment_rounding", + "r31_snap_income_limit_rounding", + "r33_snap_child_support_treatment" + ], + "excluded_outputs_untouched": true, + "changed": [ + { + "scenario_id": "scenario_008", + "variable": "snap", + "frozen": 15246.9052734375, + "regenerated": 15108.0 + }, + { + "scenario_id": "scenario_012", + "variable": "snap", + "frozen": 4952.08935546875, + "regenerated": 4884.0 + }, + { + "scenario_id": "scenario_027", + "variable": "snap", + "frozen": 287.68316650390625, + "regenerated": 288.0 + }, + { + "scenario_id": "scenario_030", + "variable": "snap", + "frozen": 287.68316650390625, + "regenerated": 288.0 + }, + { + "scenario_id": "scenario_038", + "variable": "snap", + "frozen": 7286.9443359375, + "regenerated": 7212.0 + }, + { + "scenario_id": "scenario_043", + "variable": "snap", + "frozen": 3596.039794921875, + "regenerated": 3576.0 + }, + { + "scenario_id": "scenario_045", + "variable": "snap", + "frozen": 287.68316650390625, + "regenerated": 0.0 + }, + { + "scenario_id": "scenario_054", + "variable": "snap", + "frozen": 6125.68896484375, + "regenerated": 6060.0 + }, + { + "scenario_id": "scenario_066", + "variable": "snap", + "frozen": 3596.039794921875, + "regenerated": 3576.0 + }, + { + "scenario_id": "scenario_073", + "variable": "snap", + "frozen": 287.68316650390625, + "regenerated": 288.0 + }, + { + "scenario_id": "scenario_079", + "variable": "snap", + "frozen": 2428.017333984375, + "regenerated": 2376.0 + }, + { + "scenario_id": "scenario_108", + "variable": "snap", + "frozen": 287.68316650390625, + "regenerated": 288.0 + }, + { + "scenario_id": "scenario_109", + "variable": "snap", + "frozen": 8020.55419921875, + "regenerated": 7932.0 + } + ] + }, + { + "date": "2026-09-22", + "kind": "convention", + "convention": "c_ca_hold_2025", + "outputs": "California income tax and credits", + "rule": "A scored reference follows from the stated facts and from law published before the 2026-07-03 reference freeze. California's 2026 indexed income tax amounts hold the 2025 amounts FTB published (October 2025 Tax News; 2025 Form 540 and 3514 booklets), the last published before the 2026-07-03 reference freeze; the 2026 factor rests on June 2026 California CPI (BLS 2026-07-14; DIR 2026-08-12). The CalEITC final phase-out breakpoints take their statutory 2025 values ($252/$636), which policyengine-us 1.755.4 had projected ($257/$649).", + "basis": "Cal. R&TC 17041(h), 17052(o); FTB Tax News, October 2025; FTB 2026 Form 540-ES instructions", + "engine_version": "policyengine-us 1.755.4", + "fix_module": "r19_ca_convention.py", + "fix_module_sha256": "937429d39a8695bc70bdf33ee74c3fc67771f782f82b3d288668ad73b9057e8c", + "applied_together_with": [ + "c_id_hold_2025", + "c_irs_sales_tax_2025", + "c_md_2026", + "c_mi_published_2026", + "c_mn_published_2026", + "c_mo_published_2026", + "c_snap_hold_fy2026", + "c_wi_published_2026", + "r04_capital_gain_distributions", + "r09_ny_rptc_rent_cap", + "r17_caleitc_agi_comparison", + "r26_snap_contribution_rounding", + "r27_snap_net_income_rounding", + "r28_snap_min_allotment_rounding", + "r31_snap_income_limit_rounding", + "r33_snap_child_support_treatment" + ], + "excluded_outputs_untouched": true, + "changed": [ + { + "scenario_id": "scenario_022", + "variable": "federal_income_tax_before_refundable_credits", + "frozen": 11131.3271484375, + "regenerated": 11113.5703125 + }, + { + "scenario_id": "scenario_023", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 6.7984771728515625, + "regenerated": 12.776718139648438 + }, + { + "scenario_id": "scenario_023", + "variable": "state_refundable_credits", + "frozen": 148.3108673095703, + "regenerated": 95.15400695800781 + } + ] + }, + { + "date": "2026-09-22", + "kind": "convention", + "convention": "c_irs_sales_tax_2025", + "outputs": "federal income tax of filers who deduct general sales tax", + "rule": "A scored reference follows from the stated facts and from law published before the 2026-07-03 reference freeze. The optional state sales tax tables for 2026 are the 2025 tables the IRS published in the 2025 Instructions for Schedule A (posted 2025-12-18), the last published before the 2026-07-03 reference freeze; no 2026 edition had been published by 2026-09-22. policyengine-us 1.755.4 projected 2026 tables from its 2023 edition with chained CPI, which is not the IRS method.", + "basis": "IRS, 2025 Instructions for Schedule A (Form 1040), Optional State Sales Tax Tables", + "engine_version": "policyengine-us 1.755.4", + "fix_module": "r19_irs_sales_tax_convention.py", + "fix_module_sha256": "202f05cad631b28692edc315b61b5f1a2a5604e66d7ae3df72c66e794b8a3895", + "applied_together_with": [ + "c_ca_hold_2025", + "c_id_hold_2025", + "c_md_2026", + "c_mi_published_2026", + "c_mn_published_2026", + "c_mo_published_2026", + "c_snap_hold_fy2026", + "c_wi_published_2026", + "r04_capital_gain_distributions", + "r09_ny_rptc_rent_cap", + "r17_caleitc_agi_comparison", + "r26_snap_contribution_rounding", + "r27_snap_net_income_rounding", + "r28_snap_min_allotment_rounding", + "r31_snap_income_limit_rounding", + "r33_snap_child_support_treatment" + ], + "excluded_outputs_untouched": true, + "changed": [ + { + "scenario_id": "scenario_000", + "variable": "federal_income_tax_before_refundable_credits", + "frozen": 2883.49365234375, + "regenerated": 2906.45361328125 + } + ] + }, + { + "date": "2026-09-22", + "kind": "convention", + "convention": "c_wi_published_2026", + "outputs": "Wisconsin income tax", + "rule": "A scored reference follows from the stated facts and from law published before the 2026-07-03 reference freeze. Wisconsin's 2026 standard deduction and tax brackets are the amounts DOR published before the 2026-07-03 reference freeze (2026 Form 1-ES instructions, rev. 1-26; 2026 WT-4A worksheet, rev. 11-25), not policyengine-us 1.755.4's CPI projections.", + "basis": "Wisconsin DOR, 2026 Form 1-ES instructions (R. 1-26), pp. 2-3; 2026 WT-4A worksheet (R. 11-25), p. 2", + "engine_version": "policyengine-us 1.755.4", + "fix_module": "r19_wi_convention.py", + "fix_module_sha256": "d66c3786882542eba0e9da02b197faa3b6459b78fae6f1b5c19c1774dd04a250", + "applied_together_with": [ + "c_ca_hold_2025", + "c_id_hold_2025", + "c_irs_sales_tax_2025", + "c_md_2026", + "c_mi_published_2026", + "c_mn_published_2026", + "c_mo_published_2026", + "c_snap_hold_fy2026", + "r04_capital_gain_distributions", + "r09_ny_rptc_rent_cap", + "r17_caleitc_agi_comparison", + "r26_snap_contribution_rounding", + "r27_snap_net_income_rounding", + "r28_snap_min_allotment_rounding", + "r31_snap_income_limit_rounding", + "r33_snap_child_support_treatment" + ], + "excluded_outputs_untouched": true, + "changed": [] + }, + { + "date": "2026-09-22", + "kind": "convention", + "convention": "c_id_hold_2025", + "outputs": "Idaho income tax", + "rule": "A scored reference follows from the stated facts and from law published before the 2026-07-03 reference freeze. Idaho's 2026 zero-rate taxable income thresholds hold the 2025 amounts ($4,811 single; $9,622 joint and head of household) the Tax Commission published, the last located before the 2026-07-03 reference freeze; no 2026 publication was found by 2026-09-22. The retirement-benefit caps take their statutory 2026 values; they do not affect any benchmark household.", + "basis": "Idaho Code 63-3024(3), 63-3022A", + "engine_version": "policyengine-us 1.755.4", + "fix_module": "r19_id_convention.py", + "fix_module_sha256": "3449518830d4d2c341365241810d631f1cc3b18f26f5e3d67e64f0f1fd8ddd51", + "applied_together_with": [ + "c_ca_hold_2025", + "c_irs_sales_tax_2025", + "c_md_2026", + "c_mi_published_2026", + "c_mn_published_2026", + "c_mo_published_2026", + "c_snap_hold_fy2026", + "c_wi_published_2026", + "r04_capital_gain_distributions", + "r09_ny_rptc_rent_cap", + "r17_caleitc_agi_comparison", + "r26_snap_contribution_rounding", + "r27_snap_net_income_rounding", + "r28_snap_min_allotment_rounding", + "r31_snap_income_limit_rounding", + "r33_snap_child_support_treatment" + ], + "excluded_outputs_untouched": true, + "changed": [ + { + "scenario_id": "scenario_076", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 6806.78662109375, + "regenerated": 6818.34423828125 + } + ] + }, + { + "date": "2026-09-22", + "kind": "convention", + "convention": "c_mn_published_2026", + "outputs": "Minnesota income tax and credits", + "rule": "A scored reference follows from the stated facts and from law published before the 2026-07-03 reference freeze. Minnesota's 2026 inflation-adjusted amounts are those the Department of Revenue published on 2025-12-01 (announced 2025-12-16), before the 2026-07-03 reference freeze, not policyengine-us 1.755.4's CPI projections; the 2025 renter's credit schedule takes its published values. The marriage credit cap, first located in an August 2026 draft, holds its 2025 amount.", + "basis": "Minnesota Department of Revenue, 2026 inflation-adjusted amounts (2025-12-01), pp. 1-3, 5", + "engine_version": "policyengine-us 1.755.4", + "fix_module": "r19_mn_convention.py", + "fix_module_sha256": "b3d386f6c74af02f0b22869f5f8b6fc25e4b2a645b71762399626391c7cd42b3", + "applied_together_with": [ + "c_ca_hold_2025", + "c_id_hold_2025", + "c_irs_sales_tax_2025", + "c_md_2026", + "c_mi_published_2026", + "c_mo_published_2026", + "c_snap_hold_fy2026", + "c_wi_published_2026", + "r04_capital_gain_distributions", + "r09_ny_rptc_rent_cap", + "r17_caleitc_agi_comparison", + "r26_snap_contribution_rounding", + "r27_snap_net_income_rounding", + "r28_snap_min_allotment_rounding", + "r31_snap_income_limit_rounding", + "r33_snap_child_support_treatment" + ], + "excluded_outputs_untouched": true, + "changed": [ + { + "scenario_id": "scenario_122", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 1028.216552734375, + "regenerated": 1025.54150390625 + } + ] + }, + { + "date": "2026-09-22", + "kind": "convention", + "convention": "c_md_2026", + "outputs": "Maryland income tax; federal tax through the Maryland withholding proxy", + "rule": "A scored reference follows from the stated facts and from law published before the 2026-07-03 reference freeze. Maryland's 2026 withholding allowance is the $3,400 the Comptroller published in the 2026 Employer Withholding Guide (revised December 2025); the 2026 flat standard deduction holds the published 2025 amounts ($3,350; $6,700), because no 2026 return amount was located before the 2026-07-03 reference freeze (provisional); the child and dependent care credit caps hold their 2025 amounts.", + "basis": "Md. Tax-Gen. 10-217 (Chapter 604 of 2025); Comptroller Tax Alert rev. 2025-12-22; 2026 Employer Withholding Guide", + "engine_version": "policyengine-us 1.755.4", + "fix_module": "r19_md_convention.py", + "fix_module_sha256": "91afaba40009fbae5cc430841d5882ae04c9f025ede425bd99321e52f6c5fb1d", + "applied_together_with": [ + "c_ca_hold_2025", + "c_id_hold_2025", + "c_irs_sales_tax_2025", + "c_mi_published_2026", + "c_mn_published_2026", + "c_mo_published_2026", + "c_snap_hold_fy2026", + "c_wi_published_2026", + "r04_capital_gain_distributions", + "r09_ny_rptc_rent_cap", + "r17_caleitc_agi_comparison", + "r26_snap_contribution_rounding", + "r27_snap_net_income_rounding", + "r28_snap_min_allotment_rounding", + "r31_snap_income_limit_rounding", + "r33_snap_child_support_treatment" + ], + "excluded_outputs_untouched": true, + "changed": [ + { + "scenario_id": "scenario_068", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 1252.9677734375, + "regenerated": 1255.3427734375 + }, + { + "scenario_id": "scenario_078", + "variable": "federal_income_tax_before_refundable_credits", + "frozen": 24772.693359375, + "regenerated": 24780.61328125 + } + ] + }, + { + "date": "2026-09-22", + "kind": "convention", + "convention": "c_mi_published_2026", + "outputs": "Michigan income tax and credits", + "rule": "A scored reference follows from the stated facts and from law published before the 2026-07-03 reference freeze. Michigan's 2026 personal exemption ($5,900) and retirement limits are those Treasury published in the 2026 Form 446 (revised February 2026), before the 2026-07-03 reference freeze; amounts with no located 2026 publication (disability exemption, senior investment limits, homestead and home heating tables) hold their published 2025 values, which also replace the engine's projected 2025 entries.", + "basis": "Michigan Treasury Form 446 (2026, rev. February 2026); 2025 MI-1040 and MI-1040CR-7 instructions", + "engine_version": "policyengine-us 1.755.4", + "fix_module": "r19_mi_convention.py", + "fix_module_sha256": "15e16cfaeac13805ce3e9f32f91fc427f3b5fb687b31cc19f18c2604a233e974", + "applied_together_with": [ + "c_ca_hold_2025", + "c_id_hold_2025", + "c_irs_sales_tax_2025", + "c_md_2026", + "c_mn_published_2026", + "c_mo_published_2026", + "c_snap_hold_fy2026", + "c_wi_published_2026", + "r04_capital_gain_distributions", + "r09_ny_rptc_rent_cap", + "r17_caleitc_agi_comparison", + "r26_snap_contribution_rounding", + "r27_snap_net_income_rounding", + "r28_snap_min_allotment_rounding", + "r31_snap_income_limit_rounding", + "r33_snap_child_support_treatment" + ], + "excluded_outputs_untouched": true, + "changed": [ + { + "scenario_id": "scenario_045", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 1288.8375244140625, + "regenerated": 1290.9625244140625 + } + ] + }, + { + "date": "2026-09-22", + "kind": "convention", + "convention": "c_mo_published_2026", + "outputs": "Missouri income tax", + "rule": "A scored reference follows from the stated facts and from law published before the 2026-07-03 reference freeze. Missouri's 2026 income tax brackets are those the Department of Revenue published in its 2026 withholding formula (dated 2025-11-21), before the 2026-07-03 reference freeze, not policyengine-us 1.755.4's CPI projections.", + "basis": "Missouri DOR 2026 Withholding Formula (2025-11-21), annual table p. 2", + "engine_version": "policyengine-us 1.755.4", + "fix_module": "r19_mo_convention.py", + "fix_module_sha256": "a277c0790d2692f584d63773f62c215c917b8ebf12722a4d01d15f04f71025fc", + "applied_together_with": [ + "c_ca_hold_2025", + "c_id_hold_2025", + "c_irs_sales_tax_2025", + "c_md_2026", + "c_mi_published_2026", + "c_mn_published_2026", + "c_snap_hold_fy2026", + "c_wi_published_2026", + "r04_capital_gain_distributions", + "r09_ny_rptc_rent_cap", + "r17_caleitc_agi_comparison", + "r26_snap_contribution_rounding", + "r27_snap_net_income_rounding", + "r28_snap_min_allotment_rounding", + "r31_snap_income_limit_rounding", + "r33_snap_child_support_treatment" + ], + "excluded_outputs_untouched": true, + "changed": [ + { + "scenario_id": "scenario_093", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 3389.65087890625, + "regenerated": 3388.24560546875 + } + ] + }, + { + "date": "2026-09-22", + "kind": "upstream_fix", + "root_cause": "r04_capital_gain_distributions", + "outputs": "federal_income_tax_before_refundable_credits, state_income_tax_before_refundable_credits", + "rule": "An engine defect fixed in policyengine-us after the reference freeze is regenerated with the fix. Capital gain distributions are long-term capital gain in gross income and in the preferential-rate base.", + "defect": "PolicyEngine leaves capital gain distributions reported without Schedule D out of gross income", + "basis": "26 U.S.C. 61(a)(3), 852(b)(3)(B); Form 1040 line 7", + "upstream": "fixed in PolicyEngine/policyengine-us#8839 (issue #8828), after the reference freeze", + "engine_version": "policyengine-us 1.755.4", + "fix_module": "r04_capital_gain_distributions.py", + "fix_module_sha256": "ccbbf3dd0b866975347319bfb6778bcfcf1c6415faa4f1149c4059a9cd9ed929", + "measured_against": "frozen", + "applied_together_with": [ + "c_ca_hold_2025", + "c_id_hold_2025", + "c_irs_sales_tax_2025", + "c_md_2026", + "c_mi_published_2026", + "c_mn_published_2026", + "c_mo_published_2026", + "c_snap_hold_fy2026", + "c_wi_published_2026", + "r09_ny_rptc_rent_cap", + "r17_caleitc_agi_comparison", + "r26_snap_contribution_rounding", + "r27_snap_net_income_rounding", + "r28_snap_min_allotment_rounding", + "r31_snap_income_limit_rounding", + "r33_snap_child_support_treatment" + ], + "excluded_outputs_untouched": true, + "changed": [ + { + "scenario_id": "scenario_042", + "variable": "federal_income_tax_before_refundable_credits", + "frozen": 1979.1583251953125, + "regenerated": 2361.96484375 + }, + { + "scenario_id": "scenario_051", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 814.9500122070312, + "regenerated": 820.3499755859375 + } + ] + }, + { + "date": "2026-09-22", + "kind": "upstream_fix", + "root_cause": "r09_ny_rptc_rent_cap", + "outputs": "state_refundable_credits", + "rule": "An engine defect fixed in policyengine-us after the reference freeze is regenerated with the fix. A renter whose adjusted rent averages more than $450 a month gets no real property tax credit.", + "defect": "PolicyEngine applies New York's $450-a-month renter cap to a quarter of rent instead of the rent itself", + "basis": "N.Y. Tax Law 606(e)(7)(D); Form IT-214", + "upstream": "fixed in PolicyEngine/policyengine-us#9301 (issue #9298) and PolicyEngine/policyengine-us#9313 (the 2025 flat credit tables the sandbox module also applies), after the reference freeze", + "engine_version": "policyengine-us 1.755.4", + "fix_module": "r09_ny_rptc_rent_cap_v2.py", + "fix_module_sha256": "ccdc92a415ad516e00d0ca2f4c8710b4aa3ae332e1fc2ec8e55a69781b9b26b9", + "measured_against": "frozen", + "applied_together_with": [ + "c_ca_hold_2025", + "c_id_hold_2025", + "c_irs_sales_tax_2025", + "c_md_2026", + "c_mi_published_2026", + "c_mn_published_2026", + "c_mo_published_2026", + "c_snap_hold_fy2026", + "c_wi_published_2026", + "r04_capital_gain_distributions", + "r17_caleitc_agi_comparison", + "r26_snap_contribution_rounding", + "r27_snap_net_income_rounding", + "r28_snap_min_allotment_rounding", + "r31_snap_income_limit_rounding", + "r33_snap_child_support_treatment" + ], + "excluded_outputs_untouched": true, + "changed": [ + { + "scenario_id": "scenario_104", + "variable": "state_refundable_credits", + "frozen": 375.0, + "regenerated": 0.0 + } + ] + }, + { + "date": "2026-09-22", + "kind": "upstream_fix", + "root_cause": "r17_caleitc_agi_comparison", + "outputs": "state_refundable_credits", + "rule": "An engine defect fixed in policyengine-us after the reference freeze is regenerated with the fix. When adjusted gross income exceeds the income at which the CalEITC starts to phase out, the credit is looked up again at AGI and the smaller amount applies.", + "defect": "PolicyEngine phases out the CalEITC on earned income only, without the second lookup at adjusted gross income", + "basis": "Cal. R&TC 17052(a), incorporating IRC 32(a)(2)(B); FTB 3514 instructions, CalEITC worksheet", + "upstream": "fixed in PolicyEngine/policyengine-us#9363 (merged 2026-09-01), after the reference freeze", + "engine_version": "policyengine-us 1.755.4", + "fix_module": "r17_caleitc_agi_comparison.py", + "fix_module_sha256": "170b2766c9460bdb53491f5c375864c894b6b5e6d6b4a1d2f797c330879947a5", + "measured_against": "frozen", + "applied_together_with": [ + "c_ca_hold_2025", + "c_id_hold_2025", + "c_irs_sales_tax_2025", + "c_md_2026", + "c_mi_published_2026", + "c_mn_published_2026", + "c_mo_published_2026", + "c_snap_hold_fy2026", + "c_wi_published_2026", + "r04_capital_gain_distributions", + "r09_ny_rptc_rent_cap", + "r26_snap_contribution_rounding", + "r27_snap_net_income_rounding", + "r28_snap_min_allotment_rounding", + "r31_snap_income_limit_rounding", + "r33_snap_child_support_treatment" + ], + "excluded_outputs_untouched": true, + "changed": [ + { + "scenario_id": "scenario_023", + "variable": "state_refundable_credits", + "frozen": 148.3108673095703, + "regenerated": 95.15400695800781 + } + ] + }, + { + "date": "2026-09-22", + "kind": "upstream_fix", + "root_cause": "r26_snap_contribution_rounding", + "outputs": "snap", + "rule": "An engine defect fixed in policyengine-us after the reference freeze is regenerated with the fix. If 30% of net income ends in cents, the state rounds it up to the next dollar or rounds the allotment down to the next dollar; with a whole-dollar maximum allotment both give the same whole-dollar allotment.", + "defect": "PolicyEngine subtracts 30% of net income from the maximum allotment without making the allotment a whole-dollar amount", + "basis": "7 CFR 273.10(e)(2)(ii)(A)", + "upstream": "fixed in PolicyEngine/policyengine-us#9318 (merged 2026-08-25), after the reference freeze", + "engine_version": "policyengine-us 1.755.4", + "fix_module": "r26_snap_contribution_rounding.py", + "fix_module_sha256": "42e01d6bd04141d145c3df7ff0fad876d4a2ff62b87235cf0ee2e4607a9cf238", + "measured_against": "c_snap_hold_fy2026", + "applied_together_with": [ + "c_ca_hold_2025", + "c_id_hold_2025", + "c_irs_sales_tax_2025", + "c_md_2026", + "c_mi_published_2026", + "c_mn_published_2026", + "c_mo_published_2026", + "c_snap_hold_fy2026", + "c_wi_published_2026", + "r04_capital_gain_distributions", + "r09_ny_rptc_rent_cap", + "r17_caleitc_agi_comparison", + "r27_snap_net_income_rounding", + "r28_snap_min_allotment_rounding", + "r31_snap_income_limit_rounding", + "r33_snap_child_support_treatment" + ], + "excluded_outputs_untouched": true, + "changed": [ + { + "scenario_id": "scenario_008", + "variable": "snap", + "frozen": 15246.9052734375, + "regenerated": 15108.0 + }, + { + "scenario_id": "scenario_012", + "variable": "snap", + "frozen": 4952.08935546875, + "regenerated": 4884.0 + }, + { + "scenario_id": "scenario_038", + "variable": "snap", + "frozen": 7286.9443359375, + "regenerated": 7212.0 + }, + { + "scenario_id": "scenario_054", + "variable": "snap", + "frozen": 6125.68896484375, + "regenerated": 6060.0 + }, + { + "scenario_id": "scenario_079", + "variable": "snap", + "frozen": 2428.017333984375, + "regenerated": 2376.0 + }, + { + "scenario_id": "scenario_109", + "variable": "snap", + "frozen": 8020.55419921875, + "regenerated": 7932.0 + } + ] + }, + { + "date": "2026-09-22", + "kind": "upstream_fix", + "root_cause": "r28_snap_min_allotment_rounding", + "outputs": "snap", + "rule": "An engine defect fixed in policyengine-us after the reference freeze is regenerated with the fix. The minimum benefit is 8% of the maximum allotment for a household of one, rounded to the nearest whole dollar ($24 a month for FY2026, as USDA published).", + "defect": "PolicyEngine sets the SNAP minimum allotment at 8% of the one-person maximum without rounding ($23.84 a month for FY2026)", + "basis": "7 U.S.C. 2017(a); 7 CFR 273.10(e)(2)(ii)(C)", + "upstream": "fixed in PolicyEngine/policyengine-us#9162 (merged 2026-07-28), after the reference freeze", + "engine_version": "policyengine-us 1.755.4", + "fix_module": "r28_snap_min_allotment_rounding.py", + "fix_module_sha256": "07e555626ad1636988dbedcc2f75e312ced8ee68cd270d7296fb0c289dba8357", + "measured_against": "c_snap_hold_fy2026", + "applied_together_with": [ + "c_ca_hold_2025", + "c_id_hold_2025", + "c_irs_sales_tax_2025", + "c_md_2026", + "c_mi_published_2026", + "c_mn_published_2026", + "c_mo_published_2026", + "c_snap_hold_fy2026", + "c_wi_published_2026", + "r04_capital_gain_distributions", + "r09_ny_rptc_rent_cap", + "r17_caleitc_agi_comparison", + "r26_snap_contribution_rounding", + "r27_snap_net_income_rounding", + "r31_snap_income_limit_rounding", + "r33_snap_child_support_treatment" + ], + "excluded_outputs_untouched": true, + "changed": [ + { + "scenario_id": "scenario_027", + "variable": "snap", + "frozen": 287.68316650390625, + "regenerated": 288.0 + }, + { + "scenario_id": "scenario_030", + "variable": "snap", + "frozen": 287.68316650390625, + "regenerated": 288.0 + }, + { + "scenario_id": "scenario_045", + "variable": "snap", + "frozen": 287.68316650390625, + "regenerated": 0.0 + }, + { + "scenario_id": "scenario_073", + "variable": "snap", + "frozen": 287.68316650390625, + "regenerated": 288.0 + }, + { + "scenario_id": "scenario_108", + "variable": "snap", + "frozen": 287.68316650390625, + "regenerated": 288.0 + } + ] + }, + { + "date": "2026-09-22", + "kind": "upstream_fix", + "root_cause": "r27_snap_net_income_rounding", + "outputs": "snap", + "rule": "An engine defect fixed in policyengine-us after the reference freeze is regenerated with the fix. SNAP net income is rounded to the nearest dollar, as policyengine-us#9318 does in every state and California's CalFresh rules require; recomputing with cents kept instead moves no scored reference.", + "defect": "PolicyEngine floors SNAP net income in every state, which matches neither procedure 7 CFR 273.10(e)(1)(ii) allows", + "basis": "7 CFR 273.10(e)(1)(ii); California MPP 63-503.311 (CDSS summary)", + "upstream": "fixed in PolicyEngine/policyengine-us#9318 (merged 2026-08-25), after the reference freeze", + "engine_version": "policyengine-us 1.755.4", + "fix_module": "r27_snap_net_income_rounding.py", + "fix_module_sha256": "81eb155229603203605cf6daf259e002ecac22d4bedadd3591e2b600ab62682d", + "measured_against": "c_snap_hold_fy2026", + "applied_together_with": [ + "c_ca_hold_2025", + "c_id_hold_2025", + "c_irs_sales_tax_2025", + "c_md_2026", + "c_mi_published_2026", + "c_mn_published_2026", + "c_mo_published_2026", + "c_snap_hold_fy2026", + "c_wi_published_2026", + "r04_capital_gain_distributions", + "r09_ny_rptc_rent_cap", + "r17_caleitc_agi_comparison", + "r26_snap_contribution_rounding", + "r28_snap_min_allotment_rounding", + "r31_snap_income_limit_rounding", + "r33_snap_child_support_treatment" + ], + "excluded_outputs_untouched": true, + "changed": [ + { + "scenario_id": "scenario_008", + "variable": "snap", + "frozen": 15246.9052734375, + "regenerated": 15108.0 + }, + { + "scenario_id": "scenario_012", + "variable": "snap", + "frozen": 4952.08935546875, + "regenerated": 4884.0 + }, + { + "scenario_id": "scenario_038", + "variable": "snap", + "frozen": 7286.9443359375, + "regenerated": 7212.0 + } + ] + }, + { + "date": "2026-09-22", + "kind": "upstream_fix", + "root_cause": "r31_snap_income_limit_rounding", + "outputs": "none", + "rule": "An engine defect fixed in policyengine-us after the reference freeze is regenerated with the fix. The monthly gross and net income standards are rounded up to the next whole dollar.", + "defect": "PolicyEngine compares SNAP income to the unrounded gross and net income standards", + "basis": "7 CFR 273.9(a)(3)", + "upstream": "fixed in PolicyEngine/policyengine-us#9162 (merged 2026-07-28), after the reference freeze", + "engine_version": "policyengine-us 1.755.4", + "fix_module": "r31_snap_income_limit_rounding.py", + "fix_module_sha256": "9800f9c2275733d825039041de6e3df2b792cf4a72663f0c2e687be61eb4bf35", + "measured_against": "c_snap_hold_fy2026", + "applied_together_with": [ + "c_ca_hold_2025", + "c_id_hold_2025", + "c_irs_sales_tax_2025", + "c_md_2026", + "c_mi_published_2026", + "c_mn_published_2026", + "c_mo_published_2026", + "c_snap_hold_fy2026", + "c_wi_published_2026", + "r04_capital_gain_distributions", + "r09_ny_rptc_rent_cap", + "r17_caleitc_agi_comparison", + "r26_snap_contribution_rounding", + "r27_snap_net_income_rounding", + "r28_snap_min_allotment_rounding", + "r33_snap_child_support_treatment" + ], + "excluded_outputs_untouched": true, + "changed": [] + }, + { + "date": "2026-09-22", + "kind": "upstream_fix", + "root_cause": "r33_snap_child_support_treatment", + "outputs": "snap", + "rule": "An engine defect fixed in policyengine-us after the reference freeze is regenerated with the fix. A state that does not take the option in 7 CFR 273.9(c)(17) counts legally obligated child support paid to nonhousehold members in gross income and deducts it when computing net income (7 CFR 273.9(d)(5)). USDA's 16th and 17th State Options Reports list Michigan among those states (the 15th lists it among the exclusion states), and Michigan's budget (BEM 556) subtracts child support at line 20, after gross income at line 10.", + "defect": "PolicyEngine reads its SNAP child support flag as the option to exclude child support paid from gross income, but the values carry the opposite meaning: for 2026 it excludes the payments from gross income in 37 jurisdictions that USDA's State Options Report lists as deducting them from net income, Michigan among them, and deducts them in 9 of the 14 it lists as excluding them", + "basis": "7 CFR 273.9(c)(17); 7 CFR 273.9(d)(5); USDA SNAP State Options Report, 16th edition (June 2024), Treatment of Child Support Payments, p. 15, and 17th edition, p. 21 (Michigan: child support income expense deduction); Michigan Bridges Eligibility Manual 556 (11-1-2025), line 20", + "upstream": "fixed in PolicyEngine/policyengine-us#9586 (merged 2026-09-24)", + "engine_version": "policyengine-us 1.755.4", + "fix_module": "r33_snap_child_support_treatment.py", + "fix_module_sha256": "1c05732b502a83ce164c443e88341dc9c48040cb8cb4c454bdf42273c97dffad", + "measured_against": "c_snap_hold_fy2026", + "applied_together_with": [ + "c_ca_hold_2025", + "c_id_hold_2025", + "c_irs_sales_tax_2025", + "c_md_2026", + "c_mi_published_2026", + "c_mn_published_2026", + "c_mo_published_2026", + "c_snap_hold_fy2026", + "c_wi_published_2026", + "r04_capital_gain_distributions", + "r09_ny_rptc_rent_cap", + "r17_caleitc_agi_comparison", + "r26_snap_contribution_rounding", + "r27_snap_net_income_rounding", + "r28_snap_min_allotment_rounding", + "r31_snap_income_limit_rounding" + ], + "excluded_outputs_untouched": true, + "changed": [ + { + "scenario_id": "scenario_045", + "variable": "snap", + "frozen": 287.68316650390625, + "regenerated": 0.0 + } + ] + }, + { + "date": "2026-09-29", + "kind": "engine_upgrade", + "root_cause": "engine_upgrade_policyengine_us_2_15_17", + "outputs": "every scored output", + "rule": "A scored reference follows from the stated facts and from law published before the 2026-07-03 reference freeze. References come from the newest policyengine-us release when PolicyBench begins the reference sweep; at publication PolicyBench checks that the newest release gives the same values. Max's ruling, 2026-09-28: 'we should be using the latest pe for this always!' The conventions that hold pre-freeze law are re-expressed for the release the sweep uses.", + "engine_version": "policyengine-us 2.15.17", + "previous_engine_version": "policyengine-us 1.755.4", + "policyengine_py": "policyengine 6.1.2, provenance only: its certified US bundle is policyengine-us 2.2.1, and it refuses to import next to a newer model", + "fix_modules": [ + { + "module": "latest_c_ca_hold_2025.py", + "sha256": "f19a47b9583032a0602a31e52f995eee824a427a76e87a9d4257d6682a016fa2" + }, + { + "module": "latest_c_irs_sales_tax_2025.py", + "sha256": "7f7fd235b29c45d1d5cceded0c3391aceb38740518dfda770e3aebcc3003228e" + }, + { + "module": "latest_c_wi_published_2026.py", + "sha256": "4edf4c714c05d300e6fa32c4b56879aad8aa0de1d9ddd9a77987eefe3b06acce" + }, + { + "module": "latest_c_id_hold_2025.py", + "sha256": "39fb99292691600cd273a1c6ef3c90847453e21e4d7b872603bcaac71727f8a5" + }, + { + "module": "latest_c_mn_published_2026.py", + "sha256": "02a8ccc1fce71485fc9411d4a55f33226de4c8de09cf6375f99866b79da70522" + }, + { + "module": "latest_c_md_2026.py", + "sha256": "8111c77ffd2e43d434d083994a7e8506ba42461a0845b33ac47ce0df988c2c76" + }, + { + "module": "latest_c_mi_published_2026.py", + "sha256": "787cf837422e0bdf331a8e01a6fa8e8f2e3b78c35c248a4da83f3b2dbfa9ef9e" + }, + { + "module": "latest_c_mo_published_2026.py", + "sha256": "0474524c83a7eb0c8440abf06bbeee38d4394e08260464d0dacb195ed3a8d916" + }, + { + "module": "latest_c_snap_hold_fy2026.py", + "sha256": "3a8709ef36582af2248e460136db618fd319d490b7aeed94adbd6143ad9c07dd" + }, + { + "module": "latest_conventions.py", + "sha256": "4155ed4a0be72c907815b33e2b3603cf0b5ea3eca351ad7509f8bd9ea5bb8ddb" + }, + { + "module": "latest_md_local_output_scope.py", + "sha256": "53a6de3cd9b149467e5d86a5bb1fcc258e859478a7c16b7d3df951c713e423dd" + } + ], + "builder": "policybench.scenarios.Scenario.to_pe_household passes stated usual weekly hours (hours_worked_last_week) to weekly_hours_worked_before_lsr as well; upstream policyengine-us#9261 changed that input's default from 40 to 0", + "excluded_outputs_untouched": true, + "excluded_outputs_rechecked": [ + { + "scenario_id": "scenario_005", + "variable": "federal_income_tax_before_refundable_credits", + "kept_value": 106505.8984375, + "value_on_2_15_17": 107833.15625, + "reason": "r02 is unfixed in 2.15.17. gov.irs.ald.deductions (2026) still lists traditional_ira_contributions; the list and the retirement variables are identical to 1.755.4 apart from uprating attributes (44001a4c24). No 219(g) or active-participant code exists, and upstream #8388 scoped 219(g) out with no follow-up. Both spouses list 401(k) deferrals, so both are active participants under 219(g)(5)(A)(i); ira_219g_magi is $543,076, far above $149,000, so the deductible limit is $0 and the engine's $2,163.84 deduction is wrong. The +$1,327.26 move is #9122 alone: salt_refund_income=0 on 2.15.17 gives exactly 106505.8984375. The alternative on 2.15.17 is 108525.578125 with the refund in AGI; 107198.3359375 applies with both readings or under a hold. Both were reproduced by the harness and by my engine-free calculation to $0.01. It also depends on the unlisted 402(g) excess allocation (106,342.59 to 108,096.20 on latest), so it should stay excluded even after an upstream r02 fix unless that allocation is ruled. NIIT is included (r25), as in the board." + }, + { + "scenario_id": "scenario_005", + "variable": "state_income_tax_before_refundable_credits", + "kept_value": 41051.51171875, + "value_on_2_15_17": 41267.01171875, + "reason": "Both r11 and r02 are still in 2.15.17. The CA itemized, charity and misc variables and parameters, traditional_ira_contributions and gov/irs/ald/deductions.yaml are identical over 06665727d8..79be99f671, and git grep finds no active_participant or 219(g) logic. The stored, unscored value is 2.15.17 + conventions = 41,267.011719; I reproduced it in the harness and by hand. The +215.50 gap to the board splits as +168.36 from c_ca_hold_2025 (the board kept raw v1.1 for this excluded output) and +47.14 from #9122: 23.14 through the line 29 limitation (248.86 x 9.3%) and 24.00 through the exemption credits (13 to 15 phase-out steps x $6 x 2). With #9122 reverted on the conventions, the value is 41,219.867188 = 1.755.4 + r19. The output also depends on three stated-but-unresolved or unlisted facts: whether the SALT refund was taxable (40,975.25 vs 40,920.40 after r11 + r02), who issued the tax-exempt interest (+833.41 if non-California), and how the over-limit 401(k) deferrals are cut (-491.85). The exclusion should therefore also carry an unlisted-input reason, and alternative_value should record both SALT-refund readings rather than a single 'law-correct' 40,975.25." + }, + { + "scenario_id": "scenario_007", + "variable": "state_income_tax_before_refundable_credits", + "kept_value": 755.7783203125, + "value_on_2_15_17": 761.5570068359375, + "reason": "Reproduced with sweep_latest.py on 2.15.17. Raw gives 755.7783203125, identical to v11_1755. latest_conventions gives 761.5570068359375 (+5.7787 = 0.053 x (4920.0313 - 4811)). latest_conventions + r07_v2 gives 651.3170166. The subtractions.yaml and main/single.yaml files are identical between 1.755.4 and 2.15.17, and the premium subtraction is still absent, so the r07 defect is still present. The board row is the raw 755.7783 because the c_id_hold_2025 revision has excluded_outputs_untouched: true. By hand: taxable SS 13,784.125, Idaho TI 19,180, and 0.053 x (19,180 - 4,811) = 761.557. With the premium subtraction, 0.053 x (17,100 - 4,811) = 651.317, which matches the exclusion record's alternative_value. Keep excluded; scoring does not change." + }, + { + "scenario_id": "scenario_020", + "variable": "federal_income_tax_before_refundable_credits", + "kept_value": 68056.7109375, + "value_on_2_15_17": 68334.734375, + "reason": "Confirmed. On 2.15.17, sweep_latest.py gives 68334.734375 both raw and with latest_conventions.py. latest_conventions plus r25_niit_excluded gives 68112.09375, exactly the exclusion record's alternative_value, so the two readings still differ by 222.64 (more than the $1 tolerance). The r25 root cause is the benchmark_specs.json output definition ('federal individual income tax after nonrefundable credits and before refundable credits'), which is unchanged. The engine formula (income_tax_before_refundable_credits.py; git diff 06665727d8..79be99f671 is empty; cmp of the installed files is identical) still adds net_investment_income_tax, and net_investment_income_tax.py has the same sha1 in both engines. The move comes only from #9616 (3f029abf5b, 2026-09-27), which fixed the column-shifted sales tax table. The IRS figure it carries, the 2025 TX size-1 $300k+ cell of 1,595, was published in December 2025, before the freeze. No hold module is needed, because raw and conventions agree." + }, + { + "scenario_id": "scenario_022", + "variable": "state_income_tax_before_refundable_credits", + "kept_value": 2439.650146484375, + "value_on_2_15_17": 2505.8701171875, + "reason": "r11 is still present. ca_itemized_deductions_pre_limitation carries the federal charitable_deduction (0.5% floor from 2026: 14,847.67 instead of 15,393.41) and the federal misc_deduction (0 since 2018). R&TC 17076(c) (Stats. 2025 ch. 231, SB 711 Sec. 11, effective 2025-10-01) and the conformity date in 17024.5(a)(1)(Q) (IRC as of 2025-01-01) mean California allows both. The law-correct value is 1,968.81; I reproduced it by harness and by hand. Federal AGI is 109,149.16 and CA AGI is 91,524.41; itemized deductions are 8,829 + 15,393.41 + 6,167.56 = 30,389.97; CA taxable income 61,134.44 gives tax of 2,274.81, less 306 of exemption credits. That equals the Sept 22 alternative. Raw 2.15.17 equals the board exactly, and 2.15.17 + conventions = 2,505.870117 = 1.755.4 + r19, so c_ca_hold_2025 alone moves it. I found no unlisted-input dependence: medical stays under the floor under any reading, and the prompt lists no refund and no tax-exempt interest. This is a pure engine defect, so the output could be un-excluded once r11 is fixed upstream. The value uses the rate schedule, as for every CA output (FTB's tax table for taxable income of $100,000 or less could differ by about a dollar)." + }, + { + "scenario_id": "scenario_023", + "variable": "snap", + "kept_value": 461.3397216796875, + "value_on_2_15_17": 408.0, + "reason": "Reproduced on the harness. latest_conventions gives 408 ($34/mo); raw 2.15.17 gives 462. Hand check: gross $2,120.22 (wages $1,453.55 plus 403(b) $666.67); minus 20% earned ($290.71) and the $209 standard deduction gives $1,620.51; minus the $744 cap (binds with or without the SUA) gives $876.51, rounded to $877; 30% is $263.10, rounded up to $264; $298 - $264 = $34. The unlisted input still decides the output under law. Under reading B, federal SSI is $0 (countable $1,340.94 > $994) and CA SSP is $0 (countable income over the $1,335.81 standard). She has no MAGI route (141.19% FPL > 138%). Her Medi-Cal is a disability pathway (engine: SENIOR_OR_DISABLED), and receiving it makes her an elderly-or-disabled member under 7 U.S.C. 2012(j)(2)(B) and 7 CFR 271.2(11), both text-verified. 2.15.17 does not model that route, so flipping meets_ssi_disability_criteria alone gives 408 (rv_probe conv_B). Record the alternative as 3,576 with the engine's CA heat-and-eat SUA, and 2,832 if no LIHEAP payment is inferred (a SUA of about $206 suffices, not $384). Reword the record: in 2.15.17 SSI criteria no longer confer SNAP status (#9345); the route is Medi-Cal receipt." + }, + { + "scenario_id": "scenario_042", + "variable": "state_income_tax_before_refundable_credits", + "kept_value": 284.74090576171875, + "value_on_2_15_17": 464.18280029296875, + "reason": "Both defects are still present in policyengine-us 2.15.17, and I confirmed each directly.\n- diff -rq shows wi_capital_gain_loss_subtraction.py and wi_income_tax_before_refundable_credits.py byte-identical to 1.755.4, and git log 06665727d8..79be99f671 shows no commit touching either file.\n- My probe of 2.15.17 plus latest_conventions shows non_sch_d_capital_gains 3,753 in federal AGI (50,580.71; net_capital_gain 4,681) but wi_capital_gain_loss_subtraction 0.\n- The probe also shows wi_income_tax 0 (the min with the line-16 exclusion path, since wi_retirement_income_exclusion_amount is 24,000 and wi_retirement_income_exclusion_tax is 0) while wi_income_tax_before_refundable_credits is 464.1828.\nHarness runs on 042/091:\n- latest_conventions: 464.1828.\n- Plus r32: 408.698425.\n- Plus r32 and the r06 elected-path port: 0.0.\nAn engine-free recompute on the 2026 1-ES parameters reproduces 464.1827 (standard path, no r32), 408.6984 (with r32) and 0.0 (elected line 16). 71.05(6)(b)54m lets a filer aged 67 or older subtract up to $24,000 of qualified-plan and IRA distributions, and 54m.d forfeits the credits. On the elected path, WI income 8,608.81 is below the 13,960 standard deduction plus 950 exemptions, so tax is 0, and 0 is below the standard path's net 408.70, so the filer elects it. The 0.0 holds under every alternative reading I tried:\n- only the 19,200 IRA counts as line 16 (WI income 14,534.71 or 13,408.81, both below 14,910);\n- the farm loss is double-counted;\n- qualified_bdc_income is added.\nr06 alone suffices; r32 does not change the alternative. #9122 does not apply (salt_refund_income is 0). If the record is refreshed, engine value 464.1828 and alternative 0.0." + }, + { + "scenario_id": "scenario_053", + "variable": "state_income_tax_before_refundable_credits", + "kept_value": 2435.2783203125, + "value_on_2_15_17": 2441.05712890625, + "reason": "Reproduced with sweep_latest.py on 2.15.17. Raw gives 2435.2783203125, identical to v11_1755. latest_conventions gives 2441.05712890625. latest_conventions + r07_v2 gives 2176.05712890625 (-265.00 = 0.053 x 5,000). id_subtractions is 0 and the r07 defect is still present. By hand: 0.053 x (50,868.68 - 4,811) = 2441.057, and 0.053 x (45,868.68 - 4,811) = 2176.057. The alternative also assumes the $5,000 is not paid through a pre-tax salary reduction. The prompt leaves that unstated (the household has wages and ESI), which gives an additional unlisted-input reason to keep this output excluded. Keep excluded; scoring does not change." + }, + { + "scenario_id": "scenario_056", + "variable": "snap", + "kept_value": 1140.0, + "value_on_2_15_17": 95.0, + "reason": "Two inputs are still unlisted: hours, and whether the mortgage (and the property tax) is on the occupied home. At 0 hours the value also depends on the county and on 3-in-36 history. Refresh the record: frozen_value 95, alternative_value 1,908, engine_version 2.15.17, flipped alternative_reading. The 95 is January 2026 only, from the FNS-approved 20-county waiver (letter 2024-12-16, through 2026-01-31; NJ DFD confirms) applied to the engine's Atlantic County fallback. The amount is the NJ state minimum $95 (law signed 2023-02-08; federal formula $54). The alternative of 40 hours with the mortgage counted gives shelter capped at $744, net $461, contribution $139, so 12 x 159 = 1,908. I reproduced it with my own composition (latest_alt_snap_mortgage_residence reform plus the latest_alt_unlisted_hours_40 patch) and by hand. The one-input alternatives are 1,140 (40 hours only) and 159 (mortgage only)." + }, + { + "scenario_id": "scenario_057", + "variable": "snap", + "kept_value": 2669.217041015625, + "value_on_2_15_17": 2628.0, + "reason": "Reproduced. latest_conventions gives 2,628 ($219/mo); raw gives 2,682. Hand and engine agree. Head SSI is $994 - $391.42 = $602.58/mo; gross is $1,472.42; minus $173.33 (20% of earned) and $209 gives $1,090.08, which rounds to $1,090; 30% is $327; $546 - $327 = $219. Under reading B (rv_probe conv_B, and with the r30 port and the title XIX route), both spouses get SSI at the couple rate: $1,491 - $392.42 = $1,098.58/mo in total ($6,591.50 per person per year). Net is $1,586, 30% is $476, $546 - $476 = $70, and 840 per year, so the recorded alternative of 840 stands on 2.15.17 plus the hold. LA always_standard is false, so there is no SUA and the r30 port cannot move it. The dependence runs through actual SSI receipt, an unlisted-input ambiguity that no engine version resolves." + }, + { + "scenario_id": "scenario_064", + "variable": "state_income_tax_before_refundable_credits", + "kept_value": 4605.9970703125, + "value_on_2_15_17": 4598.47607421875, + "reason": "Root cause r01 is still present in 2.15.17. traditional_ira_contributions.py, ira_contribution_limit.py, ira_contribution_scale.py, above_the_line_deductions.py and gov/irs/ald/deductions.yaml have identical blobs at 06665727d8 and 79be99f671, and upstream/main is 79be99f671. The dependent's $18.03 IRA contribution (stated in the prompt; $0 wages) is still in the joint return's ALD (19,926.22 = 19,800 loss ALD + 108.19 + 18.03). Under 26 U.S.C. 219(a), (b)(1)(B) and (c) (LII, re-fetched this session) it is not deductible there. The review harness gives 2.15.17 + latest_conventions = 4,598.476074, which equals 1.755.4 + r19_wi_convention (re-run this session). Adding r01_v2 gives 4,599.621582, and also reproduces the 064 federal (4,441.455078) and 003 federal (22,400.654297) alternative values exactly; the only other output it moves is scenario_085 federal, by +0.089. Under the board's formula convention the defect moves this output by $1.15, beyond tolerance, so it stays excluded. Caveat: Wis. Stat. 71.05(22)(dp)2 makes DOR's $500-bracket table determinative. On that reading r01's effect is $0.96, and 4,598.476 is $0.64 from a table-law value of about 4,597.83, but the 2026 table was not published before the freeze. Exclusion is the safe call under either reading. Update frozen_value to 4598.476074 and engine_version to 2.15.17. Keep alternative_value at 4599.621582, and note in the exclusion record that it is formula-convention based." + }, + { + "scenario_id": "scenario_080", + "variable": "snap", + "kept_value": 3596.039794921875, + "value_on_2_15_17": 3576.0, + "reason": "The r30 defect is unfixed in 2.15.17. snap_state_using_standard_utility_allowance.py is byte-identical to 1.755.4 and returns p.always_standard[state]. always_standard.yaml's only change since 06665727d8 is metadata (d7fc17abfe), and PA stays true from 2015-10-01. snap_utility_allowance_type still grants the SUA on has_heating_cooling | always_sua. The only upstream fix in progress (draft PR #9610) covers California only. My trace on 2.15.17 + latest_conventions shows always_sua=True, has_heating_cooling_expense=False, is_usda_disabled=False and has_snap_elderly_disabled_member=False. The $857 SUA is capped at $744, net income is 0, and the benefit is $298 x 12 = 3,576. With r30 added it is $270 x 12 = 3,240 (net $92, contribution $28). Under 7 U.S.C. 2014(e)(6)(C)(iv)(I) as amended by P.L. 119-21 sec. 10103(a) (approved 2025-07-04, before the freeze), the engine's own reading (no elderly or disabled member) should give 3,240, so 3,576 is defect-driven under that reading. With is_usda_disabled forced True, 2.15.17 gives 3,576 with or without r30, and the household stays eligible. The prompt supports both readings. It says 'is disabled' but gives no 2012(j) receipt route. Its $3,600 'financial assistance' is unexplained and could be disability-based general assistance. Its $2,000 'spm unit energy subsidy' could be LIHEAP or a state-law payment. It states no certification timing, which matters under the FNS recertification transition. Model answers split the same way: 15 near the SUA-conferred value (3,492-3,576) against 3,240, 3,228 and 2,964-2,988 on other readings. The output is therefore both defect-affected and indeterminate on the stated facts, and stays excluded. The -$20.04 move against the board (3,596.04 to 3,576) comes from the FY2026 SNAP hold convention: the FY2027 COLA memo is dated 2026-08-21, after the freeze. It does not come from r30. Scoring is unaffected." + }, + { + "scenario_id": "scenario_082", + "variable": "federal_income_tax_before_refundable_credits", + "kept_value": 9563.052734375, + "value_on_2_15_17": 9577.90234375, + "reason": "r02 is unfixed in 2.15.17 (same evidence as 005). The HoH head lists a $181 traditional 401(k) deferral with $100,195 of wages, so is an active participant; ira_219g_magi is $117,661, above $91,000, so the limit is $0 but the engine deducts $8.48. The +$14.85 move is #9122 alone (67.50 at 22%); refund=0 on 2.15.17 gives exactly 9563.052734375. The alternative on 2.15.17 is 9579.767578125 with the refund in AGI, or 9564.9169921875 with both readings or under a hold. My engine-free calc reproduces these (standard deduction $24,150 + 170(p) $700; CTC $2,200; CDCC 20% of $3,000). No other unlisted dependence was found. The only non-excluded output r02 moves is 082 state, by $0.59, under the $1 tolerance." + }, + { + "scenario_id": "scenario_091", + "variable": "state_income_tax_before_refundable_credits", + "kept_value": 843.6614990234375, + "value_on_2_15_17": 895.8131103515625, + "reason": "The r32 defect is still present in 2.15.17. The subtraction file is byte-identical to 1.755.4 and no commit in the range touches it. My probe on 2.15.17 plus conventions shows non_sch_d_capital_gains 1,170 in AGI 36,182.56 but wi_capital_gain_loss_subtraction 0.\nThe harness gives 895.81311 with latest_conventions and 878.515747 with r32 added; the engine-free recompute gives 895.8131 and 878.5158. 71.05(6)(b)9 subtracts 30% of long-term gain, IRC 852(b)(3)(B) treats capital gain dividends as long-term, and 2025 SB line 5 applies the 30% exclusion to distributions reported without Schedule WD.\nThere is a second, independent reason to keep this excluded. 2.15.17 does not model the WI medical care insurance subtraction: 71.05(6)(b)42, which covers an employee whose employer pays part of the cost, and 2025 SB line 6, Worksheet 2. The prompt lists $1,800 of other health insurance premiums (repeated as 'health insurance premiums excluding Medicare Part B') without saying whether they were paid pre-tax. The law-correct value is:\n- 878.52 if the premiums were pre-tax;\n- 789.81 if the $1,800 was paid after tax, the reading the prompt's unlisted-boolean-false rule and the engine's own AGI point to;\n- 701.11 if a reader sums both lines.\nThe exclusion record should list root causes r32_wi_capital_gain_distributions plus this unlisted pre-tax-premium ambiguity, and it should label 878.515747 as the r32-only correction, not the unique law-correct value." + }, + { + "scenario_id": "scenario_099", + "variable": "state_income_tax_before_refundable_credits", + "kept_value": 4493.7431640625, + "value_on_2_15_17": 4640.77734375, + "reason": "r11 and r02 are still present. The engine's federal floor removes 797.93 of charity (-63.83). Both spouses defer into a 401(k), which makes them active participants, and MAGI of 159,729.30 exceeds the $149,000 top of the 2026 joint range (IRS Notice 2025-67, posted 2025-11-13), so the $144.26 IRA deduction is fully phased out (+11.54 after r11). Together these give 4,588.48, the Sept 22 alternative. I confirm the new educator-expense defect: FTB 2025 Schedule CA line 11 says 'California law does not conform to federal law regarding educator expenses', but 2.15.17's ca_additions adds only ca_hsa_addition. Adding back $337.50 x 8% = +27.00 gives a fully law-correct 4,615.48 (harness and hand calculation agree). The exclusion reason should cite this third defect. Raw 2.15.17 equals the board exactly, and 2.15.17 + conventions = 4,640.777344 = 1.755.4 + r19, so c_ca_hold_2025 alone moves it. Possible extra reading: if both premium lines are summed, the output moves -241.62." + }, + { + "scenario_id": "scenario_100", + "variable": "snap", + "kept_value": 8625.8896484375, + "value_on_2_15_17": 8556.0, + "reason": "Reproduced. latest_conventions gives 8,556 ($713/mo); raw gives 8,637. Pre-shelter net is $690.73 (earned $492.89 plus the engine's MT TANF of $505.41/mo, minus $98.58 and $209). With the $799 SUA (FNS FY2026 SUA table: MT HCSUA $799), net is $237, 30% rounds up to $72, and $785 - $72 = $713. r30 is confirmed still present in 2.15.17. The engine grants the always_standard SUA with has_heating_cooling_expense = 0 and no elderly-or-disabled member. My r30 port (rv_fix_r30.py, full sweep rv_r30_full.csv) moves only 080 and 100, giving 100 = 6,924: net $691, $208, $785 - $208 = $577. Keep the output excluded under both bases. Add r30_snap_heat_and_eat_sua with the stated-facts corrected value 6,924. Do not drop the unlisted-input basis. Under reading B, the working head qualifies for Montana MWD (ABD 201-6; CMA 001 $15,000 resource limit), and 42 CFR 435.404 lets her select it. Receipt makes her elderly or disabled under 7 CFR 271.2(11), giving 8,844 with the engine's SUA (the existing alternative) or 7,116 without. The mechanism text should change from 'SSI criteria' to 'MWD (title XIX) receipt', which 2.15.17 does not model." + }, + { + "scenario_id": "scenario_112", + "variable": "snap", + "kept_value": 287.68316650390625, + "value_on_2_15_17": 0.0, + "reason": "Hours are unlisted, and at 0 hours the law also depends on unlisted 3-in-36 history, so no engine version resolves this. Refresh the record: frozen_value 0 (the 2.15.17 plus conventions reference), alternative_value 288, engine_version 2.15.17, and flip the alternative_reading text. At 20 or more hours, TX BBCE (165%; $5,000 assets with one vehicle up to $22,000 excluded) is met, and the net income of about $1,269 (engine) or $1,429 (farm rent counted) leaves only the $24 one-person minimum: 12 x 24 = 288. The text should say the 0 comes from the engine's no-history shortcut (the law gives up to $72), and that the stated wages imply at most 15.7 hours a week at the federal minimum wage." + }, + { + "scenario_id": "scenario_118", + "variable": "snap", + "kept_value": 2903.9404296875, + "value_on_2_15_17": 2868.0, + "reason": "Keep excluded, now for three independent reasons.\n1. The mortgage-residence ambiguity (r15_snap_mortgage_interest), which no engine version resolves. 2.15.17 still counts only mortgage_payments, not mortgage interest, as a SNAP shelter cost.\n2. A second unlisted input, the county. The prompt gives only NY, and New York's FY2026 HCSUA is $877, $988 or $1,062 by region. That gives 2,868, 3,276 or 3,540 on 2.15.17 + conventions.\n3. An unfixed 2.15.17 defect: the NY State Supplement Program ($87 a month for an individual living alone in 2026, per the OTDA chart revised 2025-10-27; pre-freeze law) is missing from SNAP income. With it, the value would be 2,400, 2,796 or 3,072 by region.\nRecord 2,868 as the regenerated engine value, replacing the stale raw-1.755.4 2,903.94. Label it as 2.15.17 + latest_conventions under the engine's default county (Albany, Rest of State SUA) without NY SSP, not as the law-correct stated-facts value. Add the NY SSP omission as an unfixed-defect root cause and the county/SUA region as a second unlisted input. The alternative value stays 3,576 (298 x 12). It is the same across all three regions, with or without SSP, and under every 7 CFR 273.10(e) rounding option. Scoring is unaffected." + }, + { + "scenario_id": "scenario_120", + "variable": "federal_income_tax_before_refundable_credits", + "kept_value": 40021.81640625, + "value_on_2_15_17": 40416.66796875, + "reason": "r02 is unfixed in 2.15.17. The single head (76) lists a $617 traditional 401(k) deferral with $165,597 of wages, so is an active participant; ira_219g_magi is $234,414, above $91,000, so the limit is $0 but the engine deducts $28.85. The +$394.85 move is #9122 alone. Taxable income rises $1,645.22, because the engine's ct_withheld_income_tax proxy (CT single rates on federal AGI less $15,000) raises SALT by $113.77 and the 0.5% charitable floor rises $8.75; CT's own tax is unchanged at 11917.18 because CT subtracts salt_refund_income. Refund=0 gives exactly 40021.81640625. The alternative on 2.15.17 is 40423.17578125 with the refund in AGI, or 40028.3203125 with both readings or under a hold. Beyond r02 the output also depends on the engine's missing 469 limit (+24.75) and the unlisted mortgage origination date (-224.64 if grandfathered), so it should not be un-excluded on an r02 fix alone." + } + ], + "changed": [ + { + "scenario_id": "scenario_008", + "variable": "state_refundable_credits", + "frozen": 5342.39990234375, + "previous": 5342.39990234375, + "regenerated": 5842.39990234375, + "cause": "nj_ctc_fy2027_budget", + "basis": "New Jersey child tax credit schedule for 2026-2028 (P.L.2026, c.26, approved June 30, 2026), encoded upstream in policyengine-us#8971 (0319635b6e)." + }, + { + "scenario_id": "scenario_013", + "variable": "snap", + "frozen": 0.0, + "previous": 0.0, + "regenerated": 240.0, + "cause": "az_snap_bbce_200", + "basis": "Arizona raised its expanded categorical eligibility gross limit from 185% to 200% of poverty from benefit month 03/2026 (DES CNAP \"What's Changed on 03/23/2026\"); encoded upstream after 1.755.4." + }, + { + "scenario_id": "scenario_028", + "variable": "reduced_price_school_meals_eligible", + "frozen": 1.0, + "previous": 1.0, + "regenerated": 0.0, + "cause": "school_meals_child_support_income", + "basis": "Child support received counts as household income for school meals (7 CFR 245.6(a)(5)(ii)); policyengine-us added it to the school-meal income sources after 1.755.4." + }, + { + "scenario_id": "scenario_033", + "variable": "federal_income_tax_before_refundable_credits", + "frozen": 3788.988037109375, + "previous": 3788.988037109375, + "regenerated": 3818.148193359375, + "cause": "excluded_reference_depends_on_unlisted_input", + "basis": "Newly excluded from scoring on 2026-09-29 (reference_exclusions.json): whether the prior-year deduction of the refunded state and local tax reduced federal tax (prior-year itemization, the income-versus-sales-tax election, SALT-cap headroom)" + }, + { + "scenario_id": "scenario_078", + "variable": "federal_income_tax_before_refundable_credits", + "frozen": 24772.693359375, + "previous": 24780.61328125, + "regenerated": 24164.45703125, + "cause": "excluded_reference_depends_on_unlisted_input", + "basis": "Newly excluded from scoring on 2026-09-29 (reference_exclusions.json): whether the prior-year deduction of the refunded state and local tax reduced federal tax (prior-year itemization, the income-versus-sales-tax election, SALT-cap headroom)" + }, + { + "scenario_id": "scenario_082", + "variable": "state_refundable_credits", + "frozen": 650.5, + "previous": 650.5, + "regenerated": 667.0, + "cause": "ny_ctc_phaseout_rounding_9425", + "basis": "New York Empire State child credit phase-out rounding corrected upstream (policyengine-us#9425)." + }, + { + "scenario_id": "scenario_117", + "variable": "federal_income_tax_before_refundable_credits", + "frozen": 24391.796875, + "previous": 24391.796875, + "regenerated": 24961.33984375, + "cause": "excluded_reference_depends_on_unlisted_input", + "basis": "Newly excluded from scoring on 2026-09-29 (reference_exclusions.json): whether the prior-year deduction of the refunded state and local tax reduced federal tax (prior-year itemization, the income-versus-sales-tax election, SALT-cap headroom)" + }, + { + "scenario_id": "scenario_078", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 6936.33740234375, + "previous": 6936.33740234375, + "regenerated": 6936.87646484375, + "cause": "engine_upgrade_within_1", + "basis": "Moves by $1 or less on policyengine-us 2.15.17; no score changes at the exact-match tolerance." + }, + { + "scenario_id": "scenario_117", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 7984.05419921875, + "previous": 7984.05419921875, + "regenerated": 7984.53369140625, + "cause": "engine_upgrade_within_1", + "basis": "Moves by $1 or less on policyengine-us 2.15.17; no score changes at the exact-match tolerance." + } + ] + }, + { + "date": "2026-10-10", + "kind": "engine_upgrade", + "root_cause": "engine_upgrade_policyengine_us_2_38_6", + "outputs": "every scored output", + "rule": "A scored reference follows from the stated facts and from law published before the 2026-07-03 reference freeze. References come from the newest policyengine-us release when PolicyBench begins the reference sweep; at publication PolicyBench checks that the newest release gives the same values. Max, 2026-10-09, on waiting for the release that fixes the engine defects behind PolicyBench's exclusions: 'yes i want to wait for hte fixed engine'. An excluded output whose engine defect the new release fixes, landing on its audited corrected value, is regenerated and its exclusion record removed; every other excluded output keeps the value it was decided on.", + "engine_version": "policyengine-us 2.38.6", + "previous_engine_version": "policyengine-us 2.15.17", + "policyengine_py": "policyengine 6.1.2, provenance only: its certified US bundle is policyengine-us 2.2.1", + "fix_modules": [ + { + "module": "latest_c_ca_hold_2025.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_ca_hold_2025.py", + "sha256": "f19a47b9583032a0602a31e52f995eee824a427a76e87a9d4257d6682a016fa2" + }, + { + "module": "latest_c_irs_sales_tax_2025.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_irs_sales_tax_2025.py", + "sha256": "7f7fd235b29c45d1d5cceded0c3391aceb38740518dfda770e3aebcc3003228e" + }, + { + "module": "latest_c_wi_published_2026.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_wi_published_2026.py", + "sha256": "4edf4c714c05d300e6fa32c4b56879aad8aa0de1d9ddd9a77987eefe3b06acce" + }, + { + "module": "latest_c_id_hold_2025.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_id_hold_2025.py", + "sha256": "39fb99292691600cd273a1c6ef3c90847453e21e4d7b872603bcaac71727f8a5" + }, + { + "module": "latest_c_mn_published_2026.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_mn_published_2026.py", + "sha256": "02a8ccc1fce71485fc9411d4a55f33226de4c8de09cf6375f99866b79da70522" + }, + { + "module": "latest_c_md_2026.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_md_2026.py", + "sha256": "8111c77ffd2e43d434d083994a7e8506ba42461a0845b33ac47ce0df988c2c76" + }, + { + "module": "latest_c_mi_published_2026.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_mi_published_2026.py", + "sha256": "787cf837422e0bdf331a8e01a6fa8e8f2e3b78c35c248a4da83f3b2dbfa9ef9e" + }, + { + "module": "latest_c_mo_published_2026.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_mo_published_2026.py", + "sha256": "0474524c83a7eb0c8440abf06bbeee38d4394e08260464d0dacb195ed3a8d916" + }, + { + "module": "latest_c_snap_hold_fy2026.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_snap_hold_fy2026.py", + "sha256": "3a8709ef36582af2248e460136db618fd319d490b7aeed94adbd6143ad9c07dd" + }, + { + "module": "latest_conventions.py", + "path": "reference_audit/2026-09-28/fixes/latest_conventions.py", + "sha256": "4155ed4a0be72c907815b33e2b3603cf0b5ea3eca351ad7509f8bd9ea5bb8ddb" + }, + { + "module": "latest_md_local_output_scope.py", + "path": "reference_audit/2026-09-28/fixes/latest_md_local_output_scope.py", + "sha256": "53a6de3cd9b149467e5d86a5bb1fcc258e859478a7c16b7d3df951c713e423dd" + }, + { + "module": "latest_final.py", + "path": "reference_audit/2026-09-28/fixes/latest_final.py", + "sha256": "dbbdd228b99933c6f336af97970821c25c863a18606285e8d6d9ffb3bc9af78e" + }, + { + "module": "r19_irs_sales_tax_2025.json", + "path": "reference_audit/2026-09-22/fixes/r19_irs_sales_tax_2025.json", + "sha256": "7cf93799aad6a8c3a6fc70e7df4acc6043202a1ecc083f2c3101f76b87a85eae" + } + ], + "builder": "reference_audit/2026-10-09-engine-upgrade/scripts/build_references_upgrade.py; households from policybench.scenarios.Scenario.to_pe_household through reference_audit/2026-09-28/scripts/sweep.py build_situation, as in the 2026-09-29 upgrade", + "provenance": { + "builder_sha256": "9fd003be76a7a00ae83e5e17bc652dc7cdee3a7c351fb3efb26308d93c0ca6f5", + "harness": "reference_audit/2026-09-28/scripts/sweep.py", + "harness_sha256": "f4c7783453a473a1bedcf64ef554c3a2fc29f9d663626948d920ed3ef2ea2b69", + "actions_sha256": "ef23b50ec389598a231850d0b87c3635c1306bac965e1ee08cf402d7aad9e201", + "release_spec_sha256": "5e7856a42548746bc37760adea1af718050429e0b9c87c4d62755c7d036dab71", + "base_commit": "9ce4ade8382962a9134860c23f56d92509b5e57f", + "policyengine_core": "3.32.29" + }, + "excluded_outputs_untouched": true, + "kept_exclusions_from_release": [ + { + "scenario_id": "scenario_051", + "variable": "state_income_tax_before_refundable_credits" + }, + { + "scenario_id": "scenario_077", + "variable": "state_income_tax_before_refundable_credits" + }, + { + "scenario_id": "scenario_093", + "variable": "federal_income_tax_before_refundable_credits" + }, + { + "scenario_id": "scenario_093", + "variable": "state_income_tax_before_refundable_credits" + }, + { + "scenario_id": "scenario_123", + "variable": "federal_income_tax_before_refundable_credits" + }, + { + "scenario_id": "scenario_123", + "variable": "state_income_tax_before_refundable_credits" + } + ], + "excluded_outputs_rechecked": [ + { + "scenario_id": "scenario_005", + "variable": "federal_income_tax_before_refundable_credits", + "kept_value": 106505.8984375, + "value_on_2_38_6": 108525.578125, + "reason": "Stays excluded on policyengine-us 2.38.6: the engine gives $108,525.58, on the record's corrected value $108,525.58, but the record names a second reason that a new engine does not settle (Corrected value applies r02_ira_219g_v2 with every publication convention and upstream fix. The output also moves under r25_niit_in_federal_output (unlisted input).); the record keeps $106,505.90." + }, + { + "scenario_id": "scenario_007", + "variable": "state_income_tax_before_refundable_credits", + "kept_value": 755.7783203125, + "value_on_2_38_6": 771.5570068359375, + "reason": "Stays excluded on policyengine-us 2.38.6: the engine gives $771.56, $110.24 from the record's corrected value $661.32, so the defect (r07_idaho_health_premiums) is not fixed in this release; the record keeps $755.78." + }, + { + "scenario_id": "scenario_020", + "variable": "federal_income_tax_before_refundable_credits", + "kept_value": 68056.7109375, + "value_on_2_38_6": 68334.734375, + "reason": "Stays excluded on policyengine-us 2.38.6: the reference depends on whether federal income tax before refundable credits includes the net investment income tax, which the output's definition does not say (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $68,056.71, and policyengine-us 2.38.6 gives $68,334.73. The value is 2.15.17's, rechecked on 2026-09-29 (the first engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_023", + "variable": "snap", + "kept_value": 461.3397216796875, + "value_on_2_38_6": 408.0, + "reason": "Stays excluded on policyengine-us 2.38.6: the reference depends on meets_ssi_disability_criteria (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $461.34, and policyengine-us 2.38.6 gives $408.00. The value is 2.15.17's, rechecked on 2026-09-29 (the first engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_042", + "variable": "state_income_tax_before_refundable_credits", + "kept_value": 284.74090576171875, + "value_on_2_38_6": 464.18280029296875, + "reason": "Stays excluded on policyengine-us 2.38.6: the engine gives $464.18, $464.18 from the record's corrected value $0.00, so the defect (r06_wi_act15_before_refundable+r32_wi_capital_gain_distributions) is not fixed in this release; the record keeps $284.74. The value is 2.15.17's, rechecked on 2026-09-29 (the first engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_052", + "variable": "federal_income_tax_before_refundable_credits", + "kept_value": 104211.40625, + "value_on_2_38_6": 104225.2578125, + "reason": "Stays excluded on policyengine-us 2.38.6: the engine gives $104,225.26, on the record's corrected value $104,225.26, but the record names a second reason that a new engine does not settle (Corrected value applies r02_ira_219g_v2 with every publication convention and upstream fix. The output also moves under r25_niit_in_federal_output (unlisted input).); the record keeps $104,211.41." + }, + { + "scenario_id": "scenario_053", + "variable": "state_income_tax_before_refundable_credits", + "kept_value": 2435.2783203125, + "value_on_2_38_6": 2451.05712890625, + "reason": "Stays excluded on policyengine-us 2.38.6: the engine gives $2,451.06, $265.00 from the record's corrected value $2,186.06, so the defect (r07_idaho_health_premiums) is not fixed in this release; the record keeps $2,435.28." + }, + { + "scenario_id": "scenario_056", + "variable": "snap", + "kept_value": 1140.0, + "value_on_2_38_6": 95.0, + "reason": "Stays excluded on policyengine-us 2.38.6: the reference depends on weekly_hours_worked_before_lsr and whether the listed home mortgage interest is on the home the SNAP household occupies (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $1,140.00, and policyengine-us 2.38.6 gives $95.00. The value is 2.15.17's, rechecked on 2026-09-29 (the first engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_057", + "variable": "snap", + "kept_value": 2669.217041015625, + "value_on_2_38_6": 2628.0, + "reason": "Stays excluded on policyengine-us 2.38.6: the reference depends on meets_ssi_disability_criteria (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $2,669.22, and policyengine-us 2.38.6 gives $2,628.00. The value is 2.15.17's, rechecked on 2026-09-29 (the first engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_080", + "variable": "snap", + "kept_value": 3596.039794921875, + "value_on_2_38_6": 3576.0, + "reason": "Stays excluded on policyengine-us 2.38.6: the engine gives $3,576.00, $336.00 from the record's corrected value $3,240.00, so the defect (r30_snap_heat_and_eat_sua) is not fixed in this release; the record keeps $3,596.04. The value is 2.15.17's, rechecked on 2026-09-29 (the first engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_081", + "variable": "state_income_tax_before_refundable_credits", + "kept_value": 8238.40625, + "value_on_2_38_6": 8232.900390625, + "reason": "Stays excluded on policyengine-us 2.38.6: the engine gives $8,232.90, on the record's corrected value $8,232.90, but the record names a second reason that a new engine does not settle (Corrected value applies ma_part_a_loss_offset with every publication convention and upstream fix. The output also moves under r23_ma_interest_source (unlisted input).); the record keeps $8,238.41." + }, + { + "scenario_id": "scenario_091", + "variable": "state_income_tax_before_refundable_credits", + "kept_value": 843.6614990234375, + "value_on_2_38_6": 895.8131103515625, + "reason": "Stays excluded on policyengine-us 2.38.6: the engine gives $895.81, $17.30 from the record's corrected value $878.52, so the defect (r32_wi_capital_gain_distributions) is not fixed in this release; the record keeps $843.66. The value is 2.15.17's, rechecked on 2026-09-29 (the first engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_099", + "variable": "state_income_tax_before_refundable_credits", + "kept_value": 4493.7431640625, + "value_on_2_38_6": 4588.48388671875, + "reason": "Stays excluded on policyengine-us 2.38.6: the engine gives $4,588.48, on the record's audited corrected value, but the reference rests on a further engine defect the new engine does not fix. California does not conform to the federal above-the-line deduction for educator expenses (R&TC 17072; FTB 2025 Instructions for Schedule CA (540), Section C, line 11: 'California law does not conform to federal law regarding educator expenses'), so California AGI adds back the spouse's $337.50 educator expense; policyengine-us sets ca_agi to federal AGI ($159,729.30) without it, and the tax is about $26.90 lower than the law gives. Found by the release's Opus 5.5 judge (reference flag on the re-opened case, 2026-10-10) and confirmed against the FTB instructions; not yet fixed upstream." + }, + { + "scenario_id": "scenario_100", + "variable": "snap", + "kept_value": 8625.8896484375, + "value_on_2_38_6": 8556.0, + "reason": "Stays excluded on policyengine-us 2.38.6: the reference depends on meets_ssi_disability_criteria (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $8,625.89, and policyengine-us 2.38.6 gives $8,556.00. The value is 2.15.17's, rechecked on 2026-09-29 (the first engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_112", + "variable": "snap", + "kept_value": 287.68316650390625, + "value_on_2_38_6": 0.0, + "reason": "Stays excluded on policyengine-us 2.38.6: the reference depends on weekly_hours_worked_before_lsr (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $287.68, and policyengine-us 2.38.6 gives $0.00. The value is 2.15.17's, rechecked on 2026-09-29 (the first engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_118", + "variable": "snap", + "kept_value": 2903.9404296875, + "value_on_2_38_6": 2868.0, + "reason": "Stays excluded on policyengine-us 2.38.6: the reference depends on whether the listed home mortgage interest is on the home the SNAP household occupies (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $2,903.94, and policyengine-us 2.38.6 gives $2,868.00. The value is 2.15.17's, rechecked on 2026-09-29 (the first engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_120", + "variable": "federal_income_tax_before_refundable_credits", + "kept_value": 40021.81640625, + "value_on_2_38_6": 40423.17578125, + "reason": "Stays excluded on policyengine-us 2.38.6: the engine gives $40,423.18, on the record's corrected value $40,423.18, but the record names a second reason that a new engine does not settle (Corrected value applies r02_ira_219g_v2 with every publication convention and upstream fix. The output also moves under r25_niit_in_federal_output (unlisted input). The output also moves under the state income tax withheld reading (unlisted input): the reference's SALT uses the Connecticut withholding estimate ($12,010.05); with the engine's own liability ($11,917.18) the 2.15.17 value is $40,438.95, and with no state income tax paid it is $43,619.93. With r02's IRA fix on 2.15.17 the value is $40,423.18 under the withholding estimate, $40,445.46 under the liability and $43,629.21 with no state income tax paid. policyengine-us 2.15.17 also leaves the household's Connecticut paid leave contributions ($827.98) out of SALT (Rev. Rul. 2025-4); with them the 2.15.17 value is $40,217.95.); the record keeps $40,021.82." + } + ], + "regenerated_exclusions": [ + { + "scenario_id": "scenario_003", + "variable": "federal_income_tax_before_refundable_credits", + "root_cause": "r01_ira_compensation", + "decided_on": "2026-09-22", + "kept_value": 22154.69921875, + "value_on_2_38_6": 22400.654296875, + "audited_alternative_value": 22400.654297, + "target": { + "kind": "record", + "value": 22400.654297, + "engine": "policyengine-us 1.755.4" + }, + "regenerated": 22400.654296875, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10032", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10032) is regenerated with the fix: policyengine-us 2.38.6 gives $22,400.65, within $1 of the corrected value $22,400.65 the 2026-09-22 record computed (r01_ira_compensation: PolicyEngine deducts traditional IRA contributions above the compensation limit and counts a dependent's contributions on the filers' return).", + "record": { + "scenario_id": "scenario_003", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r01_ira_compensation", + "alternative_reading": "A filer deducts traditional IRA contributions only up to their own compensation (wages plus net self-employment earnings), or the couple's combined compensation on a joint return, and a dependent's contributions never reach the parents' return.", + "frozen_value": 22154.69921875, + "alternative_value": 22400.654297, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine deducts traditional IRA contributions above the compensation limit and counts a dependent's contributions on the filers' return", + "law": "26 U.S.C. 219(a), 219(b)(1)(B), 219(c), 219(f)(1); IRS Notice 2025-67", + "upstream": "to be filed", + "note": "Corrected value applies r01_ira_compensation_v2 with every publication convention and upstream fix." + } + }, + { + "scenario_id": "scenario_005", + "variable": "state_income_tax_before_refundable_credits", + "root_cause": "r02_ira_219g+r11_ca_itemized_conformity", + "decided_on": "2026-09-22", + "kept_value": 41051.51171875, + "value_on_2_38_6": 40975.25390625, + "audited_alternative_value": 40920.402344, + "target": { + "kind": "fix_modules", + "value": 40975.25390625, + "engine": "policyengine-us 2.37.2", + "engine_value": 41267.01171875, + "modules": [ + { + "module": "r02_ira_219g_v2.py", + "sha256": "937514fb1199c4ca172dfc5252db7f2483adade193922e6e5283d0b6ab4c4c8c" + }, + { + "module": "r11_ca_itemized_conformity_v2.py", + "sha256": "2bcb8ba6694c053f3c9a8509b96bfee4976ba00e3fb676c0c504e06c2d6c046d" + } + ], + "dependencies": [ + { + "module": "r02_ira_219g.py", + "sha256": "295a0b975ced8964fc1b2c5d52c47bce177eed399f49735eafb88441e7561b84" + } + ], + "evidence": "reference_audit/2026-10-09-engine-upgrade/evidence/pe2.37.2.json", + "evidence_sha256": "4ccc7160b0d8513dedab1fb60ef57bfbd08cb495f445e7ca955141cb6c6c17a6", + "value_with_modules": 40975.25390625 + }, + "regenerated": 40975.25390625, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10032; PolicyEngine/policyengine-us#10034", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10032; PolicyEngine/policyengine-us#10034) is regenerated with the fix: policyengine-us 2.38.6 gives $40,975.25, within $1 of the corrected value $40,975.25 its fix modules (r02_ira_219g_v2.py + r11_ca_itemized_conformity_v2.py) give on policyengine-us 2.37.2, which still has the defect ($41,267.01 without them) (r02_ira_219g+r11_ca_itemized_conformity: PolicyEngine deducts traditional IRA contributions without the active-participant phase-out; PolicyEngine applies the federal charitable deduction floor and the suspension of miscellaneous deductions to California itemized deductions).", + "record": { + "scenario_id": "scenario_005", + "variable": "state_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r02_ira_219g+r11_ca_itemized_conformity", + "alternative_reading": "A filer who defers wages into a 401(k) or 403(b) is an active participant, and above the 2026 phase-out range ($81,000 to $91,000 single or head of household, $129,000 to $149,000 joint) deducts nothing. California itemizers deduct charitable gifts without the federal 0.5%-of-AGI floor and deduct miscellaneous expenses above 2% of AGI.", + "frozen_value": 41051.51171875, + "alternative_value": 40920.402344, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine deducts traditional IRA contributions without the active-participant phase-out; PolicyEngine applies the federal charitable deduction floor and the suspension of miscellaneous deductions to California itemized deductions", + "law": "26 U.S.C. 219(g); IRS Notice 2025-67 (2026 ranges); Cal. R&TC 17024.5 (conformity date), 17076", + "upstream": "to be filed", + "note": "Corrected value applies r02_ira_219g_v2 and r11_ca_itemized_conformity_v2 together with every publication convention and upstream fix." + } + }, + { + "scenario_id": "scenario_008", + "variable": "payroll_tax", + "root_cause": "r05_nj_worker_ui", + "decided_on": "2026-09-22", + "kept_value": 2162.760009765625, + "value_on_2_38_6": 2276.659912109375, + "audited_alternative_value": 2276.659912, + "target": { + "kind": "record", + "value": 2276.659912, + "engine": "policyengine-us 1.755.4" + }, + "regenerated": 2276.659912109375, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10031", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10031) is regenerated with the fix: policyengine-us 2.38.6 gives $2,276.66, within $1 of the corrected value $2,276.66 the 2026-09-22 record computed (r05_nj_worker_ui: PolicyEngine leaves the New Jersey worker unemployment and workforce contributions out of employee payroll tax).", + "record": { + "scenario_id": "scenario_008", + "variable": "payroll_tax", + "reason_code": "reference_engine_defect", + "root_cause": "r05_nj_worker_ui", + "alternative_reading": "New Jersey workers contribute 0.3825% of wages to unemployment insurance and 0.0425% to the workforce funds, up to the 2026 wage base of $44,800, alongside the TDI and FLI contributions.", + "frozen_value": 2162.760009765625, + "alternative_value": 2276.659912, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine leaves the New Jersey worker unemployment and workforce contributions out of employee payroll tax", + "law": "N.J.S.A. 43:21-7(d)(1); NJDOL 2026 contribution rates", + "upstream": "to be filed", + "note": "Corrected value applies r05_nj_worker_ui_v2 with every publication convention and upstream fix." + } + }, + { + "scenario_id": "scenario_018", + "variable": "state_income_tax_before_refundable_credits", + "root_cause": "az_standard_deduction_indexing", + "decided_on": "2026-10-06", + "kept_value": 1146.05224609375, + "value_on_2_38_6": 1137.30224609375, + "audited_alternative_value": 1137.302246, + "target": { + "kind": "record", + "value": 1137.302246, + "engine": "policyengine-us 2.15.17" + }, + "regenerated": 1137.30224609375, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#9928", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#9928) is regenerated with the fix: policyengine-us 2.38.6 gives $1,137.30, within $1 of the corrected value $1,137.30 the 2026-10-06 record computed (az_standard_deduction_indexing: policyengine-us puts the Arizona standard deduction's uprating on the parent parameter node, which policyengine-core does not propagate to the filing-status children, so the 2025 amount ($15,750 single) carries into 2026 unindexed).", + "record": { + "scenario_id": "scenario_018", + "variable": "state_income_tax_before_refundable_credits", + "frozen_value": 1146.05224609375, + "alternative_value": 1137.302246, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-10-06", + "decided_by": "developer", + "decision": "d1022", + "law": "A.R.S. 43-1041(A)(1) and (H), as amended by Laws 2026, Ch. 140 (HB 4168, approved 2026-06-13); 26 U.S.C. 63(c)(7)(B); Rev. Proc. 2025-32 s. 4.14", + "note": "Found 2026-10-05 by the reference adversary (runs/claude/cases/us__scenario_018__state_income_tax_before_refundable_credits) and verified independently on 2026-10-06 (verification/independent/az_018.md). Alternative value: engine counterfactual: policyengine-us 2.15.17 with latest_final and az_standard_deduction = 16,100 (verification/probes/az_standard_deduction_scenario_018.json).", + "reason_code": "reference_engine_defect", + "root_cause": "az_standard_deduction_indexing", + "alternative_reading": "HB 4168 set the single standard deduction at $15,750 'subject to subsection H', and subsection H requires the department to adjust it 'in the same manner in which the federal basic standard deduction is adjusted for inflation pursuant to section 63'. The federal basic standard deduction starts from the same $15,750 and is $16,100 for 2026 (Rev. Proc. 2025-32), so Arizona's 2026 single deduction is $16,100.", + "defect": "policyengine-us puts the Arizona standard deduction's uprating on the parent parameter node, which policyengine-core does not propagate to the filing-status children, so the 2025 amount ($15,750 single) carries into 2026 unindexed", + "upstream": "PolicyEngine/policyengine-us#9928" + } + }, + { + "scenario_id": "scenario_022", + "variable": "state_income_tax_before_refundable_credits", + "root_cause": "r11_ca_itemized_conformity", + "decided_on": "2026-09-22", + "kept_value": 2439.650146484375, + "value_on_2_38_6": 1968.805419921875, + "audited_alternative_value": 1968.80542, + "target": { + "kind": "record", + "value": 1968.80542, + "engine": "policyengine-us 1.755.4" + }, + "regenerated": 1968.805419921875, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10034", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10034) is regenerated with the fix: policyengine-us 2.38.6 gives $1,968.81, within $1 of the corrected value $1,968.81 the 2026-09-22 record computed (r11_ca_itemized_conformity: PolicyEngine applies the federal charitable deduction floor and the suspension of miscellaneous deductions to California itemized deductions).", + "record": { + "scenario_id": "scenario_022", + "variable": "state_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r11_ca_itemized_conformity", + "alternative_reading": "California itemizers deduct charitable gifts without the federal 0.5%-of-AGI floor and deduct miscellaneous expenses above 2% of AGI.", + "frozen_value": 2439.650146484375, + "alternative_value": 1968.80542, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine applies the federal charitable deduction floor and the suspension of miscellaneous deductions to California itemized deductions", + "law": "Cal. R&TC 17024.5 (conformity date), 17076", + "upstream": "to be filed", + "note": "Corrected value applies r11_ca_itemized_conformity_v2 with every publication convention and upstream fix." + } + }, + { + "scenario_id": "scenario_025", + "variable": "state_income_tax_before_refundable_credits", + "root_cause": "oh_medical_deduction_premiums", + "decided_on": "2026-10-06", + "kept_value": 1921.57275390625, + "value_on_2_38_6": 1916.606201171875, + "audited_alternative_value": 1916.604, + "target": { + "kind": "record", + "value": 1916.604, + "engine": "policyengine-us 2.15.17" + }, + "regenerated": 1916.606201171875, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10020; related: PolicyEngine/policyengine-us#9925", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10020; related: PolicyEngine/policyengine-us#9925) is regenerated with the fix: policyengine-us 2.38.6 gives $1,916.61, within $1 of the corrected value $1,916.60 the 2026-10-06 record computed (oh_medical_deduction_premiums: policyengine-us counts health insurance premiums toward Ohio's 7.5%-of-federal-AGI medical deduction only when the person is Medicare-eligible AND has no employer-paid plan, where Ohio's worksheet line 3 reads 'Medicare or an employer-paid health care plan', so a non-Medicare filer with employer coverage gets no premium credit).", + "record": { + "scenario_id": "scenario_025", + "variable": "state_income_tax_before_refundable_credits", + "frozen_value": 1921.57275390625, + "alternative_value": 1916.604, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-10-06", + "decided_by": "developer", + "decision": "d1022", + "law": "R.C. 5747.01(A)(10)(b)-(c) (effective 2026-03-05); 26 U.S.C. 213(d)(1)(D); Ohio IT 1040 instructions, unreimbursed medical and health care expense worksheet line 3", + "note": "Found 2026-10-05 by the reference adversary (runs/claude/cases/us__scenario_025__state_income_tax_before_refundable_credits) and verified independently on 2026-10-06 (verification/independent/oh_025.md). Alternative value: hand computation from the engine's Ohio AGI, exemptions, rate schedule and retirement income credit (verification/independent/oh_025.md section 4).", + "reason_code": "reference_engine_defect", + "root_cause": "oh_medical_deduction_premiums", + "alternative_reading": "R.C. 5747.01(A)(10)(b) deducts unreimbursed medical care above 7.5% of federal AGI, and (A)(10)(c) defines medical care by IRC 213(d), which includes insurance premiums. The head's $6,500 of after-tax non-employer premiums plus $800 of other medical expenses ($7,300) exceed 7.5% of federal AGI ($7,119.40) by $180.60.", + "defect": "policyengine-us counts health insurance premiums toward Ohio's 7.5%-of-federal-AGI medical deduction only when the person is Medicare-eligible AND has no employer-paid plan, where Ohio's worksheet line 3 reads 'Medicare or an employer-paid health care plan', so a non-Medicare filer with employer coverage gets no premium credit", + "upstream": "PolicyEngine/policyengine-us#10020; related: PolicyEngine/policyengine-us#9925" + } + }, + { + "scenario_id": "scenario_039", + "variable": "federal_income_tax_before_refundable_credits", + "root_cause": "r03_estate_income", + "decided_on": "2026-09-22", + "kept_value": 1345.510498046875, + "value_on_2_38_6": 8596.0283203125, + "audited_alternative_value": 8596.02832, + "target": { + "kind": "record", + "value": 8596.02832, + "engine": "policyengine-us 1.755.4" + }, + "regenerated": 8596.0283203125, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10027", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10027) is regenerated with the fix: policyengine-us 2.38.6 gives $8,596.03, within $1 of the corrected value $8,596.03 the 2026-09-22 record computed (r03_estate_income: PolicyEngine leaves estate income out of gross income while counting it as qualified business income).", + "record": { + "scenario_id": "scenario_039", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r03_estate_income", + "alternative_reading": "Income from an interest in an estate is gross income to the beneficiary; the corrected value adds it to AGI and treats it as non-qualified business income, as the prompt's rule that unlisted flags are false implies.", + "frozen_value": 1345.510498046875, + "alternative_value": 8596.02832, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine leaves estate income out of gross income while counting it as qualified business income", + "law": "26 U.S.C. 61(a)(14), 662(a), 199A(c)(3)(A)(ii)", + "upstream": "related: PolicyEngine/policyengine-us#9304", + "note": "Corrected value applies r03_estate_income__qbi_false_v2 with every publication convention and upstream fix." + } + }, + { + "scenario_id": "scenario_039", + "variable": "state_income_tax_before_refundable_credits", + "root_cause": "r03_estate_income", + "decided_on": "2026-09-22", + "kept_value": 514.4984130859375, + "value_on_2_38_6": 1975.7982177734375, + "audited_alternative_value": 1975.798218, + "target": { + "kind": "record", + "value": 1975.798218, + "engine": "policyengine-us 1.755.4" + }, + "regenerated": 1975.7982177734375, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#9633", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#9633) is regenerated with the fix: policyengine-us 2.38.6 gives $1,975.80, within $1 of the corrected value $1,975.80 the 2026-09-22 record computed (r03_estate_income: PolicyEngine leaves estate income out of gross income while counting it as qualified business income).", + "record": { + "scenario_id": "scenario_039", + "variable": "state_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r03_estate_income", + "alternative_reading": "Income from an interest in an estate is gross income to the beneficiary; the corrected value adds it to AGI and treats it as non-qualified business income, as the prompt's rule that unlisted flags are false implies.", + "frozen_value": 514.4984130859375, + "alternative_value": 1975.798218, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine leaves estate income out of gross income while counting it as qualified business income", + "law": "26 U.S.C. 61(a)(14), 662(a), 199A(c)(3)(A)(ii)", + "upstream": "related: PolicyEngine/policyengine-us#9304", + "note": "Corrected value applies r03_estate_income__qbi_false_v2 with every publication convention and upstream fix." + } + }, + { + "scenario_id": "scenario_043", + "variable": "state_refundable_credits", + "root_cause": "co_sales_tax_refund_surplus", + "decided_on": "2026-10-06", + "kept_value": 19.0, + "value_on_2_38_6": 0.0, + "audited_alternative_value": 0.0, + "target": { + "kind": "record", + "value": 0.0, + "engine": "policyengine-us 2.15.17" + }, + "regenerated": 0.0, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#9946", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#9946) is regenerated with the fix: policyengine-us 2.38.6 gives $0.00, within $1 of the corrected value $0.00 the 2026-10-06 record computed (co_sales_tax_refund_surplus: policyengine-us pays Colorado's six-tier state sales tax refund without the statute's condition that the fiscal year ending in the tax year had excess state revenues, carrying the tax year 2025 table into 2026).", + "record": { + "scenario_id": "scenario_043", + "variable": "state_refundable_credits", + "frozen_value": 19.0, + "alternative_value": 0.0, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-10-06", + "decided_by": "developer", + "decision": "d1022", + "law": "C.R.S. 39-22-2003(2), 39-22-2002(2)(a), 39-3-209; Colorado Legislative Council Staff forecasts of December 2025, March 2026 and June 2026 (tax year 2026 refund table $0 in every tier); OSPB forecast of 2026-06-18", + "note": "Found 2026-10-05 by the reference adversary (runs/claude/cases/us__scenario_043__state_refundable_credits) and verified independently on 2026-10-06 (verification/independent/co_043.md). Alternative value: law: no tax year 2026 sales tax refund; the household has no other Colorado refundable credit (verification/independent/co_043.md section 5).", + "reason_code": "reference_engine_defect", + "root_cause": "co_sales_tax_refund_surplus", + "alternative_reading": "C.R.S. 39-22-2003(2) allows the refund for a tax year only 'if there were excess state revenues for the fiscal year ending in that tax year'. Each Legislative Council Staff forecast before the freeze (December 2025, March and June 2026) published a tax year 2026 refund table of $0 in every tier, OSPB's June 2026 outlook put FY 2025-26 $15.3 million below the cap and anticipated no refunds, and no pre-freeze official source described a tax year 2026 six-tier refund; the State Controller certified a $175.9 million shortfall on 2026-09-08.", + "defect": "policyengine-us pays Colorado's six-tier state sales tax refund without the statute's condition that the fiscal year ending in the tax year had excess state revenues, carrying the tax year 2025 table into 2026", + "upstream": "PolicyEngine/policyengine-us#9946" + } + }, + { + "scenario_id": "scenario_049", + "variable": "federal_income_tax_before_refundable_credits", + "root_cause": "r02_ira_219g", + "decided_on": "2026-09-22", + "kept_value": 30543.908203125, + "value_on_2_38_6": 30702.58984375, + "audited_alternative_value": 30702.589844, + "target": { + "kind": "record", + "value": 30702.589844, + "engine": "policyengine-us 1.755.4" + }, + "regenerated": 30702.58984375, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10032", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10032) is regenerated with the fix: policyengine-us 2.38.6 gives $30,702.59, within $1 of the corrected value $30,702.59 the 2026-09-22 record computed (r02_ira_219g: PolicyEngine deducts traditional IRA contributions without the active-participant phase-out).", + "record": { + "scenario_id": "scenario_049", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r02_ira_219g", + "alternative_reading": "A filer who defers wages into a 401(k) or 403(b) is an active participant, and above the 2026 phase-out range ($81,000 to $91,000 single or head of household, $129,000 to $149,000 joint) deducts nothing.", + "frozen_value": 30543.908203125, + "alternative_value": 30702.589844, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine deducts traditional IRA contributions without the active-participant phase-out", + "law": "26 U.S.C. 219(g); IRS Notice 2025-67 (2026 ranges)", + "upstream": "to be filed", + "note": "Corrected value applies r02_ira_219g_v2 with every publication convention and upstream fix." + } + }, + { + "scenario_id": "scenario_064", + "variable": "federal_income_tax_before_refundable_credits", + "root_cause": "r01_ira_compensation", + "decided_on": "2026-09-22", + "kept_value": 4439.28955078125, + "value_on_2_38_6": 4441.455078125, + "audited_alternative_value": 4441.455078, + "target": { + "kind": "record", + "value": 4441.455078, + "engine": "policyengine-us 1.755.4" + }, + "regenerated": 4441.455078125, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#9801", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#9801) is regenerated with the fix: policyengine-us 2.38.6 gives $4,441.46, within $1 of the corrected value $4,441.46 the 2026-09-22 record computed (r01_ira_compensation: PolicyEngine deducts traditional IRA contributions above the compensation limit and counts a dependent's contributions on the filers' return).", + "record": { + "scenario_id": "scenario_064", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r01_ira_compensation", + "alternative_reading": "A filer deducts traditional IRA contributions only up to their own compensation (wages plus net self-employment earnings), or the couple's combined compensation on a joint return, and a dependent's contributions never reach the parents' return.", + "frozen_value": 4439.28955078125, + "alternative_value": 4441.455078, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine deducts traditional IRA contributions above the compensation limit and counts a dependent's contributions on the filers' return", + "law": "26 U.S.C. 219(a), 219(b)(1)(B), 219(c), 219(f)(1); IRS Notice 2025-67", + "upstream": "to be filed", + "note": "Corrected value applies r01_ira_compensation_v2 with every publication convention and upstream fix." + } + }, + { + "scenario_id": "scenario_064", + "variable": "state_income_tax_before_refundable_credits", + "root_cause": "r01_ira_compensation", + "decided_on": "2026-09-22", + "kept_value": 4605.9970703125, + "value_on_2_38_6": 4599.62158203125, + "audited_alternative_value": 4599.621582, + "target": { + "kind": "record", + "value": 4599.621582, + "engine": "policyengine-us 1.755.4" + }, + "regenerated": 4599.62158203125, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#9801", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#9801) is regenerated with the fix: policyengine-us 2.38.6 gives $4,599.62, within $1 of the corrected value $4,599.62 the 2026-09-22 record computed (r01_ira_compensation: PolicyEngine deducts traditional IRA contributions above the compensation limit and counts a dependent's contributions on the filers' return).", + "record": { + "scenario_id": "scenario_064", + "variable": "state_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r01_ira_compensation", + "alternative_reading": "A filer deducts traditional IRA contributions only up to their own compensation (wages plus net self-employment earnings), or the couple's combined compensation on a joint return, and a dependent's contributions never reach the parents' return.", + "frozen_value": 4605.9970703125, + "alternative_value": 4599.621582, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine deducts traditional IRA contributions above the compensation limit and counts a dependent's contributions on the filers' return", + "law": "26 U.S.C. 219(a), 219(b)(1)(B), 219(c), 219(f)(1); IRS Notice 2025-67", + "upstream": "to be filed", + "note": "Corrected value applies r01_ira_compensation_v2 with every publication convention and upstream fix." + } + }, + { + "scenario_id": "scenario_082", + "variable": "federal_income_tax_before_refundable_credits", + "root_cause": "r02_ira_219g", + "decided_on": "2026-09-22", + "kept_value": 9563.052734375, + "value_on_2_38_6": 9579.767578125, + "audited_alternative_value": 9564.916992, + "target": { + "kind": "fix_modules", + "value": 9579.767578125, + "engine": "policyengine-us 2.37.2", + "engine_value": 9577.90234375, + "modules": [ + { + "module": "r02_ira_219g_v2.py", + "sha256": "937514fb1199c4ca172dfc5252db7f2483adade193922e6e5283d0b6ab4c4c8c" + } + ], + "dependencies": [ + { + "module": "r02_ira_219g.py", + "sha256": "295a0b975ced8964fc1b2c5d52c47bce177eed399f49735eafb88441e7561b84" + } + ], + "evidence": "reference_audit/2026-10-09-engine-upgrade/evidence/pe2.37.2.json", + "evidence_sha256": "4ccc7160b0d8513dedab1fb60ef57bfbd08cb495f445e7ca955141cb6c6c17a6", + "value_with_modules": 9579.767578125 + }, + "regenerated": 9579.767578125, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10032", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10032) is regenerated with the fix: policyengine-us 2.38.6 gives $9,579.77, within $1 of the corrected value $9,579.77 its fix modules (r02_ira_219g_v2.py) give on policyengine-us 2.37.2, which still has the defect ($9,577.90 without them) (r02_ira_219g: PolicyEngine deducts traditional IRA contributions without the active-participant phase-out).", + "record": { + "scenario_id": "scenario_082", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r02_ira_219g", + "alternative_reading": "A filer who defers wages into a 401(k) or 403(b) is an active participant, and above the 2026 phase-out range ($81,000 to $91,000 single or head of household, $129,000 to $149,000 joint) deducts nothing.", + "frozen_value": 9563.052734375, + "alternative_value": 9564.916992, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine deducts traditional IRA contributions without the active-participant phase-out", + "law": "26 U.S.C. 219(g); IRS Notice 2025-67 (2026 ranges)", + "upstream": "to be filed", + "note": "Corrected value applies r02_ira_219g_v2 with every publication convention and upstream fix." + } + }, + { + "scenario_id": "scenario_082", + "variable": "state_refundable_credits", + "root_cause": "ny_cdcc_606_c2", + "decided_on": "2026-10-06", + "kept_value": 667.0, + "value_on_2_38_6": 1187.5478515625, + "audited_alternative_value": 1187.611, + "target": { + "kind": "record", + "value": 1187.611, + "engine": "policyengine-us 2.15.17" + }, + "regenerated": 1187.5478515625, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#9948", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#9948) is regenerated with the fix: policyengine-us 2.38.6 gives $1,187.55, within $1 of the corrected value $1,187.61 the 2026-10-06 record computed (ny_cdcc_606_c2: policyengine-us computes New York's 2026 child and dependent care credit with the pre-2026 formula (a percentage of the federal credit), which L.2026 ch. 59 limited to tax years beginning before 2026 and replaced with the refundable 606(c-2) credit on qualifying expenses).", + "record": { + "scenario_id": "scenario_082", + "variable": "state_refundable_credits", + "frozen_value": 667.0, + "alternative_value": 1187.611, + "engine_version": "policyengine-us 2.15.17", + "decided_on": "2026-10-06", + "decided_by": "developer", + "decision": "d1022", + "law": "N.Y. Tax Law 606(c)(1) and 606(c-2), as amended and added by L.2026, ch. 59, Part A (S.9009-C/A.10009-C, signed 2026-05-28)", + "note": "Found 2026-10-05 by the reference adversary (runs/claude/cases/us__scenario_082__state_refundable_credits) and verified independently on 2026-10-06 (verification/independent/ny_082.md). Alternative value: hand computation from the engine's New York AGI and Empire State child credit (verification/independent/ny_082.md section 3).", + "reason_code": "reference_engine_defect", + "root_cause": "ny_cdcc_606_c2", + "alternative_reading": "Tax Law 606(c-2) gives, for tax years beginning on or after 2026-01-01, a refundable credit of the applicable percentage (55%, less 0.00025 percentage points per dollar of New York AGI above $15,000, floor 4%) of qualifying expenses up to $3,000 for one child. At New York AGI of $117,585.15 that is 29.3537% of $3,000 = $880.61, plus the $307 Empire State child credit.", + "defect": "policyengine-us computes New York's 2026 child and dependent care credit with the pre-2026 formula (a percentage of the federal credit), which L.2026 ch. 59 limited to tax years beginning before 2026 and replaced with the refundable 606(c-2) credit on qualifying expenses", + "upstream": "PolicyEngine/policyengine-us#9948" + } + }, + { + "scenario_id": "scenario_099", + "variable": "federal_income_tax_before_refundable_credits", + "root_cause": "r02_ira_219g", + "decided_on": "2026-09-22", + "kept_value": 10679.75, + "value_on_2_38_6": 10711.484375, + "audited_alternative_value": 10711.484375, + "target": { + "kind": "record", + "value": 10711.484375, + "engine": "policyengine-us 1.755.4" + }, + "regenerated": 10711.484375, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10032", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10032) is regenerated with the fix: policyengine-us 2.38.6 gives $10,711.48, within $1 of the corrected value $10,711.48 the 2026-09-22 record computed (r02_ira_219g: PolicyEngine deducts traditional IRA contributions without the active-participant phase-out).", + "record": { + "scenario_id": "scenario_099", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r02_ira_219g", + "alternative_reading": "A filer who defers wages into a 401(k) or 403(b) is an active participant, and above the 2026 phase-out range ($81,000 to $91,000 single or head of household, $129,000 to $149,000 joint) deducts nothing.", + "frozen_value": 10679.75, + "alternative_value": 10711.484375, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine deducts traditional IRA contributions without the active-participant phase-out", + "law": "26 U.S.C. 219(g); IRS Notice 2025-67 (2026 ranges)", + "upstream": "to be filed", + "note": "Corrected value applies r02_ira_219g_v2 with every publication convention and upstream fix." + } + }, + { + "scenario_id": "scenario_110", + "variable": "federal_income_tax_before_refundable_credits", + "root_cause": "r02_ira_219g+r03_estate_income", + "decided_on": "2026-09-22", + "kept_value": 23897.443359375, + "value_on_2_38_6": 25747.7734375, + "audited_alternative_value": 25747.773438, + "target": { + "kind": "record", + "value": 25747.773438, + "engine": "policyengine-us 1.755.4" + }, + "regenerated": 25747.7734375, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10032; PolicyEngine/policyengine-us#10027", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10032; PolicyEngine/policyengine-us#10027) is regenerated with the fix: policyengine-us 2.38.6 gives $25,747.77, within $1 of the corrected value $25,747.77 the 2026-09-22 record computed (r02_ira_219g+r03_estate_income: PolicyEngine deducts traditional IRA contributions without the active-participant phase-out; PolicyEngine leaves estate income out of gross income while counting it as qualified business income).", + "record": { + "scenario_id": "scenario_110", + "variable": "federal_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r02_ira_219g+r03_estate_income", + "alternative_reading": "A filer who defers wages into a 401(k) or 403(b) is an active participant, and above the 2026 phase-out range ($81,000 to $91,000 single or head of household, $129,000 to $149,000 joint) deducts nothing. Income from an interest in an estate is gross income to the beneficiary; the corrected value adds it to AGI and treats it as non-qualified business income, as the prompt's rule that unlisted flags are false implies.", + "frozen_value": 23897.443359375, + "alternative_value": 25747.773438, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine deducts traditional IRA contributions without the active-participant phase-out; PolicyEngine leaves estate income out of gross income while counting it as qualified business income", + "law": "26 U.S.C. 219(g); IRS Notice 2025-67 (2026 ranges); 26 U.S.C. 61(a)(14), 662(a), 199A(c)(3)(A)(ii)", + "upstream": "related: PolicyEngine/policyengine-us#9304", + "note": "Corrected value applies r02_ira_219g_v2 and r03_estate_income__qbi_false_v2 together with every publication convention and upstream fix." + } + }, + { + "scenario_id": "scenario_110", + "variable": "state_income_tax_before_refundable_credits", + "root_cause": "r02_ira_219g+r03_estate_income", + "decided_on": "2026-09-22", + "kept_value": 4057.47216796875, + "value_on_2_38_6": 4236.8076171875, + "audited_alternative_value": 4236.807617, + "target": { + "kind": "record", + "value": 4236.807617, + "engine": "policyengine-us 1.755.4" + }, + "regenerated": 4236.8076171875, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10032; PolicyEngine/policyengine-us#10027", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10032; PolicyEngine/policyengine-us#10027) is regenerated with the fix: policyengine-us 2.38.6 gives $4,236.81, within $1 of the corrected value $4,236.81 the 2026-09-22 record computed (r02_ira_219g+r03_estate_income: PolicyEngine deducts traditional IRA contributions without the active-participant phase-out; PolicyEngine leaves estate income out of gross income while counting it as qualified business income).", + "record": { + "scenario_id": "scenario_110", + "variable": "state_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r02_ira_219g+r03_estate_income", + "alternative_reading": "A filer who defers wages into a 401(k) or 403(b) is an active participant, and above the 2026 phase-out range ($81,000 to $91,000 single or head of household, $129,000 to $149,000 joint) deducts nothing. Income from an interest in an estate is gross income to the beneficiary; the corrected value adds it to AGI and treats it as non-qualified business income, as the prompt's rule that unlisted flags are false implies.", + "frozen_value": 4057.47216796875, + "alternative_value": 4236.807617, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine deducts traditional IRA contributions without the active-participant phase-out; PolicyEngine leaves estate income out of gross income while counting it as qualified business income", + "law": "26 U.S.C. 219(g); IRS Notice 2025-67 (2026 ranges); 26 U.S.C. 61(a)(14), 662(a), 199A(c)(3)(A)(ii)", + "upstream": "related: PolicyEngine/policyengine-us#9304", + "note": "Corrected value applies r02_ira_219g_v2 and r03_estate_income__qbi_false_v2 together with every publication convention and upstream fix." + } + }, + { + "scenario_id": "scenario_120", + "variable": "state_income_tax_before_refundable_credits", + "root_cause": "r02_ira_219g", + "decided_on": "2026-09-22", + "kept_value": 11917.18359375, + "value_on_2_38_6": 11919.0576171875, + "audited_alternative_value": 11919.057617, + "target": { + "kind": "record", + "value": 11919.057617, + "engine": "policyengine-us 1.755.4" + }, + "regenerated": 11919.0576171875, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10032", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10032) is regenerated with the fix: policyengine-us 2.38.6 gives $11,919.06, within $1 of the corrected value $11,919.06 the 2026-09-22 record computed (r02_ira_219g: PolicyEngine deducts traditional IRA contributions without the active-participant phase-out).", + "record": { + "scenario_id": "scenario_120", + "variable": "state_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r02_ira_219g", + "alternative_reading": "A filer who defers wages into a 401(k) or 403(b) is an active participant, and above the 2026 phase-out range ($81,000 to $91,000 single or head of household, $129,000 to $149,000 joint) deducts nothing.", + "frozen_value": 11917.18359375, + "alternative_value": 11919.057617, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine deducts traditional IRA contributions without the active-participant phase-out", + "law": "26 U.S.C. 219(g); IRS Notice 2025-67 (2026 ranges)", + "upstream": "to be filed", + "note": "Corrected value applies r02_ira_219g_v2 with every publication convention and upstream fix." + } + } + ], + "new_exclusions": [ + { + "scenario_id": "scenario_015", + "variable": "local_income_tax", + "reason_code": "reference_depends_on_unlisted_input", + "frozen_value": 670.5501098632812, + "alternative_value": 0.0, + "decided_on": "2026-10-10" + }, + { + "scenario_id": "scenario_067", + "variable": "local_income_tax", + "reason_code": "reference_depends_on_unlisted_input", + "frozen_value": 1348.83203125, + "alternative_value": 0.0, + "decided_on": "2026-10-10" + } + ], + "changed": [ + { + "scenario_id": "scenario_003", + "variable": "federal_income_tax_before_refundable_credits", + "frozen": 22154.69921875, + "previous": 22154.69921875, + "regenerated": 22400.654296875, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10032) is regenerated with the fix: policyengine-us 2.38.6 gives $22,400.65, within $1 of the corrected value $22,400.65 the 2026-09-22 record computed (r01_ira_compensation: PolicyEngine deducts traditional IRA contributions above the compensation limit and counts a dependent's contributions on the filers' return)." + }, + { + "scenario_id": "scenario_005", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 41051.51171875, + "previous": 41051.51171875, + "regenerated": 40975.25390625, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10032; PolicyEngine/policyengine-us#10034) is regenerated with the fix: policyengine-us 2.38.6 gives $40,975.25, within $1 of the corrected value $40,975.25 its fix modules (r02_ira_219g_v2.py + r11_ca_itemized_conformity_v2.py) give on policyengine-us 2.37.2, which still has the defect ($41,267.01 without them) (r02_ira_219g+r11_ca_itemized_conformity: PolicyEngine deducts traditional IRA contributions without the active-participant phase-out; PolicyEngine applies the federal charitable deduction floor and the suspension of miscellaneous deductions to California itemized deductions)." + }, + { + "scenario_id": "scenario_008", + "variable": "payroll_tax", + "frozen": 2162.760009765625, + "previous": 2162.760009765625, + "regenerated": 2276.659912109375, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10031) is regenerated with the fix: policyengine-us 2.38.6 gives $2,276.66, within $1 of the corrected value $2,276.66 the 2026-09-22 record computed (r05_nj_worker_ui: PolicyEngine leaves the New Jersey worker unemployment and workforce contributions out of employee payroll tax)." + }, + { + "scenario_id": "scenario_015", + "variable": "local_income_tax", + "frozen": 0.0, + "previous": 0.0, + "regenerated": 670.5501098632812, + "cause": "excluded_reference_depends_on_unlisted_input", + "basis": "Newly excluded from scoring on 2026-10-10 (reference_exclusions.json): county of residence (Indiana county income tax)" + }, + { + "scenario_id": "scenario_018", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 1146.05224609375, + "previous": 1146.05224609375, + "regenerated": 1137.30224609375, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#9928) is regenerated with the fix: policyengine-us 2.38.6 gives $1,137.30, within $1 of the corrected value $1,137.30 the 2026-10-06 record computed (az_standard_deduction_indexing: policyengine-us puts the Arizona standard deduction's uprating on the parent parameter node, which policyengine-core does not propagate to the filing-status children, so the 2025 amount ($15,750 single) carries into 2026 unindexed)." + }, + { + "scenario_id": "scenario_022", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 2439.650146484375, + "previous": 2439.650146484375, + "regenerated": 1968.805419921875, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10034) is regenerated with the fix: policyengine-us 2.38.6 gives $1,968.81, within $1 of the corrected value $1,968.81 the 2026-09-22 record computed (r11_ca_itemized_conformity: PolicyEngine applies the federal charitable deduction floor and the suspension of miscellaneous deductions to California itemized deductions)." + }, + { + "scenario_id": "scenario_025", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 1921.57275390625, + "previous": 1921.57275390625, + "regenerated": 1916.606201171875, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10020; related: PolicyEngine/policyengine-us#9925) is regenerated with the fix: policyengine-us 2.38.6 gives $1,916.61, within $1 of the corrected value $1,916.60 the 2026-10-06 record computed (oh_medical_deduction_premiums: policyengine-us counts health insurance premiums toward Ohio's 7.5%-of-federal-AGI medical deduction only when the person is Medicare-eligible AND has no employer-paid plan, where Ohio's worksheet line 3 reads 'Medicare or an employer-paid health care plan', so a non-Medicare filer with employer coverage gets no premium credit)." + }, + { + "scenario_id": "scenario_039", + "variable": "federal_income_tax_before_refundable_credits", + "frozen": 1345.510498046875, + "previous": 1345.510498046875, + "regenerated": 8596.0283203125, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10027) is regenerated with the fix: policyengine-us 2.38.6 gives $8,596.03, within $1 of the corrected value $8,596.03 the 2026-09-22 record computed (r03_estate_income: PolicyEngine leaves estate income out of gross income while counting it as qualified business income)." + }, + { + "scenario_id": "scenario_039", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 514.4984130859375, + "previous": 514.4984130859375, + "regenerated": 1975.7982177734375, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#9633) is regenerated with the fix: policyengine-us 2.38.6 gives $1,975.80, within $1 of the corrected value $1,975.80 the 2026-09-22 record computed (r03_estate_income: PolicyEngine leaves estate income out of gross income while counting it as qualified business income)." + }, + { + "scenario_id": "scenario_043", + "variable": "state_refundable_credits", + "frozen": 19.0, + "previous": 19.0, + "regenerated": 0.0, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#9946) is regenerated with the fix: policyengine-us 2.38.6 gives $0.00, within $1 of the corrected value $0.00 the 2026-10-06 record computed (co_sales_tax_refund_surplus: policyengine-us pays Colorado's six-tier state sales tax refund without the statute's condition that the fiscal year ending in the tax year had excess state revenues, carrying the tax year 2025 table into 2026)." + }, + { + "scenario_id": "scenario_049", + "variable": "federal_income_tax_before_refundable_credits", + "frozen": 30543.908203125, + "previous": 30543.908203125, + "regenerated": 30702.58984375, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10032) is regenerated with the fix: policyengine-us 2.38.6 gives $30,702.59, within $1 of the corrected value $30,702.59 the 2026-09-22 record computed (r02_ira_219g: PolicyEngine deducts traditional IRA contributions without the active-participant phase-out)." + }, + { + "scenario_id": "scenario_064", + "variable": "federal_income_tax_before_refundable_credits", + "frozen": 4439.28955078125, + "previous": 4439.28955078125, + "regenerated": 4441.455078125, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#9801) is regenerated with the fix: policyengine-us 2.38.6 gives $4,441.46, within $1 of the corrected value $4,441.46 the 2026-09-22 record computed (r01_ira_compensation: PolicyEngine deducts traditional IRA contributions above the compensation limit and counts a dependent's contributions on the filers' return)." + }, + { + "scenario_id": "scenario_064", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 4605.9970703125, + "previous": 4605.9970703125, + "regenerated": 4599.62158203125, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#9801) is regenerated with the fix: policyengine-us 2.38.6 gives $4,599.62, within $1 of the corrected value $4,599.62 the 2026-09-22 record computed (r01_ira_compensation: PolicyEngine deducts traditional IRA contributions above the compensation limit and counts a dependent's contributions on the filers' return)." + }, + { + "scenario_id": "scenario_067", + "variable": "local_income_tax", + "frozen": 0.0, + "previous": 0.0, + "regenerated": 1348.83203125, + "cause": "excluded_reference_depends_on_unlisted_input", + "basis": "Newly excluded from scoring on 2026-10-10 (reference_exclusions.json): county of residence (Indiana county income tax)" + }, + { + "scenario_id": "scenario_076", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 6806.78662109375, + "previous": 6818.34423828125, + "regenerated": 6828.34423828125, + "cause": "id_permanent_building_fund_tax", + "basis": "Idaho's $10 permanent building fund tax counts in state income tax: on policyengine-us 2.38.6, state_income_tax_before_refundable_credits adds id_pbf ($10 for a filer liable for it, id_pbf_liable; Idaho Form 40 instructions) to Idaho income tax before refundable credits, since policyengine-us 2.30.0 (PolicyEngine/policyengine-us#9810)." + }, + { + "scenario_id": "scenario_082", + "variable": "federal_income_tax_before_refundable_credits", + "frozen": 9563.052734375, + "previous": 9563.052734375, + "regenerated": 9579.767578125, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10032) is regenerated with the fix: policyengine-us 2.38.6 gives $9,579.77, within $1 of the corrected value $9,579.77 its fix modules (r02_ira_219g_v2.py) give on policyengine-us 2.37.2, which still has the defect ($9,577.90 without them) (r02_ira_219g: PolicyEngine deducts traditional IRA contributions without the active-participant phase-out)." + }, + { + "scenario_id": "scenario_082", + "variable": "state_refundable_credits", + "frozen": 650.5, + "previous": 667.0, + "regenerated": 1187.5478515625, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#9948) is regenerated with the fix: policyengine-us 2.38.6 gives $1,187.55, within $1 of the corrected value $1,187.61 the 2026-10-06 record computed (ny_cdcc_606_c2: policyengine-us computes New York's 2026 child and dependent care credit with the pre-2026 formula (a percentage of the federal credit), which L.2026 ch. 59 limited to tax years beginning before 2026 and replaced with the refundable 606(c-2) credit on qualifying expenses)." + }, + { + "scenario_id": "scenario_099", + "variable": "federal_income_tax_before_refundable_credits", + "frozen": 10679.75, + "previous": 10679.75, + "regenerated": 10711.484375, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10032) is regenerated with the fix: policyengine-us 2.38.6 gives $10,711.48, within $1 of the corrected value $10,711.48 the 2026-09-22 record computed (r02_ira_219g: PolicyEngine deducts traditional IRA contributions without the active-participant phase-out)." + }, + { + "scenario_id": "scenario_110", + "variable": "federal_income_tax_before_refundable_credits", + "frozen": 23897.443359375, + "previous": 23897.443359375, + "regenerated": 25747.7734375, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10032; PolicyEngine/policyengine-us#10027) is regenerated with the fix: policyengine-us 2.38.6 gives $25,747.77, within $1 of the corrected value $25,747.77 the 2026-09-22 record computed (r02_ira_219g+r03_estate_income: PolicyEngine deducts traditional IRA contributions without the active-participant phase-out; PolicyEngine leaves estate income out of gross income while counting it as qualified business income)." + }, + { + "scenario_id": "scenario_110", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 4057.47216796875, + "previous": 4057.47216796875, + "regenerated": 4236.8076171875, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10032; PolicyEngine/policyengine-us#10027) is regenerated with the fix: policyengine-us 2.38.6 gives $4,236.81, within $1 of the corrected value $4,236.81 the 2026-09-22 record computed (r02_ira_219g+r03_estate_income: PolicyEngine deducts traditional IRA contributions without the active-participant phase-out; PolicyEngine leaves estate income out of gross income while counting it as qualified business income)." + }, + { + "scenario_id": "scenario_120", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 11917.18359375, + "previous": 11917.18359375, + "regenerated": 11919.0576171875, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10032) is regenerated with the fix: policyengine-us 2.38.6 gives $11,919.06, within $1 of the corrected value $11,919.06 the 2026-09-22 record computed (r02_ira_219g: PolicyEngine deducts traditional IRA contributions without the active-participant phase-out)." + }, + { + "scenario_id": "scenario_082", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 5598.55224609375, + "previous": 5598.55224609375, + "regenerated": 5599.1435546875, + "cause": "engine_upgrade_within_1", + "basis": "Moves by $1 or less on policyengine-us 2.38.6; no score changes at the exact-match tolerance." + }, + { + "scenario_id": "scenario_085", + "variable": "federal_income_tax_before_refundable_credits", + "frozen": 2322.760009765625, + "previous": 2322.760009765625, + "regenerated": 2322.8486328125, + "cause": "engine_upgrade_within_1", + "basis": "Moves by $1 or less on policyengine-us 2.38.6; no score changes at the exact-match tolerance." + } + ] + }, + { + "date": "2026-10-13", + "kind": "engine_upgrade", + "root_cause": "engine_upgrade_policyengine_us_2_41_0", + "outputs": "every scored output", + "rule": "A scored reference follows from the stated facts and from law published before the 2026-07-03 reference freeze. References come from the newest policyengine-us release when PolicyBench begins the reference sweep; at publication PolicyBench checks that the newest release gives the same values. Max, 2026-10-09, on waiting for the release that fixes the engine defects behind PolicyBench's exclusions: 'yes i want to wait for hte fixed engine'; and 2026-10-12, of the fixes release 20261010 left excluded: 'If any have shipped, regenerate their cells instead of excluding them.' An excluded output whose engine defect the new release fixes, landing on its audited corrected value, is regenerated and its exclusion record removed; every other excluded output keeps the value it was decided on.", + "engine_version": "policyengine-us 2.41.0", + "previous_engine_version": "policyengine-us 2.38.6", + "policyengine_py": "policyengine 6.1.2, provenance only: its certified US bundle is policyengine-us 2.2.1", + "fix_modules": [ + { + "module": "latest_c_ca_hold_2025.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_ca_hold_2025.py", + "sha256": "f19a47b9583032a0602a31e52f995eee824a427a76e87a9d4257d6682a016fa2" + }, + { + "module": "latest_c_irs_sales_tax_2025.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_irs_sales_tax_2025.py", + "sha256": "7f7fd235b29c45d1d5cceded0c3391aceb38740518dfda770e3aebcc3003228e" + }, + { + "module": "latest_c_wi_published_2026.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_wi_published_2026.py", + "sha256": "4edf4c714c05d300e6fa32c4b56879aad8aa0de1d9ddd9a77987eefe3b06acce" + }, + { + "module": "latest_c_id_hold_2025.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_id_hold_2025.py", + "sha256": "39fb99292691600cd273a1c6ef3c90847453e21e4d7b872603bcaac71727f8a5" + }, + { + "module": "latest_c_mn_published_2026.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_mn_published_2026.py", + "sha256": "02a8ccc1fce71485fc9411d4a55f33226de4c8de09cf6375f99866b79da70522" + }, + { + "module": "latest_c_md_2026.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_md_2026.py", + "sha256": "8111c77ffd2e43d434d083994a7e8506ba42461a0845b33ac47ce0df988c2c76" + }, + { + "module": "latest_c_mi_published_2026.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_mi_published_2026.py", + "sha256": "787cf837422e0bdf331a8e01a6fa8e8f2e3b78c35c248a4da83f3b2dbfa9ef9e" + }, + { + "module": "latest_c_mo_published_2026.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_mo_published_2026.py", + "sha256": "0474524c83a7eb0c8440abf06bbeee38d4394e08260464d0dacb195ed3a8d916" + }, + { + "module": "latest_c_snap_hold_fy2026.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_snap_hold_fy2026.py", + "sha256": "3a8709ef36582af2248e460136db618fd319d490b7aeed94adbd6143ad9c07dd" + }, + { + "module": "latest_conventions.py", + "path": "reference_audit/2026-09-28/fixes/latest_conventions.py", + "sha256": "4155ed4a0be72c907815b33e2b3603cf0b5ea3eca351ad7509f8bd9ea5bb8ddb" + }, + { + "module": "latest_md_local_output_scope.py", + "path": "reference_audit/2026-09-28/fixes/latest_md_local_output_scope.py", + "sha256": "53a6de3cd9b149467e5d86a5bb1fcc258e859478a7c16b7d3df951c713e423dd" + }, + { + "module": "latest_final.py", + "path": "reference_audit/2026-09-28/fixes/latest_final.py", + "sha256": "dbbdd228b99933c6f336af97970821c25c863a18606285e8d6d9ffb3bc9af78e" + }, + { + "module": "r19_irs_sales_tax_2025.json", + "path": "reference_audit/2026-09-22/fixes/r19_irs_sales_tax_2025.json", + "sha256": "7cf93799aad6a8c3a6fc70e7df4acc6043202a1ecc083f2c3101f76b87a85eae" + } + ], + "builder": "reference_audit/2026-10-12-engine-upgrade/scripts/build_references_upgrade.py; households from policybench.scenarios.Scenario.to_pe_household through reference_audit/2026-09-28/scripts/sweep.py build_situation, as in the 2026-09-29 upgrade", + "provenance": { + "builder_sha256": "106359647da224dae243c6365b78fa324102f832e830cbc2d1b82a1ba1e7cf29", + "harness": "reference_audit/2026-09-28/scripts/sweep.py", + "harness_sha256": "f4c7783453a473a1bedcf64ef554c3a2fc29f9d663626948d920ed3ef2ea2b69", + "actions_sha256": "cfe9f33544b08f962be62ba8601518c82d072bdbada0b2962351a01f8ae04a42", + "release_spec_sha256": "ea4c63192bcd072dd12ce15e9cfd9cde5d2f9e548160149b19e78cee62c7c347", + "base_commit": "5a8164a001efb27fa55f47fe7ea26666a0de31f8", + "policyengine_core": "3.32.29" + }, + "excluded_outputs_untouched": true, + "kept_exclusions_from_release": [], + "excluded_outputs_rechecked": [ + { + "scenario_id": "scenario_005", + "variable": "federal_income_tax_before_refundable_credits", + "kept_value": 106505.8984375, + "value_on_2_41_0": 108525.578125, + "reason": "Stays excluded on policyengine-us 2.41.0: the engine gives $108,525.58, the value policyengine-us 2.38.6 gave when release 20261010's recheck found it on its corrected value, but the record names a second reason that a new engine does not settle (Corrected value applies r02_ira_219g_v2 with every publication convention and upstream fix. The output also moves under r25_niit_in_federal_output (unlisted input).); the record keeps $106,505.90. The value is 2.38.6's, rechecked on 2026-10-10 (release 20261010's engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_020", + "variable": "federal_income_tax_before_refundable_credits", + "kept_value": 68056.7109375, + "value_on_2_41_0": 68334.734375, + "reason": "Stays excluded on policyengine-us 2.41.0: the reference depends on whether federal income tax before refundable credits includes the net investment income tax, which the output's definition does not say (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $68,056.71, and policyengine-us 2.41.0 gives $68,334.73. The value is 2.38.6's, rechecked on 2026-10-10 (release 20261010's engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_023", + "variable": "snap", + "kept_value": 461.3397216796875, + "value_on_2_41_0": 408.0, + "reason": "Stays excluded on policyengine-us 2.41.0: the reference depends on meets_ssi_disability_criteria (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $461.34, and policyengine-us 2.41.0 gives $408.00. The value is 2.38.6's, rechecked on 2026-10-10 (release 20261010's engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_052", + "variable": "federal_income_tax_before_refundable_credits", + "kept_value": 104211.40625, + "value_on_2_41_0": 104225.2578125, + "reason": "Stays excluded on policyengine-us 2.41.0: the engine gives $104,225.26, on the record's corrected value $104,225.26, but the record names a second reason that a new engine does not settle (Corrected value applies r02_ira_219g_v2 with every publication convention and upstream fix. The output also moves under r25_niit_in_federal_output (unlisted input).); the record keeps $104,211.41." + }, + { + "scenario_id": "scenario_056", + "variable": "snap", + "kept_value": 1140.0, + "value_on_2_41_0": 95.0, + "reason": "Stays excluded on policyengine-us 2.41.0: the reference depends on weekly_hours_worked_before_lsr and whether the listed home mortgage interest is on the home the SNAP household occupies (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $1,140.00, and policyengine-us 2.41.0 gives $95.00. The value is 2.38.6's, rechecked on 2026-10-10 (release 20261010's engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_057", + "variable": "snap", + "kept_value": 2669.217041015625, + "value_on_2_41_0": 2628.0, + "reason": "Stays excluded on policyengine-us 2.41.0: the reference depends on meets_ssi_disability_criteria (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $2,669.22, and policyengine-us 2.41.0 gives $2,628.00. The value is 2.38.6's, rechecked on 2026-10-10 (release 20261010's engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_080", + "variable": "snap", + "kept_value": 3596.039794921875, + "value_on_2_41_0": 3240.0, + "reason": "Stays excluded on policyengine-us 2.41.0: the engine gives $3,240.00, on the record's corrected value $3,240.00, so its defect (r30_snap_heat_and_eat_sua) is fixed there (PolicyEngine/policyengine-us#10033), but the 2026-09-29 recheck found the output indeterminate on the stated facts, a second reason that a new engine does not settle: the prompt calls the head disabled but states no route by which 7 U.S.C. 2012(j) makes a member disabled (the allowance would stand, at $3,576, were the head one), and it does not say whether the $2,000 energy subsidy is a LIHEAP payment or a State-law payment, which 7 U.S.C. 2014(k)(4) treats differently. The record keeps $3,596.04." + }, + { + "scenario_id": "scenario_081", + "variable": "state_income_tax_before_refundable_credits", + "kept_value": 8238.40625, + "value_on_2_41_0": 8232.900390625, + "reason": "Stays excluded on policyengine-us 2.41.0: the engine gives $8,232.90, on the record's corrected value $8,232.90, but the record names a second reason that a new engine does not settle (Corrected value applies ma_part_a_loss_offset with every publication convention and upstream fix. The output also moves under r23_ma_interest_source (unlisted input).); the record keeps $8,238.41." + }, + { + "scenario_id": "scenario_100", + "variable": "snap", + "kept_value": 8625.8896484375, + "value_on_2_41_0": 6924.0, + "reason": "Stays excluded on policyengine-us 2.41.0: the reference depends on meets_ssi_disability_criteria (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $8,625.89, and policyengine-us 2.41.0 gives $6,924.00." + }, + { + "scenario_id": "scenario_112", + "variable": "snap", + "kept_value": 287.68316650390625, + "value_on_2_41_0": 0.0, + "reason": "Stays excluded on policyengine-us 2.41.0: the reference depends on weekly_hours_worked_before_lsr (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $287.68, and policyengine-us 2.41.0 gives $0.00. The value is 2.38.6's, rechecked on 2026-10-10 (release 20261010's engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_118", + "variable": "snap", + "kept_value": 2903.9404296875, + "value_on_2_41_0": 2868.0, + "reason": "Stays excluded on policyengine-us 2.41.0: the reference depends on whether the listed home mortgage interest is on the home the SNAP household occupies (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $2,903.94, and policyengine-us 2.41.0 gives $2,868.00. The value is 2.38.6's, rechecked on 2026-10-10 (release 20261010's engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_120", + "variable": "federal_income_tax_before_refundable_credits", + "kept_value": 40021.81640625, + "value_on_2_41_0": 40423.17578125, + "reason": "Stays excluded on policyengine-us 2.41.0: the engine gives $40,423.18, the value policyengine-us 2.38.6 gave when release 20261010's recheck found it on its corrected value, but the record names a second reason that a new engine does not settle (Corrected value applies r02_ira_219g_v2 with every publication convention and upstream fix. The output also moves under r25_niit_in_federal_output (unlisted input). The output also moves under the state income tax withheld reading (unlisted input): the reference's SALT uses the Connecticut withholding estimate ($12,010.05); with the engine's own liability ($11,917.18) the 2.15.17 value is $40,438.95, and with no state income tax paid it is $43,619.93. With r02's IRA fix on 2.15.17 the value is $40,423.18 under the withholding estimate, $40,445.46 under the liability and $43,629.21 with no state income tax paid. policyengine-us 2.15.17 also leaves the household's Connecticut paid leave contributions ($827.98) out of SALT (Rev. Rul. 2025-4); with them the 2.15.17 value is $40,217.95.); the record keeps $40,021.82. The value is 2.38.6's, rechecked on 2026-10-10 (release 20261010's engine_upgrade revision's excluded_outputs_rechecked)." + } + ], + "regenerated_exclusions": [ + { + "scenario_id": "scenario_007", + "variable": "state_income_tax_before_refundable_credits", + "root_cause": "r07_idaho_health_premiums", + "decided_on": "2026-09-22", + "kept_value": 755.7783203125, + "value_on_2_41_0": 661.3170166015625, + "audited_alternative_value": 651.317017, + "target": { + "kind": "fix_modules", + "value": 661.3170166015625, + "engine": "policyengine-us 2.38.6", + "engine_value": 771.5570068359375, + "modules": [ + { + "module": "r07_idaho_health_premiums_v2.py", + "sha256": "af9b7cc6dbd25b1e60b547cc1bee167527dbf7faee4dc88512c4c28416808222" + } + ], + "dependencies": [], + "evidence": "reference_audit/2026-10-12-engine-upgrade/evidence/pe2.38.6.json", + "evidence_sha256": "a0b47622f8edb95162970f9f237f64bccf2e8b438de3ebfe9186f9b111bd3df4", + "value_with_modules": 661.3170166015625 + }, + "regenerated": 661.3170166015625, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10023", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10023) is regenerated with the fix: policyengine-us 2.41.0 gives $661.32, within $1 of the corrected value $661.32 its fix modules (r07_idaho_health_premiums_v2.py) give on policyengine-us 2.38.6, which still has the defect ($771.56 without them) (r07_idaho_health_premiums: PolicyEngine omits Idaho's subtraction for health insurance premiums the taxpayer pays).", + "record": { + "scenario_id": "scenario_007", + "variable": "state_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r07_idaho_health_premiums", + "alternative_reading": "Idaho subtracts health insurance premiums the taxpayer pays that are not otherwise deducted or excluded.", + "frozen_value": 755.7783203125, + "alternative_value": 651.317017, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine omits Idaho's subtraction for health insurance premiums the taxpayer pays", + "law": "Idaho Code 63-3022P; Idaho Form 39R", + "upstream": "to be filed", + "note": "Corrected value applies r07_idaho_health_premiums_v2 with every publication convention and upstream fix." + } + }, + { + "scenario_id": "scenario_042", + "variable": "state_income_tax_before_refundable_credits", + "root_cause": "r06_wi_act15_before_refundable+r32_wi_capital_gain_distributions", + "decided_on": "2026-09-22", + "kept_value": 284.74090576171875, + "value_on_2_41_0": 0.0, + "audited_alternative_value": 0.0, + "target": { + "kind": "record", + "value": 0.0, + "engine": "policyengine-us 1.755.4" + }, + "regenerated": 0.0, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10026", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10026) is regenerated with the fix: policyengine-us 2.41.0 gives $0.00, within $1 of the corrected value $0.00 the 2026-09-22 record computed (r06_wi_act15_before_refundable+r32_wi_capital_gain_distributions: PolicyEngine's Wisconsin tax before refundable credits ignores the retirement income exclusion the filer elects, which its final Wisconsin tax applies; PolicyEngine's Wisconsin capital gain subtraction leaves out capital gain distributions reported without Schedule D, so once they reach federal AGI Wisconsin taxes all of them instead of 70%).", + "record": { + "scenario_id": "scenario_042", + "variable": "state_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r06_wi_act15_before_refundable+r32_wi_capital_gain_distributions", + "alternative_reading": "A filer aged 67 or older who elects the retirement income exclusion computes Wisconsin tax on the reduced income and forfeits the credits, so the tax before refundable credits follows the elected path. Wisconsin subtracts 30% of net long-term capital gain, and a capital gain distribution reported without Schedule D is long-term capital gain.", + "frozen_value": 284.74090576171875, + "alternative_value": 0.0, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine's Wisconsin tax before refundable credits ignores the retirement income exclusion the filer elects, which its final Wisconsin tax applies; PolicyEngine's Wisconsin capital gain subtraction leaves out capital gain distributions reported without Schedule D, so once they reach federal AGI Wisconsin taxes all of them instead of 70%", + "law": "Wis. Stat. 71.05(6)(b)54m (2025 Wisconsin Act 15); 2025 Schedule SB line 16; Wis. Stat. 71.05(6)(b)9; 26 U.S.C. 852(b)(3)(B); 2025 Wisconsin Schedule SB instructions, line 5", + "upstream": "to be filed", + "note": "Corrected value applies r06_wi_act15_before_refundable_v2 and r32_wi_capital_gain_distributions together with every publication convention and upstream fix. The output also moves under r04_capital_gain_distributions (engine defect, fixed upstream)." + } + }, + { + "scenario_id": "scenario_053", + "variable": "state_income_tax_before_refundable_credits", + "root_cause": "r07_idaho_health_premiums", + "decided_on": "2026-09-22", + "kept_value": 2435.2783203125, + "value_on_2_41_0": 2186.05712890625, + "audited_alternative_value": 2176.057129, + "target": { + "kind": "fix_modules", + "value": 2186.05712890625, + "engine": "policyengine-us 2.38.6", + "engine_value": 2451.05712890625, + "modules": [ + { + "module": "r07_idaho_health_premiums_v2.py", + "sha256": "af9b7cc6dbd25b1e60b547cc1bee167527dbf7faee4dc88512c4c28416808222" + } + ], + "dependencies": [], + "evidence": "reference_audit/2026-10-12-engine-upgrade/evidence/pe2.38.6.json", + "evidence_sha256": "a0b47622f8edb95162970f9f237f64bccf2e8b438de3ebfe9186f9b111bd3df4", + "value_with_modules": 2186.05712890625 + }, + "regenerated": 2186.05712890625, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10023", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10023) is regenerated with the fix: policyengine-us 2.41.0 gives $2,186.06, within $1 of the corrected value $2,186.06 its fix modules (r07_idaho_health_premiums_v2.py) give on policyengine-us 2.38.6, which still has the defect ($2,451.06 without them) (r07_idaho_health_premiums: PolicyEngine omits Idaho's subtraction for health insurance premiums the taxpayer pays).", + "record": { + "scenario_id": "scenario_053", + "variable": "state_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r07_idaho_health_premiums", + "alternative_reading": "Idaho subtracts health insurance premiums the taxpayer pays that are not otherwise deducted or excluded.", + "frozen_value": 2435.2783203125, + "alternative_value": 2176.057129, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine omits Idaho's subtraction for health insurance premiums the taxpayer pays", + "law": "Idaho Code 63-3022P; Idaho Form 39R", + "upstream": "to be filed", + "note": "Corrected value applies r07_idaho_health_premiums_v2 with every publication convention and upstream fix." + } + }, + { + "scenario_id": "scenario_091", + "variable": "state_income_tax_before_refundable_credits", + "root_cause": "r32_wi_capital_gain_distributions", + "decided_on": "2026-09-22", + "kept_value": 843.6614990234375, + "value_on_2_41_0": 878.5157470703125, + "audited_alternative_value": 878.515747, + "target": { + "kind": "record", + "value": 878.515747, + "engine": "policyengine-us 1.755.4" + }, + "regenerated": 878.5157470703125, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10026", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10026) is regenerated with the fix: policyengine-us 2.41.0 gives $878.52, within $1 of the corrected value $878.52 the 2026-09-22 record computed (r32_wi_capital_gain_distributions: PolicyEngine's Wisconsin capital gain subtraction leaves out capital gain distributions reported without Schedule D, so once they reach federal AGI Wisconsin taxes all of them instead of 70%).", + "record": { + "scenario_id": "scenario_091", + "variable": "state_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r32_wi_capital_gain_distributions", + "alternative_reading": "Wisconsin subtracts 30% of net long-term capital gain, and a capital gain distribution reported without Schedule D is long-term capital gain.", + "frozen_value": 843.6614990234375, + "alternative_value": 878.515747, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine's Wisconsin capital gain subtraction leaves out capital gain distributions reported without Schedule D, so once they reach federal AGI Wisconsin taxes all of them instead of 70%", + "law": "Wis. Stat. 71.05(6)(b)9; 26 U.S.C. 852(b)(3)(B); 2025 Wisconsin Schedule SB instructions, line 5", + "upstream": "to be filed", + "note": "Corrected value applies r32_wi_capital_gain_distributions with every publication convention and upstream fix. The output also moves under r04_capital_gain_distributions (engine defect, fixed upstream)." + } + }, + { + "scenario_id": "scenario_099", + "variable": "state_income_tax_before_refundable_credits", + "root_cause": "r02_ira_219g+r11_ca_itemized_conformity", + "decided_on": "2026-09-22", + "kept_value": 4493.7431640625, + "value_on_2_41_0": 4615.48388671875, + "audited_alternative_value": 4588.483887, + "target": { + "kind": "fix_modules", + "value": 4615.48388671875, + "engine": "policyengine-us 2.38.6", + "engine_value": 4588.48388671875, + "modules": [ + { + "module": "r02_ira_219g_v2.py", + "sha256": "937514fb1199c4ca172dfc5252db7f2483adade193922e6e5283d0b6ab4c4c8c" + }, + { + "module": "r11_ca_itemized_conformity_v2.py", + "sha256": "2bcb8ba6694c053f3c9a8509b96bfee4976ba00e3fb676c0c504e06c2d6c046d" + }, + { + "module": "r33_ca_educator_expense_addback.py", + "sha256": "4545d27858790ed537be056b9d1ae3e0a7c39389486ff8af1e273106cb58efad", + "path": "reference_audit/2026-10-12-engine-upgrade/fixes/r33_ca_educator_expense_addback.py" + } + ], + "dependencies": [ + { + "module": "r02_ira_219g.py", + "sha256": "295a0b975ced8964fc1b2c5d52c47bce177eed399f49735eafb88441e7561b84" + } + ], + "evidence": "reference_audit/2026-10-12-engine-upgrade/evidence/pe2.38.6.json", + "evidence_sha256": "a0b47622f8edb95162970f9f237f64bccf2e8b438de3ebfe9186f9b111bd3df4", + "value_with_modules": 4615.48388671875 + }, + "regenerated": 4615.48388671875, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10032; PolicyEngine/policyengine-us#10034; PolicyEngine/policyengine-us#10052", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10032; PolicyEngine/policyengine-us#10034; PolicyEngine/policyengine-us#10052) is regenerated with the fix: policyengine-us 2.41.0 gives $4,615.48, within $1 of the corrected value $4,615.48 its fix modules (r02_ira_219g_v2.py + r11_ca_itemized_conformity_v2.py + r33_ca_educator_expense_addback.py) give on policyengine-us 2.38.6, which still has the defect ($4,588.48 without them) (r02_ira_219g+r11_ca_itemized_conformity: PolicyEngine deducts traditional IRA contributions without the active-participant phase-out; PolicyEngine applies the federal charitable deduction floor and the suspension of miscellaneous deductions to California itemized deductions).", + "record": { + "scenario_id": "scenario_099", + "variable": "state_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r02_ira_219g+r11_ca_itemized_conformity", + "alternative_reading": "A filer who defers wages into a 401(k) or 403(b) is an active participant, and above the 2026 phase-out range ($81,000 to $91,000 single or head of household, $129,000 to $149,000 joint) deducts nothing. California itemizers deduct charitable gifts without the federal 0.5%-of-AGI floor and deduct miscellaneous expenses above 2% of AGI.", + "frozen_value": 4493.7431640625, + "alternative_value": 4588.483887, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine deducts traditional IRA contributions without the active-participant phase-out; PolicyEngine applies the federal charitable deduction floor and the suspension of miscellaneous deductions to California itemized deductions", + "law": "26 U.S.C. 219(g); IRS Notice 2025-67 (2026 ranges); Cal. R&TC 17024.5 (conformity date), 17076", + "upstream": "to be filed", + "note": "Corrected value applies r02_ira_219g_v2 and r11_ca_itemized_conformity_v2 together with every publication convention and upstream fix." + } + }, + { + "scenario_id": "scenario_100", + "variable": "federal_refundable_credits", + "root_cause": "r08_eitc_earned_income_deferrals", + "decided_on": "2026-09-22", + "kept_value": 2878.0966796875, + "value_on_2_41_0": 822.2882690429688, + "audited_alternative_value": 822.288269, + "target": { + "kind": "record", + "value": 822.288269, + "engine": "policyengine-us 1.755.4" + }, + "regenerated": 822.2882690429688, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10030", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10030) is regenerated with the fix: policyengine-us 2.41.0 gives $822.29, within $1 of the corrected value $822.29 the 2026-09-22 record computed (r08_eitc_earned_income_deferrals: PolicyEngine counts elective 401(k) deferrals as earned income for the EITC and refundable child tax credit).", + "record": { + "scenario_id": "scenario_100", + "variable": "federal_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r08_eitc_earned_income_deferrals", + "alternative_reading": "EITC earned income counts wages only if they are includible in gross income, which excludes elective deferrals (W-2 box 1 wages); the refundable child tax credit and state credits built on the EITC follow.", + "frozen_value": 2878.0966796875, + "alternative_value": 822.288269, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine counts elective 401(k) deferrals as earned income for the EITC and refundable child tax credit", + "law": "26 U.S.C. 32(c)(2)(A)(i), 24(d)(1)(B)(i), 402(e)(3); Cal. R&TC 17052(c)(4)(A)", + "upstream": "to be filed", + "note": "Corrected value applies r08_eitc_earned_income_deferrals_v2 with every publication convention and upstream fix." + } + }, + { + "scenario_id": "scenario_100", + "variable": "state_refundable_credits", + "root_cause": "r08_eitc_earned_income_deferrals", + "decided_on": "2026-09-22", + "kept_value": 473.1777038574219, + "value_on_2_41_0": 164.45765686035156, + "audited_alternative_value": 164.457657, + "target": { + "kind": "record", + "value": 164.457657, + "engine": "policyengine-us 1.755.4" + }, + "regenerated": 164.45765686035156, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10030", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10030) is regenerated with the fix: policyengine-us 2.41.0 gives $164.46, within $1 of the corrected value $164.46 the 2026-09-22 record computed (r08_eitc_earned_income_deferrals: PolicyEngine counts elective 401(k) deferrals as earned income for the EITC and refundable child tax credit).", + "record": { + "scenario_id": "scenario_100", + "variable": "state_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r08_eitc_earned_income_deferrals", + "alternative_reading": "EITC earned income counts wages only if they are includible in gross income, which excludes elective deferrals (W-2 box 1 wages); the refundable child tax credit and state credits built on the EITC follow.", + "frozen_value": 473.1777038574219, + "alternative_value": 164.457657, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine counts elective 401(k) deferrals as earned income for the EITC and refundable child tax credit", + "law": "26 U.S.C. 32(c)(2)(A)(i), 24(d)(1)(B)(i), 402(e)(3); Cal. R&TC 17052(c)(4)(A)", + "upstream": "to be filed", + "note": "Corrected value applies r08_eitc_earned_income_deferrals_v2 with every publication convention and upstream fix." + } + }, + { + "scenario_id": "scenario_119", + "variable": "federal_refundable_credits", + "root_cause": "r08_eitc_earned_income_deferrals", + "decided_on": "2026-09-22", + "kept_value": 2854.0087890625, + "value_on_2_41_0": 3366.07373046875, + "audited_alternative_value": 3366.07373, + "target": { + "kind": "record", + "value": 3366.07373, + "engine": "policyengine-us 1.755.4" + }, + "regenerated": 3366.07373046875, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10030", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10030) is regenerated with the fix: policyengine-us 2.41.0 gives $3,366.07, within $1 of the corrected value $3,366.07 the 2026-09-22 record computed (r08_eitc_earned_income_deferrals: PolicyEngine counts elective 401(k) deferrals as earned income for the EITC and refundable child tax credit).", + "record": { + "scenario_id": "scenario_119", + "variable": "federal_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r08_eitc_earned_income_deferrals", + "alternative_reading": "EITC earned income counts wages only if they are includible in gross income, which excludes elective deferrals (W-2 box 1 wages); the refundable child tax credit and state credits built on the EITC follow.", + "frozen_value": 2854.0087890625, + "alternative_value": 3366.07373, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine counts elective 401(k) deferrals as earned income for the EITC and refundable child tax credit", + "law": "26 U.S.C. 32(c)(2)(A)(i), 24(d)(1)(B)(i), 402(e)(3); Cal. R&TC 17052(c)(4)(A)", + "upstream": "to be filed", + "note": "Corrected value applies r08_eitc_earned_income_deferrals_v2 with every publication convention and upstream fix." + } + }, + { + "scenario_id": "scenario_119", + "variable": "state_income_tax_before_refundable_credits", + "root_cause": "r08_eitc_earned_income_deferrals", + "decided_on": "2026-09-22", + "kept_value": 1859.0943603515625, + "value_on_2_41_0": 1756.681396484375, + "audited_alternative_value": 1756.681396, + "target": { + "kind": "record", + "value": 1756.681396, + "engine": "policyengine-us 1.755.4" + }, + "regenerated": 1756.681396484375, + "tolerance": 1.0, + "upstream": "PolicyEngine/policyengine-us#10030", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10030) is regenerated with the fix: policyengine-us 2.41.0 gives $1,756.68, within $1 of the corrected value $1,756.68 the 2026-09-22 record computed (r08_eitc_earned_income_deferrals: PolicyEngine counts elective 401(k) deferrals as earned income for the EITC and refundable child tax credit).", + "record": { + "scenario_id": "scenario_119", + "variable": "state_income_tax_before_refundable_credits", + "reason_code": "reference_engine_defect", + "root_cause": "r08_eitc_earned_income_deferrals", + "alternative_reading": "EITC earned income counts wages only if they are includible in gross income, which excludes elective deferrals (W-2 box 1 wages); the refundable child tax credit and state credits built on the EITC follow.", + "frozen_value": 1859.0943603515625, + "alternative_value": 1756.681396, + "engine_version": "policyengine-us 1.755.4", + "decided_on": "2026-09-22", + "decided_by": "developer", + "defect": "PolicyEngine counts elective 401(k) deferrals as earned income for the EITC and refundable child tax credit", + "law": "26 U.S.C. 32(c)(2)(A)(i), 24(d)(1)(B)(i), 402(e)(3); Cal. R&TC 17052(c)(4)(A)", + "upstream": "to be filed", + "note": "Corrected value applies r08_eitc_earned_income_deferrals_v2 with every publication convention and upstream fix." + } + } + ], + "new_exclusions": [], + "changed": [ + { + "scenario_id": "scenario_007", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 755.7783203125, + "previous": 755.7783203125, + "regenerated": 661.3170166015625, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10023) is regenerated with the fix: policyengine-us 2.41.0 gives $661.32, within $1 of the corrected value $661.32 its fix modules (r07_idaho_health_premiums_v2.py) give on policyengine-us 2.38.6, which still has the defect ($771.56 without them) (r07_idaho_health_premiums: PolicyEngine omits Idaho's subtraction for health insurance premiums the taxpayer pays)." + }, + { + "scenario_id": "scenario_042", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 284.74090576171875, + "previous": 284.74090576171875, + "regenerated": 0.0, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10026) is regenerated with the fix: policyengine-us 2.41.0 gives $0.00, within $1 of the corrected value $0.00 the 2026-09-22 record computed (r06_wi_act15_before_refundable+r32_wi_capital_gain_distributions: PolicyEngine's Wisconsin tax before refundable credits ignores the retirement income exclusion the filer elects, which its final Wisconsin tax applies; PolicyEngine's Wisconsin capital gain subtraction leaves out capital gain distributions reported without Schedule D, so once they reach federal AGI Wisconsin taxes all of them instead of 70%)." + }, + { + "scenario_id": "scenario_053", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 2435.2783203125, + "previous": 2435.2783203125, + "regenerated": 2186.05712890625, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10023) is regenerated with the fix: policyengine-us 2.41.0 gives $2,186.06, within $1 of the corrected value $2,186.06 its fix modules (r07_idaho_health_premiums_v2.py) give on policyengine-us 2.38.6, which still has the defect ($2,451.06 without them) (r07_idaho_health_premiums: PolicyEngine omits Idaho's subtraction for health insurance premiums the taxpayer pays)." + }, + { + "scenario_id": "scenario_091", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 843.6614990234375, + "previous": 843.6614990234375, + "regenerated": 878.5157470703125, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10026) is regenerated with the fix: policyengine-us 2.41.0 gives $878.52, within $1 of the corrected value $878.52 the 2026-09-22 record computed (r32_wi_capital_gain_distributions: PolicyEngine's Wisconsin capital gain subtraction leaves out capital gain distributions reported without Schedule D, so once they reach federal AGI Wisconsin taxes all of them instead of 70%)." + }, + { + "scenario_id": "scenario_099", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 4493.7431640625, + "previous": 4493.7431640625, + "regenerated": 4615.48388671875, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10032; PolicyEngine/policyengine-us#10034; PolicyEngine/policyengine-us#10052) is regenerated with the fix: policyengine-us 2.41.0 gives $4,615.48, within $1 of the corrected value $4,615.48 its fix modules (r02_ira_219g_v2.py + r11_ca_itemized_conformity_v2.py + r33_ca_educator_expense_addback.py) give on policyengine-us 2.38.6, which still has the defect ($4,588.48 without them) (r02_ira_219g+r11_ca_itemized_conformity: PolicyEngine deducts traditional IRA contributions without the active-participant phase-out; PolicyEngine applies the federal charitable deduction floor and the suspension of miscellaneous deductions to California itemized deductions)." + }, + { + "scenario_id": "scenario_100", + "variable": "federal_refundable_credits", + "frozen": 2878.0966796875, + "previous": 2878.0966796875, + "regenerated": 822.2882690429688, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10030) is regenerated with the fix: policyengine-us 2.41.0 gives $822.29, within $1 of the corrected value $822.29 the 2026-09-22 record computed (r08_eitc_earned_income_deferrals: PolicyEngine counts elective 401(k) deferrals as earned income for the EITC and refundable child tax credit)." + }, + { + "scenario_id": "scenario_100", + "variable": "state_refundable_credits", + "frozen": 473.1777038574219, + "previous": 473.1777038574219, + "regenerated": 164.45765686035156, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10030) is regenerated with the fix: policyengine-us 2.41.0 gives $164.46, within $1 of the corrected value $164.46 the 2026-09-22 record computed (r08_eitc_earned_income_deferrals: PolicyEngine counts elective 401(k) deferrals as earned income for the EITC and refundable child tax credit)." + }, + { + "scenario_id": "scenario_119", + "variable": "federal_refundable_credits", + "frozen": 2854.0087890625, + "previous": 2854.0087890625, + "regenerated": 3366.07373046875, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10030) is regenerated with the fix: policyengine-us 2.41.0 gives $3,366.07, within $1 of the corrected value $3,366.07 the 2026-09-22 record computed (r08_eitc_earned_income_deferrals: PolicyEngine counts elective 401(k) deferrals as earned income for the EITC and refundable child tax credit)." + }, + { + "scenario_id": "scenario_119", + "variable": "state_income_tax_before_refundable_credits", + "frozen": 1859.0943603515625, + "previous": 1859.0943603515625, + "regenerated": 1756.681396484375, + "cause": "regenerated_upstream_fix", + "basis": "An engine defect fixed upstream (PolicyEngine/policyengine-us#10030) is regenerated with the fix: policyengine-us 2.41.0 gives $1,756.68, within $1 of the corrected value $1,756.68 the 2026-09-22 record computed (r08_eitc_earned_income_deferrals: PolicyEngine counts elective 401(k) deferrals as earned income for the EITC and refundable child tax credit)." + } + ] + }, + { + "date": "2026-10-23", + "kind": "engine_upgrade", + "root_cause": "engine_upgrade_policyengine_us_2_60_0", + "outputs": "every scored output", + "rule": "A scored reference follows from the stated facts and from law published before the 2026-07-03 reference freeze. References come from the newest policyengine-us release when PolicyBench begins the reference sweep; at publication PolicyBench checks that the newest release gives the same values. Max, 2026-09-28: 'we should be using the latest pe for this always!'; and 2026-10-09, on waiting for the release that fixes the engine defects behind PolicyBench's exclusions: 'yes i want to wait for hte fixed engine'. An excluded output whose engine defect the new release fixes, landing on its audited corrected value, is regenerated and its exclusion record removed (the #178 precedent); every other excluded output keeps the value it was decided on.", + "engine_version": "policyengine-us 2.60.0", + "previous_engine_version": "policyengine-us 2.41.0", + "policyengine_py": "policyengine 6.1.2, provenance only: its certified US bundle is policyengine-us 2.2.1", + "fix_modules": [ + { + "module": "latest_c_ca_hold_2025.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_ca_hold_2025.py", + "sha256": "f19a47b9583032a0602a31e52f995eee824a427a76e87a9d4257d6682a016fa2" + }, + { + "module": "latest_c_irs_sales_tax_2025.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_irs_sales_tax_2025.py", + "sha256": "7f7fd235b29c45d1d5cceded0c3391aceb38740518dfda770e3aebcc3003228e" + }, + { + "module": "latest_c_wi_published_2026.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_wi_published_2026.py", + "sha256": "4edf4c714c05d300e6fa32c4b56879aad8aa0de1d9ddd9a77987eefe3b06acce" + }, + { + "module": "latest_c_id_hold_2025.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_id_hold_2025.py", + "sha256": "39fb99292691600cd273a1c6ef3c90847453e21e4d7b872603bcaac71727f8a5" + }, + { + "module": "latest_c_mn_published_2026.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_mn_published_2026.py", + "sha256": "02a8ccc1fce71485fc9411d4a55f33226de4c8de09cf6375f99866b79da70522" + }, + { + "module": "latest_c_md_2026.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_md_2026.py", + "sha256": "8111c77ffd2e43d434d083994a7e8506ba42461a0845b33ac47ce0df988c2c76" + }, + { + "module": "latest_c_mi_published_2026.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_mi_published_2026.py", + "sha256": "787cf837422e0bdf331a8e01a6fa8e8f2e3b78c35c248a4da83f3b2dbfa9ef9e" + }, + { + "module": "latest_c_mo_published_2026.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_mo_published_2026.py", + "sha256": "0474524c83a7eb0c8440abf06bbeee38d4394e08260464d0dacb195ed3a8d916" + }, + { + "module": "latest_c_snap_hold_fy2026.py", + "path": "reference_audit/2026-09-28/fixes/latest_c_snap_hold_fy2026.py", + "sha256": "3a8709ef36582af2248e460136db618fd319d490b7aeed94adbd6143ad9c07dd" + }, + { + "module": "latest_conventions.py", + "path": "reference_audit/2026-09-28/fixes/latest_conventions.py", + "sha256": "4155ed4a0be72c907815b33e2b3603cf0b5ea3eca351ad7509f8bd9ea5bb8ddb" + }, + { + "module": "latest_md_local_output_scope.py", + "path": "reference_audit/2026-09-28/fixes/latest_md_local_output_scope.py", + "sha256": "53a6de3cd9b149467e5d86a5bb1fcc258e859478a7c16b7d3df951c713e423dd" + }, + { + "module": "latest_final.py", + "path": "reference_audit/2026-09-28/fixes/latest_final.py", + "sha256": "dbbdd228b99933c6f336af97970821c25c863a18606285e8d6d9ffb3bc9af78e" + }, + { + "module": "r19_irs_sales_tax_2025.json", + "path": "reference_audit/2026-09-22/fixes/r19_irs_sales_tax_2025.json", + "sha256": "7cf93799aad6a8c3a6fc70e7df4acc6043202a1ecc083f2c3101f76b87a85eae" + } + ], + "builder": "reference_audit/2026-10-22-engine-upgrade/scripts/build_references_upgrade.py; households from policybench.scenarios.Scenario.to_pe_household through reference_audit/2026-09-28/scripts/sweep.py build_situation, as in the 2026-09-29 upgrade", + "provenance": { + "builder_sha256": "d4b00204390c6ada97bdf91358dc3d60ae3307d101062b8982fa62923cc9c645", + "harness": "reference_audit/2026-09-28/scripts/sweep.py", + "harness_sha256": "f4c7783453a473a1bedcf64ef554c3a2fc29f9d663626948d920ed3ef2ea2b69", + "actions_sha256": "a6a4e07b91eb9376f655fd43434fbbd7de9f0ea3b16939d41fb934c9ccdc10b4", + "base_commit": "bf845cbe4e92de495150c8660c35ea357d996a8c", + "policyengine_core": "3.32.29" + }, + "excluded_outputs_untouched": true, + "excluded_outputs_rechecked": [ + { + "scenario_id": "scenario_002", + "variable": "federal_income_tax_before_refundable_credits", + "kept_value": 0.0, + "value_on_2_60_0": 1890.300048828125, + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $1,890.30, the record's alternative value, since it takes that reading by default, but the reference depends on an input the prompt does not state (who paid for the coverage behind listed employment disability benefits, which decides whether they are taxable; reference_depends_on_unlisted_input), and an engine default does not settle it; the record keeps $0.00. policyengine-us#10185 (Count taxable employment disability benefits in federal gross income (IRC 105(a)), released in 2.50.0) counts disability_benefits less tax_exempt_disability_benefits, the part from coverage the recipient paid for with after-tax money (IRC 104(a)(3)), in gross income, and that input defaults to zero: the engine treats the benefits as coming from an employer-paid plan. The prompt lists only the benefits, so who paid for the coverage is still unstated." + }, + { + "scenario_id": "scenario_005", + "variable": "federal_income_tax_before_refundable_credits", + "kept_value": 106505.8984375, + "value_on_2_60_0": 108525.578125, + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $108,525.58, the value policyengine-us 2.41.0 gave when the 2026-10-13 recheck found it on its corrected value, but the record names a second reason that a new engine does not settle (Corrected value applies r02_ira_219g_v2 with every publication convention and upstream fix. The output also moves under r25_niit_in_federal_output (unlisted input).); the record keeps $106,505.90. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_020", + "variable": "federal_income_tax_before_refundable_credits", + "kept_value": 68056.7109375, + "value_on_2_60_0": 68334.734375, + "reason": "Stays excluded on policyengine-us 2.60.0: the reference depends on whether federal income tax before refundable credits includes the net investment income tax, which the output's definition does not say (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $68,056.71, and policyengine-us 2.60.0 gives $68,334.73. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_023", + "variable": "snap", + "kept_value": 461.3397216796875, + "value_on_2_60_0": 408.0, + "reason": "Stays excluded on policyengine-us 2.60.0: the reference depends on meets_ssi_disability_criteria (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $461.34, and policyengine-us 2.60.0 gives $408.00. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_052", + "variable": "federal_income_tax_before_refundable_credits", + "kept_value": 104211.40625, + "value_on_2_60_0": 104225.2578125, + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $104,225.26, on the record's corrected value $104,225.26, but the record names a second reason that a new engine does not settle (Corrected value applies r02_ira_219g_v2 with every publication convention and upstream fix. The output also moves under r25_niit_in_federal_output (unlisted input).); the record keeps $104,211.41. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_056", + "variable": "snap", + "kept_value": 1140.0, + "value_on_2_60_0": 95.0, + "reason": "Stays excluded on policyengine-us 2.60.0: the reference depends on weekly_hours_worked_before_lsr and whether the listed home mortgage interest is on the home the SNAP household occupies (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $1,140.00, and policyengine-us 2.60.0 gives $95.00. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_057", + "variable": "snap", + "kept_value": 2669.217041015625, + "value_on_2_60_0": 2628.0, + "reason": "Stays excluded on policyengine-us 2.60.0: the reference depends on meets_ssi_disability_criteria (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $2,669.22, and policyengine-us 2.60.0 gives $2,628.00. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_080", + "variable": "snap", + "kept_value": 3596.039794921875, + "value_on_2_60_0": 3240.0, + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $3,240.00, on the record's corrected value $3,240.00, so its defect (r30_snap_heat_and_eat_sua) is fixed there, but the 2026-09-29 recheck found the output indeterminate on the stated facts, a second reason that a new engine does not settle; the record keeps $3,596.04. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_081", + "variable": "state_income_tax_before_refundable_credits", + "kept_value": 8238.40625, + "value_on_2_60_0": 8232.900390625, + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $8,232.90, on the record's corrected value $8,232.90, but the record names a second reason that a new engine does not settle (Corrected value applies ma_part_a_loss_offset with every publication convention and upstream fix. The output also moves under r23_ma_interest_source (unlisted input).); the record keeps $8,238.41. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_100", + "variable": "snap", + "kept_value": 8625.8896484375, + "value_on_2_60_0": 6924.0, + "reason": "Stays excluded on policyengine-us 2.60.0: the reference depends on meets_ssi_disability_criteria (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $8,625.89, and policyengine-us 2.60.0 gives $6,924.00. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_107", + "variable": "federal_income_tax_before_refundable_credits", + "kept_value": 0.0, + "value_on_2_60_0": 211.232421875, + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $211.23, the record's alternative value, since it takes that reading by default, but the reference depends on an input the prompt does not state (who paid for the coverage behind listed employment disability benefits, which decides whether they are taxable; reference_depends_on_unlisted_input), and an engine default does not settle it; the record keeps $0.00. policyengine-us#10185 (Count taxable employment disability benefits in federal gross income (IRC 105(a)), released in 2.50.0) counts disability_benefits less tax_exempt_disability_benefits, the part from coverage the recipient paid for with after-tax money (IRC 104(a)(3)), in gross income, and that input defaults to zero: the engine treats the benefits as coming from an employer-paid plan. The prompt lists only the benefits, so who paid for the coverage is still unstated." + }, + { + "scenario_id": "scenario_112", + "variable": "snap", + "kept_value": 287.68316650390625, + "value_on_2_60_0": 0.0, + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $0.00, the record's alternative value, since it takes that reading by default, but the reference depends on an input the prompt does not state (weekly_hours_worked_before_lsr; reference_depends_on_unlisted_input), and an engine default does not settle it; the record keeps $287.68. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_118", + "variable": "snap", + "kept_value": 2903.9404296875, + "value_on_2_60_0": 2400.0, + "reason": "Stays excluded on policyengine-us 2.60.0: the reference depends on whether the listed home mortgage interest is on the home the SNAP household occupies (reference_depends_on_unlisted_input), which an engine release does not settle; the record keeps $2,903.94, and policyengine-us 2.60.0 gives $2,400.00. policyengine-us 2.41.0 gave $2,868.00 when it was rechecked on 2026-10-13. It moves because policyengine-us#10158 (Add New York state supplementation for 2026) models New York's state supplement to SSI, $87 a month for this person living alone (ny_ssp), which counts as SNAP unearned income: gross income rises from $1,014 to $1,101 a month, net income from $194 to $325, and the allotment from $239 to $200 a month." + }, + { + "scenario_id": "scenario_120", + "variable": "federal_income_tax_before_refundable_credits", + "kept_value": 40021.81640625, + "value_on_2_60_0": 40423.17578125, + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $40,423.18, the value policyengine-us 2.41.0 gave when the 2026-10-13 recheck found it on its corrected value, but the record names a second reason that a new engine does not settle (Corrected value applies r02_ira_219g_v2 with every publication convention and upstream fix. The output also moves under r25_niit_in_federal_output (unlisted input). The output also moves under the state income tax withheld reading (unlisted input): the reference's SALT uses the Connecticut withholding estimate ($12,010.05); with the engine's own liability ($11,917.18) the 2.15.17 value is $40,438.95, and with no state income tax paid it is $43,619.93. With r02's IRA fix on 2.15.17 the value is $40,423.18 under the withholding estimate, $40,445.46 under the liability and $43,629.21 with no state income tax paid. policyengine-us 2.15.17 also leaves the household's Connecticut paid leave contributions ($827.98) out of SALT (Rev. Rul. 2025-4); with them the 2.15.17 value is $40,217.95.); the record keeps $40,021.82. The value is 2.41.0's, rechecked on 2026-10-13 (the 2026-10-13 engine_upgrade revision's excluded_outputs_rechecked)." + }, + { + "scenario_id": "scenario_121", + "variable": "federal_income_tax_before_refundable_credits", + "kept_value": 0.0, + "value_on_2_60_0": 875.3375244140625, + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $875.34, the record's alternative value, since it takes that reading by default, but the reference depends on an input the prompt does not state (who paid for the coverage behind listed employment disability benefits, which decides whether they are taxable; reference_depends_on_unlisted_input), and an engine default does not settle it; the record keeps $0.00. policyengine-us#10185 (Count taxable employment disability benefits in federal gross income (IRC 105(a)), released in 2.50.0) counts disability_benefits less tax_exempt_disability_benefits, the part from coverage the recipient paid for with after-tax money (IRC 104(a)(3)), in gross income, and that input defaults to zero: the engine treats the benefits as coming from an employer-paid plan. The prompt lists only the benefits, so who paid for the coverage is still unstated." + }, + { + "scenario_id": "scenario_121", + "variable": "state_income_tax_before_refundable_credits", + "kept_value": 0.0, + "value_on_2_60_0": 212.23350524902344, + "reason": "Stays excluded on policyengine-us 2.60.0: the engine gives $212.23, the record's alternative value, since it takes that reading by default, but the reference depends on an input the prompt does not state (who paid for the coverage behind listed employment disability benefits, which decides whether they are taxable; reference_depends_on_unlisted_input), and an engine default does not settle it; the record keeps $0.00. policyengine-us#10185 (Count taxable employment disability benefits in federal gross income (IRC 105(a)), released in 2.50.0) counts disability_benefits less tax_exempt_disability_benefits, the part from coverage the recipient paid for with after-tax money (IRC 104(a)(3)), in gross income, and that input defaults to zero: the engine treats the benefits as coming from an employer-paid plan. The prompt lists only the benefits, so who paid for the coverage is still unstated." + } + ], + "regenerated_exclusions": [], + "new_exclusions": [], + "changed": [ + { + "scenario_id": "scenario_028", + "variable": "free_school_meals_eligible", + "frozen": 0.0, + "previous": 0.0, + "regenerated": 1.0, + "cause": "state_universal_free_breakfast_10238", + "basis": "Pennsylvania Act 33 of 2023 (24 P.S. \u00a7 13-1337.1(c.2), codified December 13, 2023) gives every public school student a free breakfast regardless of household income. PolicyEngine/policyengine-us#10238 (Model state school meal coverage beyond universal meals) models it: on policyengine-us 2.60.0 state_has_universal_free_school_breakfast is true for PA, so the household's K-12 children take the free breakfast tier (school_meal_breakfast_tier) whatever their income while lunch stays in the paid tier (school_meal_lunch_tier), and free_school_meals is positive. Here its three K-12 children, at 186% of the poverty guideline, get $1,112.40 of free breakfast support for 2026. The output asks whether PolicyEngine returns positive annual free school meal support, so it is 1; on policyengine-us 2.41.0 the household's income put both meals in the paid tier and it was 0." + }, + { + "scenario_id": "scenario_031", + "variable": "snap", + "frozen": 0.0, + "previous": 0.0, + "regenerated": 288.0, + "cause": "ca_snap_mce_no_net_income_test_10036", + "basis": "California's Modified Categorical Eligibility (MCE) makes a household with gross income within 200% of the poverty guideline categorically eligible for CalFresh without the net income test, elderly or disabled households included (CDSS ACL 12-62, 13-32, 14-56 and 15-42; 7 CFR 273.2(j)(2)), and gives an eligible one- or two-person household the minimum allotment (CDSS MCE letter, June 30, 2014; 7 U.S.C. 2017(a); 7 CFR 273.10(e)(2)(ii)(C)). policyengine-us 2.41.0 applied the net income test to MCE households with an elderly or disabled member, so this one-person household, an elderly member with $1,987.79 of monthly gross income (within the $2,608.33 MCE limit) and $1,611 of net income (above the $1,304.17 guideline), was ineligible and its SNAP was $0. PolicyEngine/policyengine-us#10036 (Remove the BBCE net income test from California's Modified Categorical Eligibility) drops that test; on policyengine-us 2.60.0 the household is categorically eligible and its calculated allotment, the $298 maximum less 30% of net income ($484), is below the $24 minimum, so it receives $24 a month (snap_min_allotment): $288.00 for 2026." + }, + { + "scenario_id": "scenario_117", + "variable": "free_school_meals_eligible", + "frozen": 0.0, + "previous": 0.0, + "regenerated": 1.0, + "cause": "state_universal_free_breakfast_10238", + "basis": "Arkansas Act 123 of 2025 (SB 59; A.C.A. \u00a7 6-18-722(f)), from the 2025-26 school year, gives every public school student a free breakfast regardless of household income. PolicyEngine/policyengine-us#10238 (Model state school meal coverage beyond universal meals) models it: on policyengine-us 2.60.0 state_has_universal_free_school_breakfast is true for AR, so the household's K-12 children take the free breakfast tier (school_meal_breakfast_tier) whatever their income while lunch stays in the paid tier (school_meal_lunch_tier), and free_school_meals is positive. Here its two K-12 children, at 643% of the poverty guideline, get $741.60 of free breakfast support for 2026. The output asks whether PolicyEngine returns positive annual free school meal support, so it is 1; on policyengine-us 2.41.0 the household's income put both meals in the paid tier and it was 0." + }, + { + "scenario_id": "scenario_123", + "variable": "free_school_meals_eligible", + "frozen": 0.0, + "previous": 0.0, + "regenerated": 1.0, + "cause": "state_universal_free_breakfast_10238", + "basis": "Pennsylvania Act 33 of 2023 (24 P.S. \u00a7 13-1337.1(c.2), codified December 13, 2023) gives every public school student a free breakfast regardless of household income. PolicyEngine/policyengine-us#10238 (Model state school meal coverage beyond universal meals) models it: on policyengine-us 2.60.0 state_has_universal_free_school_breakfast is true for PA, so the household's K-12 children take the free breakfast tier (school_meal_breakfast_tier) whatever their income while lunch stays in the paid tier (school_meal_lunch_tier), and free_school_meals is positive. Here its one K-12 child, at 531% of the poverty guideline, gets $370.80 of free breakfast support for 2026. The output asks whether PolicyEngine returns positive annual free school meal support, so it is 1; on policyengine-us 2.41.0 the household's income put both meals in the paid tier and it was 0." + } + ] + } + ], + "regenerated_at_utc": "2026-10-23T02:16:15.575879+00:00" +} diff --git a/reference_audit/2026-10-22-engine-upgrade/reference-build/reference_traces.json b/reference_audit/2026-10-22-engine-upgrade/reference-build/reference_traces.json new file mode 100644 index 00000000..f1d9c27d --- /dev/null +++ b/reference_audit/2026-10-22-engine-upgrade/reference-build/reference_traces.json @@ -0,0 +1,18 @@ +{ + "scenario_028|free_school_meals_eligible": { + "pe_variable": "free_school_meals", + "trace": "free_school_meals = 1112.4\n state_group_str = CONTIGUOUS_US\n school_meal_breakfast_tier = 0\n school_meal_tier = 2\n school_meal_fpg_ratio = 1.86\n school_meal_countable_income = 61277\n employment_income = 60000 (per entity: 60000, 0, 0, 0)\n employment_income_before_lsr = 60000 (per entity: 60000, 0, 0, 0)\n interest_income = 10 (per entity: 10, 0, 0, 0)\n taxable_interest_income = 10 (per entity: 10, 0, 0, 0)\n child_support_received = 1267 (per entity: 1267, 0, 0, 0)\n spm_unit_fpg = 33000\n spm_unit_size = 4\n state_group_str = CONTIGUOUS_US\n state_code_str = PA\n state_has_universal_free_school_breakfast = True\n state_code_str = PA\n state_code_str = PA\n school_meal_fpg_ratio = 1.86\n school_meal_lunch_tier = 2\n school_meal_tier = 2\n state_code_str = PA\n school_meal_net_subsidy = 1112.4\n school_meal_daily_subsidy = 2.9\n state_group_str = CONTIGUOUS_US\n school_meal_lunch_tier = 2\n school_meal_paid_daily_subsidy = 0.84\n state_group_str = CONTIGUOUS_US\n is_in_k12_school = [False, True, True, True]" + }, + "scenario_031|snap": { + "pe_variable": "snap", + "trace": "snap = 288\n snap = 24\n takes_up_snap_if_eligible = True\n snap_if_takes_up = 24\n snap_normal_allotment = 24\n is_snap_eligible = True\n meets_snap_gross_income_test = True\n snap_gross_test_income = 1987.79\n snap_gross_income = 1987.79\n snap_income_counted_share = 1\n snap_countable_earner = True\n snap_unearned_income_person = 1987.79\n state_code_str = CA\n snap_fpg = 1304.17\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n has_snap_elderly_disabled_member = True\n meets_snap_asset_test = True\n has_snap_elderly_disabled_member = True\n snap_assets = 4200\n bank_account_assets = 4200\n meets_snap_categorical_eligibility = True\n is_tanf_non_cash_eligible = True\n meets_tanf_non_cash_gross_income_test = True\n snap_gross_test_income = 1987.79\n tanf_non_cash_gross_income_limit = 2608.33\n meets_tanf_non_cash_net_income_test = True\n state_code_str = CA\n is_tanf_non_cash_hheod = True\n snap_net_income = 1611\n snap_fpg = 1304.17\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n meets_tanf_non_cash_asset_test = True\n snap_assets = 4200\n state_code_str = CA\n ca_snap_meets_allotment_requirement = True\n CA = True\n snap_allotment_before_eligibility = 24\n snap_expected_contribution = 484\n snap_net_income = 1611\n snap_max_allotment = 298\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n snap_unit_size = 1\n snap_min_allotment = 24\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n state_code_str = CA\n snap_allotment_before_eligibility = 24\n snap = 24\n takes_up_snap_if_eligible = True\n snap_if_takes_up = 24\n snap_normal_allotment = 24\n is_snap_eligible = True\n meets_snap_gross_income_test = True\n snap_gross_test_income = 1987.79\n snap_gross_income = 1987.79\n snap_income_counted_share = 1\n snap_countable_earner = True\n snap_unearned_income_person = 1987.79\n state_code_str = CA\n snap_fpg = 1304.17\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n has_snap_elderly_disabled_member = True\n meets_snap_asset_test = True\n has_snap_elderly_disabled_member = True\n snap_assets = 4200\n meets_snap_categorical_eligibility = True\n is_tanf_non_cash_eligible = True\n meets_tanf_non_cash_gross_income_test = True\n snap_gross_test_income = 1987.79\n tanf_non_cash_gross_income_limit = 2608.33\n meets_tanf_non_cash_net_income_test = True\n state_code_str = CA\n is_tanf_non_cash_hheod = True\n snap_net_income = 1611\n snap_fpg = 1304.17\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n meets_tanf_non_cash_asset_test = True\n snap_assets = 4200\n state_code_str = CA\n ca_snap_meets_allotment_requirement = True\n CA = True\n snap_allotment_before_eligibility = 24\n snap_expected_contribution = 484\n snap_net_income = 1611\n snap_max_allotment = 298\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n snap_unit_size = 1\n snap_min_allotment = 24\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n state_code_str = CA\n snap_allotment_before_eligibility = 24\n snap = 24\n takes_up_snap_if_eligible = True\n snap_if_takes_up = 24\n snap_normal_allotment = 24\n is_snap_eligible = True\n meets_snap_gross_income_test = True\n snap_gross_test_income = 1987.79\n snap_gross_income = 1987.79\n snap_income_counted_share = 1\n snap_countable_earner = True\n snap_unearned_income_person = 1987.79\n state_code_str = CA\n snap_fpg = 1304.17\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n has_snap_elderly_disabled_member = True\n meets_snap_asset_test = True\n has_snap_elderly_disabled_member = True\n snap_assets = 4200\n meets_snap_categorical_eligibility = True\n is_tanf_non_cash_eligible = True\n meets_tanf_non_cash_gross_income_test = True\n snap_gross_test_income = 1987.79\n tanf_non_cash_gross_income_limit = 2608.33\n meets_tanf_non_cash_net_income_test = True\n state_code_str = CA\n is_tanf_non_cash_hheod = True\n snap_net_income = 1611\n snap_fpg = 1304.17\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n meets_tanf_non_cash_asset_test = True\n snap_assets = 4200\n state_code_str = CA\n ca_snap_meets_allotment_requirement = True\n CA = True\n snap_allotment_before_eligibility = 24\n snap_expected_contribution = 484\n snap_net_income = 1611\n snap_max_allotment = 298\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n snap_unit_size = 1\n snap_min_allotment = 24\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n state_code_str = CA\n snap_allotment_before_eligibility = 24\n snap = 24\n takes_up_snap_if_eligible = True\n snap_if_takes_up = 24\n snap_normal_allotment = 24\n is_snap_eligible = True\n meets_snap_gross_income_test = True\n snap_gross_test_income = 1987.79\n snap_gross_income = 1987.79\n snap_income_counted_share = 1\n snap_countable_earner = True\n snap_unearned_income_person = 1987.79\n state_code_str = CA\n snap_fpg = 1304.17\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n has_snap_elderly_disabled_member = True\n meets_snap_asset_test = True\n has_snap_elderly_disabled_member = True\n snap_assets = 4200\n meets_snap_categorical_eligibility = True\n is_tanf_non_cash_eligible = True\n meets_tanf_non_cash_gross_income_test = True\n snap_gross_test_income = 1987.79\n tanf_non_cash_gross_income_limit = 2608.33\n meets_tanf_non_cash_net_income_test = True\n state_code_str = CA\n is_tanf_non_cash_hheod = True\n snap_net_income = 1611\n snap_fpg = 1304.17\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n meets_tanf_non_cash_asset_test = True\n snap_assets = 4200\n state_code_str = CA\n ca_snap_meets_allotment_requirement = True\n CA = True\n snap_allotment_before_eligibility = 24\n snap_expected_contribution = 484\n snap_net_income = 1611\n snap_max_allotment = 298\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n snap_unit_size = 1\n snap_min_allotment = 24\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n state_code_str = CA\n snap_allotment_before_eligibility = 24\n snap = 24\n takes_up_snap_if_eligible = True\n snap_if_takes_up = 24\n snap_normal_allotment = 24\n is_snap_eligible = True\n meets_snap_gross_income_test = True\n snap_gross_test_income = 1987.79\n snap_gross_income = 1987.79\n snap_income_counted_share = 1\n snap_countable_earner = True\n snap_unearned_income_person = 1987.79\n state_code_str = CA\n snap_fpg = 1304.17\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n has_snap_elderly_disabled_member = True\n meets_snap_asset_test = True\n has_snap_elderly_disabled_member = True\n snap_assets = 4200\n meets_snap_categorical_eligibility = True\n is_tanf_non_cash_eligible = True\n meets_tanf_non_cash_gross_income_test = True\n snap_gross_test_income = 1987.79\n tanf_non_cash_gross_income_limit = 2608.33\n meets_tanf_non_cash_net_income_test = True\n state_code_str = CA\n is_tanf_non_cash_hheod = True\n snap_net_income = 1611\n snap_fpg = 1304.17\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n meets_tanf_non_cash_asset_test = True\n snap_assets = 4200\n state_code_str = CA\n ca_snap_meets_allotment_requirement = True\n CA = True\n snap_allotment_before_eligibility = 24\n snap_expected_contribution = 484\n snap_net_income = 1611\n snap_max_allotment = 298\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n snap_unit_size = 1\n snap_min_allotment = 24\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n state_code_str = CA\n snap_allotment_before_eligibility = 24\n snap = 24\n takes_up_snap_if_eligible = True\n snap_if_takes_up = 24\n snap_normal_allotment = 24\n is_snap_eligible = True\n meets_snap_gross_income_test = True\n snap_gross_test_income = 1987.79\n snap_gross_income = 1987.79\n snap_income_counted_share = 1\n snap_countable_earner = True\n snap_unearned_income_person = 1987.79\n state_code_str = CA\n snap_fpg = 1304.17\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n has_snap_elderly_disabled_member = True\n meets_snap_asset_test = True\n has_snap_elderly_disabled_member = True\n snap_assets = 4200\n meets_snap_categorical_eligibility = True\n is_tanf_non_cash_eligible = True\n meets_tanf_non_cash_gross_income_test = True\n snap_gross_test_income = 1987.79\n tanf_non_cash_gross_income_limit = 2608.33\n meets_tanf_non_cash_net_income_test = True\n state_code_str = CA\n is_tanf_non_cash_hheod = True\n snap_net_income = 1611\n snap_fpg = 1304.17\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n meets_tanf_non_cash_asset_test = True\n snap_assets = 4200\n state_code_str = CA\n ca_snap_meets_allotment_requirement = True\n CA = True\n snap_allotment_before_eligibility = 24\n snap_expected_contribution = 484\n snap_net_income = 1611\n snap_max_allotment = 298\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n snap_unit_size = 1\n snap_min_allotment = 24\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n state_code_str = CA\n snap_allotment_before_eligibility = 24\n snap = 24\n takes_up_snap_if_eligible = True\n snap_if_takes_up = 24\n snap_normal_allotment = 24\n is_snap_eligible = True\n meets_snap_gross_income_test = True\n snap_gross_test_income = 1987.79\n snap_gross_income = 1987.79\n snap_income_counted_share = 1\n snap_countable_earner = True\n snap_unearned_income_person = 1987.79\n state_code_str = CA\n snap_fpg = 1304.17\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n has_snap_elderly_disabled_member = True\n meets_snap_asset_test = True\n has_snap_elderly_disabled_member = True\n snap_assets = 4200\n meets_snap_categorical_eligibility = True\n is_tanf_non_cash_eligible = True\n meets_tanf_non_cash_gross_income_test = True\n snap_gross_test_income = 1987.79\n tanf_non_cash_gross_income_limit = 2608.33\n meets_tanf_non_cash_net_income_test = True\n state_code_str = CA\n is_tanf_non_cash_hheod = True\n snap_net_income = 1611\n snap_fpg = 1304.17\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n meets_tanf_non_cash_asset_test = True\n snap_assets = 4200\n state_code_str = CA\n ca_snap_meets_allotment_requirement = True\n CA = True\n snap_allotment_before_eligibility = 24\n snap_expected_contribution = 484\n snap_net_income = 1611\n snap_max_allotment = 298\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n snap_unit_size = 1\n snap_min_allotment = 24\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n state_code_str = CA\n snap_allotment_before_eligibility = 24\n snap = 24\n takes_up_snap_if_eligible = True\n snap_if_takes_up = 24\n snap_normal_allotment = 24\n is_snap_eligible = True\n meets_snap_gross_income_test = True\n snap_gross_test_income = 1987.79\n snap_gross_income = 1987.79\n snap_income_counted_share = 1\n snap_countable_earner = True\n snap_unearned_income_person = 1987.79\n state_code_str = CA\n snap_fpg = 1304.17\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n has_snap_elderly_disabled_member = True\n meets_snap_asset_test = True\n has_snap_elderly_disabled_member = True\n snap_assets = 4200\n meets_snap_categorical_eligibility = True\n is_tanf_non_cash_eligible = True\n meets_tanf_non_cash_gross_income_test = True\n snap_gross_test_income = 1987.79\n tanf_non_cash_gross_income_limit = 2608.33\n meets_tanf_non_cash_net_income_test = True\n state_code_str = CA\n is_tanf_non_cash_hheod = True\n snap_net_income = 1611\n snap_fpg = 1304.17\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n meets_tanf_non_cash_asset_test = True\n snap_assets = 4200\n state_code_str = CA\n ca_snap_meets_allotment_requirement = True\n CA = True\n snap_allotment_before_eligibility = 24\n snap_expected_contribution = 484\n snap_net_income = 1611\n snap_max_allotment = 298\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n snap_unit_size = 1\n snap_min_allotment = 24\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n state_code_str = CA\n snap_allotment_before_eligibility = 24\n snap = 24\n takes_up_snap_if_eligible = True\n snap_if_takes_up = 24\n snap_normal_allotment = 24\n is_snap_eligible = True\n meets_snap_gross_income_test = True\n snap_gross_test_income = 1987.79\n snap_gross_income = 1987.79\n snap_income_counted_share = 1\n snap_countable_earner = True\n snap_unearned_income_person = 1987.79\n state_code_str = CA\n snap_fpg = 1304.17\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n has_snap_elderly_disabled_member = True\n meets_snap_asset_test = True\n has_snap_elderly_disabled_member = True\n snap_assets = 4200\n meets_snap_categorical_eligibility = True\n is_tanf_non_cash_eligible = True\n meets_tanf_non_cash_gross_income_test = True\n snap_gross_test_income = 1987.79\n tanf_non_cash_gross_income_limit = 2608.33\n meets_tanf_non_cash_net_income_test = True\n state_code_str = CA\n is_tanf_non_cash_hheod = True\n snap_net_income = 1611\n snap_fpg = 1304.17\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n meets_tanf_non_cash_asset_test = True\n snap_assets = 4200\n state_code_str = CA\n ca_snap_meets_allotment_requirement = True\n CA = True\n snap_allotment_before_eligibility = 24\n snap_expected_contribution = 484\n snap_net_income = 1611\n snap_max_allotment = 298\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n snap_unit_size = 1\n snap_min_allotment = 24\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n state_code_str = CA\n snap_allotment_before_eligibility = 24\n snap = 24\n takes_up_snap_if_eligible = True\n snap_if_takes_up = 24\n snap_normal_allotment = 24\n is_snap_eligible = True\n meets_snap_gross_income_test = True\n snap_gross_test_income = 1987.79\n snap_gross_income = 1987.79\n snap_income_counted_share = 1\n snap_countable_earner = True\n snap_unearned_income_person = 1987.79\n state_code_str = CA\n snap_fpg = 1330\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n has_snap_elderly_disabled_member = True\n meets_snap_asset_test = True\n has_snap_elderly_disabled_member = True\n snap_assets = 4200\n meets_snap_categorical_eligibility = True\n is_tanf_non_cash_eligible = True\n meets_tanf_non_cash_gross_income_test = True\n snap_gross_test_income = 1987.79\n tanf_non_cash_gross_income_limit = 2660\n meets_tanf_non_cash_net_income_test = True\n state_code_str = CA\n is_tanf_non_cash_hheod = True\n snap_net_income = 1611\n snap_fpg = 1330\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n meets_tanf_non_cash_asset_test = True\n snap_assets = 4200\n state_code_str = CA\n ca_snap_meets_allotment_requirement = True\n CA = True\n snap_allotment_before_eligibility = 24\n snap_expected_contribution = 484\n snap_net_income = 1611\n snap_max_allotment = 298\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n snap_unit_size = 1\n snap_region_str = CONTIGUOUS_US\n snap_min_allotment = 24\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n state_code_str = CA\n snap_allotment_before_eligibility = 24\n snap = 24\n takes_up_snap_if_eligible = True\n snap_if_takes_up = 24\n snap_normal_allotment = 24\n is_snap_eligible = True\n meets_snap_gross_income_test = True\n snap_gross_test_income = 1987.79\n snap_gross_income = 1987.79\n snap_income_counted_share = 1\n snap_countable_earner = True\n snap_unearned_income_person = 1987.79\n state_code_str = CA\n snap_fpg = 1330\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n has_snap_elderly_disabled_member = True\n meets_snap_asset_test = True\n has_snap_elderly_disabled_member = True\n snap_assets = 4200\n meets_snap_categorical_eligibility = True\n is_tanf_non_cash_eligible = True\n meets_tanf_non_cash_gross_income_test = True\n snap_gross_test_income = 1987.79\n tanf_non_cash_gross_income_limit = 2660\n meets_tanf_non_cash_net_income_test = True\n state_code_str = CA\n is_tanf_non_cash_hheod = True\n snap_net_income = 1611\n snap_fpg = 1330\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n meets_tanf_non_cash_asset_test = True\n snap_assets = 4200\n state_code_str = CA\n ca_snap_meets_allotment_requirement = True\n CA = True\n snap_allotment_before_eligibility = 24\n snap_expected_contribution = 484\n snap_net_income = 1611\n snap_max_allotment = 298\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n snap_unit_size = 1\n snap_region_str = CONTIGUOUS_US\n snap_min_allotment = 24\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n state_code_str = CA\n snap_allotment_before_eligibility = 24\n snap = 24\n takes_up_snap_if_eligible = True\n snap_if_takes_up = 24\n snap_normal_allotment = 24\n is_snap_eligible = True\n meets_snap_gross_income_test = True\n snap_gross_test_income = 1987.79\n snap_gross_income = 1987.79\n snap_income_counted_share = 1\n snap_countable_earner = True\n snap_unearned_income_person = 1987.79\n state_code_str = CA\n snap_fpg = 1330\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n has_snap_elderly_disabled_member = True\n meets_snap_asset_test = True\n has_snap_elderly_disabled_member = True\n snap_assets = 4200\n meets_snap_categorical_eligibility = True\n is_tanf_non_cash_eligible = True\n meets_tanf_non_cash_gross_income_test = True\n snap_gross_test_income = 1987.79\n tanf_non_cash_gross_income_limit = 2660\n meets_tanf_non_cash_net_income_test = True\n state_code_str = CA\n is_tanf_non_cash_hheod = True\n snap_net_income = 1611\n snap_fpg = 1330\n snap_unit_size = 1\n state_group_str = CONTIGUOUS_US\n meets_tanf_non_cash_asset_test = True\n snap_assets = 4200\n state_code_str = CA\n ca_snap_meets_allotment_requirement = True\n CA = True\n snap_allotment_before_eligibility = 24\n snap_expected_contribution = 484\n snap_net_income = 1611\n snap_max_allotment = 298\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n snap_unit_size = 1\n snap_region_str = CONTIGUOUS_US\n snap_min_allotment = 24\n snap_region_str = CONTIGUOUS_US\n snap_unit_size = 1\n state_code_str = CA\n snap_allotment_before_eligibility = 24" + }, + "scenario_117|free_school_meals_eligible": { + "pe_variable": "free_school_meals", + "trace": "free_school_meals = 741.6\n state_group_str = CONTIGUOUS_US\n school_meal_breakfast_tier = 0\n school_meal_tier = 2\n school_meal_fpg_ratio = 6.43\n school_meal_countable_income = 248675\n employment_income = 248675 (per entity: 0, 248675, 0, 0, 0)\n employment_income_before_lsr = 248675 (per entity: 0, 248675, 0, 0, 0)\n spm_unit_fpg = 38680\n spm_unit_size = 5\n state_group_str = CONTIGUOUS_US\n state_code_str = AR\n state_has_universal_free_school_breakfast = True\n state_code_str = AR\n state_code_str = AR\n school_meal_fpg_ratio = 6.43\n school_meal_lunch_tier = 2\n school_meal_tier = 2\n state_code_str = AR\n school_meal_net_subsidy = 741.6\n school_meal_daily_subsidy = 2.9\n state_group_str = CONTIGUOUS_US\n school_meal_lunch_tier = 2\n school_meal_paid_daily_subsidy = 0.84\n state_group_str = CONTIGUOUS_US\n is_in_k12_school = [False, False, True, True, False]" + }, + "scenario_123|free_school_meals_eligible": { + "pe_variable": "free_school_meals", + "trace": "free_school_meals = 370.8\n state_group_str = CONTIGUOUS_US\n school_meal_breakfast_tier = 0\n school_meal_tier = 2\n school_meal_fpg_ratio = 5.31\n school_meal_countable_income = 145002\n employment_income = 145000 (per entity: 100000, 0, 45000)\n employment_income_before_lsr = 145000 (per entity: 100000, 0, 45000)\n interest_income = 2 (per entity: 1, 1, 0)\n taxable_interest_income = 2 (per entity: 1, 1, 0)\n spm_unit_fpg = 27320\n spm_unit_size = 3\n state_group_str = CONTIGUOUS_US\n state_code_str = PA\n state_has_universal_free_school_breakfast = True\n state_code_str = PA\n state_code_str = PA\n school_meal_fpg_ratio = 5.31\n school_meal_lunch_tier = 2\n school_meal_tier = 2\n state_code_str = PA\n school_meal_net_subsidy = 370.8\n school_meal_daily_subsidy = 2.9\n state_group_str = CONTIGUOUS_US\n school_meal_lunch_tier = 2\n school_meal_paid_daily_subsidy = 0.84\n state_group_str = CONTIGUOUS_US\n is_in_k12_school = [False, False, True]" + } +} \ No newline at end of file diff --git a/reference_audit/2026-10-22-engine-upgrade/scripts/build_references_upgrade.py b/reference_audit/2026-10-22-engine-upgrade/scripts/build_references_upgrade.py index 00b39db4..5947f6b4 100644 --- a/reference_audit/2026-10-22-engine-upgrade/scripts/build_references_upgrade.py +++ b/reference_audit/2026-10-22-engine-upgrade/scripts/build_references_upgrade.py @@ -19,7 +19,7 @@ and the 49-record exclusion record, each file pinned by sha256. No release is being frozen with this build, so no release spec rules an exclusion: the record this script edits is the base's own. The next board release installs -the build (reference_audit/2026-10-22-engine-upgrade/build/); a release that +the build (reference_audit/2026-10-22-engine-upgrade/reference-build/); a release that rules exclusions of its own applies them after installing it. The original v1.1 frozen values (each change's "frozen") come from FROZEN_COMMIT. diff --git a/reference_audit/2026-10-22-engine-upgrade/scripts/sweep_timing.py b/reference_audit/2026-10-22-engine-upgrade/scripts/sweep_timing.py index 32048ccc..caf43812 100644 --- a/reference_audit/2026-10-22-engine-upgrade/scripts/sweep_timing.py +++ b/reference_audit/2026-10-22-engine-upgrade/scripts/sweep_timing.py @@ -30,7 +30,7 @@ Reads PyPI again. The build must be the committed one: its sidecar names the sweep's engine, pins its CSV and names the committed builder, its reference CSV, sidecar and exclusion record are the committed copy's byte - for byte (--snapshot: this audit's build/ directory while the build is + for byte (--snapshot: this audit's reference-build/ while the build is staged for the next board release, the snapshot once a release installs it; the default is the snapshot), and its computed.csv gives every scored reference, every value finite. When a newer release is out, check runs the check sweep @@ -81,7 +81,7 @@ SNAPSHOT = ROOT / "paper/snapshot/20260501/runs" / RUN BUILDER = AUDIT / "scripts" / "build_references_upgrade.py" # The staged copy of the build the next board release installs. -STAGED_BUILD = AUDIT / "build" +STAGED_BUILD = AUDIT / "reference-build" # The builder's arguments that name files or directories, and its flag. BUILDER_PATH_FLAGS = ( "--actions", diff --git a/reference_audit/2026-10-22-engine-upgrade/verification/sweep_timing.json b/reference_audit/2026-10-22-engine-upgrade/verification/sweep_timing.json index a200c0c1..a24fd097 100644 --- a/reference_audit/2026-10-22-engine-upgrade/verification/sweep_timing.json +++ b/reference_audit/2026-10-22-engine-upgrade/verification/sweep_timing.json @@ -2,7 +2,7 @@ "note": "When PolicyBench began sweeping the references for the 2026-10-22 move, which policyengine-us release was the newest then and at publication, and the publication check. Times are UTC. The PyPI upload times were read from the PyPI JSON API; the install and first-output times are filesystem birth times (st_birthtime) of the engine's dist-info directory and of the first file the sweep wrote.", "pypi": { "source": "https://pypi.org/pypi/policyengine-us/json", - "read_at_utc": "2026-10-23T02:11:36Z", + "read_at_utc": "2026-10-23T02:16:18Z", "newest_at_read": "2.60.0", "wheel_uploaded_at_utc": { "2.60.0": "2026-10-22T22:47:49.733557Z" @@ -28,13 +28,13 @@ "publication_check": { "engine": "2.60.0", "result": "policyengine-us 2.60.0, the reference engine, was still the newest release when PolicyBench read PyPI", - "build": "reference_audit/2026-10-22-engine-upgrade/build", + "build": "reference_audit/2026-10-22-engine-upgrade/reference-build", "build_sha256": { "computed.csv": "98b0257548477a69f8c9f3cbdd85bb6fdbc430529189821bcd45068672f06008", "reference_outputs.csv": "eab09a0c184c14b0c33679d9ac132d6f1de720c439ac30685a67ca38655184cb", - "reference_outputs.csv.meta.json": "a222c2de9b5c1fabe2c77e4acd27ca36b8961a9879f5aeaf529be5a5cabbadb4", + "reference_outputs.csv.meta.json": "3e0e42ecef728e97f8b46ed49cbd9f46cf2e570890e384042b7abd5c0b4dd3c1", "reference_exclusions.json": "91408c0f3d49e1984b436164a047f8cedc3e501feb2099ba0e7d2782ee8ac73d", - "builder": "2aa0a6b1e41fd067278303afeeea45de2ffe1bf4c2af797f532777bab587d89b" + "builder": "d4b00204390c6ada97bdf91358dc3d60ae3307d101062b8982fa62923cc9c645" }, "scored_outputs": 1935 } diff --git a/tests/test_build_references_upgrade_1022.py b/tests/test_build_references_upgrade_1022.py index 4e34ba66..7bd3dbe7 100644 --- a/tests/test_build_references_upgrade_1022.py +++ b/tests/test_build_references_upgrade_1022.py @@ -42,7 +42,7 @@ ROOT = Path(__file__).resolve().parents[1] UPGRADE = ROOT / "reference_audit" / "2026-10-22-engine-upgrade" -BUILD = UPGRADE / "build" +BUILD = UPGRADE / "reference-build" RUN_DIR = ( ROOT / "paper/snapshot/20260501/runs" diff --git a/tests/test_sweep_timing_1022.py b/tests/test_sweep_timing_1022.py index 69af4476..77362d08 100644 --- a/tests/test_sweep_timing_1022.py +++ b/tests/test_sweep_timing_1022.py @@ -2,7 +2,7 @@ 2026-10-22 engine move's timing record and publication check, on MOCK PyPI data. A copy of tests/test_sweep_timing_1012.py, which tests the 2026-10-12 audit's script, pointed at this audit's; the check also takes --snapshot, the -committed copy of the build it must equal (this audit's build/ while it is +committed copy of the build it must equal (this audit's reference-build/ while it is staged).""" import importlib.util @@ -353,16 +353,17 @@ def test_the_check_records_a_still_newest_engine(tmp_path, monkeypatch): def test_the_cli_check_takes_the_committed_copy_of_the_build(tmp_path, monkeypatch): - """MOCK: ``check --snapshot DIR`` holds the build to DIR (this audit's build/ - while the build is staged for the next board release); without it, the - build is held to the paper snapshot, which here it is not.""" + """MOCK: ``check --snapshot DIR`` holds the build to DIR (this audit's + reference-build/ while the build is staged for the next board release); + without it, the build is held to the paper snapshot, which here it is + not.""" build, snapshot = _check_setup(tmp_path, monkeypatch, ONLY_ENGINE) timing.main(["check", "--build", str(build), "--snapshot", str(snapshot)]) record = json.loads(timing.TIMING.read_text()) assert record["publication_check"]["engine"] == "2.38.4" with pytest.raises(timing.Refusal, match="is not the committed snapshot's"): timing.main(["check", "--build", str(build)]) - assert timing.STAGED_BUILD == timing.AUDIT / "build" + assert timing.STAGED_BUILD == timing.AUDIT / "reference-build" assert timing.BASE_ENGINE == "policyengine-us 2.41.0" From 830c7aec16fe02288b2b84cb8e325ac36d8e0fe4 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Thu, 22 Oct 2026 22:22:09 -0400 Subject: [PATCH 3/4] Check 2.60.0's release commit against the published wheel Built from source, 2bc4ccc970 gives a computed.csv byte-identical to the wheel's on all 1,984 outputs, as the 2026-10-12 audit checked for 2.41.0 (verification/release_commit_check.json, with a test). Co-Authored-By: Claude Opus 5.5 --- .../2026-10-22-engine-upgrade/README.md | 6 ++++-- .../verification/release_commit_check.json | 19 +++++++++++++++++++ tests/test_build_references_upgrade_1022.py | 15 +++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 reference_audit/2026-10-22-engine-upgrade/verification/release_commit_check.json diff --git a/reference_audit/2026-10-22-engine-upgrade/README.md b/reference_audit/2026-10-22-engine-upgrade/README.md index 6169da8a..319a34e5 100644 --- a/reference_audit/2026-10-22-engine-upgrade/README.md +++ b/reference_audit/2026-10-22-engine-upgrade/README.md @@ -40,7 +40,8 @@ get a free breakfast. `final_actions.json` gives each change's basis, with the f `reference-build/reference_traces.json`. Each named pull request (#10036, #10158, #10185 and #10238) is an ancestor of 2.60.0's release -commit, 2bc4ccc970. #10238 is not in 2.59.0's, 05813807e1. +commit, 2bc4ccc970. #10238 is not in 2.59.0's, 05813807e1. Built from source, that commit's +1,984 outputs are identical to the published wheel's (`verification/release_commit_check.json`). ## The r24 outputs stay excluded @@ -141,7 +142,8 @@ files or this build's. - `reference-build/`: the build. `computed.csv` is every output on 2.60.0, byte-identical to the sweep's first output. - `hand_corrected_narratives.json` and `.md`: the four changed outputs' reference narratives. -- `verification/sweep_timing.json` and `verification/superseded_2_59_0.json`. +- `verification/sweep_timing.json`, `verification/superseded_2_59_0.json` and + `verification/release_commit_check.json`. There is no `evidence/` or `fixes/` directory, because no regeneration here needs a `fix_modules` target. If a later one does, the 2026-10-12 audit's `check_against_evidence.py` diff --git a/reference_audit/2026-10-22-engine-upgrade/verification/release_commit_check.json b/reference_audit/2026-10-22-engine-upgrade/verification/release_commit_check.json new file mode 100644 index 00000000..8ce69f22 --- /dev/null +++ b/reference_audit/2026-10-22-engine-upgrade/verification/release_commit_check.json @@ -0,0 +1,19 @@ +{ + "note": "The published policyengine-us 2.60.0 wheel against its release commit. 2bc4ccc970 (\"Update PolicyEngine US\", the commit whose pyproject.toml first reads 2.60.0) was built from source into a fresh environment and run through scripts/sweep_timing.py run with empty draft actions, as the reference sweep was. Its computed.csv is byte-identical to the wheel's (reference-build/computed.csv): every one of the 1,984 outputs agrees. Each pull request this upgrade names (#10036, #10158, #10185, #10238) is an ancestor of the commit; #10238 is not an ancestor of 2.59.0's release commit, 05813807e1.", + "release_commit": "2bc4ccc970912798a67b054e718800dd93cf70b6", + "previous_release_commit_2_59_0": "05813807e1", + "engine_install": { + "version": "2.60.0", + "files_verified": 19508, + "editable": false, + "imported_from_package": true + }, + "computed_sha256": "98b0257548477a69f8c9f3cbdd85bb6fdbc430529189821bcd45068672f06008", + "wheel_computed_sha256": "98b0257548477a69f8c9f3cbdd85bb6fdbc430529189821bcd45068672f06008", + "ancestors": { + "PolicyEngine/policyengine-us#10036": "73d9c6ca0c", + "PolicyEngine/policyengine-us#10158": "f4b1644230", + "PolicyEngine/policyengine-us#10185": "b829c86733", + "PolicyEngine/policyengine-us#10238": "271d5e945b" + } +} diff --git a/tests/test_build_references_upgrade_1022.py b/tests/test_build_references_upgrade_1022.py index 7bd3dbe7..ad66db88 100644 --- a/tests/test_build_references_upgrade_1022.py +++ b/tests/test_build_references_upgrade_1022.py @@ -2371,3 +2371,18 @@ def test_the_superseded_sweep_differs_only_on_the_approved_school_meals(): (d["scenario_id"], d["variable"]) for d in doc["differ_2_59_0_vs_2_60_0"] } == {k for k in APPROVED if k[1] == "free_school_meals_eligible"} assert all(d["scored"] for d in doc["differ_2_59_0_vs_2_60_0"]) + + +def test_the_release_commit_gives_the_wheels_outputs(): + """Built from source, 2.60.0's release commit gives the published wheel's + computed.csv byte for byte.""" + doc = json.loads( + (UPGRADE / "verification" / "release_commit_check.json").read_text() + ) + assert doc["release_commit"].startswith("2bc4ccc970") + assert doc["engine_install"]["version"] == "2.60.0" + assert ( + doc["computed_sha256"] + == doc["wheel_computed_sha256"] + == build.sha256(BUILD / "computed.csv") + ) From 87f40d57a93907e8143a489f91203b6342fdd187 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Thu, 22 Oct 2026 22:32:42 -0400 Subject: [PATCH 4/4] State the breakfast statutes' conditions and both halves of 031's guideline Review r1 (GPT-6.1 Sol, APPROVE at 830c7aec) findings: 1. (minor) "every public school student" overstated both statutes. The bases and narratives now say Pennsylvania reimburses participating schools to the extent funds are available and Arkansas gives the breakfast on request, and that #10238 assumes a student at a covered school without either condition. 2. (nit) scenario_031's figures were January-September's. The basis and the narrative now give $1,304.17 and $2,608.33 through September and $1,330 and $2,660 from October; the household is eligible and gets $24 in every month. The build was run again on 2.60.0: the reference CSV, exclusion record, computed.csv and traces are byte-identical; the sidecar's actions sha256 and time change. Publication check rerun (2.60.0 still the newest release). Co-Authored-By: Claude Opus 5.5 --- .../2026-10-22-engine-upgrade/README.md | 8 +++-- .../actions_from_cells.py | 31 +++++++++++++------ .../final_actions.json | 8 ++--- .../hand_corrected_narratives.json | 8 ++--- .../hand_corrected_narratives.md | 4 +++ .../reference_outputs.csv.meta.json | 12 +++---- .../verification/sweep_timing.json | 4 +-- tests/test_build_references_upgrade_1022.py | 18 +++++++++-- 8 files changed, 63 insertions(+), 30 deletions(-) diff --git a/reference_audit/2026-10-22-engine-upgrade/README.md b/reference_audit/2026-10-22-engine-upgrade/README.md index 319a34e5..aa3947ee 100644 --- a/reference_audit/2026-10-22-engine-upgrade/README.md +++ b/reference_audit/2026-10-22-engine-upgrade/README.md @@ -34,6 +34,10 @@ All four come from law in force before the 2026-07-03 reference freeze. Californ dates from CDSS's 2011-2015 letters. Pennsylvania codified its breakfast program on 2023-12-13, and Arkansas's applies from the 2025-26 school year. Both are standing statutes. +Neither breakfast statute is unconditional. Pennsylvania reimburses participating schools to the +extent funds are available, and Arkansas gives the breakfast on request. #10238 assumes a student +at a covered school and models neither condition; the bases and narratives say so. + The school-meal output asks "whether PolicyEngine returns positive annual free school meal support". Each of these households is in the paid tier for lunch, but its K-12 children now get a free breakfast. `final_actions.json` gives each change's basis, with the figures from @@ -118,7 +122,7 @@ with `--check-venv` if a newer release is out. --hand-corrected hand_corrected_narratives.json --out ``` - On release 20261014's explanations this gives sha256 `a1691832…`. + On release 20261014's explanations this gives sha256 `47c33db0…`. 3. Re-score and re-freeze the board, then rerun the publication check. Judges' prompts render a case's reference value and narrative, so the cases on the four changed outputs are judged again. @@ -128,7 +132,7 @@ files or this build's. ## Files -- `final_actions.json`: the reviewed actions the build ran on. Its sha256, `a6a4e07b…`, is the +- `final_actions.json`: the reviewed actions the build ran on. Its sha256, `93fc088f…`, is the sidecar's `provenance.actions_sha256`. It is `actions_from_cells.py`'s draft with figures and upstream pull requests added to four bases and five reasons; no placement changed. - `actions_from_cells.py`: drafts the actions from a first pass. Its rules recognize the two diff --git a/reference_audit/2026-10-22-engine-upgrade/actions_from_cells.py b/reference_audit/2026-10-22-engine-upgrade/actions_from_cells.py index 2af78959..0110b0c6 100644 --- a/reference_audit/2026-10-22-engine-upgrade/actions_from_cells.py +++ b/reference_audit/2026-10-22-engine-upgrade/actions_from_cells.py @@ -106,14 +106,25 @@ def money(value: float) -> str: # 2017(a)), as policyengine-us carries it for every month of 2026 under the # pre-freeze conventions. SNAP_MIN_ALLOTMENT_2026 = 24.0 -# States whose free breakfast for every public school student #10238 models, +# States whose free breakfast regardless of household income #10238 models, # by standing statute in force for all of 2026, enacted before the -# 2026-07-03 reference freeze. +# 2026-07-03 reference freeze: what the statute provides, and the condition +# #10238 notes it does not model (it also assumes a student at a covered +# school). UNIVERSAL_BREAKFAST = { - "PA": "Pennsylvania Act 33 of 2023 (24 P.S. § 13-1337.1(c.2), codified " - "December 13, 2023)", - "AR": "Arkansas Act 123 of 2025 (SB 59; A.C.A. § 6-18-722(f)), from the " - "2025-26 school year,", + "PA": ( + "Pennsylvania Act 33 of 2023 (24 P.S. § 13-1337.1(c.2), codified December " + "13, 2023) provides a free breakfast to students at participating schools " + "regardless of household income, reimbursed to the extent funds are " + "available", + "the funding condition", + ), + "AR": ( + "Arkansas Act 123 of 2025 (SB 59; A.C.A. § 6-18-722(f)) gives each public " + "school student who does not otherwise receive a free breakfast one " + "breakfast a day at no cost, upon request, from the 2025-26 school year", + "the request condition", + ), } @@ -155,7 +166,7 @@ def _ca_mce_minimum_allotment(cell: Cell, engine: str, date: str) -> dict: def _state_universal_breakfast(cell: Cell, engine: str, date: str) -> dict: - law = UNIVERSAL_BREAKFAST[cell.state] + law, unmodeled = UNIVERSAL_BREAKFAST[cell.state] return { "action": "approved", "rule": "state_universal_free_breakfast", @@ -165,9 +176,9 @@ def _state_universal_breakfast(cell: Cell, engine: str, date: str) -> dict: "value": cell.new, "cause": "state_universal_free_breakfast_10238", "basis": ( - f"{law} gives every public school student a free breakfast " - f"regardless of household income. {BREAKFAST_PR} (Model state " - "school meal coverage beyond universal meals) models it: on " + f"{law}. {BREAKFAST_PR} (Model state school meal coverage beyond " + "universal meals) models it for a student enrolled at a covered " + f"school, without {unmodeled}: on " f"{engine} state_has_universal_free_school_breakfast is true for " f"{cell.state}, so the household's K-12 children take the free " "breakfast tier (school_meal_breakfast_tier) whatever their " diff --git a/reference_audit/2026-10-22-engine-upgrade/final_actions.json b/reference_audit/2026-10-22-engine-upgrade/final_actions.json index 5ec7a4dc..4d15d849 100644 --- a/reference_audit/2026-10-22-engine-upgrade/final_actions.json +++ b/reference_audit/2026-10-22-engine-upgrade/final_actions.json @@ -9,28 +9,28 @@ "variable": "free_school_meals_eligible", "value": 1.0, "cause": "state_universal_free_breakfast_10238", - "basis": "Pennsylvania Act 33 of 2023 (24 P.S. \u00a7 13-1337.1(c.2), codified December 13, 2023) gives every public school student a free breakfast regardless of household income. PolicyEngine/policyengine-us#10238 (Model state school meal coverage beyond universal meals) models it: on policyengine-us 2.60.0 state_has_universal_free_school_breakfast is true for PA, so the household's K-12 children take the free breakfast tier (school_meal_breakfast_tier) whatever their income while lunch stays in the paid tier (school_meal_lunch_tier), and free_school_meals is positive. Here its three K-12 children, at 186% of the poverty guideline, get $1,112.40 of free breakfast support for 2026. The output asks whether PolicyEngine returns positive annual free school meal support, so it is 1; on policyengine-us 2.41.0 the household's income put both meals in the paid tier and it was 0." + "basis": "Pennsylvania Act 33 of 2023 (24 P.S. \u00a7 13-1337.1(c.2), codified December 13, 2023) provides a free breakfast to students at participating schools regardless of household income, reimbursed to the extent funds are available. PolicyEngine/policyengine-us#10238 (Model state school meal coverage beyond universal meals) models it for a student enrolled at a covered school, without the funding condition: on policyengine-us 2.60.0 state_has_universal_free_school_breakfast is true for PA, so the household's K-12 children take the free breakfast tier (school_meal_breakfast_tier) whatever their income while lunch stays in the paid tier (school_meal_lunch_tier), and free_school_meals is positive. Here its three K-12 children, at 186% of the poverty guideline, get $1,112.40 of free breakfast support for 2026. The output asks whether PolicyEngine returns positive annual free school meal support, so it is 1; on policyengine-us 2.41.0 the household's income put both meals in the paid tier and it was 0." }, { "scenario_id": "scenario_031", "variable": "snap", "value": 288.0, "cause": "ca_snap_mce_no_net_income_test_10036", - "basis": "California's Modified Categorical Eligibility (MCE) makes a household with gross income within 200% of the poverty guideline categorically eligible for CalFresh without the net income test, elderly or disabled households included (CDSS ACL 12-62, 13-32, 14-56 and 15-42; 7 CFR 273.2(j)(2)), and gives an eligible one- or two-person household the minimum allotment (CDSS MCE letter, June 30, 2014; 7 U.S.C. 2017(a); 7 CFR 273.10(e)(2)(ii)(C)). policyengine-us 2.41.0 applied the net income test to MCE households with an elderly or disabled member, so this one-person household, an elderly member with $1,987.79 of monthly gross income (within the $2,608.33 MCE limit) and $1,611 of net income (above the $1,304.17 guideline), was ineligible and its SNAP was $0. PolicyEngine/policyengine-us#10036 (Remove the BBCE net income test from California's Modified Categorical Eligibility) drops that test; on policyengine-us 2.60.0 the household is categorically eligible and its calculated allotment, the $298 maximum less 30% of net income ($484), is below the $24 minimum, so it receives $24 a month (snap_min_allotment): $288.00 for 2026." + "basis": "California's Modified Categorical Eligibility (MCE) makes a household with gross income within 200% of the poverty guideline categorically eligible for CalFresh without the net income test, elderly or disabled households included (CDSS ACL 12-62, 13-32, 14-56 and 15-42; 7 CFR 273.2(j)(2)), and gives an eligible one- or two-person household the minimum allotment (CDSS MCE letter, June 30, 2014; 7 U.S.C. 2017(a); 7 CFR 273.10(e)(2)(ii)(C)). policyengine-us 2.41.0 applied the net income test to MCE households with an elderly or disabled member, so this one-person household, an elderly member with $1,987.79 of monthly gross income (within the MCE limit, $2,608.33 a month through September and $2,660 from October) and $1,611 of net income (above the $1,304.17 and $1,330 monthly guidelines), was ineligible and its SNAP was $0. PolicyEngine/policyengine-us#10036 (Remove the BBCE net income test from California's Modified Categorical Eligibility) drops that test; on policyengine-us 2.60.0 the household is categorically eligible and its calculated allotment, the $298 maximum less 30% of net income ($484), is below the $24 minimum, so it receives $24 a month (snap_min_allotment): $288.00 for 2026." }, { "scenario_id": "scenario_117", "variable": "free_school_meals_eligible", "value": 1.0, "cause": "state_universal_free_breakfast_10238", - "basis": "Arkansas Act 123 of 2025 (SB 59; A.C.A. \u00a7 6-18-722(f)), from the 2025-26 school year, gives every public school student a free breakfast regardless of household income. PolicyEngine/policyengine-us#10238 (Model state school meal coverage beyond universal meals) models it: on policyengine-us 2.60.0 state_has_universal_free_school_breakfast is true for AR, so the household's K-12 children take the free breakfast tier (school_meal_breakfast_tier) whatever their income while lunch stays in the paid tier (school_meal_lunch_tier), and free_school_meals is positive. Here its two K-12 children, at 643% of the poverty guideline, get $741.60 of free breakfast support for 2026. The output asks whether PolicyEngine returns positive annual free school meal support, so it is 1; on policyengine-us 2.41.0 the household's income put both meals in the paid tier and it was 0." + "basis": "Arkansas Act 123 of 2025 (SB 59; A.C.A. \u00a7 6-18-722(f)) gives each public school student who does not otherwise receive a free breakfast one breakfast a day at no cost, upon request, from the 2025-26 school year. PolicyEngine/policyengine-us#10238 (Model state school meal coverage beyond universal meals) models it for a student enrolled at a covered school, without the request condition: on policyengine-us 2.60.0 state_has_universal_free_school_breakfast is true for AR, so the household's K-12 children take the free breakfast tier (school_meal_breakfast_tier) whatever their income while lunch stays in the paid tier (school_meal_lunch_tier), and free_school_meals is positive. Here its two K-12 children, at 643% of the poverty guideline, get $741.60 of free breakfast support for 2026. The output asks whether PolicyEngine returns positive annual free school meal support, so it is 1; on policyengine-us 2.41.0 the household's income put both meals in the paid tier and it was 0." }, { "scenario_id": "scenario_123", "variable": "free_school_meals_eligible", "value": 1.0, "cause": "state_universal_free_breakfast_10238", - "basis": "Pennsylvania Act 33 of 2023 (24 P.S. \u00a7 13-1337.1(c.2), codified December 13, 2023) gives every public school student a free breakfast regardless of household income. PolicyEngine/policyengine-us#10238 (Model state school meal coverage beyond universal meals) models it: on policyengine-us 2.60.0 state_has_universal_free_school_breakfast is true for PA, so the household's K-12 children take the free breakfast tier (school_meal_breakfast_tier) whatever their income while lunch stays in the paid tier (school_meal_lunch_tier), and free_school_meals is positive. Here its one K-12 child, at 531% of the poverty guideline, gets $370.80 of free breakfast support for 2026. The output asks whether PolicyEngine returns positive annual free school meal support, so it is 1; on policyengine-us 2.41.0 the household's income put both meals in the paid tier and it was 0." + "basis": "Pennsylvania Act 33 of 2023 (24 P.S. \u00a7 13-1337.1(c.2), codified December 13, 2023) provides a free breakfast to students at participating schools regardless of household income, reimbursed to the extent funds are available. PolicyEngine/policyengine-us#10238 (Model state school meal coverage beyond universal meals) models it for a student enrolled at a covered school, without the funding condition: on policyengine-us 2.60.0 state_has_universal_free_school_breakfast is true for PA, so the household's K-12 children take the free breakfast tier (school_meal_breakfast_tier) whatever their income while lunch stays in the paid tier (school_meal_lunch_tier), and free_school_meals is positive. Here its one K-12 child, at 531% of the poverty guideline, gets $370.80 of free breakfast support for 2026. The output asks whether PolicyEngine returns positive annual free school meal support, so it is 1; on policyengine-us 2.41.0 the household's income put both meals in the paid tier and it was 0." } ], "regenerated_exclusions": [], diff --git a/reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.json b/reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.json index 21ae708a..ffb7ef22 100644 --- a/reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.json +++ b/reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.json @@ -1,6 +1,6 @@ { - "scenario_028|free_school_meals_eligible": "PolicyEngine determined that this Pennsylvania household of four receives free school meal support in 2026, so the value is 1. School meals count the household's income of $61,277: $60,000 of wages, $10 of interest and $1,267 of child support received. That is 1.86 times the $33,000 poverty guideline for a household of four, above the 185% limit for reduced-price meals, so on income alone both meals are in the paid tier. Pennsylvania gives every public school student a free breakfast regardless of household income (Act 33 of 2023, 24 P.S. § 13-1337.1(c.2)), so breakfast is in the free tier for the household's three K-12 children while lunch stays paid. PolicyEngine values that breakfast at $1,112.40 for the year: $2.06 a school day for each child (the $2.90 daily subsidy less the $0.84 paid-meal rate) over 180 school days. That free school meal support is positive, so the value is 1.", - "scenario_031|snap": "PolicyEngine calculated a SNAP benefit of $288 for this California household in 2026: the $24 monthly minimum allotment for each of the twelve months. The household is one 67-year-old, so the elderly-or-disabled rules apply. Its countable gross income is $1,987.79 a month ($9,445.47 of Social Security, $13,608.00 of private pension income and $800.00 of IRA distributions a year), within the $2,608.33 limit of California's Modified Categorical Eligibility (200% of the $1,304.17 monthly poverty guideline for one person), and its $4,200 of bank assets pass the asset test. That makes the household categorically eligible for CalFresh, which waives the net income test, so its net income of $1,611 a month, above the poverty guideline, does not disqualify it. The benefit formula gives the $298 maximum allotment less 30% of net income ($484), which is below zero, so as an eligible one-person household it receives the $24 minimum allotment (7 U.S.C. 2017(a)) each month: $288 for the year.", - "scenario_117|free_school_meals_eligible": "PolicyEngine determined that this Arkansas household of five receives free school meal support in 2026, so the value is 1. School meals count the household's $248,675 of wages, 6.43 times the $38,680 poverty guideline for a household of five, so on income alone both meals are in the paid tier. Arkansas gives every public school student a free breakfast regardless of household income from the 2025-26 school year (Act 123 of 2025, A.C.A. § 6-18-722(f)), so breakfast is in the free tier for the household's two K-12 children while lunch stays paid. PolicyEngine values that breakfast at $741.60 for the year: $2.06 a school day for each child (the $2.90 daily subsidy less the $0.84 paid-meal rate) over 180 school days. That free school meal support is positive, so the value is 1.", - "scenario_123|free_school_meals_eligible": "PolicyEngine determined that this Pennsylvania household of three receives free school meal support in 2026, so the value is 1. School meals count the household's income of $145,002: $145,000 of wages and $2 of interest. That is 5.31 times the $27,320 poverty guideline for a household of three, so on income alone both meals are in the paid tier. Pennsylvania gives every public school student a free breakfast regardless of household income (Act 33 of 2023, 24 P.S. § 13-1337.1(c.2)), so breakfast is in the free tier for the household's one K-12 student, the 16-year-old, while lunch stays paid. PolicyEngine values that breakfast at $370.80 for the year: $2.06 a school day (the $2.90 daily subsidy less the $0.84 paid-meal rate) over 180 school days. That free school meal support is positive, so the value is 1." + "scenario_028|free_school_meals_eligible": "PolicyEngine determined that this Pennsylvania household of four receives free school meal support in 2026, so the value is 1. School meals count the household's income of $61,277: $60,000 of wages, $10 of interest and $1,267 of child support received. That is 1.86 times the $33,000 poverty guideline for a household of four, above the 185% limit for reduced-price meals, so on income alone both meals are in the paid tier. Pennsylvania provides a free breakfast to students at participating schools regardless of household income, reimbursed to the extent funds are available (Act 33 of 2023, 24 P.S. § 13-1337.1(c.2)), and PolicyEngine assumes the children attend such a school, so breakfast is in the free tier for the household's three K-12 children while lunch stays paid. PolicyEngine values that breakfast at $1,112.40 for the year: $2.06 a school day for each child (the $2.90 daily subsidy less the $0.84 paid-meal rate) over 180 school days. That free school meal support is positive, so the value is 1.", + "scenario_031|snap": "PolicyEngine calculated a SNAP benefit of $288 for this California household in 2026: the $24 monthly minimum allotment for each of the twelve months. The household is one 67-year-old, so the elderly-or-disabled rules apply. Its countable gross income is $1,987.79 a month ($9,445.47 of Social Security, $13,608.00 of private pension income and $800.00 of IRA distributions a year), within the limit of California's Modified Categorical Eligibility, 200% of the monthly poverty guideline for one person ($2,608.33 on the $1,304.17 guideline through September, $2,660 on the $1,330 guideline from October), and its $4,200 of bank assets pass the asset test. That makes the household categorically eligible for CalFresh, which waives the net income test, so its net income of $1,611 a month, above the guideline in every month, does not disqualify it. The benefit formula gives the $298 maximum allotment less 30% of net income ($484), which is below zero, so as an eligible one-person household it receives the $24 minimum allotment (7 U.S.C. 2017(a)) each month: $288 for the year.", + "scenario_117|free_school_meals_eligible": "PolicyEngine determined that this Arkansas household of five receives free school meal support in 2026, so the value is 1. School meals count the household's $248,675 of wages, 6.43 times the $38,680 poverty guideline for a household of five, so on income alone both meals are in the paid tier. From the 2025-26 school year Arkansas gives each public school student who does not otherwise receive a free breakfast one breakfast a day at no cost, on request (Act 123 of 2025, A.C.A. § 6-18-722(f)), and PolicyEngine assumes the children take it, so breakfast is in the free tier for the household's two K-12 children while lunch stays paid. PolicyEngine values that breakfast at $741.60 for the year: $2.06 a school day for each child (the $2.90 daily subsidy less the $0.84 paid-meal rate) over 180 school days. That free school meal support is positive, so the value is 1.", + "scenario_123|free_school_meals_eligible": "PolicyEngine determined that this Pennsylvania household of three receives free school meal support in 2026, so the value is 1. School meals count the household's income of $145,002: $145,000 of wages and $2 of interest. That is 5.31 times the $27,320 poverty guideline for a household of three, so on income alone both meals are in the paid tier. Pennsylvania provides a free breakfast to students at participating schools regardless of household income, reimbursed to the extent funds are available (Act 33 of 2023, 24 P.S. § 13-1337.1(c.2)), and PolicyEngine assumes the household's one K-12 student, the 16-year-old, attends such a school, so breakfast is in the free tier while lunch stays paid. PolicyEngine values that breakfast at $370.80 for the year: $2.06 a school day (the $2.90 daily subsidy less the $0.84 paid-meal rate) over 180 school days. That free school meal support is positive, so the value is 1." } diff --git a/reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.md b/reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.md index c370e4e9..c7cf81c2 100644 --- a/reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.md +++ b/reference_audit/2026-10-22-engine-upgrade/hand_corrected_narratives.md @@ -6,6 +6,10 @@ not called. The 2026-10-12 upgrade's writer misstated the change behind six of its nine outputs. Each text states figures from the 2.60.0 build's traces (`reference-build/reference_traces.json`). +scenario_031's states both halves of the year's poverty guideline ($1,304.17 through September, +$1,330 from October) and the MCE limit on each. The school-meal texts state each breakfast +statute's condition (Pennsylvania's funding, Arkansas's request) and that PolicyEngine assumes +it is met. `tests/test_build_references_upgrade_1022.py` checks each figure against the trace and recomputes every sum the texts state. Each rule a text names is the one the upstream pull request encodes, with its law: #10036 for California's MCE, and #10238 for the Pennsylvania and diff --git a/reference_audit/2026-10-22-engine-upgrade/reference-build/reference_outputs.csv.meta.json b/reference_audit/2026-10-22-engine-upgrade/reference-build/reference_outputs.csv.meta.json index e01a24a2..51895ffb 100644 --- a/reference_audit/2026-10-22-engine-upgrade/reference-build/reference_outputs.csv.meta.json +++ b/reference_audit/2026-10-22-engine-upgrade/reference-build/reference_outputs.csv.meta.json @@ -2967,7 +2967,7 @@ "builder_sha256": "d4b00204390c6ada97bdf91358dc3d60ae3307d101062b8982fa62923cc9c645", "harness": "reference_audit/2026-09-28/scripts/sweep.py", "harness_sha256": "f4c7783453a473a1bedcf64ef554c3a2fc29f9d663626948d920ed3ef2ea2b69", - "actions_sha256": "a6a4e07b91eb9376f655fd43434fbbd7de9f0ea3b16939d41fb934c9ccdc10b4", + "actions_sha256": "93fc088f0d2617e9e6d5bf5f0b65e4e8709d46bdd64da12e5cb9d92c06c8fd21", "base_commit": "bf845cbe4e92de495150c8660c35ea357d996a8c", "policyengine_core": "3.32.29" }, @@ -3096,7 +3096,7 @@ "previous": 0.0, "regenerated": 1.0, "cause": "state_universal_free_breakfast_10238", - "basis": "Pennsylvania Act 33 of 2023 (24 P.S. \u00a7 13-1337.1(c.2), codified December 13, 2023) gives every public school student a free breakfast regardless of household income. PolicyEngine/policyengine-us#10238 (Model state school meal coverage beyond universal meals) models it: on policyengine-us 2.60.0 state_has_universal_free_school_breakfast is true for PA, so the household's K-12 children take the free breakfast tier (school_meal_breakfast_tier) whatever their income while lunch stays in the paid tier (school_meal_lunch_tier), and free_school_meals is positive. Here its three K-12 children, at 186% of the poverty guideline, get $1,112.40 of free breakfast support for 2026. The output asks whether PolicyEngine returns positive annual free school meal support, so it is 1; on policyengine-us 2.41.0 the household's income put both meals in the paid tier and it was 0." + "basis": "Pennsylvania Act 33 of 2023 (24 P.S. \u00a7 13-1337.1(c.2), codified December 13, 2023) provides a free breakfast to students at participating schools regardless of household income, reimbursed to the extent funds are available. PolicyEngine/policyengine-us#10238 (Model state school meal coverage beyond universal meals) models it for a student enrolled at a covered school, without the funding condition: on policyengine-us 2.60.0 state_has_universal_free_school_breakfast is true for PA, so the household's K-12 children take the free breakfast tier (school_meal_breakfast_tier) whatever their income while lunch stays in the paid tier (school_meal_lunch_tier), and free_school_meals is positive. Here its three K-12 children, at 186% of the poverty guideline, get $1,112.40 of free breakfast support for 2026. The output asks whether PolicyEngine returns positive annual free school meal support, so it is 1; on policyengine-us 2.41.0 the household's income put both meals in the paid tier and it was 0." }, { "scenario_id": "scenario_031", @@ -3105,7 +3105,7 @@ "previous": 0.0, "regenerated": 288.0, "cause": "ca_snap_mce_no_net_income_test_10036", - "basis": "California's Modified Categorical Eligibility (MCE) makes a household with gross income within 200% of the poverty guideline categorically eligible for CalFresh without the net income test, elderly or disabled households included (CDSS ACL 12-62, 13-32, 14-56 and 15-42; 7 CFR 273.2(j)(2)), and gives an eligible one- or two-person household the minimum allotment (CDSS MCE letter, June 30, 2014; 7 U.S.C. 2017(a); 7 CFR 273.10(e)(2)(ii)(C)). policyengine-us 2.41.0 applied the net income test to MCE households with an elderly or disabled member, so this one-person household, an elderly member with $1,987.79 of monthly gross income (within the $2,608.33 MCE limit) and $1,611 of net income (above the $1,304.17 guideline), was ineligible and its SNAP was $0. PolicyEngine/policyengine-us#10036 (Remove the BBCE net income test from California's Modified Categorical Eligibility) drops that test; on policyengine-us 2.60.0 the household is categorically eligible and its calculated allotment, the $298 maximum less 30% of net income ($484), is below the $24 minimum, so it receives $24 a month (snap_min_allotment): $288.00 for 2026." + "basis": "California's Modified Categorical Eligibility (MCE) makes a household with gross income within 200% of the poverty guideline categorically eligible for CalFresh without the net income test, elderly or disabled households included (CDSS ACL 12-62, 13-32, 14-56 and 15-42; 7 CFR 273.2(j)(2)), and gives an eligible one- or two-person household the minimum allotment (CDSS MCE letter, June 30, 2014; 7 U.S.C. 2017(a); 7 CFR 273.10(e)(2)(ii)(C)). policyengine-us 2.41.0 applied the net income test to MCE households with an elderly or disabled member, so this one-person household, an elderly member with $1,987.79 of monthly gross income (within the MCE limit, $2,608.33 a month through September and $2,660 from October) and $1,611 of net income (above the $1,304.17 and $1,330 monthly guidelines), was ineligible and its SNAP was $0. PolicyEngine/policyengine-us#10036 (Remove the BBCE net income test from California's Modified Categorical Eligibility) drops that test; on policyengine-us 2.60.0 the household is categorically eligible and its calculated allotment, the $298 maximum less 30% of net income ($484), is below the $24 minimum, so it receives $24 a month (snap_min_allotment): $288.00 for 2026." }, { "scenario_id": "scenario_117", @@ -3114,7 +3114,7 @@ "previous": 0.0, "regenerated": 1.0, "cause": "state_universal_free_breakfast_10238", - "basis": "Arkansas Act 123 of 2025 (SB 59; A.C.A. \u00a7 6-18-722(f)), from the 2025-26 school year, gives every public school student a free breakfast regardless of household income. PolicyEngine/policyengine-us#10238 (Model state school meal coverage beyond universal meals) models it: on policyengine-us 2.60.0 state_has_universal_free_school_breakfast is true for AR, so the household's K-12 children take the free breakfast tier (school_meal_breakfast_tier) whatever their income while lunch stays in the paid tier (school_meal_lunch_tier), and free_school_meals is positive. Here its two K-12 children, at 643% of the poverty guideline, get $741.60 of free breakfast support for 2026. The output asks whether PolicyEngine returns positive annual free school meal support, so it is 1; on policyengine-us 2.41.0 the household's income put both meals in the paid tier and it was 0." + "basis": "Arkansas Act 123 of 2025 (SB 59; A.C.A. \u00a7 6-18-722(f)) gives each public school student who does not otherwise receive a free breakfast one breakfast a day at no cost, upon request, from the 2025-26 school year. PolicyEngine/policyengine-us#10238 (Model state school meal coverage beyond universal meals) models it for a student enrolled at a covered school, without the request condition: on policyengine-us 2.60.0 state_has_universal_free_school_breakfast is true for AR, so the household's K-12 children take the free breakfast tier (school_meal_breakfast_tier) whatever their income while lunch stays in the paid tier (school_meal_lunch_tier), and free_school_meals is positive. Here its two K-12 children, at 643% of the poverty guideline, get $741.60 of free breakfast support for 2026. The output asks whether PolicyEngine returns positive annual free school meal support, so it is 1; on policyengine-us 2.41.0 the household's income put both meals in the paid tier and it was 0." }, { "scenario_id": "scenario_123", @@ -3123,10 +3123,10 @@ "previous": 0.0, "regenerated": 1.0, "cause": "state_universal_free_breakfast_10238", - "basis": "Pennsylvania Act 33 of 2023 (24 P.S. \u00a7 13-1337.1(c.2), codified December 13, 2023) gives every public school student a free breakfast regardless of household income. PolicyEngine/policyengine-us#10238 (Model state school meal coverage beyond universal meals) models it: on policyengine-us 2.60.0 state_has_universal_free_school_breakfast is true for PA, so the household's K-12 children take the free breakfast tier (school_meal_breakfast_tier) whatever their income while lunch stays in the paid tier (school_meal_lunch_tier), and free_school_meals is positive. Here its one K-12 child, at 531% of the poverty guideline, gets $370.80 of free breakfast support for 2026. The output asks whether PolicyEngine returns positive annual free school meal support, so it is 1; on policyengine-us 2.41.0 the household's income put both meals in the paid tier and it was 0." + "basis": "Pennsylvania Act 33 of 2023 (24 P.S. \u00a7 13-1337.1(c.2), codified December 13, 2023) provides a free breakfast to students at participating schools regardless of household income, reimbursed to the extent funds are available. PolicyEngine/policyengine-us#10238 (Model state school meal coverage beyond universal meals) models it for a student enrolled at a covered school, without the funding condition: on policyengine-us 2.60.0 state_has_universal_free_school_breakfast is true for PA, so the household's K-12 children take the free breakfast tier (school_meal_breakfast_tier) whatever their income while lunch stays in the paid tier (school_meal_lunch_tier), and free_school_meals is positive. Here its one K-12 child, at 531% of the poverty guideline, gets $370.80 of free breakfast support for 2026. The output asks whether PolicyEngine returns positive annual free school meal support, so it is 1; on policyengine-us 2.41.0 the household's income put both meals in the paid tier and it was 0." } ] } ], - "regenerated_at_utc": "2026-10-23T02:16:15.575879+00:00" + "regenerated_at_utc": "2026-10-23T02:31:08.391848+00:00" } diff --git a/reference_audit/2026-10-22-engine-upgrade/verification/sweep_timing.json b/reference_audit/2026-10-22-engine-upgrade/verification/sweep_timing.json index a24fd097..0b4c989b 100644 --- a/reference_audit/2026-10-22-engine-upgrade/verification/sweep_timing.json +++ b/reference_audit/2026-10-22-engine-upgrade/verification/sweep_timing.json @@ -2,7 +2,7 @@ "note": "When PolicyBench began sweeping the references for the 2026-10-22 move, which policyengine-us release was the newest then and at publication, and the publication check. Times are UTC. The PyPI upload times were read from the PyPI JSON API; the install and first-output times are filesystem birth times (st_birthtime) of the engine's dist-info directory and of the first file the sweep wrote.", "pypi": { "source": "https://pypi.org/pypi/policyengine-us/json", - "read_at_utc": "2026-10-23T02:16:18Z", + "read_at_utc": "2026-10-23T02:31:23Z", "newest_at_read": "2.60.0", "wheel_uploaded_at_utc": { "2.60.0": "2026-10-22T22:47:49.733557Z" @@ -32,7 +32,7 @@ "build_sha256": { "computed.csv": "98b0257548477a69f8c9f3cbdd85bb6fdbc430529189821bcd45068672f06008", "reference_outputs.csv": "eab09a0c184c14b0c33679d9ac132d6f1de720c439ac30685a67ca38655184cb", - "reference_outputs.csv.meta.json": "3e0e42ecef728e97f8b46ed49cbd9f46cf2e570890e384042b7abd5c0b4dd3c1", + "reference_outputs.csv.meta.json": "55c17fe298f9ac09ff56b2187d1d314ede7d239e94924da6abb6e0ad2542260c", "reference_exclusions.json": "91408c0f3d49e1984b436164a047f8cedc3e501feb2099ba0e7d2782ee8ac73d", "builder": "d4b00204390c6ada97bdf91358dc3d60ae3307d101062b8982fa62923cc9c645" }, diff --git a/tests/test_build_references_upgrade_1022.py b/tests/test_build_references_upgrade_1022.py index ad66db88..2d368dbb 100644 --- a/tests/test_build_references_upgrade_1022.py +++ b/tests/test_build_references_upgrade_1022.py @@ -2045,7 +2045,7 @@ def test_the_draft_places_every_moved_output_exactly_once(moved): } # narratives_upgrade.py with hand_corrected_narratives.json on this build and # release 20261014's explanations (no writer call). -EXPLANATIONS_SHA256 = "a1691832890b9f6b9140ff1df199421cb7d8179b971cbb8cee19bc0333b682a4" +EXPLANATIONS_SHA256 = "47c33db094072c97ca18bb763526767c9fc23ecc50d153951be54b43182bc5e4" EXPLANATIONS_PATH = ( "annotations/us_full_run_20260612_policyengine_4_16_1_populace/" "us_case_reference_explanations.csv" @@ -2274,12 +2274,26 @@ def refuse(**_): assert {(r[0], r[1]) for r in results} == set(APPROVED) figures = { "scenario_031|snap": ( - ["$288", "$24", "$1,987.79", "$2,608.33", "$1,611", "$298", "$484"], + [ + "$288", + "$24", + "$1,987.79", + "$2,608.33", + "$1,304.17", + "$2,660", + "$1,330", + "$1,611", + "$298", + "$484", + ], [ "snap = 288", "snap_min_allotment = 24", "snap_net_income = 1611", "tanf_non_cash_gross_income_limit = 2608.33", + "tanf_non_cash_gross_income_limit = 2660", + "snap_fpg = 1304.17", + "snap_fpg = 1330", "snap_expected_contribution = 484", "snap_max_allotment = 298", ],