Repository navigation
G8-r2c E-G: NZ's wage map, coarse income rows, stand-in measure, variants and pre-fit gate - #1478
Merged
Merged
Conversation
The generator adds the TY2026 wage interval table ird_wage_salary_national_ty2026 (rows 7-241, right-closed, no nil band, negative wages refused, open tail over $1,000,000) from the pinned feed's labels, and activates the 235 P1 precal rows, which drops their exemptions. The transport builder writes earnings_bands.json: for each aging_index profile, every edge is cut_cents x P1 factor / 100, computed in Fraction and rounded once to binary64, with the factor id, its receipt SHA-256 and the wage table's SHA-256. nz.earnings.map (transport.quantile_map@2, grouped_pareto_mle@1 on rows 231-241) rewrites person.employment_income beside nz.money.normalize, and nz.earnings.cents writes employment_income_cents half-even, both before nz.encode.person. Each calibration variant repeats them with its own profile (V1 low, V2 high). R2C-6 adds person.employment_income to the export contract and both slices. Three wage labels repeat the previous upper endpoint ($20,000, $50,000, $80,000: rows 27, 57, 87); the generator pins them and the right-closed cuts give each endpoint to the lower band. Invariants: every edge equals cut x factor exactly for every profile (example test, plus a builder --check that refuses a hand-edited edge, a stale factor receipt, a stale table and a changed tail); the edges stay contiguous and increasing for any positive factor (Hypothesis); the scaled-edge map equals the unscaled map x f within 2^-49 relative (measured at most 4.3e-16); the toy's @2 support row is quantile_mapped with 0 records outside. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6Fwj4yUEPsD3wfNstU
test_nz_spec_package pins the active row count per reference set. G8-r2c E activates the 235 wage rows, so precal's active count moves from 80 to 315. The calibration and hold-out counts stay as they were. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6Fwj4yUEPsD3wfNstU
The generator adds the coarse table ird_taxable_income_standin_ty2024 (person, right-closed, no nil band, floor_zero, first lower cut $40,000, cuts at $50k to $1m and an open tail: 12 bands) with count and amount companions on every band and per-band source-household support (support_household_entity: household), which measurement_prefit needs. It writes 24 rows in A's summed form: 12 count rows with value_operation sum and no operands, 12 identity amount rows measuring ird_taxable_income_proxy_nzd (R2C-10, R2C-17), each pinning its band's native labels and expected_member_count. The rows keep the prerequisites reference_profile:aging_index and measurement:ird_taxable_income_ty2027_v1, stay requires_prerequisites and are not exempt. The calibration document allows sum. R2C-4 moves the 474 native rows to the non-executable income_diagnostic_references.json (key diagnostic_references) and drops their exemptions. The national table loses its companions and becomes declared and validated only. The aging_index transform now scales the 24 rows and the coarse table. Invariants: each coarse band is the sum of whole native rows 50-244 (generator check, a feed-gated label audit and a differential that compiles each aged coarse row against its native rows' aged sum); the central first cut is exactly 4,468,436 cents; no native row sits in an executable document; the rows stay parked and unexempt without a producer; the scaled coarse table tiles the positive range for any positive factor (Hypothesis, through scale_interval_table and classify_records). The NZ composition tests add a compile-only measurement producer, as they already add synthetic money producers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6Fwj4yUEPsD3wfNstU
The hub's R2C-19 lifts the freeze for these tests on E. Each edit follows from what E changes in NZ's own resources: - test_spec_engine_country_bundles: NZ's legacy resources include earnings_bands.json. - test_transport_composed_graph: _GAPS no longer names the person.employment_income quantile-map gap, which nz.earnings.map closes. - test_transport_evidence_kernels: the roster gains one quantile_mapped row (R2C-6), and derived rows miss only rent and liquid assets; the per-row assertion over every derived row stays. - test_transport_quantile_map_v2: _spec_with_map first removes the packaged nz.central producer of employment_income, so the kernel under test stands alone; that spec without a map still reports a central wage gap; the packaged spec reports none. Both accepted kernels and the transport.currency@1 refusal stay. Mutant run: with _money_producer_gaps accepting any kernel, test_composition_accepts_v2_as_the_quantile_mapped_money_producer goes red (the currency@1 refusal finds no gap). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6Fwj4yUEPsD3wfNstU
The hub's R2C-19 item 1 lifts the freeze on test_nz_generation_zero_views_come_from_the_country_spec_seam for F: NZ's legacy resources now include income_diagnostic_references.json, the non-executable home of the 474 native IRD rows (R2C-4). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6Fwj4yUEPsD3wfNstU
test_nz_transport_declarations memoizes resolved reference views by the content of the documents the resolver reads. A's measurement proof now reads the transport graph too, so a view resolved for a graph without a measurement producer was reused for a graph with one, and the composition tests saw "no proof". The cache key now includes the graph. Checked: the full file passes in one process after the change; before it, the five composition tests failed only when an earlier test in the same process had cached a producer-less view. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6Fwj4yUEPsD3wfNstU
R2C-4 moves the 474 native rows out of the executable documents, so the aging_index profiles scale the coarse stand-in table, not the national one. The hub's R2C-22 lifts the freeze for: - test_reference_profiles test_nz_default_factor_receipt_is_compact_and_covers_the_exact_roster: the receipt names ird_taxable_income_standin_ty2024 (12 bands) and 24 companions, whose source carries A's expected_member_count. - test_transport_composed_graph test_declared_scenarios_scale_national_cuts_with_their_own_factor: the per-scenario cut check moves to the coarse table (local name coarse), and the national and age tables must stay unscaled. Mutants: a resolver that also scales the national table turns both tests red (the second at tables[unscaled] == by_id[unscaled]); giving the low profile the central factor id turns the second test red. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6Fwj4yUEPsD3wfNstU
- income_measurements.json (written by the transport builder) holds C's measure.combine@1 declaration for ird_taxable_income_ty2027_v1 from design 80's component table: person, floor 0, scale 100 (R2C-10), rental income as the add-back, outputs ird_taxable_income_proxy_cents, _nzd and _universe_status. A VSI sibling drops the four transfer addends. The document also holds the omission register (every size "unknown": the design's percentages have no repo source), VSI's review triggers and the R2C-8 wage-earner diagnostic, none of them gates. - nz.income.standin (measure.combine@1, measurement_id ird_taxable_income_ty2027_v1) runs after nz.benefits.annual_transfers and before nz.targets.prepare on every calibration branch. A's proof names it as the measurement's only producer for nz.calibrate, which lifts the 24 coarse rows' measurement prerequisite. - calibration_bindings.json binds the coarse table's 12 band indicators by interval; prepare reads the measure and universe columns, and the problem reads them plus household.source_household_id, which targets.problem@1's per-band support needs (target_kernels.py:994-1002, reference_intervals.py:1137-1160). - R2C-2: the S5 stage nz.precal.nz_super lists NZS eligibility and the before-tax weekly amount, with the cents as a derived output; nz.gross_up.super_cents names the nz_super engine_ref and period. - Scenarios VSI (income_measure vsi), VEX (exposure.central "0.75", a declared judgment, R2C-7) and VPT (earnings_tail_anchor vpt) with their knob domains; both cell-support gates require them, and the structural-zero superannuitant cell lists them. - gates.json adds measurement_prefit with R2C-3's frozen numbers and R2C-18's six evidence aliases, none wired, so the gate refuses for missing evidence until G8-x. R2C-20: the NZS sharing input keeps its default; the binding needs a new transform kind, which the hub carries as H1 and H2. Invariants: A's proof finds exactly nz.income.standin and refuses a second declaring producer; without the stand-in the 24 rows refuse activation by name; VSI omits exactly the four transfer columns; each declaration's digest is its canonical text's; the prefit entry equals R2C3_PREFIT_THRESHOLDS; the S5 guard refuses a reader of a non-public nz_super column. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6Fwj4yUEPsD3wfNstU
The hub's R2C-23 extends R2C-19 item 1 to G: test_nz_generation_zero_views_come_from_the_country_spec_seam lists income_measurements.json, the new home of C's declaration. As R2C-23 asks, E's earnings_bands.json moves to its sorted place between currency_bridge.json and entitlement_graph.json; F's and G's lines sit in theirs. The test passes (22 of 22). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6Fwj4yUEPsD3wfNstU
G's closed list showed NZ resources and tests that pin the scenario set or the pre-G state: - reporting_classifiers.json's baseline_cell_contract lists VSI, VEX and VPT, so every scenario has a baseline cell contract. - VEX's knob is the number 0.75 (central 1), as NZ's scenario contract wants for a non-list domain; the builder writes it into the annual-transfers declaration as the exact decimal text "0.75". - NZ tests: the scenario list and structural-zero cells include the three variants; the active-or-exempt check accepts the coarse rows as active once A's proof holds; the family-reconciliation check prepares without G's person interval outputs; the MSD rate check strips super_cents' S5 provenance selections, which name the stage and not the rounding, because the shared helper prepares only two bindings. Checked: the 59 tests that failed or touch these lines pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6Fwj4yUEPsD3wfNstU
This was referenced Nov 3, 2026
The hub's R2C-24 lifts the freeze for two lines on G: - test_transport_weight_quality test_adopted_cell_targets_are_flagged_and_never_block: 43 * 10 becomes 43 * 13, because both cell-support gates now require 13 scenarios (main's 10 plus VSI, VEX and VPT). - test_transport_evidence_kernels test_the_nz_roster_classes: derived 307 becomes 321. G adds 14 derived rows: the stand-in's measure and universe columns and the 12 coarse band indicators. The per-row assertion stands; all 321 rows miss exactly rent and liquid assets. Both tests pass at this commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6Fwj4yUEPsD3wfNstU
The 12 coarse amount rows measure ird_taxable_income_proxy_nzd, and targets.problem@1 refuses any target whose measure its node doesn't slice (T/target_kernels.py _compiled_problem: "every reference must name columns the node slices"). G wired the measure and universe columns and the source households but not this one, so a real run would have refused the 12 amount rows. Every calibration branch's problem now reads it. The test now checks that the problem slices every income row's measure. With the builder and resources reverted it goes red; with them it passes. This adds one derived row to the support roster (322), so test_the_nz_roster_classes' R2C-24 count of 321 goes red; the hub rules on it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6Fwj4yUEPsD3wfNstU
10 tasks
a3fe195 adds person.ird_taxable_income_proxy_nzd to the problem inputs of every calibration branch, so the unit column joins the support roster as a derived row. R2C-25 amends R2C-24's second line in test_the_nz_roster_classes from 321 to 322. The per-row assertion stays as it was: every derived row still misses exactly household.rent and person.liquid_financial_assets. I ran the test at this head and it passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6J45cyZzJWT9gGBLYB
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>
The E-G review's fix 3. Only the Chronicle feed, which CI doesn't load, checked R2C-16's membership, so a coarse row that lost a member label passed every feed-free test. The new test reads the committed income_diagnostic_references.json: each coarse row's labels equal, in order, the labels of the native rows its metadata.native_rows names, its selector otherwise equals theirs, and each measure's rows tile 50 to 244 once. Without the feed, the review's b05 member drop turns this test red and no other in test_nz_target_references.py, test_nz_reference_intervals.py or test_nz_spec_package.py (1 failed, 1237 passed, 42 skipped). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The E-G review's fix 4. Only the feed checked the wage table's cents against their labels, so a $1 change to one upper_cent passed every feed-free test, even after the builder rewrote earnings_bands.json to match. The new test reads each band's committed label as the right-closed band (a - 1, b] dollars, so the cut below it is 100(a - 1) cents and its upper_cent is 100b. A label whose lower endpoint repeats the previous band's upper one starts at that cut, and the test pins those rows to 27, 57 and 87. Without the feed, the review's row_107 mutant turns this test red and no other in test_nz_transport_declarations.py or test_nz_earnings_bands.py (1 failed, 63 passed, 2 skipped). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Belgium's hub asked for this rename when it cleared E to G's shared test lines: since F, the test checks the coarse stand-in table, not the national one. Only the name changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The stack last met main at D's head (91bf4c0). Since then main has landed eleven PRs whose content the stack lacks: #1432, #1442, #1410, #1428, #1051, #1444, #1471, #1479, #1472, #1477 and #1463. #1472 brings the holdout test whose pinned NZ stage set the next commit extends (R2C-26). git merge-tree resolves the merge without conflicts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
G's nz.precal.nz_super (R2C-2) adds the nz_super binding to NZ's precalibration stages. At main + G, this test failed on its pinned set alone, and the stage guard itself accepts the stage: test_packaged_precalibration_stages_pass_the_stage_guard[nz] Hub ruling R2C-26 lifts the freeze for this one line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
G's 714e10d adds twelve stand-in income band outputs to NZ's calibration_bindings.json, each an "interval" entry. The tests in test_calibration_columns.py call prepare_calibration_columns on that file without the effective interval document, so the check at packages/microcosm-build/src/microcosm/build/calibration_columns.py:106-107 refuses them with "Interval outputs need the effective interval document." Brief 214 counted 17 such failures at 891cb9f. The prepare kernel passes the document (packages/microcosm-build/src/microcosm/build/transport/target_kernels.py:679); these tests call the function directly. _bindings() now drops the interval entries, and a new test pins the refusal: NZ's packaged bindings declare interval outputs, and prepare_calibration_columns refuses them without the document. The file's interval tests still cover interval outputs on their own fixture. With the fix the file gives 106 passed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 3, 2026
MaxGhenis
marked this pull request as ready for review
November 4, 2026 00:13
Contributor
Author
|
Merged by the NZ hub (session local_e407a527) at f43e8fb with --merge. Gates: |
MaxGhenis
added a commit
that referenced
this pull request
Nov 4, 2026
G landed on main as f8f543a, and this PR now targets main. After the retarget, GitHub's merge ref kept G's old branch head f43e8fb as its first parent, so this merge starts CI on main as it now stands. The merge writes the tree git merge-tree gives for main and b64eb6c, 57481e8, where the measurement-proof, NZ toy-graph, calibration-column, evidence-kernel and composed-graph test files all passed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
added a commit
that referenced
this pull request
Nov 4, 2026
G landed on main as f8f543a after this PR's last CI run, which tested 8a4e7a4 merged into main 79a533c. GitHub's merge ref still has 79a533c as its first parent, so this merge starts CI on main as it now stands. G and this PR change no file in common, and git merge-tree writes tree 5c0a6b9 with no conflict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
added a commit
that referenced
this pull request
Nov 4, 2026
…1488) * Prove extension calibration nodes' measurement producers in compose The extension pass of compose_transport_graph compiled the extended graph and reran the ancestry guard, but never ran _check_measurement_proofs. So a calibration-tier scenario's calibrate.* node could calibrate against a money-scaled measurement that no proof covered: measurement_proofs reads only the declared graph's rows and never names those nodes. The extension pass now runs the check after the ancestry guard, as the skeleton pass does. For a calibration node that an extension adds, the compiled graph proves the producer under R2C-1's rule: exactly one compiled ancestor declares the measurement, and that ancestor outputs every proof column. R2C-15's only-writer rule applies as before. A skeleton calibration node keeps the declared comparison, which the pass now also runs against the extended graph. Tests: unit cases on the compiled toy; a differential property that the declared proof and the compiled extension proof agree, refusal for refusal, on chains of declarers and writers; and NZ's synthetic graph with four V3 mutants (M1, M2, M4 and the NZ hub's G7), each of which composes without this change. * Move the NZ-toy measurement-proof tests into NZ's toy-graph file The five tests that run the extension proof on NZ's synthetic graph name the toy's V3 nodes, and the NZ hub owns the toy and its node ids. They move, with their helpers, from test_transport_measurement_proof.py into test_nz_transport_toy_graph.py and use that file's module `toy` fixture, so a change to the toy edits only NZ's files. The shared file keeps the unit tests on the compiled toy and the differential property. The move adds G7 in the NZ hub's placement. V3's calibration keeps its base on V3, while preparation, the compiled targets and the problem move into the review version that rewrites both measured columns. The problem reads the rewritten columns, so only the calibration's artifact edge from the problem puts the rewrite among its compiled ancestors. The earlier G7 opens the calibration from the review version, where the rewrite joins its base, and doesn't need that edge. * Refuse a malformed measurement_id in the compiled proof check Review r2 found that the compiled check skipped a node whose measurement_id was neither None nor a nonempty string, while the declared check refuses it. With the string producer still in place, an extra upstream node declaring measurement_id 7 composed, though the same param on a declared row parks every measurement. r2 showed it on NZ's toy graph, where V3's earnings.cents with id 7 composed. _check_measurement_proofs now refuses such a node with the declared check's reason before it proves any producer, and reads an explicit None as no declaration, as measurement_proofs does. The new test gives a node upstream of calibration a measurement_id of 7, "" or None, and runs the declared check and the compiled check on a calibration node that an extension adds and on a skeleton one. Both checks refuse 7 and "" with the same reason, and both ignore None. Without the fix, the compiled check accepts the four 7 and "" cases, and those cases fail. The commit also fixes three docstrings that r2 flagged: the test module's account of the compiled tests, which patch in a proof; _chain's, whose nodes chain by step columns; and compose's module docstring, which now names gate_inputs, the other explicit way an extension may add a skeleton predecessor. * Say the compiled proof check scans malformed ids only under a proof _check_measurement_proofs returns before its malformed-id scan when the declaration proves no measurement, and its docstring now says so. The independent review of b64eb6c noted that the sentence read as unconditional. Two merges of main bring G (#1478) and then H2 (#1485) and #1501. The second keeps main's test_nz_transport_toy_graph.py whole and appends this PR's section. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
G8-r2c hunks E, F and G (#1183), with G's toy-graph tests and two fix rounds, in one merge commit (R2C-21a): E maps NZ's P1 wages onto IRD's scaled wage bands (#1475), F replaces NZ's 474 native income rows with 24 coarse stand-in rows (#1476), and G wires NZ's stand-in income measure, its variants, the NZS S5 stage and the pre-fit gate. Paths:
B/ispackages/microcosm-build/src/microcosm/build/,N/isB/nz/,T/isB/transport/, and tests sit inpackages/microcosm-build/tests/engine_free/shared/. File:line in G's sections refers to G's head,64ef20af.What this merge brings (R2C-21a)
One merge commit of
f43e8fbbinto main brings the 36 commits inmain..f43e8fbb: hunks E, F and G, the toy-graph tests and two hub fix rounds. Each part's PR body holds its change list, invariants and tests; the sections below this one describe G.fee9f17b,572ee347,385d5967and two merges of the integration basetransport.quantile_map@2c91a7808,8167c424,a52efb77,c9f5b0c2and four merges714e10d0,75eee5f6,50b033a7,8c66267e,a3fe1952,423ca43a,64ef20afand three merges9ae0914c,4ae5810e,85d55af585d55af5checks that each of NZ's nine calibration nodes has its own stand-in as the only writer of the measured columns06760993,0506c9d6,044440a7,d1d72353(merges main4a36edcf),20507ad8f43e8fbbGates at
f43e8fbb.64ef20afand requested changes (six fixes owed). Brief 213 v4 reviewed the toy tests and both fix rounds atf43e8fbb: APPROVE_WITH_NITS, Needs Max: no (Activate the NZ graph against pinned Chronicle facts (NZ graph G8) #1183 comment 6615417145). It found nothing that blocks the landing, reproduced every mutant the authors reported, and listed five places where a test checks less than its name claims; the hub tightens those in a follow-up PR once this lands.64ef20af(patch-id8e90b9bb380ec92a), fix round 1 at20507ad8(10:26Z 11/03) and fix round 2 atf43e8fbb(11/03, with two mutants of its own).f43e8fbb: probe CI probe: the G8-r2c E-G stack with its fix round, against main (don't merge) #1487 passed all ten checks against main4a36edcf(run 41639277717, 11/03). This PR's run 41729696579 tested the head merged into main79a533c7(merge commitdcf88410) and passed all ten checks (done 11/04 00:01Z). Two earlier runs failed only on main's own break, which Count the two modules #1342 added to the transport bindings' identity, and merge main's US re-pin (#1496) #1495 fixed: run 41719443029 tested main815147de, and run 41724413989 reused that stale merge ref. Brief 213 v4 ran the three toy-graph files on the head merged into main31c89390(154 passed); run 41729696579 also covers what main took since: Hand staged dataset bundles to the emitter with stage_dataset_bundle #1460, F1 (Give a person with no household no household's row, and read malformed holdout rows alike in both guards #1481) and Count the two modules #1342 added to the transport bindings' identity, and merge main's US re-pin (#1496) #1495.4a36edcfalone, so GitHub reads this PR as mergeable. E's own head has two merge bases with main, which is why E lands here and not on its own (R2C-21a, Activate the NZ graph against pinned Chronicle facts (NZ graph G8) #1183 comment 6604753490).Two sessions built this PR. Brief 194's session built it up to
a3fe1952. Brief 209's session (this update) added R2C-25's line, the tests listed under "Added at the hand-off", the mutant runs, the hash table and this body.Landing (R2C-21a, #1183 comment 6604753490). E, F and G land together. At 21:10Z 11/03 the hub retargeted this PR to main and fast-forwarded its branch to the fix rounds' top
f43e8fbb(#1486). One merge commit brings E's and F's commits, the toy tests (#1483) and both fix rounds, so #1475 and #1476 never land alone. GitHub marked #1483 merged into this branch when the branch moved.Change
N/income_measurements.json(new; written bytools/build_nz_transport_graph.py:487,income_measurements_document):measures.central(:8): C'smeasure.combine@1declaration forird_taxable_income_ty2027_v1onperson, floor 0 and scale 100 (R2C-10), outputsird_taxable_income_proxy_cents,_nzdand_universe_status, with rental income as the one add-back. Components follow design §3's table: wages, signed non-farm and farm self-employment, interest, dividends, rental, and the annual gross JS, SPS, SLP and NZS transfers.measures.vsi(:67): the same declaration without the four transfer addends.omission_register(:111): the 13 items design §3 excludes. Every size readsunknown, because design 80's percentages are the proposal's claims and no repo resource or cited public source gives one.review_triggers(:181): VSI's three R2C-3 escalation triggers.diagnostics.wage_earner_count(:200): R2C-8's diagnostic.nz.income.standin(N/transport_graph.json:1845; buildertools/build_nz_transport_graph.py:603,standin_node):measure.combine@1onnz.central, afternz.benefits.annual_transfersand beforenz.targets.prepare, withmeasurement_id: ird_taxable_income_ty2027_v1in its params (:1901, R2C-13). Every calibration variant repeats it on its own branch inN/scenarios.json; VSI's selectsmeasures.vsi.nz.targets.preparereads the income and universe columns.nz.targets.problemreads those, the unit columnird_taxable_income_proxy_nzd(a3fe1952) andhousehold.source_household_id(tools/build_nz_transport_graph.py:815-819).N/calibration_bindings.json:4418onward declares the 12 band indicators (tools/generate_nz_target_references.py:408).nz.precal.nz_super(N/precalibration_stages.json:84, R2C-2): outputsentitled_to_new_zealand_superannuation(classification) andnz_super_weekly_amount_before_tax(calibration measure), and the derivednz_super_weekly_amount_before_tax_cents.nz.gross_up.super_centsgainsengine_refandperiodselections ofnz_super(N/benefit_gross_up.json:336-345;tools/build_nz_benefit_gross_up.py).N/scenarios.json: VSI (:27520, knobincome_measure: vsi), VEX (:32117,annual_transfer_exposure: 0.75) and VPT (knobearnings_tail_anchor: vpt, E's $300,000 anchor). VEX's annual-transfers declaration (:33563) carries the exact decimal text"0.75", and the knob's domain text (:68) calls 0.75 a declared judgment, not a measured exposure (R2C-7). That declaration keeps theconventionlabelfull_year_stock_equivalentat 0.75, as the E-G review notes. The knob domains sit at:64-69.tools/build_nz_entitlement_graph.py:628-629carries the two new knobs into the variant branches, andN/reporting_classifiers.jsonadds the three variants to the carried scenarios and the structural-zero list.N/gates.json):measurement_prefit(:101), release-blocking, terminal: R2C-3's frozen numbers in the parameter names D's gate reads (roster_total_bounds [0.75, 1.25],band_bounds [0.5, 2.0],maximum_discrepant_bands 2,minimum_source_households 30,minimum_kish_ess 30), tableird_taxable_income_standin_ty2024, and R2C-18's sixrequired_evidencealiases.required_scenariosinreported_cell_support(:352) andreported_cell_support_target_a(:443).incomefamily lists stay unchanged.N/country_package.json:116registersincome_measurements.json. The NZ golden moves with these resources.nz_super_shares_residence_with_person_at_least_adult_agekeeps its default, and neither closure entry nor NZ's concept mapping changes. H1 and H2 carry the binding.Invariants and tests
All in
test_nz_transport_declarations.pyunless named. "Red under" names the mutant I ran this session (details under "Mutants").test_the_measure_declarations_are_c_shaped_with_r2c10_floor_and_scale(:1254)vsi_keeps_nzsandcentral_floor_1(each with its SHA-256 recomputed)includedexactly when x > 0 (Hypothesis, 150 examples, throughcombine_measure)test_property_vsi_is_the_central_measure_less_its_four_transfers(:1617, added)vsi_keeps_nzstest_the_omission_register_gives_no_unsourced_size(:1293)register_size(ACC set to "1.0653%")source_household_idand every income row's measure; VEX's exposure is the text "0.75"test_every_calibration_branch_has_one_standin_between_transfers_and_prepare(:1305)a3fe1952revert;vex_exposure_1(exposure set back to 1)nz.income.standinas the only producer fornz.calibratetest_a_proves_nz_income_standin_the_measurements_only_producer(:1390)no_measurement_idtest_a_refuses_a_second_declared_producer_upstream_of_calibration(:1401),test_without_the_standin_the_24_rows_refuse_activation_by_name(:1413)nz.precal.nz_superlists its two rules outputs and its derived cents output, and no stage lists the stand-intest_the_nz_super_stage_lists_its_rules_outputs_for_r2c2(:1426)no_super_stagenz_supercolumn, both a rules output (:1564, added, parametrized) and the derived output (:1446)s5_guard_ignores_unlisted(the guard's "undeclared pre-calibration stage output" check deleted inT/compose.py, worktree only): all three redtest_vsi_vex_and_vpt_change_only_their_own_knob(:1370)measurement_prefitcarries R2C-3's numbers and the six aliasestest_measurement_prefit_carries_r2c3s_frozen_numbers_and_six_aliases(:1461)kish_29nz.gates.terminal(R2C-18)test_r2c18_wires_no_placeholder_evidence_into_the_terminal_battery(:1505)placeholder_aliasincomefamily lists holdtest_cell_support_gates_require_the_three_new_variants_and_income_lists_hold(:1518),test_transport_weight_quality.py:499target_a_drops_vpt: both redtest_the_prefit_table_has_12_bands_each_with_both_companions(:1491)coarse_nil_presenttest_every_prepared_table_on_the_standins_columns_has_no_nil_band(:1578, added)coarse_nil_presentgates.jsontest_vsi_review_triggers_and_the_wage_earner_count_stay_diagnostic(:1543)no_wage_earner_diagMutants. I ran each mutant in a separate worktree with its own environment, at G
423ca43awith the added tests copied in, and selected the named tests. Each mutant turned its test red, so none survived. An earlier batch ran two series concurrently in that worktree by mistake, so I discarded it and reran every mutant in one clean series.super_cents_no_engine_ref(droppingengine_refandperiodfromnz.gross_up.super_cents) ran only in the discarded batch, where it turnedtest_the_s5_guard_refuses_an_undeclared_nz_super_derived_outputred. I didn't rerun it.a3fe1952: the problem slices the amount rows' measureird_taxable_income_proxy_nzd._compiled_problem(T/target_kernels.py:541-551) refuses any target whose measure its node doesn't slice ("every reference must name columns the node slices"). At8c66267e, notargets.problemnode sliced that column, so a real run would have refused all 12 amount rows.tools/build_nz_transport_graph.py:816-819,N/transport_graph.json(the central problem's person inputs),N/scenarios.json(each variant's problem), the goldennz_country_spec.json, andtest_nz_transport_declarations.py(test_every_calibration_branch_has_one_standin_between_transfers_and_prepare, the_PROXY[1]line and the income-row measure check).tools/build_nz_transport_graph.py,N/transport_graph.jsonandN/scenarios.jsonto8c66267eand kept the test.test_every_calibration_branch_has_one_standin_between_transfers_and_preparewent red; with the files restored, it passes.Shared-test lines at G (for Belgium's hub)
test_spec_engine_country_bundles.py:252earnings_bands.jsonmoved to its sorted placetest_spec_engine_country_bundles.py:264income_measurements.jsonaddedtest_transport_weight_quality.py:49943 * 10→43 * 13test_transport_evidence_kernels.py:2706"derived": 307→"derived": 322(423ca43a)test_reference_profiles.py:1163-1187,test_transport_composed_graph.py:2424-2441R2C-21.
git diff <E head> <G head> -- test_transport_composed_graph.pytouches only R2C-22's two hunks (@@ -2424,7 +2424,8and@@ -2433,2 +2434,2)._GAPSandtest_packaged_spec_refuses_with_every_activation_gap_namedmatch E's text, and the test passes at G.The 15 derived rows the stand-in adds (the roster reads 322 = E's 307 + 15; every one still misses exactly
household.rentandperson.liquid_financial_assets):person.ird_taxable_income_proxy_cents,person.ird_taxable_income_proxy_nzd,person.ird_taxable_income_proxy_universe_status, andperson.ird_taxable_income_standin_band_b01_indicatorthrough…_b12_indicator. The NZD unit column joins asderivedbecause the problem now slices it (a3fe1952).pending_outputsafter GN/transport_graph.json:4980lists two entries:measurement_prefitrequires (R2C-18), and the NZS sharing binding (R2C-5)".Hashes
I hashed all 42 engine-free transport kernels (
implementation_hash()[:16], nosimulate.*) in their own trees, from the NZ toy fixture's registry: once at int3e5f5edband once at G423ca43a. The two tables match exactly, so no kernel hash moves. G changes only declarations and tests, and its later commits touch tests only. The values also match #1476's table column by column.3e5f5edb423ca43acalibrate.ordered_adam@10d4577effa147ebe0d4577effa147ebecalibration.prepare@1180823901b9a0d99180823901b9a0d99concepts.encode@17815fae8ed573af67815fae8ed573af6concepts.encode_groups@1062f88411ad605ab062f88411ad605abdiagnostics.calibration@130654dfc7038f56030654dfc7038f560export.prepare@1af31fa6e1690b90caf31fa6e1690b90cexport.readback@196be393c760ca76896be393c760ca768gates.battery@1ac050bab09f48dc2ac050bab09f48dc2geography.assign_atomic@1d60f7ec388903678d60f7ec388903678geography.derive@1d60f7ec388903678d60f7ec388903678geography.gate@1d60f7ec388903678d60f7ec388903678geography.person_location@13efcbe3741d044973efcbe3741d04497geography.support_from_facts@1ad0a8e73d20405bead0a8e73d20405begeography.support_import@1d60f7ec388903678d60f7ec388903678measure.combine@1d609832882ffc113d609832882ffc113money.annual_transfers@1c8a067cd750ed2fec8a067cd750ed2femoney.minor_units@1c8a067cd750ed2fec8a067cd750ed2femoney.normalize@1f10fbeeaf87467b6f10fbeeaf87467b6reporting.carry_income_decile@180335f0183c2741080335f0183c27410reporting.income_decile@180335f0183c2741080335f0183c27410reporting.receipt_group@180335f0183c2741080335f0183c27410takeup.assign@1b2a3a50cc376108bb2a3a50cc376108btakeup.bands@11ceca3ba7c7c9b921ceca3ba7c7c9b92takeup.cell_diagnostics@11ceca3ba7c7c9b921ceca3ba7c7c9b92takeup.compare@11605d7e8519f4b0f1605d7e8519f4b0ftakeup.gap@154f79560d896fab454f79560d896fab4targets.compile@1dc91d1479f8f84b1dc91d1479f8f84b1targets.problem@1fe401c736551e351fe401c736551e351transport.boundary@1fc9d10670f6a092ffc9d10670f6a092ftransport.create@1865c21926cee0ac0865c21926cee0ac0transport.create@2865c21926cee0ac0865c21926cee0ac0transport.currency@19c3457ddb908aa969c3457ddb908aa96transport.donor_ranges@162def362139a52e462def362139a52e4transport.donor_receipt@162def362139a52e462def362139a52e4transport.input_closure@123134112061495b723134112061495b7transport.package@1e86be552287a6eb3e86be552287a6eb3transport.quantile_map@1b25bb6538b19dd64b25bb6538b19dd64transport.quantile_map@276c81605aa416dc976c81605aa416dc9transport.scenario_override@1062f88411ad605ab062f88411ad605abtransport.support_bounds@12303c60a7ec6135c2303c60a7ec6135ctransport.unit_attributes@1f50ec74a1bfe35bbf50ec74a1bfe35bbtransport.weights_audit@11f3d4750134561271f3d475013456127Golden
I regenerated
tests/golden/nz_country_spec.jsonat G with its own summary (test_country_spec.py's_loaded_spec_summary("nz")throughcanonical_json_bytes), and it comes out byte-identical to the committed file. Against F, the golden moves only through G's resources:measurement_prefitingate_ids;income_measurements.jsonamong the resources and their hashes;benefit_gross_up.json,calibration_bindings.json,country_package.json,gates.json,precalibration_stages.json,reporting_classifiers.json,scenarios.jsonandtransport_graph.json.Tests
The closed list ran at G
423ca43a, with no--maxfailand-n 4, withNZ_CHRONICLE_ARTIFACTset to the artifact I built from Chronicle8f4cfd57under Python 3.13. Both digests match the pin (facts_sha256 03f5ea0f…,manifest_sha256 1ea2d1ee…). The result is 4383 passed, 18 skipped, 0 failed. G's final head64ef20afchanges onlytest_nz_transport_declarations.py, and that file passes there with 60 passed (56 + the 4 added tests). The other 57 files are byte-identical between the two heads. Counts read passed / skipped.423ca43aframe/test_transport_donor.pyframe/test_transport_quantile.pytest_country_spec.pytest_nz_as_area_crosswalk.pytest_nz_as_bridge.pytest_nz_axiom_input_closure.pytest_nz_benefit_gross_up.pytest_nz_earnings_bands.pytest_nz_family_reconciliation.pytest_nz_joint_geography.pytest_nz_money_normalization.pytest_nz_msd_benefit_rates.pytest_nz_msd_pre_activation_reconciliation.pytest_nz_reference_aging.pytest_nz_reference_intervals.pytest_nz_spec_package.pytest_nz_target_references.pytest_nz_transport_declarations.pytest_nz_transport_toy_graph.pytest_reference_interval_support.pytest_reference_intervals.pytest_reference_profiles.pytest_reference_summed_bands.pytest_spec_engine_country_bundles.pytest_spec_only_country_packages.pytest_transport_annual_transfers.pytest_transport_binding_identity.pytest_transport_bridge_differential.pytest_transport_codecs_geography.pytest_transport_column_kernels.pytest_transport_composed_graph.pytest_transport_declared_units.pytest_transport_dependent_children.pytest_transport_entitlement_graph.pytest_transport_evidence_kernels.pytest_transport_gate_bindings.pytest_transport_gate_kernels.pytest_transport_graph.pytest_transport_grossup_selectors.pytest_transport_measure_kernels.pytest_transport_measurement_prefit.pytest_transport_measurement_proof.pytest_transport_money_kernels.pytest_transport_population_kernels.pytest_transport_quantile_map_v2.pytest_transport_receipt_v2.pytest_transport_receipt_v2_kernel.pytest_transport_reference_selection.pytest_transport_registry.pytest_transport_reporting_kernels.pytest_transport_run_entry_factors.pytest_transport_run_entry_forms.pytest_transport_source_household_lineage.pytest_transport_takeup_kernels.pytest_transport_target_kernels.pytest_transport_terminal_kernels.pytest_transport_weight_quality.pyuk/test_transport_gate_bindings.pySkips (18), each for a source this container lacks:
test_nz_joint_geography.py11 (NZ_AS_AREA_SOURCES and NZ_JOINT_GEOGRAPHY_SOURCES unset);test_nz_as_area_crosswalk.py3 (pinned ArcGIS bytes);test_nz_axiom_input_closure.py2 (Axiom dense engine and a rulespec-nz checkout);frame/test_transport_donor.py2 (pinned real donor not cached). Every feed audit ran.Also at G:
ci_test_plan.py verifyprintsverification=ok.--checkexits 0 forbuild_nz_transport_graph.py,build_nz_entitlement_graph.py,build_nz_benefit_gross_up.py,generate_nz_target_references.py(with the artifact),generate_nz_msd_pre_activation_reconciliation.pyandpython -m tools.generate_nz_reference_aging. ruff check and format are clean on the changed test file. I didn't rerun E's or F's closed lists, for lack of time; #1475 and #1476 report them.Left for the hub
test_support/microcosm_build/transport_nz_toy.py, and I didn't either, for lack of time. So no toy test yet shows the 24 rows reaching the matrix,target_profile_coveragepassing onincome,measurement_prefitrunning with only unwired-alias failures, or the differential (the toy problem's income row equal to the summed coarse reference). Those tests need a toy stand-in node, a toy coarse table and toy summed references. All of that sits in scope, but it's real work. F'stest_coarse_amounts_equal_the_aged_sum_of_their_native_rowsgives the compile-side differential on the packaged feed only.income_measurements.jsonreview_triggers, not ingates.json. Agates.jsonentry must name a gate inALLOWED_GATE_FUNCTIONS(B/country_spec.py:115), and no gate kind computes these triggers, so a diagnostic gate entry would need a shared change. The wage-earner count (item 8) sits beside them underdiagnostics. G8-x reports both.below_zeroandat_zero(T/measure_kernels.py:264-265). No G artifact surfaces those figures yet, and G8-x's native-band report owes them. The no-nil-band rule now has a test (:1578).measurement_prefitrefuses asevidence: the run lacks required evidence …until G8-x.https://claude.ai/code/session_01LwQq6J45cyZzJWT9gGBLYB
🤖 Generated with Claude Code