diff --git a/packages/microcosm-build/tests/engine_free/shared/test_nz_target_references.py b/packages/microcosm-build/tests/engine_free/shared/test_nz_target_references.py index 3fb7e1d243..43b4d75f63 100644 --- a/packages/microcosm-build/tests/engine_free/shared/test_nz_target_references.py +++ b/packages/microcosm-build/tests/engine_free/shared/test_nz_target_references.py @@ -6,6 +6,7 @@ import json import math import os +import re from collections import Counter from dataclasses import replace from pathlib import Path @@ -1347,6 +1348,20 @@ def test_each_coarse_band_lists_exactly_its_native_rows_labels(artifact): } +# The native income rows whose label repeats the previous row's upper endpoint +# ($50,000, $80,000 and $300,000). Each opens a coarse band, and right closure +# leaves the shared endpoint in the band below. +_INCOME_SHARED_ENDPOINT_ROWS = {"row_60", "row_90", "row_230"} + + +def _label_cents(label): + """The cents at each end of a "$a - $b" label.""" + lower, upper = re.fullmatch( + r"\$([\d,]+) - \$([\d,]+)", " ".join(label.split()) + ).groups() + return 100 * int(lower.replace(",", "")), 100 * int(upper.replace(",", "")) + + def test_each_coarse_row_selects_its_native_rows_committed_labels(): """R2C-16 without the feed: membership checked against committed rows. @@ -1355,6 +1370,11 @@ def test_each_coarse_row_selects_its_native_rows_committed_labels(): equals theirs. For each measure the 12 bands' native rows tile rows 50 to 244 once, in order. The feed audit above checks the same labels against the feed, which CI doesn't load. + + Each finite band's first label starts $1 above the band's lower cut (at the + cut, for the three pinned rows) and its last label ends at its + ``upper_cent``, so no native row can move to a neighbouring band in both + lists unnoticed. The open tail's one label is "Over $1,000,000". """ native = { row["name"]: row @@ -1385,3 +1405,29 @@ def test_each_coarse_row_selects_its_native_rows_committed_labels(): assert labels == expected, row["name"] for kind, members in tiled.items(): assert members == [f"row_{n}" for n in range(50, 245)], kind + (table,) = ( + table + for table in _document("reference_intervals.json")["tables"] + if table["id"] == "ird_taxable_income_standin_ty2024" + ) + coarse = {row["name"]: row for row in _rows()} + cut, shared = table["first_lower_cut_cents"], set() + for band in table["bands"]: + for name in (band["count_reference"], band["amount_reference"]): + row = coarse[name] + (labels,) = row["ledger_selector"]["dimension_values"].values() + if band["upper_cent"] is None: + assert [" ".join(label.split()) for label in labels] == [ + "Over $1,000,000" + ], name + assert cut == 100_000_000, name + continue + lower, _ = _label_cents(labels[0]) + _, upper = _label_cents(labels[-1]) + if lower == cut: + shared.add(row["metadata"]["native_rows"].split(",")[0]) + else: + assert lower == cut + 100, name + assert upper == band["upper_cent"], name + cut = band["upper_cent"] + assert shared == _INCOME_SHARED_ENDPOINT_ROWS diff --git a/packages/microcosm-build/tests/engine_free/shared/test_nz_transport_toy_graph.py b/packages/microcosm-build/tests/engine_free/shared/test_nz_transport_toy_graph.py index 5d07658f56..a475f7ae78 100644 --- a/packages/microcosm-build/tests/engine_free/shared/test_nz_transport_toy_graph.py +++ b/packages/microcosm-build/tests/engine_free/shared/test_nz_transport_toy_graph.py @@ -834,6 +834,18 @@ def test_target_profile_coverage_passes_on_the_toy_with_income_required(toy): assert "income" in entry["parameters"]["required_families"] row = _gate_row(run, "toy_target_profile_coverage") assert row["status"] == "passed", row["failures"] + # The gate needs one income match; this pins all six stand-in rows, so a + # row that leaves the income family turns the test red while the gate + # still passes. The binding hands the gate the problem's row names, which + # read name@period (target_kernels.py), so the comparison drops the period. + from test_support.microcosm_build.transport_nz_toy import toy_standin_table + + matched = row["details"]["matches_by_requirement"]["income"] + assert sorted(name.partition("@")[0] for name in matched) == sorted( + band[role] + for band in toy_standin_table()["bands"] + for role in ("count_reference", "amount_reference") + ) def test_measurement_prefit_fails_the_toy_only_on_its_unwired_evidence(toy): @@ -847,6 +859,7 @@ def test_measurement_prefit_fails_the_toy_only_on_its_unwired_evidence(toy): from test_support.microcosm_build.transport_nz_toy import ( TOY_PREFIT_EVIDENCE, + TOY_PREFIT_SUPPORT, TOY_STANDIN_TABLE, ) @@ -856,6 +869,18 @@ def test_measurement_prefit_fails_the_toy_only_on_its_unwired_evidence(toy): gate for gate in gates["gates"] if gate["gate"] == "measurement_prefit" ] assert list(TOY_PREFIT_EVIDENCE) == packaged["parameters"]["required_evidence"] + (entry,) = [ + gate + for gate in fixture.spec["resources"]["gates"]["gates"] + if gate["id"] == "toy_measurement_prefit" + ] + # R2C-3's ratio bounds stand on the toy; only the two support floors scale + # down to forty households. + assert set(entry["parameters"]) == set(packaged["parameters"]) + for key in ("roster_total_bounds", "band_bounds", "maximum_discrepant_bands"): + assert entry["parameters"][key] == packaged["parameters"][key], key + for key, value in TOY_PREFIT_SUPPORT.items(): + assert entry["parameters"][key] == value, key row = _gate_row(run, "toy_measurement_prefit") assert row["gate"] == "measurement_prefit" assert row["status"] == "failed" @@ -954,7 +979,7 @@ def test_property_a_positive_standin_above_the_first_cut_lands_in_one_band( in none, and x <= 0 is ``excluded`` and in none. The table, as NZ's, has no nil band and a first cut above zero. """ - from hypothesis import given, settings + from hypothesis import example, given, settings from hypothesis import strategies as st from microcosm.build.reference_intervals import interval_indicators @@ -971,6 +996,13 @@ def test_property_a_positive_standin_above_the_first_cut_lands_in_one_band( factor = Fraction(11, 10) cuts = [factor * cut for cut in (TOY_STANDIN_FIRST_CUT, *TOY_STANDIN_CUTS)] signed = st.integers(-150_000, 150_000) + # Wages at zero and on each aged cut, one either side, with every other + # component zero: random draws almost never land on an edge. + edges = [ + (value + step, *(0 for _ in TOY_STANDIN_COMPONENTS[1:])) + for value in (0, *(int(cut) for cut in cuts)) + for step in (-1, 0, 1) + ] @settings(max_examples=150, deadline=None) @given( @@ -980,6 +1012,7 @@ def test_property_a_positive_standin_above_the_first_cut_lands_in_one_band( max_size=12, ) ) + @example(edges) def check(records): columns = { column: pd.Series([row[i] for row in records], dtype="int64") @@ -1007,6 +1040,29 @@ def check(records): check() +def test_the_toy_standin_measure_keeps_the_packaged_central_rules(): + """The toy declaration differs from ``measures.central`` only in its columns. + + Its entity, add-backs, floor and scale equal the packaged declaration's, it + names the same three outputs, and both give every component sign +1, so + the toy's gates run on the packaged measure's arithmetic. The toy sums + seven toy columns where the packaged measure sums ten. + """ + from importlib.resources import files + + from test_support.microcosm_build.transport_nz_toy import toy_standin_declaration + + packaged = json.loads( + (files("microcosm.build") / "nz" / "income_measurements.json").read_text() + )["measures"]["central"]["declaration"] + toy = toy_standin_declaration() + for key in ("entity", "add_backs", "floor", "scale"): + assert toy[key] == packaged[key], key + assert set(toy["outputs"]) == set(packaged["outputs"]) + assert {row["sign"] for row in toy["components"]} == {1} + assert {row["sign"] for row in packaged["components"]} == {1} + + def test_without_the_toy_standin_its_six_rows_refuse_activation_by_name(toy): """The drop-the-node mutant, built in the test: A's proof fails closed.""" from test_support.microcosm_build.transport_nz_toy import (