From eee0c525973e6986d2add537a6b1b5851199df36 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sun, 11 Oct 2026 20:11:52 -0400 Subject: [PATCH 1/6] Derive raw-PUF partnership SE earnings with the archived formula The raw-column fallback in puf_support._person_source_values returned E25960 + E26180 for partnership_self_employment_net_earnings: the partnership loss leg plus the S corporation loss leg, the same two columns the function subtracts a few lines above to build partnership_income and s_corp_income. Port the archived processed-PUF derivation instead (policyengine-us-data 42ed5d45, datasets/puf/puf.py lines 723-746): (E30400 + E30500) / 0.9235 - (E00900 + E02100) where E25940 + E25980 - E25920 - E25960 is nonzero, else zero. All eight columns are required, so a raw PUF carrying only some of them derives nothing and the donor build fails closed. The certified default is unaffected: its pinned processed_puf carries partnership_se_income and no raw E-columns, so it takes the alias branch. Spec-engine pins that attest puf_support.py's bytes follow in the next commit. Co-Authored-By: Claude Opus 5.5 --- ...x-raw-puf-partnership-se-fallback.fixed.md | 1 + .../microcosm/build/us_runtime/puf_support.py | 74 ++- .../test_us_puf_partnership_se_derivation.py | 425 ++++++++++++++++++ .../engine_free/us/test_us_puf_support.py | 15 +- 4 files changed, 509 insertions(+), 6 deletions(-) create mode 100644 changelog.d/fix-raw-puf-partnership-se-fallback.fixed.md create mode 100644 packages/microcosm-build/tests/engine_free/us/test_us_puf_partnership_se_derivation.py diff --git a/changelog.d/fix-raw-puf-partnership-se-fallback.fixed.md b/changelog.d/fix-raw-puf-partnership-se-fallback.fixed.md new file mode 100644 index 0000000000..2da439cf80 --- /dev/null +++ b/changelog.d/fix-raw-puf-partnership-se-fallback.fixed.md @@ -0,0 +1 @@ +Derive `partnership_self_employment_net_earnings` from a raw PUF with the archived pipeline's Schedule SE residual instead of the sum of partnership and S corporation losses, and fail closed when a raw PUF lacks any of its eight input columns. The certified default reads the processed donor's `partnership_se_income` column and is unchanged. diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/puf_support.py b/packages/microcosm-build/src/microcosm/build/us_runtime/puf_support.py index 6d609532a9..3016aec488 100644 --- a/packages/microcosm-build/src/microcosm/build/us_runtime/puf_support.py +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/puf_support.py @@ -607,6 +607,23 @@ def puf_tax_detail_tail_bound_quantiles_identity() -> dict[str, float]: } # The omitted 13.7% E17500 share represented reported Medicare Part B premiums. # Do not redistribute it: the engine computes its distinct singular Part B output. +# Raw-PUF inputs of the archived partnership self-employment derivation +# (:func:`_puf_partnership_se_net_earnings_from_raw_columns`). All eight are +# required: a raw PUF carrying only some of them derives nothing, so the donor +# build fails closed instead of substituting a different quantity. +_PUF_PARTNERSHIP_SE_RAW_COLUMNS = ( + "E30400", + "E30500", + "E00900", + "E02100", + "E25920", + "E25940", + "E25960", + "E25980", +) +# The archived pipeline's ``SE_DEDUCTION_FACTOR``: it treats E30400 and E30500 +# as already multiplied by this factor and divides it back out. +_PUF_SE_NET_EARNINGS_FACTOR = 0.9235 _PUF_PREDICTOR_PREFIX = "puf_predictor_" @@ -4265,11 +4282,10 @@ def _person_source_values( return _numeric_array(arrays["E25980"]) - _numeric_array(arrays["E25960"]) if output == "s_corp_income" and {"E26190", "E26180"}.issubset(arrays): return _numeric_array(arrays["E26190"]) - _numeric_array(arrays["E26180"]) - if output == "partnership_self_employment_net_earnings" and { - "E25960", - "E26180", - }.issubset(arrays): - return _numeric_array(arrays["E25960"]) + _numeric_array(arrays["E26180"]) + if output == "partnership_self_employment_net_earnings" and set( + _PUF_PARTNERSHIP_SE_RAW_COLUMNS + ).issubset(arrays): + return _puf_partnership_se_net_earnings_from_raw_columns(arrays) if output in _PUF_MEDICAL_EXPENSE_CATEGORY_BREAKDOWNS and "E17500" in arrays: return ( _numeric_array(arrays["E17500"]) @@ -4296,6 +4312,54 @@ def _person_source_values( return None +def _puf_partnership_se_net_earnings_from_raw_columns( + arrays: Mapping[str, Sequence[Any]], +) -> np.ndarray: + """Derive partnership self-employment net earnings from raw PUF columns. + + This ports, operation for operation, the derivation the archived + processed-PUF pipeline used for this leaf (PolicyEngine/policyengine-us-data + at 42ed5d45c56df80d754fbe24cce21cfeb8d05cbe, + ``policyengine_us_data/datasets/puf/puf.py`` lines 723-746), which matches + ``part_se`` in Yale Budget Lab Tax-Data's ``src/process_puf.R``. It is a + residual, not a read of a Schedule K-1 box 14 field: gross self-employment + earnings less the Schedule C and Schedule F amounts. + + The column meanings below are the archived pipeline's own; this module does + not check them against the PUF documentation: + + * ``E30400`` and ``E30500``: the taxpayer's and the spouse's taxable + self-employment income, already multiplied by 0.9235. Their sum is + divided by that factor to recover gross self-employment earnings. + * ``E00900`` and ``E02100``: Schedule C net profit or loss and Schedule F + farm income, subtracted from the gross amount. + * ``E25940 + E25980 - E25920 - E25960``: net partnership income. A record + where it is exactly zero has no partnership activity and gets zero. + + No S corporation column (``E26180``, ``E26190``) enters the derivation. A + missing or nonnumeric value counts as zero, as the archived ``fillna(0)`` + did. + + Args: + arrays: Mapping carrying every column of + ``_PUF_PARTNERSHIP_SE_RAW_COLUMNS`` at one common grain. + + Returns: + Partnership self-employment net earnings, one value per input row. + """ + + raw = { + column: _numeric_array(arrays[column]) + for column in _PUF_PARTNERSHIP_SE_RAW_COLUMNS + } + gross_se = (raw["E30400"] + raw["E30500"]) / _PUF_SE_NET_EARNINGS_FACTOR + schedule_c_f_income = raw["E00900"] + raw["E02100"] + has_partnership = ( + raw["E25940"] + raw["E25980"] - raw["E25920"] - raw["E25960"] + ) != 0 + return np.where(has_partnership, gross_se - schedule_c_f_income, 0.0) + + _TAX_UNIT_ROLE_COLUMN = "tax_unit_role_input" _TAX_UNIT_ROLES = ("HEAD", "SPOUSE", "DEPENDENT") diff --git a/packages/microcosm-build/tests/engine_free/us/test_us_puf_partnership_se_derivation.py b/packages/microcosm-build/tests/engine_free/us/test_us_puf_partnership_se_derivation.py new file mode 100644 index 0000000000..f32d0b8622 --- /dev/null +++ b/packages/microcosm-build/tests/engine_free/us/test_us_puf_partnership_se_derivation.py @@ -0,0 +1,425 @@ +"""The raw-PUF derivation of ``partnership_self_employment_net_earnings``. + +``puf_support._person_source_values`` derives this leaf from raw PUF columns +only when the donor arrays carry neither the leaf nor the processed +``partnership_se_income`` column. The derivation ports the archived +processed-PUF pipeline (PolicyEngine/policyengine-us-data at +42ed5d45c56df80d754fbe24cce21cfeb8d05cbe, ``datasets/puf/puf.py`` lines +723-746), copied below as ``_archived_partnership_se``. + +Invariants, each for every input Hypothesis draws: + +1. It equals the archived formula bit for bit, on float columns with missing + values and on the integer columns a raw PUF extract carries. +2. A record with no partnership activity (its net partnership income + ``E25940 + E25980 - E25920 - E25960`` is exactly zero) gets exactly zero, + whatever its Schedule SE, C and F amounts. +3. On a record with partnership activity, the result plus the Schedule C and + Schedule F amounts, times 0.9235, returns the Schedule SE amounts. +4. No S corporation column changes it. +5. Rows are derived independently: permuting the rows permutes the result. +6. On integer-dollar amounts it is homogeneous of degree one under + power-of-two rescaling, bit for bit. +7. It fails closed: with any of the eight raw columns absent it derives + nothing, whatever other raw columns are present. + +Plus worked examples, the source precedence, and the donor-builder seam. +""" + +from __future__ import annotations + +from itertools import combinations + +import numpy as np +import pandas as pd +import pytest +from hypothesis import HealthCheck, given, settings +from hypothesis import strategies as st + +import microcosm.build.us_runtime.puf_support as puf_support_module +from microcosm.build.us_runtime import puf_tax_unit_donor_from_arrays + +_LEAF = "partnership_self_employment_net_earnings" +_RAW_COLUMNS = ( + "E30400", + "E30500", + "E00900", + "E02100", + "E25920", + "E25940", + "E25960", + "E25980", +) +_S_CORP_COLUMNS = ("E26180", "E26190") +_ARCHIVED_SE_DEDUCTION_FACTOR = 0.9235 +_SETTINGS = settings( + max_examples=200, + deadline=None, + suppress_health_check=[HealthCheck.too_slow], +) +_MAX_ROWS = 12 +_INTEGER_DOLLARS = st.integers(min_value=-(10**9), max_value=10**9) +# Mostly zero, like a raw PUF extract, with integer dollars, arbitrary finite +# floats and missing values mixed in. +_FLOAT_CELL = st.one_of( + st.just(0.0), + _INTEGER_DOLLARS.map(float), + st.floats(min_value=-1e9, max_value=1e9, allow_nan=False, width=64), + st.just(float("nan")), +) + + +def _archived_partnership_se(puf: pd.DataFrame) -> np.ndarray: + """Lines 734-745 of the archived ``puf.py``. + + Verbatim apart from the factor's name, which the archive binds as a local + ``SE_DEDUCTION_FACTOR``. + """ + + taxable_se = puf["E30400"].fillna(0) + puf["E30500"].fillna(0) + gross_se = taxable_se / _ARCHIVED_SE_DEDUCTION_FACTOR + schedule_c_f_income = puf["E00900"].fillna(0) + puf["E02100"].fillna(0) + # Only compute when there's partnership activity (net partnership income != 0) + has_partnership = ( + puf["E25940"].fillna(0) + + puf["E25980"].fillna(0) + - puf["E25920"].fillna(0) + - puf["E25960"].fillna(0) + ) != 0 + partnership_se = np.where(has_partnership, gross_se - schedule_c_f_income, 0) + return partnership_se + + +def _derive(arrays: dict[str, np.ndarray]) -> np.ndarray: + values = puf_support_module._person_source_values(arrays, _LEAF) + assert values is not None + return values + + +def _assert_bit_identical(actual: np.ndarray, expected: np.ndarray) -> None: + assert actual.dtype == np.float64 + assert expected.dtype == np.float64 + np.testing.assert_array_equal(actual.view(np.uint64), expected.view(np.uint64)) + + +@st.composite +def _float_arrays(draw: st.DrawFn) -> dict[str, np.ndarray]: + rows = draw(st.integers(min_value=1, max_value=_MAX_ROWS)) + return { + column: np.asarray( + draw(st.lists(_FLOAT_CELL, min_size=rows, max_size=rows)), + dtype=np.float64, + ) + for column in _RAW_COLUMNS + } + + +@st.composite +def _integer_arrays(draw: st.DrawFn) -> dict[str, np.ndarray]: + rows = draw(st.integers(min_value=1, max_value=_MAX_ROWS)) + return { + column: np.asarray( + draw(st.lists(_INTEGER_DOLLARS, min_size=rows, max_size=rows)), + dtype=np.int64, + ) + for column in _RAW_COLUMNS + } + + +@st.composite +def _arrays_without_partnership_activity(draw: st.DrawFn) -> dict[str, np.ndarray]: + """Integer-dollar records whose net partnership income cancels exactly.""" + + arrays = draw(_integer_arrays()) + arrays["E25960"] = arrays["E25940"] + arrays["E25980"] - arrays["E25920"] + return arrays + + +@_SETTINGS +@given(arrays=_float_arrays()) +def test_derivation_equals_the_archived_formula_on_float_columns( + arrays: dict[str, np.ndarray], +) -> None: + _assert_bit_identical( + _derive(arrays), _archived_partnership_se(pd.DataFrame(arrays)) + ) + + +@_SETTINGS +@given(arrays=_integer_arrays()) +def test_derivation_equals_the_archived_formula_on_integer_columns( + arrays: dict[str, np.ndarray], +) -> None: + _assert_bit_identical( + _derive(arrays), _archived_partnership_se(pd.DataFrame(arrays)) + ) + + +@_SETTINGS +@given(arrays=_arrays_without_partnership_activity()) +def test_no_partnership_activity_gives_exactly_zero( + arrays: dict[str, np.ndarray], +) -> None: + derived = _derive(arrays) + + assert derived.tolist() == [0.0] * len(derived) + assert not np.signbit(derived).any() + + +@_SETTINGS +@given(arrays=_integer_arrays()) +def test_active_records_return_the_schedule_se_amounts( + arrays: dict[str, np.ndarray], +) -> None: + derived = _derive(arrays) + active = ( + arrays["E25940"] + arrays["E25980"] - arrays["E25920"] - arrays["E25960"] + ) != 0 + + assert (derived[~active] == 0.0).all() + np.testing.assert_allclose( + (derived + arrays["E00900"] + arrays["E02100"])[active] + * _ARCHIVED_SE_DEDUCTION_FACTOR, + (arrays["E30400"] + arrays["E30500"])[active], + rtol=1e-12, + atol=1e-5, + ) + + +@_SETTINGS +@given(arrays=_float_arrays(), data=st.data()) +def test_s_corporation_columns_never_change_the_result( + arrays: dict[str, np.ndarray], + data: st.DataObject, +) -> None: + rows = len(arrays["E30400"]) + with_s_corp = dict(arrays) + for column in _S_CORP_COLUMNS: + with_s_corp[column] = np.asarray( + data.draw(st.lists(_FLOAT_CELL, min_size=rows, max_size=rows)), + dtype=np.float64, + ) + + _assert_bit_identical(_derive(with_s_corp), _derive(arrays)) + + +@_SETTINGS +@given(arrays=_float_arrays(), data=st.data()) +def test_rows_are_derived_independently( + arrays: dict[str, np.ndarray], + data: st.DataObject, +) -> None: + rows = len(arrays["E30400"]) + order = np.asarray(data.draw(st.permutations(range(rows))), dtype=np.intp) + permuted = {column: values[order] for column, values in arrays.items()} + + _assert_bit_identical(_derive(permuted), _derive(arrays)[order]) + + +@_SETTINGS +@given(arrays=_integer_arrays(), exponent=st.integers(min_value=-8, max_value=8)) +def test_derivation_is_homogeneous_under_power_of_two_rescaling( + arrays: dict[str, np.ndarray], + exponent: int, +) -> None: + # Integer dollars keep every intermediate in the normal float range, where + # a power-of-two rescaling commutes exactly with each rounding. + scale = 2.0**exponent + scaled = {column: values * scale for column, values in arrays.items()} + + _assert_bit_identical(_derive(scaled), _derive(arrays) * scale) + + +@_SETTINGS +@given( + arrays=_float_arrays(), + present=st.sets(st.sampled_from(_RAW_COLUMNS), max_size=len(_RAW_COLUMNS) - 1), + s_corp=st.sets(st.sampled_from(_S_CORP_COLUMNS)), +) +def test_incomplete_raw_columns_derive_nothing( + arrays: dict[str, np.ndarray], + present: set[str], + s_corp: set[str], +) -> None: + rows = len(arrays["E30400"]) + partial = {column: arrays[column] for column in present} + partial.update({column: np.ones(rows) for column in s_corp}) + + assert puf_support_module._person_source_values(partial, _LEAF) is None + + +def test_derivation_does_not_mutate_its_inputs_and_is_deterministic() -> None: + rng = np.random.default_rng(20261011) + arrays = { + column: rng.integers(-5_000, 5_000, size=50).astype(np.float64) + for column in _RAW_COLUMNS + } + before = {column: values.copy() for column, values in arrays.items()} + + first = _derive(arrays) + second = _derive(arrays) + + _assert_bit_identical(first, second) + for column, values in arrays.items(): + np.testing.assert_array_equal(values, before[column]) + + +def test_worked_examples_match_hand_arithmetic() -> None: + arrays = { + # (E30400 + E30500) / 0.9235 = 1,000; 2,000; 1,000; 1,000; 0; 500. + "E30400": [923.5, 0.0, 923.5, 923.5, 0.0, 461.75], + "E30500": [0.0, 1_847.0, 0.0, 0.0, 0.0, 0.0], + # Schedule C plus Schedule F = 400; 300; 1,500; 400; 250; 0. + "E00900": [300.0, 500.0, 1_500.0, 300.0, 250.0, 0.0], + "E02100": [100.0, -200.0, 0.0, 100.0, 0.0, 0.0], + # Net partnership income = 45; 60; -30; 0 (cancelling); 80; 0 (absent). + "E25940": [0.0, 0.0, 0.0, 10.0, 0.0, 0.0], + "E25980": [50.0, 70.0, 0.0, 50.0, 80.0, 0.0], + "E25920": [0.0, 0.0, 30.0, 55.0, 0.0, 0.0], + "E25960": [5.0, 10.0, 0.0, 5.0, 0.0, 0.0], + } + + derived = _derive(arrays) + + np.testing.assert_allclose( + derived, + [ + 600.0, # 1,000 - 400 + 1_700.0, # 2,000 - 300 + -500.0, # 1,000 - 1,500: Schedule C exceeds Schedule SE earnings + 0.0, # income and losses cancel: no partnership activity + -250.0, # 0 - 250: the residual goes negative the same way + 0.0, # no partnership columns at all, so not the residual 500 + ], + rtol=0.0, + atol=1e-9, + ) + assert derived[3] == 0.0 + assert derived[5] == 0.0 + + +def test_derivation_is_not_the_sum_of_partnership_and_s_corporation_losses() -> None: + """The replaced fallback returned ``E25960 + E26180``.""" + + arrays = {column: np.zeros(2) for column in _RAW_COLUMNS} + arrays["E25960"] = np.asarray([5.0, 10.0]) + arrays["E26180"] = np.asarray([20.0, 30.0]) + + derived = _derive(arrays) + + # A partnership loss with no Schedule SE earnings is no SE earnings, and an + # S corporation loss never enters. + assert derived.tolist() == [0.0, 0.0] + + +def test_missing_values_count_as_zero_like_the_archived_fillna() -> None: + arrays = {column: np.zeros(1) for column in _RAW_COLUMNS} + arrays["E30400"] = np.asarray([np.nan]) + arrays["E30500"] = np.asarray([923.5]) + arrays["E00900"] = np.asarray([np.nan]) + arrays["E25980"] = np.asarray([40.0]) + arrays["E25920"] = np.asarray([np.nan]) + + np.testing.assert_allclose(_derive(arrays), [1_000.0], rtol=0.0, atol=1e-9) + + +def test_stored_leaf_and_processed_column_take_precedence_over_raw_columns() -> None: + raw = {column: np.asarray([1.0, 2.0]) for column in _RAW_COLUMNS} + + processed = puf_support_module._person_source_values( + {**raw, "partnership_se_income": [100.0, -200.0]}, _LEAF + ) + stored = puf_support_module._person_source_values( + {**raw, "partnership_se_income": [100.0, -200.0], _LEAF: [7.0, 8.0]}, + _LEAF, + ) + + assert processed.tolist() == [100.0, -200.0] + assert stored.tolist() == [7.0, 8.0] + + +def _donor_base() -> dict[str, object]: + return { + "tax_unit_id": [10, 20, 30], + "household_weight": [100.0, 200.0, 300.0], + "filing_status": [b"SINGLE", b"JOINT", b"SINGLE"], + "person_tax_unit_id": [10, 20, 30], + } + + +def _donor_raw_columns() -> dict[str, list[float]]: + return { + "E30400": [923.5, 0.0, 923.5], + "E30500": [0.0, 1_847.0, 0.0], + "E00900": [300.0, 500.0, 300.0], + "E02100": [100.0, -200.0, 100.0], + "E25920": [0.0, 0.0, 0.0], + "E25940": [0.0, 0.0, 0.0], + "E25960": [5.0, 10.0, 0.0], + "E25980": [50.0, 70.0, 0.0], + } + + +def test_donor_builder_carries_the_archived_derivation_from_raw_columns() -> None: + raw = _donor_raw_columns() + + donor = puf_tax_unit_donor_from_arrays( + {**_donor_base(), **raw}, + person_outputs=(_LEAF,), + tax_unit_outputs=(), + ) + + np.testing.assert_allclose( + donor[_LEAF].to_numpy(), [600.0, 1_700.0, 0.0], rtol=0.0, atol=1e-9 + ) + _assert_bit_identical( + donor[_LEAF].to_numpy(), _archived_partnership_se(pd.DataFrame(raw)) + ) + + +@pytest.mark.parametrize("missing", _RAW_COLUMNS) +def test_donor_builder_fails_closed_when_a_raw_column_is_absent(missing: str) -> None: + raw = _donor_raw_columns() + del raw[missing] + + with pytest.raises(ValueError, match="cannot derive requested output") as error: + puf_tax_unit_donor_from_arrays( + {**_donor_base(), **raw}, + person_outputs=(_LEAF,), + tax_unit_outputs=(), + ) + + assert _LEAF in str(error.value) + + +def test_donor_builder_refuses_the_replaced_loss_column_pair() -> None: + with pytest.raises(ValueError, match="cannot derive requested output") as error: + puf_tax_unit_donor_from_arrays( + { + **_donor_base(), + "E25960": [5.0, 10.0, 0.0], + "E26180": [20.0, 30.0, 0.0], + }, + person_outputs=(_LEAF,), + tax_unit_outputs=(), + ) + + assert _LEAF in str(error.value) + + +def test_no_pair_of_raw_columns_derives_the_leaf() -> None: + columns = (*_RAW_COLUMNS, *_S_CORP_COLUMNS) + + for pair in combinations(columns, 2): + arrays = {column: np.ones(2) for column in pair} + assert puf_support_module._person_source_values(arrays, _LEAF) is None + + +def test_raw_column_contract_names_the_archived_inputs() -> None: + assert set(puf_support_module._PUF_PARTNERSHIP_SE_RAW_COLUMNS) == set(_RAW_COLUMNS) + assert not set(_S_CORP_COLUMNS) & set( + puf_support_module._PUF_PARTNERSHIP_SE_RAW_COLUMNS + ) + assert ( + puf_support_module._PUF_SE_NET_EARNINGS_FACTOR == _ARCHIVED_SE_DEDUCTION_FACTOR + ) diff --git a/packages/microcosm-build/tests/engine_free/us/test_us_puf_support.py b/packages/microcosm-build/tests/engine_free/us/test_us_puf_support.py index 17e1ff3a35..72ff0c8e72 100644 --- a/packages/microcosm-build/tests/engine_free/us/test_us_puf_support.py +++ b/packages/microcosm-build/tests/engine_free/us/test_us_puf_support.py @@ -1297,6 +1297,12 @@ def test_puf_tax_unit_donor_derives_partnership_and_s_corp_split_from_raw_fields "E25960": [5.0, 10.0], "E26190": [80.0, 110.0], "E26180": [20.0, 30.0], + "E25940": [0.0, 0.0], + "E25920": [0.0, 0.0], + "E30400": [923.5, 0.0], + "E30500": [0.0, 1_847.0], + "E00900": [300.0, 500.0], + "E02100": [100.0, -200.0], "E17500": [1_000.0, 2_000.0], }, person_outputs=( @@ -1312,7 +1318,14 @@ def test_puf_tax_unit_donor_derives_partnership_and_s_corp_split_from_raw_fields assert donor["partnership_income"].tolist() == [45.0, 60.0] assert donor["s_corp_income"].tolist() == [60.0, 80.0] - assert donor["partnership_self_employment_net_earnings"].tolist() == [25.0, 40.0] + # (E30400 + E30500) / 0.9235 - (E00900 + E02100): 1,000 - 400 and + # 2,000 - 300. The S corporation columns do not enter. + np.testing.assert_allclose( + donor["partnership_self_employment_net_earnings"].to_numpy(), + [600.0, 1_700.0], + rtol=0.0, + atol=1e-9, + ) assert donor["health_insurance_premiums_without_medicare_part_b"].tolist() == [ 453.0, 906.0, From cf6eb2e239cd3c32bc282257b4aff297b9b172cd Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 12 Oct 2026 08:18:05 -0400 Subject: [PATCH 2/6] Re-pin the spec-engine identities that attest puf_support.py puf_support.py is on _DIRECT_KERNEL_MODULES, so the previous commit's byte change moves the seed-protocol and seed-map digests, the US spec_sha256 and the coverage evidence. Recomputed from the tree: - EXPECTED_HASHES seed_protocol 114217a2... -> e7ed105b... - EXPECTED_HASHES seed_map b4d6ec9c... -> 533ef661... - US spec_sha256 f76f921d... -> fa609914... (pool-tool test, coverage JSON) - docs/evidence/spec-engine/us-f0-coverage.json regenerated with tools/spec_engine_coverage.py Co-Authored-By: Claude Opus 5.5 --- docs/evidence/spec-engine/us-f0-coverage.json | 16 ++++++++-------- .../build/spec_engine/inventory_coverage.py | 4 ++-- .../us/test_us_multispine_pool_tool.py | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/evidence/spec-engine/us-f0-coverage.json b/docs/evidence/spec-engine/us-f0-coverage.json index 0fabd95a86..eb7dc0d059 100644 --- a/docs/evidence/spec-engine/us-f0-coverage.json +++ b/docs/evidence/spec-engine/us-f0-coverage.json @@ -1656,13 +1656,13 @@ "compiler_ir.node_slices" ], "expected": { - "map_sha256": "b4d6ec9c11ce323d83319a3d0289e0cf7216a7936d6c6f08cef0a463ad369641", - "protocol_sha256": "114217a2918329b0601d94deb8ed83f73919584b85ca8aabe45a40665afb6560" + "map_sha256": "533ef661ce158407aec9be8962e96c234418de6fe4fde77e2c2ed488835e3e32", + "protocol_sha256": "e7ed105b78be0608b76f5c9e1f3d59073d1594850813cdb9f892b7f33e3b050b" }, "failures": [], "observed": { - "map_sha256": "b4d6ec9c11ce323d83319a3d0289e0cf7216a7936d6c6f08cef0a463ad369641", - "protocol_sha256": "114217a2918329b0601d94deb8ed83f73919584b85ca8aabe45a40665afb6560" + "map_sha256": "533ef661ce158407aec9be8962e96c234418de6fe4fde77e2c2ed488835e3e32", + "protocol_sha256": "e7ed105b78be0608b76f5c9e1f3d59073d1594850813cdb9f892b7f33e3b050b" }, "status": "covered" }, @@ -1677,7 +1677,7 @@ "compiler_ir.seed_stream_map" ], "expected": { - "implementation_sha256": "114217a2918329b0601d94deb8ed83f73919584b85ca8aabe45a40665afb6560", + "implementation_sha256": "e7ed105b78be0608b76f5c9e1f3d59073d1594850813cdb9f892b7f33e3b050b", "protocol": "legacy-v1", "streams": [ "build_model", @@ -1698,7 +1698,7 @@ }, "failures": [], "observed": { - "implementation_sha256": "114217a2918329b0601d94deb8ed83f73919584b85ca8aabe45a40665afb6560", + "implementation_sha256": "e7ed105b78be0608b76f5c9e1f3d59073d1594850813cdb9f892b7f33e3b050b", "protocol": "legacy-v1", "streams": [ "build_model", @@ -2599,7 +2599,7 @@ "country": "us", "schema_id": "country_spec", "schema_version": 1, - "spec_sha256": "f76f921d4f74392b106b8c0729ce250494e0a55455eaba7b910b19cdf7825178" + "spec_sha256": "fa6099149b641b412f10bb63de9e1135f2bb723d33bf466570b604b493b464c6" } }, "report_schema_version": 3, @@ -2609,7 +2609,7 @@ "country": "us", "schema_id": "country_spec", "schema_version": 1, - "spec_sha256": "f76f921d4f74392b106b8c0729ce250494e0a55455eaba7b910b19cdf7825178" + "spec_sha256": "fa6099149b641b412f10bb63de9e1135f2bb723d33bf466570b604b493b464c6" }, "status": "pass" } diff --git a/packages/microcosm-build/src/microcosm/build/spec_engine/inventory_coverage.py b/packages/microcosm-build/src/microcosm/build/spec_engine/inventory_coverage.py index 673ab08d35..53be33d4ba 100644 --- a/packages/microcosm-build/src/microcosm/build/spec_engine/inventory_coverage.py +++ b/packages/microcosm-build/src/microcosm/build/spec_engine/inventory_coverage.py @@ -359,8 +359,8 @@ "late_schedule": "e59c019d3d454eac99ac0ac209b6c5b6faaf9bdfcaeee18c36a25be19bf7da2f", "ownership": "5f64f0aac49e2313177564f71876bffc8c81b3ded4df701e70930e60e9c98356", "primary_tuples": "fdf23da429f8c501e198a2f5b719763d523a41565c2153fdf17b0344f21bcd7c", - "seed_map": "b4d6ec9c11ce323d83319a3d0289e0cf7216a7936d6c6f08cef0a463ad369641", - "seed_protocol": "114217a2918329b0601d94deb8ed83f73919584b85ca8aabe45a40665afb6560", + "seed_map": "533ef661ce158407aec9be8962e96c234418de6fe4fde77e2c2ed488835e3e32", + "seed_protocol": "e7ed105b78be0608b76f5c9e1f3d59073d1594850813cdb9f892b7f33e3b050b", "source_manifest": "f4f8bfeb79268a4043a843b47cec1d1c0e58e9f5dd6bc23417ada95446dd7b8e", "take_up": "9522ce40f7dea569312dd7a7beb474e5a5afadd2f1e10cb5876534c3ef623d35", "tail": "ac92829c88a1a4fb6460d61190918d5d99c6c377fc8dd8f62f02b332d09bf59c", diff --git a/packages/microcosm-build/tests/engine_workflow/us/test_us_multispine_pool_tool.py b/packages/microcosm-build/tests/engine_workflow/us/test_us_multispine_pool_tool.py index 9606d75b4c..0345afea34 100644 --- a/packages/microcosm-build/tests/engine_workflow/us/test_us_multispine_pool_tool.py +++ b/packages/microcosm-build/tests/engine_workflow/us/test_us_multispine_pool_tool.py @@ -338,7 +338,7 @@ def capture_equality(expected: object, actual: object) -> None: "country": "us", "schema_id": "country_spec", "schema_version": 1, - "spec_sha256": "f76f921d4f74392b106b8c0729ce250494e0a55455eaba7b910b19cdf7825178", + "spec_sha256": "fa6099149b641b412f10bb63de9e1135f2bb723d33bf466570b604b493b464c6", }, } From 5dd439b8404e7feff10271356c1c0537d61b3580 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 12 Oct 2026 08:39:50 -0400 Subject: [PATCH 3/6] Re-pin the attested identities on the merged tree Main's #1186 also edited puf_support.py and re-pinned, so the merge took main's pins and this commit recomputes them for the combined bytes: - EXPECTED_HASHES seed_protocol 37da8f68... -> 027e9471... - EXPECTED_HASHES seed_map 7d03cc07... -> 976dc97b... - US spec_sha256 fbf25dba... -> 2bd6fc62... (pool-tool test, coverage JSON) - docs/evidence/spec-engine/us-f0-coverage.json regenerated; tools/spec_engine_coverage.py --check exits 0 Co-Authored-By: Claude Opus 5.5 --- docs/evidence/spec-engine/us-f0-coverage.json | 16 ++++++++-------- .../build/spec_engine/inventory_coverage.py | 4 ++-- .../us/test_us_multispine_pool_tool.py | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/evidence/spec-engine/us-f0-coverage.json b/docs/evidence/spec-engine/us-f0-coverage.json index 978c19dcd8..ff506804ff 100644 --- a/docs/evidence/spec-engine/us-f0-coverage.json +++ b/docs/evidence/spec-engine/us-f0-coverage.json @@ -1656,13 +1656,13 @@ "compiler_ir.node_slices" ], "expected": { - "map_sha256": "7d03cc07e973165f38781d5932d5fe6d16ca0b1e4dc854e7841460737fd043fb", - "protocol_sha256": "37da8f68444677850a97bdf958b7f62b426a60da570b80a002eeba8af4861f68" + "map_sha256": "976dc97bc1f0b6132f53706988ec0c5931e6efb93a900010fa18de8b10d0f549", + "protocol_sha256": "027e94712f8e9c1d7ba396354f1fd7fae625d364126fde734ee3f1327a8c0b3f" }, "failures": [], "observed": { - "map_sha256": "7d03cc07e973165f38781d5932d5fe6d16ca0b1e4dc854e7841460737fd043fb", - "protocol_sha256": "37da8f68444677850a97bdf958b7f62b426a60da570b80a002eeba8af4861f68" + "map_sha256": "976dc97bc1f0b6132f53706988ec0c5931e6efb93a900010fa18de8b10d0f549", + "protocol_sha256": "027e94712f8e9c1d7ba396354f1fd7fae625d364126fde734ee3f1327a8c0b3f" }, "status": "covered" }, @@ -1677,7 +1677,7 @@ "compiler_ir.seed_stream_map" ], "expected": { - "implementation_sha256": "37da8f68444677850a97bdf958b7f62b426a60da570b80a002eeba8af4861f68", + "implementation_sha256": "027e94712f8e9c1d7ba396354f1fd7fae625d364126fde734ee3f1327a8c0b3f", "protocol": "legacy-v1", "streams": [ "build_model", @@ -1698,7 +1698,7 @@ }, "failures": [], "observed": { - "implementation_sha256": "37da8f68444677850a97bdf958b7f62b426a60da570b80a002eeba8af4861f68", + "implementation_sha256": "027e94712f8e9c1d7ba396354f1fd7fae625d364126fde734ee3f1327a8c0b3f", "protocol": "legacy-v1", "streams": [ "build_model", @@ -2599,7 +2599,7 @@ "country": "us", "schema_id": "country_spec", "schema_version": 1, - "spec_sha256": "fbf25dbae68242198972f5bef4f1fc20f65ee0769615b8d94639e6a80121f31f" + "spec_sha256": "2bd6fc6265d35c97306a98fe7d41452acfb15ca50b9296ba96cd074e1703dcc2" } }, "report_schema_version": 3, @@ -2609,7 +2609,7 @@ "country": "us", "schema_id": "country_spec", "schema_version": 1, - "spec_sha256": "fbf25dbae68242198972f5bef4f1fc20f65ee0769615b8d94639e6a80121f31f" + "spec_sha256": "2bd6fc6265d35c97306a98fe7d41452acfb15ca50b9296ba96cd074e1703dcc2" }, "status": "pass" } diff --git a/packages/microcosm-build/src/microcosm/build/spec_engine/inventory_coverage.py b/packages/microcosm-build/src/microcosm/build/spec_engine/inventory_coverage.py index 2a38471603..d0a4105abb 100644 --- a/packages/microcosm-build/src/microcosm/build/spec_engine/inventory_coverage.py +++ b/packages/microcosm-build/src/microcosm/build/spec_engine/inventory_coverage.py @@ -361,8 +361,8 @@ "primary_tuples": "fdf23da429f8c501e198a2f5b719763d523a41565c2153fdf17b0344f21bcd7c", # #1178: puf_support's source bytes attest CPS Social Security preservation. # RNG rules and the ordered QRF targets are unchanged. - "seed_map": "7d03cc07e973165f38781d5932d5fe6d16ca0b1e4dc854e7841460737fd043fb", - "seed_protocol": "37da8f68444677850a97bdf958b7f62b426a60da570b80a002eeba8af4861f68", + "seed_map": "976dc97bc1f0b6132f53706988ec0c5931e6efb93a900010fa18de8b10d0f549", + "seed_protocol": "027e94712f8e9c1d7ba396354f1fd7fae625d364126fde734ee3f1327a8c0b3f", "source_manifest": "f4f8bfeb79268a4043a843b47cec1d1c0e58e9f5dd6bc23417ada95446dd7b8e", "take_up": "9522ce40f7dea569312dd7a7beb474e5a5afadd2f1e10cb5876534c3ef623d35", "tail": "ac92829c88a1a4fb6460d61190918d5d99c6c377fc8dd8f62f02b332d09bf59c", diff --git a/packages/microcosm-build/tests/engine_workflow/us/test_us_multispine_pool_tool.py b/packages/microcosm-build/tests/engine_workflow/us/test_us_multispine_pool_tool.py index 5b1861afdd..b74b1f7191 100644 --- a/packages/microcosm-build/tests/engine_workflow/us/test_us_multispine_pool_tool.py +++ b/packages/microcosm-build/tests/engine_workflow/us/test_us_multispine_pool_tool.py @@ -338,7 +338,7 @@ def capture_equality(expected: object, actual: object) -> None: "country": "us", "schema_id": "country_spec", "schema_version": 1, - "spec_sha256": "fbf25dbae68242198972f5bef4f1fc20f65ee0769615b8d94639e6a80121f31f", + "spec_sha256": "2bd6fc6265d35c97306a98fe7d41452acfb15ca50b9296ba96cd074e1703dcc2", }, } From c27583956d20a8b58d622f3b3404fa8961d77b1a Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 12 Oct 2026 09:00:38 -0400 Subject: [PATCH 4/6] Re-pin the minimal-loader golden for the puf_support.py bytes The golden spec_sha256 in test_spec_engine_loader.py attests the direct kernel modules too (main's #1178 moved it when it edited puf_support.py). 32305247... -> a7e42313..., the value the test observes on this head. Co-Authored-By: Claude Opus 5.5 --- .../tests/engine_free/shared/test_spec_engine_loader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/microcosm-build/tests/engine_free/shared/test_spec_engine_loader.py b/packages/microcosm-build/tests/engine_free/shared/test_spec_engine_loader.py index d5ba0c21f6..0261a21f5d 100644 --- a/packages/microcosm-build/tests/engine_free/shared/test_spec_engine_loader.py +++ b/packages/microcosm-build/tests/engine_free/shared/test_spec_engine_loader.py @@ -12,7 +12,7 @@ def test_semantic_hash_has_golden_vector_and_surface_separation(tmp_path) -> Non # Pin the domain separator, normalization rules, schema-set receipt, and # exact normative projection as one reviewable golden vector. assert first.spec_sha256 == ( - "32305247436ed439181e8b5a667343436a4b5622bff0402d2f13cc08a51e2bfc" + "a7e42313a65e5ade95fa7188f6384cfb21c8361ea86fba11ef917c16ba3d5add" ) second_root = _rich_minimal(tmp_path / "xy", note="second", store="local:b") From ae20b11a61be3477d3d62a1ad64a55f97f6eb2f3 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 12 Oct 2026 18:46:06 -0400 Subject: [PATCH 5/6] Cite the archived pipeline without naming the retired package test_no_incumbent_data_package_references_in_live_tree forbids the retired data package's name outside its allowlist; cite it as the retired enhanced-CPS repository at 42ed5d45, as the other ports do. Also state that _numeric_array, not the archived fillna(0), turns a nonnumeric value into zero (review round 1, P3). Co-Authored-By: Claude Opus 5.5 --- .../src/microcosm/build/us_runtime/puf_support.py | 14 ++++++++------ .../us/test_us_puf_partnership_se_derivation.py | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/puf_support.py b/packages/microcosm-build/src/microcosm/build/us_runtime/puf_support.py index a27e9f834f..165cf5a446 100644 --- a/packages/microcosm-build/src/microcosm/build/us_runtime/puf_support.py +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/puf_support.py @@ -4385,10 +4385,10 @@ def _puf_partnership_se_net_earnings_from_raw_columns( """Derive partnership self-employment net earnings from raw PUF columns. This ports, operation for operation, the derivation the archived - processed-PUF pipeline used for this leaf (PolicyEngine/policyengine-us-data - at 42ed5d45c56df80d754fbe24cce21cfeb8d05cbe, - ``policyengine_us_data/datasets/puf/puf.py`` lines 723-746), which matches - ``part_se`` in Yale Budget Lab Tax-Data's ``src/process_puf.R``. It is a + processed-PUF pipeline used for this leaf (the retired enhanced-CPS + repository at 42ed5d45c56df80d754fbe24cce21cfeb8d05cbe, + ``datasets/puf/puf.py`` lines 723-746), which matches ``part_se`` in Yale + Budget Lab Tax-Data's ``src/process_puf.R``. It is a residual, not a read of a Schedule K-1 box 14 field: gross self-employment earnings less the Schedule C and Schedule F amounts. @@ -4404,8 +4404,10 @@ def _puf_partnership_se_net_earnings_from_raw_columns( where it is exactly zero has no partnership activity and gets zero. No S corporation column (``E26180``, ``E26190``) enters the derivation. A - missing or nonnumeric value counts as zero, as the archived ``fillna(0)`` - did. + missing value counts as zero, as the archived ``fillna(0)`` did. + ``_numeric_array`` also turns a nonnumeric value into zero, where the + archived arithmetic would raise; on numeric float64 arrays the result + equals the archived formula bit for bit. Args: arrays: Mapping carrying every column of diff --git a/packages/microcosm-build/tests/engine_free/us/test_us_puf_partnership_se_derivation.py b/packages/microcosm-build/tests/engine_free/us/test_us_puf_partnership_se_derivation.py index f32d0b8622..981bf305a6 100644 --- a/packages/microcosm-build/tests/engine_free/us/test_us_puf_partnership_se_derivation.py +++ b/packages/microcosm-build/tests/engine_free/us/test_us_puf_partnership_se_derivation.py @@ -3,7 +3,7 @@ ``puf_support._person_source_values`` derives this leaf from raw PUF columns only when the donor arrays carry neither the leaf nor the processed ``partnership_se_income`` column. The derivation ports the archived -processed-PUF pipeline (PolicyEngine/policyengine-us-data at +processed-PUF pipeline (the retired enhanced-CPS repository at 42ed5d45c56df80d754fbe24cce21cfeb8d05cbe, ``datasets/puf/puf.py`` lines 723-746), copied below as ``_archived_partnership_se``. From 7556a00cfaec04c8846d2fb8f9a04e682c5a4bee Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 12 Oct 2026 18:57:35 -0400 Subject: [PATCH 6/6] Re-pin the attested identities on main at 977ac983a The merge took main's pins; this recomputes them for this PR's puf_support.py bytes on the merged tree: - EXPECTED_HASHES seed_protocol 8d028354... -> 0e4c8a4a... - EXPECTED_HASHES seed_map bdd33986... -> 41a64b88... - US spec_sha256 638cd60e... -> 3080fe93... (pool-tool test, coverage JSON) - minimal-loader golden aadf7c8c... -> 0c0c8eea... - coverage JSON regenerated; spec_engine_coverage.py --check and generate_us_bundle_from_constants.py --check exit 0 Co-Authored-By: Claude Opus 5.5 --- docs/evidence/spec-engine/us-f0-coverage.json | 16 ++++++++-------- .../build/spec_engine/inventory_coverage.py | 4 ++-- .../shared/test_spec_engine_loader.py | 2 +- .../us/test_us_multispine_pool_tool.py | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/evidence/spec-engine/us-f0-coverage.json b/docs/evidence/spec-engine/us-f0-coverage.json index 6b91a46cac..bbced0b031 100644 --- a/docs/evidence/spec-engine/us-f0-coverage.json +++ b/docs/evidence/spec-engine/us-f0-coverage.json @@ -1656,13 +1656,13 @@ "compiler_ir.node_slices" ], "expected": { - "map_sha256": "bdd339868ee0cec07fa3a52a91c4bd97de707c15aeb0dc224b064be9ce04eb4b", - "protocol_sha256": "8d028354d487eadecf3bc4a950d70c95e5c44c792fe7fdf2d52c77e6d86a7886" + "map_sha256": "41a64b8820bf161e316c49e3f2b666a247b58f6f6d50dd4395b89c8f5b1399f6", + "protocol_sha256": "0e4c8a4ace5e10747065669a009691d0eee9179ca42b344f8912c5ca239ebde6" }, "failures": [], "observed": { - "map_sha256": "bdd339868ee0cec07fa3a52a91c4bd97de707c15aeb0dc224b064be9ce04eb4b", - "protocol_sha256": "8d028354d487eadecf3bc4a950d70c95e5c44c792fe7fdf2d52c77e6d86a7886" + "map_sha256": "41a64b8820bf161e316c49e3f2b666a247b58f6f6d50dd4395b89c8f5b1399f6", + "protocol_sha256": "0e4c8a4ace5e10747065669a009691d0eee9179ca42b344f8912c5ca239ebde6" }, "status": "covered" }, @@ -1677,7 +1677,7 @@ "compiler_ir.seed_stream_map" ], "expected": { - "implementation_sha256": "8d028354d487eadecf3bc4a950d70c95e5c44c792fe7fdf2d52c77e6d86a7886", + "implementation_sha256": "0e4c8a4ace5e10747065669a009691d0eee9179ca42b344f8912c5ca239ebde6", "protocol": "legacy-v1", "streams": [ "build_model", @@ -1698,7 +1698,7 @@ }, "failures": [], "observed": { - "implementation_sha256": "8d028354d487eadecf3bc4a950d70c95e5c44c792fe7fdf2d52c77e6d86a7886", + "implementation_sha256": "0e4c8a4ace5e10747065669a009691d0eee9179ca42b344f8912c5ca239ebde6", "protocol": "legacy-v1", "streams": [ "build_model", @@ -2599,7 +2599,7 @@ "country": "us", "schema_id": "country_spec", "schema_version": 1, - "spec_sha256": "638cd60e97a9b200f8bdfd4f92e67be986f516ac25b9a37508235963e695e640" + "spec_sha256": "3080fe938df62216dc4853c1163639817de3c537e0e932309642fbd3f7d8f266" } }, "report_schema_version": 3, @@ -2609,7 +2609,7 @@ "country": "us", "schema_id": "country_spec", "schema_version": 1, - "spec_sha256": "638cd60e97a9b200f8bdfd4f92e67be986f516ac25b9a37508235963e695e640" + "spec_sha256": "3080fe938df62216dc4853c1163639817de3c537e0e932309642fbd3f7d8f266" }, "status": "pass" } diff --git a/packages/microcosm-build/src/microcosm/build/spec_engine/inventory_coverage.py b/packages/microcosm-build/src/microcosm/build/spec_engine/inventory_coverage.py index 4b5bfb8d11..b68874986d 100644 --- a/packages/microcosm-build/src/microcosm/build/spec_engine/inventory_coverage.py +++ b/packages/microcosm-build/src/microcosm/build/spec_engine/inventory_coverage.py @@ -362,8 +362,8 @@ # #1178: puf_support's source bytes attest CPS Social Security preservation. # RNG rules and the ordered QRF targets are unchanged. microcosm#104 moves # both again: the protocol attests microcosm.calibrate.solve. - "seed_map": "bdd339868ee0cec07fa3a52a91c4bd97de707c15aeb0dc224b064be9ce04eb4b", - "seed_protocol": "8d028354d487eadecf3bc4a950d70c95e5c44c792fe7fdf2d52c77e6d86a7886", + "seed_map": "41a64b8820bf161e316c49e3f2b666a247b58f6f6d50dd4395b89c8f5b1399f6", + "seed_protocol": "0e4c8a4ace5e10747065669a009691d0eee9179ca42b344f8912c5ca239ebde6", "source_manifest": "f4f8bfeb79268a4043a843b47cec1d1c0e58e9f5dd6bc23417ada95446dd7b8e", "take_up": "9522ce40f7dea569312dd7a7beb474e5a5afadd2f1e10cb5876534c3ef623d35", "tail": "ac92829c88a1a4fb6460d61190918d5d99c6c377fc8dd8f62f02b332d09bf59c", diff --git a/packages/microcosm-build/tests/engine_free/shared/test_spec_engine_loader.py b/packages/microcosm-build/tests/engine_free/shared/test_spec_engine_loader.py index 51a88513fb..070bbc6d23 100644 --- a/packages/microcosm-build/tests/engine_free/shared/test_spec_engine_loader.py +++ b/packages/microcosm-build/tests/engine_free/shared/test_spec_engine_loader.py @@ -12,7 +12,7 @@ def test_semantic_hash_has_golden_vector_and_surface_separation(tmp_path) -> Non # Pin the domain separator, normalization rules, schema-set receipt, and # exact normative projection as one reviewable golden vector. assert first.spec_sha256 == ( - "aadf7c8cf2b0e19e75d9dc1a7b1d8190e33af9ce62657c438029b504e839867d" + "0c0c8eea8f5d350f3a73867aebfcb82450cb606124dc85cc3772cc2eae971ddb" ) second_root = _rich_minimal(tmp_path / "xy", note="second", store="local:b") diff --git a/packages/microcosm-build/tests/engine_workflow/us/test_us_multispine_pool_tool.py b/packages/microcosm-build/tests/engine_workflow/us/test_us_multispine_pool_tool.py index cb38e7427f..799d806d36 100644 --- a/packages/microcosm-build/tests/engine_workflow/us/test_us_multispine_pool_tool.py +++ b/packages/microcosm-build/tests/engine_workflow/us/test_us_multispine_pool_tool.py @@ -338,7 +338,7 @@ def capture_equality(expected: object, actual: object) -> None: "country": "us", "schema_id": "country_spec", "schema_version": 1, - "spec_sha256": "638cd60e97a9b200f8bdfd4f92e67be986f516ac25b9a37508235963e695e640", + "spec_sha256": "3080fe938df62216dc4853c1163639817de3c537e0e932309642fbd3f7d8f266", }, }