Repository navigation
Test G's income stand-in on NZ's toy graph - #1483
Merged
Merged
Conversation
Give the synthetic NZ toy its own counterpart of each piece G packages: a measure.combine@1 stand-in node with measurement_id, its declaration (floor 0, scale 100, rental as the one add-back), a cents node for the mapped wage, a three-band coarse table with no nil band, six summed rows (sum counts, identity amounts) over invented native member facts, a scale_money_and_intervals ageing profile resolved against a pinned toy feed, the prepare and problem inputs (the problem slices the unit column, R2C-25), target_profile_coverage and a diagnostic measurement_prefit entry with the packaged required_evidence list. Invariants, each checked by a new toy test: the six rows enter the problem matrix once with nonzero support; target_profile_coverage passes with income required; measurement_prefit's only failures are one evidence line per unwired alias (R2C-18); each coarse value equals its declared members' sum (times the ageing factor for amounts). A Hypothesis property checks the band membership of any toy incomes. Two existing toy tests count the new rows: n_targets moves from 4 to 10, and the compiled-row test reads the effective (profile-resolved) view. The full toy file passes (30 tests). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6FpF7dJcTwxa1pX54W
The drop-the-node mutant made the toy fixture itself refuse, so no toy test asserted the reason. This test removes nz.income.standin from a copy of the toy spec and checks that activation names each of the six coarse rows and measurement:toy_income_standin_v1, as A's proof requires (R2C-1). The toy file passes in full (31 tests). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6FpF7dJcTwxa1pX54W
compose's _check_measurement_proofs runs on the transport skeleton, before the scenario extensions append their branches, so it checks R2C-15 for nz.calibrate only and never sees the eight variant calibrations (nz.v.<V>.calibrate). The new test composes NZ's packaged graph and, for each of the nine calibration nodes, asserts that exactly one compiled ancestor declares ird_taxable_income_ty2027_v1, that it is that branch's stand-in, and that no other ancestor writes any of the proof's columns as an output or an EXPAND cell. A cached helper composes the graph once per process for this test and the existing compile test. Mutants, each restored after its run: - Removing nz.v.VSI.income.standin from scenarios.json fails the new test's declarer assertion (the test helper substitutes nz.v.VSI.synthetic_measurement), while the existing compile test passes. - Dropping that stand-in's measurement_id, or adding an undeclared second writer of a proof column to VEX, makes composition refuse the graph with two owners of one column, before the new test's assertions run. No NZ scenario declares an EXPAND node, so no mutant reaches the EXPAND-cell clause. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
G8-r2c (#1183), brief 212: design 80 section 6 G's toy-graph tests for G's income stand-in. Draft, stacked on G (#1478,
nzhub/g8r2c-g-wiringat64ef20af). The toy session's commits change only the toy fixture and the toy test file, and the hub's commit85d55afadds one test totest_nz_transport_declarations.py. The PR changes no kernel, no packaged resource and no golden. Paths:T/ispackages/microcosm-build/src/microcosm/build/transport/,N/ispackages/microcosm-build/src/microcosm/build/nz/, and tests sit inpackages/microcosm-build/tests/engine_free/shared/. File:line is at4ae5810e, the toy session's last commit;85d55afchanges no line in the toy files.Change
test_support/microcosm_build/transport_nz_toy.pygives the toy its own counterpart of each piece G packages. Every name starts withtoy_, except the stand-in node's id, which mirrors NZ's.toy_standin_declaration,:635): the toy's version ofN/income_measurements.jsonmeasures.central. It sums wages, signed farm income, interest, rental (the one add-back) and the toy's three annual transfers, with floor 0 and scale 100 (R2C-10). It writestoy_income_proxy_cents(Int64),toy_income_proxy_nzdandtoy_income_proxy_universe_status. The resourcetoy_income_measurementscarries it with its canonical SHA-256._income_standin,:722):nz.earnings.cents(money.minor_units@1, E's wage-cents node) andnz.income.standin(measure.combine@1,measurement_id: toy_income_standin_v1) onnz.central. The variant branches clone both.toy_standin_table,:649):toy_income_standin, with 3 bands, both companions and no nil band. Like NZ's table, its first cut (15,000 cents) sits above zero.toy_standin_references,:690): 6 rows in A's multi-member form (R2C-17), withsumfor counts andidentityfor amounts, each pinned to its members inTOY_STANDIN_MEMBERS(:611). Family isincome. Their measures aretoy_people, a constant like NZ'speople, andtoy_income_proxy_nzd. Nine invented native member facts (TOY_STANDIN_FACTS,:618) sit near the toy's pre-fit weighted totals.reference_profilesdeclares the dimensiontoy_aging_indexwith onescale_money_and_intervalstransform over the table and the 6 rows, underrequired_measurement_binding._pin_calibration_facts(:879) writes the toy calibration facts and the shared factor fixture's facts as one pinned feed. It then resolves the factor (1.1) against that feed and passes the pin to everytargets.compile@1node, so the compiler replays the factor as NZ's compiler does.toy_peopleand the 3 interval indicators. The problem slices those columns, the unit column (R2C-25,:846) andhousehold.source_household_id.toy_target_profile_coverage(required_families: ["income", "toy"], release-blocking) andtoy_measurement_prefit. The prefit gate uses R2C-3's ratio bounds, the packagedrequired_evidencelist (TOY_PREFIT_EVIDENCE,:909) and support thresholds of 3 source households and Kish ESS 2, sized for forty households (:632). Its criticality isdiagnostic(:873).Invariants and tests
All tests are in
test_nz_transport_toy_graph.py.incomeand its declared measure. A's proof namesnz.income.standinasnz.calibrate's producertest_each_toy_coarse_row_enters_the_problem_matrix_once_with_support(:786)problem_slices_no_nzd:targets.problem@1refuses the 3 amount rows, so the toy fixture errors and every toy test that uses it goes red, this one includedtarget_profile_coveragepasses, withincomerequiredtest_target_profile_coverage_passes_on_the_toy_with_income_required(:825)drop_standin_node: activation refuses the 6 rows, so the fixture errorsmeasurement_prefitruns. Its failures are exactly oneevidence: the run lacks required evidence '<alias>'.per packaged alias, in order, with no roster, band, support or diagnostics failure. The toy's list equalsN/gates.json'stest_measurement_prefit_fails_the_toy_only_on_its_unwired_evidence(:839)alias_as_problem_artifact(aliasnative_band_reportwired tonz.targets.problem'sproblemartifact): 5 lines instead of 6.support_threshold_10(minimum source households 10, above b2's 9): a support failure appears.alias_wired_to_problem(artifact namenative_band_report): composition refuses "reads undeclared artifact"test_each_toy_coarse_reference_equals_the_sum_of_its_member_references(:880)members_swapped(b0 and b1 trade n03 and n04 in both rows of both bands)combine_measureandinterval_indicatorson the effective table): x > the aged first cut lands in exactly one band, the one an independent cut count names; 0 < x ≤ the aged first cut lands in none; x ≤ 0 isexcludedand lands in nonetest_property_a_positive_standin_above_the_first_cut_lands_in_one_band(:949)table_first_cut_0(the table's first cut set to 0)measurement:toy_income_standin_v1test_without_the_toy_standin_its_six_rows_refuse_activation_by_name(:1010)drop_standin_nodemutant itselfMutants. I ran each mutant in place on the working tree, ran the 7 affected tests, and restored the files with
git checkoutafter each one.git statuswas clean after every series.one_member_changed(one member changed in b0's count row only) made composition refuse ("References 'toy_income_standin_amount__b0' and 'toy_income_standin_amount__b1' share a summed member"), so the fixture errored.members_swappedis the variant that composes, and the differential catches it. No mutant survived.Existing toy tests whose counts changed
test_four_regional_age_cells_prepare_and_calibrate_once(:487):n_targetsgoes from4to4 + 2 * len(TOY_STANDIN_MEMBERS)(10), because the problem now holds the 4 demography cells plus a count row and an amount row for each of the 3 coarse bands.test_each_activated_calibration_row_compiles_once_and_exempt_rows_stay_out(:240): the expected set now comes from the effective view,transport_resource(spec, "target_references"), not the raw resource. The 6 rows arerequires_prerequisitesin the raw resource, and the profile and A's proof activate them before compilation, so the compiled set holds 4 + 6 names.Tests at
4ae5810eNZ_CHRONICLE_ARTIFACTwas set to the brief's feed, and both digests match the pin (03f5ea0f…,1ea2d1ee…). Runs used-n 4.test_nz_transport_toy_graph.py: 31 passed, 0 skipped.test_nz_transport_declarations.py: 60 passed, 0 skipped.python3 tools/ci_test_plan.py verify:verification=ok.ruff checkandruff format --checkpass on both files.Hub commit
85d55afThe NZ hub added one test to
test_nz_transport_declarations.pyafter the toy hand-off, because of the proof-scope observation in Notes.test_every_calibration_node_has_its_own_standin_as_the_only_writercomposes NZ's packaged graph. For each of its nine calibration nodes (nz.calibrate, andnz.v.<V>.calibratefor V1, V2, V3, V4, VEX, VHF, VPT and VSI), it asserts R2C-15 on compiled ancestry: exactly one ancestor declaresird_taxable_income_ty2027_v1, it is that branch's stand-in, and no other ancestor writes any of the proof's columns as an output or an EXPAND cell. A cached helper,_nz_composed, composes the graph once per process for this test andtest_nz_packaged_graph_compiles_with_only_pins_and_money_producers.N/scenarios.json, restored after each run)vsi_standin_removed: dropnz.v.VSI.income.standinnz.v.VSI.synthetic_measurement. The existing compile test passes.vsi_standin_undeclared: drop that stand-in'smeasurement_idvex_undeclared_rewrite: add a second, undeclared writer of a proof column to VEXNo NZ scenario declares an EXPAND node, so no mutant reaches the EXPAND-cell clause. Before the commit, a hub script applied the same rule to G's head
64ef20afand found all nine nodes passing. The hub ran the two tests the commit touches (2 passed in 61.5 s, peak 1.45 GB),ruff checkandruff format --checkon the file, andtools/ci_test_plan.py verify(verification=ok).Notes
measurement_prefitentry isdiagnostic, notrelease_blockinglike NZ's, because R2C-18 makes it fail every run. A blocking entry would stop the toy export that the other toy tests exercise. The test checks that the refusal reaches the gate report.toy_aging_indexdeclares onlycentral.measurement_proofs(T/compose.py:610) and_check_measurement_proofs(:716, called at:4372with the skeleton graph) walk only the transport skeleton. So the proof names a producer fornz.calibrateonly, and not for the variant calibrations on scenario branches. The toy test asserts what the code does. The hub's commit85d55afchecks the rule on every calibration node of NZ's composed graph (see above).https://claude.ai/code/session_01LwQq6FpF7dJcTwxa1pX54W
Generated by Claude Code