From 84494b52461f87eacf952712acdbfb010b99201b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Fri, 11 Sep 2026 14:12:25 +0200 Subject: [PATCH 1/4] Add the frs_relationships UK spine stage and rebind the ONS household-composition cells (#791) The FRS household grid (relhrp, R01-R14, hrpid, hrpnum) becomes four exported frame columns - person.relationship_to_head, person.ons_family_role, person.ons_family_index and household.ons_household_type - derived per the ONS Families and households definitions in a new stage after age_tail. The household type carries Chronicle's ons.household_type value ids verbatim, so the frame, the manifest, the contract rows and the published facts share one string. The derivation is declared as a schema-validated derive_ons_household_composition manifest operation that the runtime lockstep-asserts, gated at the assembled boundary by a stage-health check and an enum-domain gate, and mirrored into the data contract's part scopes and digests. All ten ons.household_composition.* rows bind on the new column and the three microcosm#791 measure exclusions are retired (register 51 -> 48), which binds the national_household_composition_partition_vs_census_households bridge. A compile-time check refuses any ons_household_type condition outside the declared domain or a partition that does not cover it once. Found and fixed on the way: the graph executor's placeholder for a new dense column on a filtered population (a sampled rung) was built on a fresh RangeIndex and inserted label-aligned, widening int64 to float64; it now binds to the table's index, with a regression test. Receipts in experiments/791-household-composition-receipts.md: tape probe clean on all 16,288 households; full licensed build 17/17 spine gates; twin diff vs spine-q = only the four columns; calibration 367 targets, loss 0.0114, 0 outside the 25% fence, the ten cells within +/-0.9%; rowwise dry run binds the bridge with declared factor 1.0. Co-Authored-By: Claude Fable 5.1 (cherry picked from commit 7779747bbf8b4b306f9fd239b770feb634d95dc1) --- .../791-frs-relationships-stage.added.md | 1 + ...graph-placeholder-index-alignment.fixed.md | 1 + ...91-household-composition-rebind.changed.md | 1 + ...uk-local-cross-grain-reconciliation-802.md | 5 +- .../791-household-composition-receipts.md | 103 +++ .../src/microcosm/build/source_manifest.py | 1 + .../spec_engine/schema/sources.schema.json | 219 +++++ .../uk/calibration_measure_exclusions.json | 27 - .../src/microcosm/build/uk/gates.json | 30 + .../build/uk/local_binding_adjudications.json | 2 +- .../uk/release_input_coverage_manifest.json | 26 +- .../src/microcosm/build/uk/source_stages.json | 222 +++++ .../src/microcosm/build/uk/spec/sources.yaml | 128 +++ .../build/uk/uk_data_target_parity.json | 2 +- .../build/uk/uk_local_target_census.json | 2 +- .../build/uk/uk_population_targets.json | 204 +---- .../build/uk_runtime/battery_bindings.py | 3 + .../build/uk_runtime/calibration_run.py | 4 + .../build/uk_runtime/data_target_parity.py | 10 +- .../build/uk_runtime/frs_relationships.py | 768 ++++++++++++++++ .../src/microcosm/build/uk_runtime/graph.py | 13 + .../build/uk_runtime/graph_kernels.py | 7 +- .../build/uk_runtime/ledger_targets.py | 49 + .../build/uk_runtime/local_target_census.py | 9 +- .../build/uk_runtime/source_runtime.py | 2 + .../build/uk_runtime/stage_health.py | 252 +++++- .../build/uk_runtime/terminal_gates.py | 4 + .../tests/test_country_spec.py | 9 +- .../tests/test_spec_engine_country_bundles.py | 2 +- .../tests/test_uk_frs_relationships.py | 841 ++++++++++++++++++ .../tests/test_uk_frs_spine.py | 38 +- .../microcosm-build/tests/test_uk_graph.py | 8 +- .../tests/test_uk_ledger_targets.py | 58 +- .../tests/test_uk_measure_simulation.py | 19 +- .../tests/test_uk_population_targets.py | 34 + .../tests/test_uk_source_stages.py | 3 + .../tests/test_uk_spine_acceptance_receipt.py | 5 + .../src/microcosm/data/contract.py | 20 +- .../microcosm-data/tests/test_contract.py | 9 +- .../src/microcosm/graph/population.py | 5 + .../fixtures/parity/uk_spine/NORMALIZATION.md | 6 +- .../fixtures/parity/uk_spine/PRODUCED_BY.txt | 2 +- .../parity/uk_spine/sources/fixture.json | 252 +++++- .../parity/uk_spine/sources/frs_raw/adult.tab | 272 +++--- .../parity/uk_spine/sources/frs_raw/child.tab | 56 +- .../uk_spine/sources/frs_raw/househol.tab | 272 +++--- .../fixtures/parity/uk_spine/uk_spine.json | 2 +- .../tests/test_acceptance_h_parity.py | 10 +- .../tests/test_graph_population.py | 43 + tools/build_uk_frs_spine.py | 25 +- tools/graph_uk_spine_fixture.py | 38 +- 51 files changed, 3503 insertions(+), 621 deletions(-) create mode 100644 changelog.d/791-frs-relationships-stage.added.md create mode 100644 changelog.d/791-graph-placeholder-index-alignment.fixed.md create mode 100644 changelog.d/791-household-composition-rebind.changed.md create mode 100644 experiments/791-household-composition-receipts.md create mode 100644 packages/microcosm-build/src/microcosm/build/uk_runtime/frs_relationships.py create mode 100644 packages/microcosm-build/tests/test_uk_frs_relationships.py diff --git a/changelog.d/791-frs-relationships-stage.added.md b/changelog.d/791-frs-relationships-stage.added.md new file mode 100644 index 000000000..ef3298a81 --- /dev/null +++ b/changelog.d/791-frs-relationships-stage.added.md @@ -0,0 +1 @@ +Add the `frs_relationships` UK spine stage (microcosm#791): the FRS household grid (`relhrp`, `R01`-`R14`, `hrpid`, `hrpnum`) becomes four exported frame columns — `person.relationship_to_head`, `person.ons_family_role`, `person.ons_family_index` and `household.ons_household_type`, the last taking Chronicle's `ons.household_type` value ids verbatim — derived per the ONS Families and households definitions (family = couple or lone parent with children; dependent = under 16 or 16–18 in full-time education; one family plus other individuals stays one-family; no family present = two or more unrelated adults). The derivation is declared as a schema-validated `derive_ons_household_composition` manifest operation whose code lists (FRS SN 9563 relationship codes, ONS rules, Chronicle category ids) the runtime lockstep-asserts, and it is gated at the assembled boundary by a stage-health check (one head per household agreeing with `hrpid` and `hrpnum`, contiguous person numbers, no double partners, no unmapped codes, the ten-cell partition covering every household exactly once, a reviewed grid-reciprocity tolerance) and an enum-domain gate over the declared ten values. diff --git a/changelog.d/791-graph-placeholder-index-alignment.fixed.md b/changelog.d/791-graph-placeholder-index-alignment.fixed.md new file mode 100644 index 000000000..e575902bf --- /dev/null +++ b/changelog.d/791-graph-placeholder-index-alignment.fixed.md @@ -0,0 +1 @@ +Fix the graph executor's placeholder for a new dense (`int64`/`bool`) column on a filtered population: the zero-filled placeholder was built on a fresh RangeIndex and inserted label-aligned, so on a population whose table index is non-contiguous (a sampled spine rung after the root filter) the gaps were NaN-filled and the column silently widened to `float64`, which the patch then refused. The placeholder now binds to the table's own index. Found by the microcosm#791 sampled build (the first stage to add a new `int64` person column directly after the sampling filter); regression test on a population with a non-contiguous person index. diff --git a/changelog.d/791-household-composition-rebind.changed.md b/changelog.d/791-household-composition-rebind.changed.md new file mode 100644 index 000000000..c80dc7140 --- /dev/null +++ b/changelog.d/791-household-composition-rebind.changed.md @@ -0,0 +1 @@ +Rebind all ten `ons.household_composition.*` calibration rows on `household.ons_household_type` and retire the three microcosm#791 measure exclusions (`multi_family_households`, `unrelated_adult_households`, `lone_parent_non_dependent_children_households`; register 51 → 48 entries). The benefit-unit and person-count proxies inherited from uk-data `compute/households.py` — which read a couple with a non-dependent child or a lodger as multi-family and could not tell unrelated adults from a lone parent with adult children — are replaced by one ONS-family derivation on the frame, so the partition sums to `ons.households_total` and the `national_household_composition_partition_vs_census_households` cross-grain bridge binds (declared factor 1 by closure on the A15-uprated census cells). Contract notes on the ten rows record the translation (ONS dependency vs the engine's `is_child`; "unrelated adults" as no family present); the `uk-data` parity register and the local binding adjudication wording record the bound bridge. diff --git a/docs/uk-local-cross-grain-reconciliation-802.md b/docs/uk-local-cross-grain-reconciliation-802.md index 24cde872b..daffaac6a 100644 --- a/docs/uk-local-cross-grain-reconciliation-802.md +++ b/docs/uk-local-cross-grain-reconciliation-802.md @@ -15,7 +15,10 @@ cannot express on their own: - The 10-cell `ons.household_composition.*` partition sums to the national household-count control and bridges to the Chronicle-compiled - `ons.census.households` contract target. + `ons.census.households` contract target. Since microcosm#791 the ten cells + bind on the `frs_relationships` stage's `household.ons_household_type` + column, so the bridge is fully bound (it was reviewed-unbound while three + cells carried measure exclusions). - `dwp.uc.households` bridges to `dwp.uc.households_by_area`. The four `dwp.uc.payment_distribution_*` rows also match the by-area target exactly and form a separate exhaustive national partition. diff --git a/experiments/791-household-composition-receipts.md b/experiments/791-household-composition-receipts.md new file mode 100644 index 000000000..662195950 --- /dev/null +++ b/experiments/791-household-composition-receipts.md @@ -0,0 +1,103 @@ +# microcosm#791 receipts: relationship-to-head frame column and the ONS household-composition rebind + +Plan of record: `repos/uk-791-relationship-to-head-plan.md` (approved 2026-09-11). Branch `uk-household-composition-791` off main `6f7571e1`. + +## R1 — vintage documentation check (step 0) + +The relationship code list the stage declares (`derive_ons_household_composition.frs_household_grid_relationship_codes`) was read from the FRS 2024-25 question instructions for the pinned release, UK Data Service SN 9563 (`9563_frs_2024-25_question_instructions_final.pdf`, P18492, 408 pages, sha256 `8fec3d4e8f66a2a65ccf0b8455d410c39c41181d0c2148949a14840f1f0eb76d`), Household Grid, question "Relationship" (page 17 of the PDF): 1 spouse, 2 cohabitee, 3 son/daughter (incl adopted/legal dependent), 4 step-son/daughter, 5 foster child, 6 son-in-law/daughter-in-law, 7 father/mother/or guardian, 8 step father/mother, 9 foster parent, 10 father/mother-in-law, 11 brother/sister (incl adopted), 12 step-brother/sister, 13 foster brother/sister, 14 brother/sister-in-law, 15 grand-son/daughter, 16 grand-father/mother, 17 other relative, 18 other non-relative, 20 Civil Partner, 97 not used. Identical to the 2023-24 instructions (SN 9367). The instructions add: relatives of cohabitees are coded as if married; half-siblings are coded with step-siblings; a 16-19 in full-time education living with grandparents has the grandparents coded as legal guardian (7/3). The household reference person is the highest-income householder, the elder on ties (FRS background information and methodology). + +The ONS definitions come from Families and households in the UK: 2025 (Measuring the data / Glossary) and "Families and households statistics explained" (ONS, 2021): family, dependent child (under 16, or 16-18 in full-time education, excluding 16-18s with a partner or own child in the household), non-dependent child, one-family household ("households where there is one family and one individual are also classified as one-family households"), two or more unrelated adults ("none of whom are living as part of a family"), multi-family household, and foster children / children living with someone other than their parents as separate one-person family units. + +The ten category identifiers are Chronicle's `ons-families-households-2025` package, Table 7, `ons.household_type` value ids (`lone_households_under_65` ... `multi_family_households`); the package carries no Table 7 note text, so the definitions above are recorded on the contract rows and here. + +## R2 — licensed-tape probe (step 0, read-only, `data/ukds/frs_2024_25`, digests as pinned) + +Run of `derive_frs_relationships` over the raw adult (27,714), child (7,252) and househol (16,288) tabs with a frame-shaped person table (adult `age80`, child `age`, `hrpid == 1` as head) and `GROSS4` as the household weight. + +Invariants: head_invariant_violations 0 (one HEAD per household, equal to `hrpid == 1`; `relhrp` blank exactly 16,288 times); hrpnum_mismatches 0; person_index_gaps 0 (PERSON is contiguous 1..n, n <= 14, in every household); multi_partner_persons 0; relhrp_unmapped_codes none (adult codes 1-8, 10, 11, 14-18, 20; child codes 3-5, 7, 11, 12, 14, 15, 17, 18); family_index_violations 0; domain_violations 0; partition_closes true; full-time-education source `educft` (no `fted` on the 2024-25 tape). + +grid_reciprocity_mismatches 3 (ordered pairs), in two households: two children aged 19 and 17 record the HRP as parent (code 3) while the HRP records them as other non-relative (18); an infant records the HRP's spouse as parent (3) while that adult records the infant as sibling (11). The derivation takes either side's declaration as establishing the link (the child's parent claim wins) and the manifest declares the tolerance as this count, so a re-issued tape with a different count refuses for review. parent_tie_breaks 11 (a child-eligible person linked to two uncoupled parents; natural before step, then lowest person number). one_family_plus_individuals 189 households (the couple-plus-lodger / couple-plus-elderly-parent class the #757 person-count restrictions could not place). + +Roles: COUPLE_PARTNER 17,732; DEPENDENT_CHILD 7,238; NON_DEPENDENT_CHILD 1,978; LONE_PARENT 1,584; INDIVIDUAL 6,434. Dependency: under 16 6,376; 16-18 in FTE 862; 16-18 not in FTE 143; 19+ 1,835. + +Ten cells at design weights (GROSS4) against the published 2025 values (ratio): + +- lone_households_under_65: 2,538 records, 4,364,966 vs 4,316,000 (1.011) +- lone_households_over_65: 3,152 records, 4,115,625 vs 4,254,000 (0.967) +- unrelated_adult_households: 216 records, 590,367 vs 813,000 (0.726) +- couple_no_children_households: 5,132 records, 8,780,988 vs 8,119,000 (1.082) +- couple_under_3_children_households: 2,560 records, 4,952,586 vs 5,439,000 (0.911) +- couple_3_plus_children_households: 457 records, 1,026,478 vs 931,000 (1.103) +- couple_non_dependent_children_only_households: 626 records, 1,824,245 vs 1,848,000 (0.987) +- lone_parent_dependent_children_households: 1,004 records, 1,886,352 vs 1,835,000 (1.028) +- lone_parent_non_dependent_children_households: 536 records, 1,218,884 vs 1,204,000 (1.012) +- multi_family_households: 67 records, 211,942 vs 244,000 (0.869) +- total: 16,288 records, 28,972,433 vs 29,003,000 (0.999) + +Every cell is inside the 25 % `uk_target_fit` bound before any calibration. For comparison the #757 rebind packet (benefit-unit proxies) read multi_family +1618 %, unrelated_adult +48 %, couple_no_children +34 %. + +`househol.hhcomps` was checked and rejected as a shortcut: its 17 codes are a function of `adulth`, `depchldh` and sex/pension age only (cross-tab on the tape) and carry no family structure. + +## R3 — sampled rung (1 %) and the executor placeholder defect + +The first 1 % sampled build (`build_791.sh ... --sample-fraction 0.01 --sample-seed 42`, code `6f7571e1` + this branch, engine 2.97.0) refused at the new node: `Patched person.ons_family_index has dtype float64; declaration requires 'int64'`. Instrumenting `_patch_columns` showed the incoming column was `int64` and the household table carried a RangeIndex, but the sampled person table's index was non-contiguous (`[243, 244, 1099, ...]`) after the root filter; the executor built its zero-filled placeholder on a fresh RangeIndex and inserted it label-aligned, NaN-filling the gaps and widening the column. `frs_relationships` is the first stage to add a new dense person column right after the sampling filter, which is why no earlier sampled rung met it. Fix: the placeholder binds to the table's own index (`packages/microcosm-graph/src/microcosm/graph/population.py`, `_patch_columns`), with a regression test on a non-contiguous person index (`test_new_dense_column_on_a_filtered_population_keeps_its_dtype`). Unsampled builds carry RangeIndex tables and were never affected. + +With the executor fix the 1 % rung (`spine-r-f001`, 181 s) executed `frs_relationships` and twenty further stages and then refused inside `uc_capital_coherence` ("no positive-weight base-FRS reporter donors for dependent_children=0, couple=True"): a sparsity limit of the 1 % rung in a later stage, unrelated to this change, so the acceptance evidence is taken from the full build (R4) rather than a rung. + +## R4 — full licensed build `spine-r` + +`build_791.sh` recipe (build_twin.sh inputs: FRS 2024-25 tabs, SPI 2022-23, HMRC 2023-24 and CGT 2025 workbooks, WAS R8, LCFS 2023-24, ETB 1977-2024), tree `6f7571e1` + this branch, policyengine-uk 2.97.0, no sampling, checkpoints on: 373 s wall, 7.1 GB peak; `data/ukds/acceptance/791-relationships/spine-r/spine-r.h5` sha256 `921612e88eefcf21511ac6ad5faf60a1514f577490188c6e39aec49cb4224f27` (167,915,393 bytes); 29 stages; 52,846 households / 61,213 benunits / 113,590 persons (the spine-q counts). Spine battery 17/17 passed, phases `assembled` and `transferred`, `blocked_at_phase` null. The two new gates at the assembled boundary: `uk_stage_frs_relationships_composition` passed with the R2 counts exactly (16,288 base households typed, 3 reciprocity mismatches at the reviewed tolerance 3, every other invariant 0, partition closes); `uk_ons_household_type_enum_domain` passed (one column, ten allowed values, zero invalid). Sidecars: `spine-r.spine_gates.json`, `spine-r.build.json`, `spine-r.nonzero_shares.json`, logbook row `2aaaef18…`. + +## R5 — twin diff against spine-q (`diff-vs-spine-q/`) + +`compare_uk_h5_payload.py spine-q.h5 spine-r.h5` (whole artifact, row-aligned): store keys equal; root attributes equal; every table's row count and index values equal; `benunit` and `time_period` byte-identical; `person` and `household` have no column with differing values, no column only in the reference, and exactly the candidate-only columns `relationship_to_head`, `ons_family_role`, `ons_family_index` (person, positions 65-67 of 128) and `ons_household_type` (household, position 18 of 74). The shared columns keep their order position-wise (checked directly on the two stores). `classify_uk_payload_diff.py` against `spine-r-payload-expectation.json`: the four columns classify `expected_changed` (surface `column_only_right`); the `column_order` structural surface on person and household reads unexpected only because the classifier refuses structural surfaces under `expected_changed`, and it moves solely because the column set grew — recorded here as the adjudication. No value, weight, dtype, index or attribute moves: the stage adds and rewrites nothing else. + +## R6 — parity instrument (`parity/`, `parity-baseline-q/`) + +`build_uk_efrs_parity_reference.py --candidate-h5 spine-r.h5 --emit-candidate-json` extracts 159 candidate input layers (the enhanced-FRS reference surface is engine inputs); `verify_uk_spine_parity.py --strict` returns `defect` with 20 unsigned differences (benunit/person counts 61,213/113,590 vs the reference's 61,223/113,617 and 18 nonzero-share deltas: bus fares, corporate wealth, diesel, education consumption, employment income, employment sector, ...). The same command on spine-q (main `0afb1235`) returns the identical 20 unsigned differences and the identical register usage (dormant `scottish-water-sewerage-successor-level`; unused: consumer-debt, donor-selection-rng, frs-benunit-capital, lcfs-fuel-incidence, mortgage-debt, scottish-water-nan-zeroing), so the verdict is the pre-existing state of the pinned reference (Max's #749 re-pin), not this change. The four #791 columns are not engine variables, so the instrument does not extract them and no register entry can ever match: the two `column_missing_in_reference` entries first drafted for them were withdrawn rather than left permanently unused. The instrument sees no difference attributable to #791. + +## R7 — derivation delta on spine-r (`delta_791.json`, design weights, 52,846 households, total weight 29,247,433) + +The pre-#791 ten bindings (`origin/main` contract rows, engine variables `family_type`, `is_child`, `age`, `household_num_benunits` resolved through `UKMeasureResolver` and applied through `UKFrameTargetAdapter`) against the new `ons_household_type` column, same spine, same weights. Ratio to the published 2025 value, old → new: + +- lone_households_under_65: 1.047 → 1.047 (unchanged by construction) +- lone_households_over_65: 1.140 → 1.140 (unchanged) +- unrelated_adult_households: 4.031 → 0.620 (3,277,295 → 503,862) +- couple_no_children_households: 1.094 → 1.112 (8,885,648 → 9,025,783; the couple-plus-individual class joins) +- couple_under_3_children_households: 0.879 → 0.893 +- couple_3_plus_children_households: 0.951 → 0.962 +- couple_non_dependent_children_only_households: 1.000 → 0.817 (1,847,825 → 1,510,386; the old proxy fitted the number by counting households with an extra adult of any relationship) +- lone_parent_dependent_children_households: 1.137 → 1.004 (2,085,571 → 1,841,865) +- lone_parent_non_dependent_children_households: 2.721 → 0.884 (3,276,524 → 1,064,691) +- multi_family_households: 18.849 → 0.738 (4,599,205 → 180,012) + +The old bindings were not a partition: 6,563 households (weight 4,654,447) satisfied two or more old cells at once (none satisfied zero), which is how the old multi-family and unrelated-adult proxies absorbed everything the person-count restrictions excluded. The new column types every household exactly once. Every new cell is inside the 25 % fence at design weights before calibration; the widest, multi-family at 0.738 and unrelated adults at 0.620, are the two thinnest cells (226 and 685 spine households). The design-weighted crosstab (old first-matching cell × new cell) is in `delta_791.json`. + +## R8 — national calibration on spine-r (`calibration-r/`, `dev-791-spine-r`) + +`calibrate_791.sh`: `tools/calibrate_uk_national_dataset.py` on spine-r (sha `921612e8…`) against the pinned Chronicle artifact `ec7169b` (facts `4a50ee95…`, manifest `a95d0ee9…`), campaign settings `--epochs 1500 --target-weight-rule family_equal`, committed measure-exclusion register (48 entries after the three retirements). 367 targets bound, none skipped; initial loss 0.2987 → final loss 0.0114; 96.5 % of targets within 10 %; 0 of 367 outside the 25 % `uk_target_fit` fence; effective sample size 13,230; realized max weight ratio 10.0; all 52,846 records keep positive weight. Terminal gates 6/6 passed. The run refused to *stage* the calibrated H5 because `MICROCOSM_UK_TERMINAL_GATE_SIGNING_KEY` is not set in this environment (unsigned full-scale runs refuse to stage by design); the diagnostics and terminal-gate report were written before that refusal and are the evidence here — no staged artifact is claimed. + +The ten ONS household-composition cells, target → initial (design weights) → final, relative error: + +- lone_households_under_65: 4,316,000 → 4,520,161 → 4,321,179 (+0.12 %) +- lone_households_over_65: 4,254,000 → 4,850,900 → 4,256,780 (+0.07 %) +- unrelated_adult_households: 813,000 → 503,862 → 812,005 (−0.12 %) +- couple_no_children_households: 8,119,000 → 9,025,783 → 8,189,235 (+0.87 %) +- couple_under_3_children_households: 5,439,000 → 4,854,379 → 5,444,365 (+0.10 %) +- couple_3_plus_children_households: 931,000 → 895,393 → 931,475 (+0.05 %) +- couple_non_dependent_children_only_households: 1,848,000 → 1,510,386 → 1,846,693 (−0.07 %) +- lone_parent_dependent_children_households: 1,835,000 → 1,841,865 → 1,838,917 (+0.21 %) +- lone_parent_non_dependent_children_households: 1,204,000 → 1,064,691 → 1,203,046 (−0.08 %) +- multi_family_households: 244,000 → 180,012 → 243,910 (−0.04 %) + +For comparison: the #757 rebind packet (proxies, 403 targets, loss 0.1362) read multi_family +1618 %, unrelated_adult +48 %, couple_no_children +34 %; and the Q50f 55k run of 2026-09-10, with the three cells excluded, read lone_parent_dependent_children +21.9 % as collateral — here +0.21 %. The three retired exclusions are not needed: the cells fit as concepts, not as numbers the solver stuffs. + +## R9 — rowwise dry run, f001 rung (`rowwise-dry-run.log`, `rowwise_791.sh`) + +`tools/build_uk_rowwise_candidate.py --dry-run --sample-fraction 0.01 --n-clones 4 --seed 42` on spine-r, ladder `bed3f13d…` (the #887 rebuild), feed `ec7169b`: `cross_grain.unbound_bridges` is `[]` for the first time — the `national_household_composition_partition_vs_census_households` bridge appears in `cross_grain.groups` for both lower grains (country controls constituency, country controls la), one leg `England+Wales+Scotland+Northern Ireland` each, `declared_factor` 1.0, `relative_shift` 0.0, `new_total` 29,003,000; `census_household_uprating.applied` true with the #887 per-grain factors (constituency 1.0335597, local authority 1.0335595) unchanged. 41 inconsistencies in force (the 38 recorded on #887 plus the bound bridge's groups). The 1,011 census cells therefore keep their A15-uprated values to float precision, as the plan predicted from closure (the ten cells and the uprating control are both `ons.households_total` 2025); the local surface is unchanged numerically and the dense assembler will stop emitting the `unbound_bridge:` limitation. + +## R10 — test surface on the branch + +`spine-uk` CI group (127 files, 2,403 tests, 35 min): 2,372 passed, 21 skipped, 10 failed on the first pass; all ten were pins or fixtures that had to follow the change, and every one is green on rerun: the data-contract mirrors (the two gate ids in the entry table, the spine part scope, the full-manifest digests `policy 38a8a014…`, `gates_manifest 49e86be9…`, `spec_fingerprint 25049e61…`, the spine part digests `7f9f07e6…`/`7058df03…` and the release-cut part digests `1aaf29c5…`/`4a93792f…`, computed by the producer the sync test `test_gate_battery_contract_pins.py` holds in lockstep), the uk-data parity register regenerated from its source (`data_target_parity.py`), the local-target census regenerated from its source (`local_target_census.py`, the bound-bridge wording), the spine-driver tests' synthetic tabs and synthetic spec (grid columns, `hrpnum`, the declared operation parameters), and the release-assembler tests (which read the contract mirrors). Also green: `packages/microcosm-data/tests` (398), `packages/microcosm-graph/tests` (337, including the H2 parity acceptance on the regenerated fixture and the executor regression), `test_gate_battery_contract_pins.py`, and the targeted pin set (401). `tools/ci_test_groups.py --verify` ok; `tools/build_uk_release_input_coverage_manifest.py` regenerated (only the `source_manifest_sha256` pins moved; 145 required inputs unchanged); `tools/generate_uk_target_references.py`'s pinned-feed regeneration test passes on the ec7169b artifact (no generated surface moved); `ruff check` and `ruff format --check` clean on every changed file. + +One failure is pre-existing and untouched: `test_uk_parity_reference.py::test_cached_reference_regeneration_matches_committed_surface` regenerates `uk/efrs_parity_reference.json` from the cached licensed eFRS artifact and compares it to the committed file; the committed file was produced with policyengine-uk 2.89.0 (223 input variables) while `uv.lock` on main pins 2.97.0 (228), which now recognises `sic_industry_division`, `employment_sector` and `bus_fare_spending` as inputs. The branch changes neither file; the test skips in CI (no HF cache) and fails identically on main in this environment. The re-pin belongs with #749. diff --git a/packages/microcosm-build/src/microcosm/build/source_manifest.py b/packages/microcosm-build/src/microcosm/build/source_manifest.py index 21f450da5..d25a14bee 100644 --- a/packages/microcosm-build/src/microcosm/build/source_manifest.py +++ b/packages/microcosm-build/src/microcosm/build/source_manifest.py @@ -86,6 +86,7 @@ "derive_snap_take_up", "derive_puf_policyengine_variables", "derive_mortgage_balance_hints", + "derive_ons_household_composition", "derive_pregnancy", "derive_relationship_inputs", "derive_retirement_distributions", diff --git a/packages/microcosm-build/src/microcosm/build/spec_engine/schema/sources.schema.json b/packages/microcosm-build/src/microcosm/build/spec_engine/schema/sources.schema.json index 3f7350f03..c60aeb559 100644 --- a/packages/microcosm-build/src/microcosm/build/spec_engine/schema/sources.schema.json +++ b/packages/microcosm-build/src/microcosm/build/spec_engine/schema/sources.schema.json @@ -1921,6 +1921,225 @@ "kind" ] }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "kind": { + "const": "derive_ons_household_composition" + }, + "source_columns": { + "type": "object", + "additionalProperties": false, + "properties": { + "head": { + "type": "string" + }, + "head_flag": { + "type": "string" + }, + "head_index": { + "type": "string" + }, + "grid": { + "type": "array", + "minItems": 14, + "maxItems": 14, + "items": { + "type": "string" + } + }, + "full_time_education": { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + }, + "required": [ + "head", + "head_flag", + "head_index", + "grid", + "full_time_education" + ] + }, + "frs_household_grid_relationship_codes": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "code": { + "type": "integer", + "minimum": 1 + }, + "label": { + "type": "string", + "enum": [ + "SPOUSE", + "COHABITEE", + "CHILD", + "STEP_CHILD", + "FOSTER_CHILD", + "CHILD_IN_LAW", + "PARENT", + "STEP_PARENT", + "FOSTER_PARENT", + "PARENT_IN_LAW", + "SIBLING", + "STEP_SIBLING", + "FOSTER_SIBLING", + "SIBLING_IN_LAW", + "GRANDCHILD", + "GRANDPARENT", + "OTHER_RELATIVE", + "OTHER_NON_RELATIVE", + "CIVIL_PARTNER" + ] + } + }, + "required": [ + "code", + "label" + ] + } + }, + "head_label": { + "const": "HEAD" + }, + "family_link_codes": { + "type": "object", + "additionalProperties": false, + "properties": { + "partner": { + "type": "array", + "minItems": 1, + "items": { + "type": "integer" + } + }, + "child_of": { + "type": "array", + "minItems": 1, + "items": { + "type": "integer" + } + }, + "parent_of": { + "type": "array", + "minItems": 1, + "items": { + "type": "integer" + } + } + }, + "required": [ + "partner", + "child_of", + "parent_of" + ] + }, + "dependent_child": { + "type": "object", + "additionalProperties": false, + "properties": { + "unconditional_below_age": { + "type": "integer", + "minimum": 0 + }, + "full_time_education_through_age": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "unconditional_below_age", + "full_time_education_through_age" + ] + }, + "one_person_age_split": { + "type": "integer", + "minimum": 0 + }, + "family_role_values": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "enum": [ + "COUPLE_PARTNER", + "LONE_PARENT", + "DEPENDENT_CHILD", + "NON_DEPENDENT_CHILD", + "INDIVIDUAL" + ] + } + }, + "household_type_values": { + "type": "array", + "minItems": 10, + "maxItems": 10, + "items": { + "type": "string", + "enum": [ + "lone_households_under_65", + "lone_households_over_65", + "unrelated_adult_households", + "couple_no_children_households", + "couple_under_3_children_households", + "couple_3_plus_children_households", + "couple_non_dependent_children_only_households", + "lone_parent_dependent_children_households", + "lone_parent_non_dependent_children_households", + "multi_family_households" + ] + } + }, + "reciprocity_mismatch_tolerance": { + "type": "integer", + "minimum": 0 + }, + "documentation": { + "type": "object", + "additionalProperties": false, + "properties": { + "frs_codes": { + "type": "string" + }, + "ons_definitions": { + "type": "string" + }, + "category_ids": { + "type": "string" + } + }, + "required": [ + "frs_codes", + "ons_definitions", + "category_ids" + ] + }, + "reason": { + "type": "string" + } + }, + "required": [ + "kind", + "source_columns", + "frs_household_grid_relationship_codes", + "head_label", + "family_link_codes", + "dependent_child", + "one_person_age_split", + "family_role_values", + "household_type_values", + "reciprocity_mismatch_tolerance", + "documentation" + ] + }, { "type": "object", "additionalProperties": false, diff --git a/packages/microcosm-build/src/microcosm/build/uk/calibration_measure_exclusions.json b/packages/microcosm-build/src/microcosm/build/uk/calibration_measure_exclusions.json index 3ce5d4cfd..9bdd0566b 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/calibration_measure_exclusions.json +++ b/packages/microcosm-build/src/microcosm/build/uk/calibration_measure_exclusions.json @@ -334,33 +334,6 @@ "approved_on": "2026-08-26", "expires_on": "2026-11-26" }, - { - "name": "ons.household_composition.multi_family_households", - "reason": "The ONS household-composition split requires a relationship-to-head frame column the spine does not carry; without it multi-family, unrelated-adult, and lone-parent-with-non-dependent-children households are indistinguishable and the categories bleed into each other (multi_family +1618% on the rebind packet).", - "tracking": "microcosm#791", - "approved_by": "juaristi22", - "adjudication": "microcosm#757 (the uk_target_fit dispositions, issue comment 5427936411)", - "approved_on": "2026-08-26", - "expires_on": "2026-11-26" - }, - { - "name": "ons.household_composition.unrelated_adult_households", - "reason": "The ONS household-composition split requires a relationship-to-head frame column the spine does not carry; without it multi-family, unrelated-adult, and lone-parent-with-non-dependent-children households are indistinguishable and the categories bleed into each other (multi_family +1618% on the rebind packet).", - "tracking": "microcosm#791", - "approved_by": "juaristi22", - "adjudication": "microcosm#757 (the uk_target_fit dispositions, issue comment 5427936411)", - "approved_on": "2026-08-26", - "expires_on": "2026-11-26" - }, - { - "name": "ons.household_composition.lone_parent_non_dependent_children_households", - "reason": "The ONS household-composition split requires a relationship-to-head frame column the spine does not carry; this cell fits numerically (-0.03% on the rebind packet) but measures the wrong concept - the solver holds it by stuffing misclassified households into the sibling categories, so it must unbind together with them.", - "tracking": "microcosm#791", - "approved_by": "juaristi22", - "adjudication": "microcosm#757 (the uk_target_fit dispositions, issue comment 5427936411)", - "approved_on": "2026-08-26", - "expires_on": "2026-11-26" - }, { "name": "hmrc/dividend_income_income_band_500_000_to_1_000_000", "reason": "Sparse cell support: 6 in-band carrier records under the SPI assessable-income concept and 10 under the component-sum proxy (6,914 weighted carriers), measured identically on spine-i and spine-j (microcosm#807) - too few for the solver to hit the published value without distorting neighbouring cells. One of the three thin 500k-1m cells retained when the microcosm#807 revision lifted the three mid-band cells whose measured support was in the hundreds; re-measure on the next spine build before renewal.", diff --git a/packages/microcosm-build/src/microcosm/build/uk/gates.json b/packages/microcosm-build/src/microcosm/build/uk/gates.json index 7a2c0fd7f..1229befe8 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/gates.json +++ b/packages/microcosm-build/src/microcosm/build/uk/gates.json @@ -404,6 +404,20 @@ }, "notes": "Stage-time achieved-versus-target gate over the age-tail disaggregation receipt. At its post-frs_spine position, achieved_weighted measures raw FRS-grossed 80+ mass before clone or zero-weight support channels exist." }, + { + "id": "uk_stage_frs_relationships_composition", + "gate": "stage_health", + "phase": "assembled", + "criticality": "release_blocking", + "evidence_absent_blocks": true, + "parameters": { + "stage": "frs_relationships", + "check": "household_composition", + "max_grid_reciprocity_mismatches": 3, + "require_partition_closure": true + }, + "notes": "Stage-time invariants over the #791 relationship receipt: exactly one HEAD per household agreeing with hrpid and hrpnum, contiguous person numbers, no person with two partners, no unmapped relhrp code, family index and enum domains consistent, and the ten-cell household-type partition covering every household exactly once. The grid reciprocity tolerance is the reviewed 2024-25 tape count; a re-issued tape with a different count refuses for review." + }, { "id": "uk_release_input_coverage", "gate": "release_input_coverage", @@ -597,6 +611,7 @@ "household.msoa_code", "household.num_vehicles", "household.oa_code", + "household.ons_household_type", "household.private_pension_wealth", "household.property_purchased", "household.rail_usage", @@ -620,11 +635,14 @@ "person.is_parent", "person.is_uc_claimant", "person.legacy_jobseeker_proxy", + "person.ons_family_index", + "person.ons_family_role", "person.outpatient_visits", "person.pension_contributions_via_salary_sacrifice", "person.pip_dl_category", "person.pip_m_category", "person.receives_benefits_in_own_right", + "person.relationship_to_head", "person.salary_sacrifice_asked", "person.salary_sacrifice_reported", "person.sic_industry_division", @@ -662,6 +680,18 @@ }, "notes": "The household BRMA assignment must remain inside the PolicyEngine-UK brma enum domain. Evaluated at the assembled boundary, right after frs_brma writes the column: enum membership is a property of the values themselves, so checking it there is identical to checking it at the end and refuses fourteen stages earlier. Take-up signal stays terminal by contrast, because its weighted shares are not the same statistic before and after calibration." }, + { + "id": "uk_ons_household_type_enum_domain", + "gate": "enum_domain", + "phase": "assembled", + "criticality": "release_blocking", + "parameters": { + "columns": [ + "ons_household_type" + ] + }, + "notes": "The household ONS household-type value must be one of the ten Chronicle ons.household_type value ids the frs_relationships stage declares (the build supplies the declared domain as evidence; the column is a frame input, not a PolicyEngine-UK enum). Evaluated at the assembled boundary like the BRMA enum: membership is a property of the values themselves." + }, { "id": "uk_uc_deduction_combination_enum_domain", "gate": "enum_domain", diff --git a/packages/microcosm-build/src/microcosm/build/uk/local_binding_adjudications.json b/packages/microcosm-build/src/microcosm/build/uk/local_binding_adjudications.json index d36701e42..f96d9ae05 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/local_binding_adjudications.json +++ b/packages/microcosm-build/src/microcosm/build/uk/local_binding_adjudications.json @@ -3,7 +3,7 @@ "description": "Reviewed adjudications of the UK local binding fences (uk_local_target_census.json binding_fences). Binding a target family whose fence has no in-force entry here fails in the rowwise doctrine solve before any solve runs. Keys are fence ids; the reason states the ruling (accept the stated basis, or replace it with the named alternative) and cites the evidence.", "exclusions": { "census_disclosure_control_noise": { - "reason": "Accept the stated basis: constituency and local-authority household counts bind to the published disclosure-controlled census values compiled from the pinned Chronicle feed (ons.census.households: ONS TS041 PCON24/LAD, NRS UV404 UKPC24 and council all-occupied totals, NISRA PCON24/LGD14). Per-area dispersion of the retired OA-ladder sums against the published cells at review: England mean 7.4 / max 29, Wales 6.4 / 15, Scotland net −557 (NRS applies disclosure control per output level; same shortfall at both grains), Northern Ireland mean 7 / max 16 after the NI constituency leg moved to NISRA's published DZ2021→PARLCON24 lookup (the earlier postcode inference was a mapping defect of 10 Data Zones, max 694, not perturbation). When a national same-concept control is bound, the standing cross-grain rule declared in uk_runtime.ledger_targets rescales both grains; country wins. The census cells count the occupied-household universe and pair only through the household-composition bridge, never with dwelling stock; that cross-grain rescale applies once the bridge is bound. Today it is reviewed-unbound, so the cells bind as published after A15 uprating. Fence evidence: uk_local_target_census.json#/binding_fences/census_disclosure_control_noise; the published cells preserve the source cell-key controls. Re-worded 2026-09-10 (microcosm#887 review round 1).", + "reason": "Accept the stated basis: constituency and local-authority household counts bind to the published disclosure-controlled census values compiled from the pinned Chronicle feed (ons.census.households: ONS TS041 PCON24/LAD, NRS UV404 UKPC24 and council all-occupied totals, NISRA PCON24/LGD14). Per-area dispersion of the retired OA-ladder sums against the published cells at review: England mean 7.4 / max 29, Wales 6.4 / 15, Scotland net −557 (NRS applies disclosure control per output level; same shortfall at both grains), Northern Ireland mean 7 / max 16 after the NI constituency leg moved to NISRA's published DZ2021→PARLCON24 lookup (the earlier postcode inference was a mapping defect of 10 Data Zones, max 694, not perturbation). When a national same-concept control is bound, the standing cross-grain rule declared in uk_runtime.ledger_targets rescales both grains; country wins. The census cells count the occupied-household universe and pair only through the household-composition bridge, never with dwelling stock; that cross-grain rescale applies once the bridge is bound. Bound from microcosm#791 (2026-09-11): the three ONS household-composition cells that held the bridge reviewed-unbound now bind on the frs_relationships household type, so the cross-grain rescale runs on the A15-uprated cells; the ten-cell partition and the A15 control are both ons.households_total, so the declared factor is 1 by closure and the receipt records the bridge as bound. Fence evidence: uk_local_target_census.json#/binding_fences/census_disclosure_control_noise; the published cells preserve the source cell-key controls. Re-worded 2026-09-10 (microcosm#887 review round 1).", "approved_by": "juaristi22", "adjudication": "microcosm#802", "approved_on": "2026-08-31", diff --git a/packages/microcosm-build/src/microcosm/build/uk/release_input_coverage_manifest.json b/packages/microcosm-build/src/microcosm/build/uk/release_input_coverage_manifest.json index 3afdaedda..9211c033a 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/release_input_coverage_manifest.json +++ b/packages/microcosm-build/src/microcosm/build/uk/release_input_coverage_manifest.json @@ -473,7 +473,7 @@ "capital_gains" ], "source_manifest": "source_stages.json", - "source_manifest_sha256": "f1bb134b5456be67c10f2e09b5dc9999c75b1bf3c47165092e260cbd79a54732", + "source_manifest_sha256": "6cba5ec097b64ef3a7d2c8e32de7346473a53155005e5cc370d7bcb8d60cfd9b", "source_vintages": { "source": "HMRC Capital Gains Tax statistics, July 2025, Table 2.1a", "survey": "HMRC Capital Gains Tax statistics Table 2.1a and Advani-Summers capital-gains incidence" @@ -496,7 +496,7 @@ "capital_gains" ], "source_manifest": "source_stages.json", - "source_manifest_sha256": "f1bb134b5456be67c10f2e09b5dc9999c75b1bf3c47165092e260cbd79a54732", + "source_manifest_sha256": "6cba5ec097b64ef3a7d2c8e32de7346473a53155005e5cc370d7bcb8d60cfd9b", "source_vintages": { "source": "Advani and Summers (2020), Capital Gains and UK Inequality, CAGE Working Paper 465", "survey": "Family Resources Survey 2024-25, SPI synthetic support, and Advani-Summers capital-gains incidence" @@ -525,7 +525,7 @@ "required_mass_change_reason": "E5 source-stage transform preserves household rows and typed household weights; total household mass is conserved.", "rewrites": [], "source_manifest": "source_stages.json", - "source_manifest_sha256": "f1bb134b5456be67c10f2e09b5dc9999c75b1bf3c47165092e260cbd79a54732", + "source_manifest_sha256": "6cba5ec097b64ef3a7d2c8e32de7346473a53155005e5cc370d7bcb8d60cfd9b", "source_vintages": { "source": "UK Data Service SN 8856 Effects of Taxes and Benefits household tab, DfT rail fare index, and public NHS activity/cost table.", "survey": "Effects of Taxes and Benefits 1977-2024 and NHS age-gender public table" @@ -545,7 +545,7 @@ "required_mass_change_reason": "E5 source-stage transform preserves household rows and typed household weights; total household mass is conserved.", "rewrites": [], "source_manifest": "source_stages.json", - "source_manifest_sha256": "f1bb134b5456be67c10f2e09b5dc9999c75b1bf3c47165092e260cbd79a54732", + "source_manifest_sha256": "6cba5ec097b64ef3a7d2c8e32de7346473a53155005e5cc370d7bcb8d60cfd9b", "source_vintages": { "source": "UK Data Service SN 8856 Effects of Taxes and Benefits household tab and cited VAT anchor resource.", "survey": "Effects of Taxes and Benefits 1977-2024" @@ -576,7 +576,7 @@ "superseded_by": { "reason": "The FRS spine build executes hmrc_cgt_gains_spine, which applies the same HMRC Table 3 amounts redraw directly in source_stages.json before calibration.", "source_manifest": "source_stages.json", - "source_manifest_sha256": "f1bb134b5456be67c10f2e09b5dc9999c75b1bf3c47165092e260cbd79a54732", + "source_manifest_sha256": "6cba5ec097b64ef3a7d2c8e32de7346473a53155005e5cc370d7bcb8d60cfd9b", "stage": "hmrc_cgt_gains_spine" } }, @@ -596,7 +596,7 @@ "capital_gains" ], "source_manifest": "source_stages.json", - "source_manifest_sha256": "f1bb134b5456be67c10f2e09b5dc9999c75b1bf3c47165092e260cbd79a54732", + "source_manifest_sha256": "6cba5ec097b64ef3a7d2c8e32de7346473a53155005e5cc370d7bcb8d60cfd9b", "source_vintages": { "hmrc_surface": "2023-24", "mapped_build_period": "2024" @@ -610,7 +610,7 @@ "base_candidate_tier": "frs", "calibration_permitted": false, "canonical_source_manifest": "source_stages.json", - "canonical_source_manifest_sha256": "f1bb134b5456be67c10f2e09b5dc9999c75b1bf3c47165092e260cbd79a54732", + "canonical_source_manifest_sha256": "6cba5ec097b64ef3a7d2c8e32de7346473a53155005e5cc370d7bcb8d60cfd9b", "effective_mass_requirements": { "charitable_investment_gifts": { "mass_share_denominator": "all_person_effective_mass", @@ -693,7 +693,7 @@ "superseded_by": { "reason": "The FRS spine build executes hmrc_spi_income_spine, which supersedes the June retained-leaves/hmrc_spi_income pair inside source_stages.json.", "source_manifest": "source_stages.json", - "source_manifest_sha256": "f1bb134b5456be67c10f2e09b5dc9999c75b1bf3c47165092e260cbd79a54732", + "source_manifest_sha256": "6cba5ec097b64ef3a7d2c8e32de7346473a53155005e5cc370d7bcb8d60cfd9b", "stage": "hmrc_spi_income_spine" } }, @@ -727,7 +727,7 @@ "required_mass_change_reason": "E5 source-stage transform preserves household rows and typed household weights; total household mass is conserved.", "rewrites": [], "source_manifest": "source_stages.json", - "source_manifest_sha256": "f1bb134b5456be67c10f2e09b5dc9999c75b1bf3c47165092e260cbd79a54732", + "source_manifest_sha256": "6cba5ec097b64ef3a7d2c8e32de7346473a53155005e5cc370d7bcb8d60cfd9b", "source_vintages": { "source": "UK Data Service SN 9468 Living Costs and Food Survey 2023-24 household/person tabs, NEED 2023 headline energy tables, Ofgem Q2 2026 unit rates, and WAS round-8 bridge donor.", "survey": "Living Costs and Food Survey 2023-24" @@ -748,7 +748,7 @@ "property_wealth" ], "source_manifest": "source_stages.json", - "source_manifest_sha256": "f1bb134b5456be67c10f2e09b5dc9999c75b1bf3c47165092e260cbd79a54732", + "source_manifest_sha256": "6cba5ec097b64ef3a7d2c8e32de7346473a53155005e5cc370d7bcb8d60cfd9b", "source_vintages": { "source": "MHCLG dwellings and ONS UK House Price Index December 2025 regional average prices.", "survey": "Public regional property reference" @@ -772,7 +772,7 @@ "employee_pension_contributions" ], "source_manifest": "source_stages.json", - "source_manifest_sha256": "f1bb134b5456be67c10f2e09b5dc9999c75b1bf3c47165092e260cbd79a54732", + "source_manifest_sha256": "6cba5ec097b64ef3a7d2c8e32de7346473a53155005e5cc370d7bcb8d60cfd9b", "source_vintages": { "source": "HMRC, Salary sacrifice reform for pension contributions effective from 6 April 2029", "survey": "Family Resources Survey 2024-25 salary-sacrifice respondents and HMRC salary-sacrifice reform analysis" @@ -794,7 +794,7 @@ "student_loan_plan" ], "source_manifest": "source_stages.json", - "source_manifest_sha256": "f1bb134b5456be67c10f2e09b5dc9999c75b1bf3c47165092e260cbd79a54732", + "source_manifest_sha256": "6cba5ec097b64ef3a7d2c8e32de7346473a53155005e5cc370d7bcb8d60cfd9b", "source_vintages": { "source": "Explore Education Statistics Table 6a, Higher education total", "survey": "Family Resources Survey 2024-25 and Student Loans Company borrower forecasts for England" @@ -829,7 +829,7 @@ "required_mass_change_reason": "E5 source-stage transform preserves household rows and typed household weights; total household mass is conserved.", "rewrites": [], "source_manifest": "source_stages.json", - "source_manifest_sha256": "f1bb134b5456be67c10f2e09b5dc9999c75b1bf3c47165092e260cbd79a54732", + "source_manifest_sha256": "6cba5ec097b64ef3a7d2c8e32de7346473a53155005e5cc370d7bcb8d60cfd9b", "source_vintages": { "source": "Office for National Statistics Wealth and Assets Survey, UK Data Service SN 7215, DOI 10.5255/UKDA-SN-7215-20; local licensed 2006-22 household tab.", "survey": "Wealth and Assets Survey round 8" diff --git a/packages/microcosm-build/src/microcosm/build/uk/source_stages.json b/packages/microcosm-build/src/microcosm/build/uk/source_stages.json index 52fe5be61..b83db92af 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/source_stages.json +++ b/packages/microcosm-build/src/microcosm/build/uk/source_stages.json @@ -408,6 +408,228 @@ ], "notes": "The licensed FRS records no age above 80, so every 80+ person arrives piled at exactly 80 and the 85-89 and 90+ population targets are structurally unbindable; the incumbent shares the defect. Each piled base person draws a band from the sex-specific ONS inverse CDF and a uniform integer age within it, keyed on person_id. Runs immediately after frs_spine, before every stage that conditions on age, so all age-conditioned imputations derive from the disaggregated surface. The stage precedes person_source_id provenance; later support and capital-gains clones copy the donor's rewritten age, preserving the #623 final-age identity invariant. Ages are assigned toward the ONS distribution; calibration still owns the totals." }, + { + "stage": "frs_relationships", + "survey": "Family Resources Survey 2024-25", + "source": "Department for Work and Pensions Family Resources Survey 2024-25, UK Data Service SN 9563, DOI 10.5255/UKDA-SN-9563-1; local licensed 2024_25 tabs (household grid, relhrp and R01-R14).", + "grain": "household+person", + "artifacts": [ + { + "role": "frs_table", + "table": "adult", + "kind": "licensed_microdata", + "format": "tab", + "vintage": "2024_25", + "locator": "adult.tab", + "sha256": "4eaea0809a7ccca0fddeb98e358771e4a6e5ebb81b21c4fac4070fc9d227658d", + "size_bytes": 34885825, + "runtime_sha256_required": true, + "tax_year_start": 2024, + "ukds_study_number": 9563, + "doi": "10.5255/UKDA-SN-9563-1" + }, + { + "role": "frs_table", + "table": "child", + "kind": "licensed_microdata", + "format": "tab", + "vintage": "2024_25", + "locator": "child.tab", + "sha256": "88ec53fc52eea4374864bbc74219d551f4b4c5f54a220bf9607c7a6289719aa5", + "size_bytes": 2753961, + "runtime_sha256_required": true, + "tax_year_start": 2024, + "ukds_study_number": 9563, + "doi": "10.5255/UKDA-SN-9563-1" + }, + { + "role": "frs_table", + "table": "househol", + "kind": "licensed_microdata", + "format": "tab", + "vintage": "2024_25", + "locator": "househol.tab", + "sha256": "2b93b6aed49e1591d6f5360736b4aee3a11ef506b276435f4d2c011a8afbb6a5", + "size_bytes": 12108606, + "runtime_sha256_required": true, + "tax_year_start": 2024, + "ukds_study_number": 9563, + "doi": "10.5255/UKDA-SN-9563-1" + } + ], + "operations": [ + { + "kind": "read_tables", + "format": "tab", + "delimiter": "\t", + "lowercase_columns": true, + "numeric_errors": "coerce", + "runtime_sha256_required": true + }, + { + "kind": "derive_ons_household_composition", + "source_columns": { + "head": "relhrp", + "head_flag": "hrpid", + "head_index": "hrpnum", + "grid": [ + "r01", + "r02", + "r03", + "r04", + "r05", + "r06", + "r07", + "r08", + "r09", + "r10", + "r11", + "r12", + "r13", + "r14" + ], + "full_time_education": [ + "fted", + "educft" + ] + }, + "frs_household_grid_relationship_codes": [ + { + "code": 1, + "label": "SPOUSE" + }, + { + "code": 2, + "label": "COHABITEE" + }, + { + "code": 3, + "label": "CHILD" + }, + { + "code": 4, + "label": "STEP_CHILD" + }, + { + "code": 5, + "label": "FOSTER_CHILD" + }, + { + "code": 6, + "label": "CHILD_IN_LAW" + }, + { + "code": 7, + "label": "PARENT" + }, + { + "code": 8, + "label": "STEP_PARENT" + }, + { + "code": 9, + "label": "FOSTER_PARENT" + }, + { + "code": 10, + "label": "PARENT_IN_LAW" + }, + { + "code": 11, + "label": "SIBLING" + }, + { + "code": 12, + "label": "STEP_SIBLING" + }, + { + "code": 13, + "label": "FOSTER_SIBLING" + }, + { + "code": 14, + "label": "SIBLING_IN_LAW" + }, + { + "code": 15, + "label": "GRANDCHILD" + }, + { + "code": 16, + "label": "GRANDPARENT" + }, + { + "code": 17, + "label": "OTHER_RELATIVE" + }, + { + "code": 18, + "label": "OTHER_NON_RELATIVE" + }, + { + "code": 20, + "label": "CIVIL_PARTNER" + } + ], + "head_label": "HEAD", + "family_link_codes": { + "partner": [ + 1, + 2, + 20 + ], + "child_of": [ + 3, + 4 + ], + "parent_of": [ + 7, + 8 + ] + }, + "dependent_child": { + "unconditional_below_age": 16, + "full_time_education_through_age": 18 + }, + "one_person_age_split": 65, + "family_role_values": [ + "COUPLE_PARTNER", + "LONE_PARENT", + "DEPENDENT_CHILD", + "NON_DEPENDENT_CHILD", + "INDIVIDUAL" + ], + "household_type_values": [ + "lone_households_under_65", + "lone_households_over_65", + "unrelated_adult_households", + "couple_no_children_households", + "couple_under_3_children_households", + "couple_3_plus_children_households", + "couple_non_dependent_children_only_households", + "lone_parent_dependent_children_households", + "lone_parent_non_dependent_children_households", + "multi_family_households" + ], + "reciprocity_mismatch_tolerance": 3, + "documentation": { + "frs_codes": "UK Data Service SN 9563 (DOI 10.5255/UKDA-SN-9563-1), FRS 2024-25 question instructions, Household Grid: Relationship; HRP definition in the FRS background information and methodology", + "ons_definitions": "ONS Families and households in the UK: 2025, Measuring the data and Glossary (family, dependent and non-dependent children, one-family, two or more unrelated adults, multi-family households)", + "category_ids": "chronicle package ons-families-households-2025, Table 7, dimension ons.household_type value ids" + } + } + ], + "outputs": [ + "relationship_to_head", + "ons_family_role", + "ons_family_index", + "ons_household_type" + ], + "nonnegative_outputs": [ + "ons_family_index" + ], + "notes": "Derives the ONS Families and households Table 7 household type from the FRS household grid (microcosm#791). Every person's relhrp code becomes relationship_to_head (HEAD for the household reference person, whose relhrp is blank and whose hrpid is 1; hrpnum on the househol tab is the independent check). The pairwise R01-R14 matrix builds ONS families: any partner pair (spouse, cohabitee, civil partner) is a couple; a person with no partner and no own child in the household joins a parent's family through a natural/adopted or step child link (natural before step, then the lowest person number, on ties); foster, in-law, grandparent and sibling links never form a family, so foster children and grandchildren without a parent present stay individuals, as ONS treats them. A child is dependent under 16, or 16-18 in full-time education (child-tab members are in full-time non-advanced education by construction; adults use educft, fted on earlier tapes); 19 and over is non-dependent whatever the education status - the FRS child tab runs to 19, ONS stops at 18, so the two definitions are translated here rather than assumed equal. Household type: one person (split at 65), no family present (two or more unrelated adults, which counts related non-family households such as two siblings), exactly one family classified by that family whatever other individuals live there (a couple plus a lodger is a couple household - the class the #757 person-count restrictions could not place), or two or more families. The ten values are the Chronicle ons-families-households-2025 ons.household_type value ids verbatim, so the frame value, this declaration, the contract row and the published fact share one string. The reciprocity tolerance is the 2024-25 tape's three ordered pairs (two households) where a child records a parent link the parent records as non-relative or sibling; either side's declaration establishes the link, and any other count refuses the build for review." + }, { "stage": "frs_employment", "survey": "Family Resources Survey 2024-25", diff --git a/packages/microcosm-build/src/microcosm/build/uk/spec/sources.yaml b/packages/microcosm-build/src/microcosm/build/uk/spec/sources.yaml index 7a7308ff5..21a640a7a 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/spec/sources.yaml +++ b/packages/microcosm-build/src/microcosm/build/uk/spec/sources.yaml @@ -358,6 +358,134 @@ stages: rewrites: - age notes: "The licensed FRS records no age above 80, so every 80+ person arrives piled at exactly 80 and the 85-89 and 90+ population targets are structurally unbindable; the incumbent shares the defect. Each piled base person draws a band from the sex-specific ONS inverse CDF and a uniform integer age within it, keyed on person_id. Runs immediately after frs_spine, before every stage that conditions on age, so all age-conditioned imputations derive from the disaggregated surface. The stage precedes person_source_id provenance; later support and capital-gains clones copy the donor's rewritten age, preserving the #623 final-age identity invariant. Ages are assigned toward the ONS distribution; calibration still owns the totals." +- stage: frs_relationships + survey: Family Resources Survey 2024-25 + source: Department for Work and Pensions Family Resources Survey 2024-25, UK Data Service SN 9563, DOI 10.5255/UKDA-SN-9563-1; local licensed 2024_25 tabs (household grid, relhrp and R01-R14). + grain: household+person + artifacts: + - role: frs_table + table: adult + kind: licensed_microdata + format: tab + vintage: '2024_25' + locator: adult.tab + sha256: 4eaea0809a7ccca0fddeb98e358771e4a6e5ebb81b21c4fac4070fc9d227658d + size_bytes: 34885825 + runtime_sha256_required: true + tax_year_start: 2024 + ukds_study_number: 9563 + doi: 10.5255/UKDA-SN-9563-1 + - role: frs_table + table: child + kind: licensed_microdata + format: tab + vintage: '2024_25' + locator: child.tab + sha256: 88ec53fc52eea4374864bbc74219d551f4b4c5f54a220bf9607c7a6289719aa5 + size_bytes: 2753961 + runtime_sha256_required: true + tax_year_start: 2024 + ukds_study_number: 9563 + doi: 10.5255/UKDA-SN-9563-1 + - role: frs_table + table: househol + kind: licensed_microdata + format: tab + vintage: '2024_25' + locator: househol.tab + sha256: 2b93b6aed49e1591d6f5360736b4aee3a11ef506b276435f4d2c011a8afbb6a5 + size_bytes: 12108606 + runtime_sha256_required: true + tax_year_start: 2024 + ukds_study_number: 9563 + doi: 10.5255/UKDA-SN-9563-1 + operations: + - kind: read_tables + format: tab + delimiter: "\t" + lowercase_columns: true + numeric_errors: coerce + runtime_sha256_required: true + - kind: derive_ons_household_composition + source_columns: + head: relhrp + head_flag: hrpid + head_index: hrpnum + grid: [r01, r02, r03, r04, r05, r06, r07, r08, r09, r10, r11, r12, r13, r14] + full_time_education: [fted, educft] + frs_household_grid_relationship_codes: + - code: 1 + label: SPOUSE + - code: 2 + label: COHABITEE + - code: 3 + label: CHILD + - code: 4 + label: STEP_CHILD + - code: 5 + label: FOSTER_CHILD + - code: 6 + label: CHILD_IN_LAW + - code: 7 + label: PARENT + - code: 8 + label: STEP_PARENT + - code: 9 + label: FOSTER_PARENT + - code: 10 + label: PARENT_IN_LAW + - code: 11 + label: SIBLING + - code: 12 + label: STEP_SIBLING + - code: 13 + label: FOSTER_SIBLING + - code: 14 + label: SIBLING_IN_LAW + - code: 15 + label: GRANDCHILD + - code: 16 + label: GRANDPARENT + - code: 17 + label: OTHER_RELATIVE + - code: 18 + label: OTHER_NON_RELATIVE + - code: 20 + label: CIVIL_PARTNER + head_label: HEAD + family_link_codes: + partner: [1, 2, 20] + child_of: [3, 4] + parent_of: [7, 8] + dependent_child: + unconditional_below_age: 16 + full_time_education_through_age: 18 + one_person_age_split: 65 + family_role_values: [COUPLE_PARTNER, LONE_PARENT, DEPENDENT_CHILD, NON_DEPENDENT_CHILD, INDIVIDUAL] + household_type_values: + - lone_households_under_65 + - lone_households_over_65 + - unrelated_adult_households + - couple_no_children_households + - couple_under_3_children_households + - couple_3_plus_children_households + - couple_non_dependent_children_only_households + - lone_parent_dependent_children_households + - lone_parent_non_dependent_children_households + - multi_family_households + reciprocity_mismatch_tolerance: 3 + documentation: + frs_codes: "UK Data Service SN 9563 (DOI 10.5255/UKDA-SN-9563-1), FRS 2024-25 question instructions, Household Grid: Relationship; HRP definition in the FRS background information and methodology" + ons_definitions: "ONS Families and households in the UK: 2025, Measuring the data and Glossary (family, dependent and non-dependent children, one-family, two or more unrelated adults, multi-family households)" + category_ids: "chronicle package ons-families-households-2025, Table 7, dimension ons.household_type value ids" + outputs: + - relationship_to_head + - ons_family_role + - ons_family_index + - ons_household_type + nonnegative_outputs: + - ons_family_index + notes: "Derives the ONS Families and households Table 7 household type from the FRS household grid (microcosm#791). Every person's relhrp code becomes relationship_to_head (HEAD for the household reference person, whose relhrp is blank and whose hrpid is 1; hrpnum on the househol tab is the independent check). The pairwise R01-R14 matrix builds ONS families: any partner pair (spouse, cohabitee, civil partner) is a couple; a person with no partner and no own child in the household joins a parent's family through a natural/adopted or step child link (natural before step, then the lowest person number, on ties); foster, in-law, grandparent and sibling links never form a family, so foster children and grandchildren without a parent present stay individuals, as ONS treats them. A child is dependent under 16, or 16-18 in full-time education (child-tab members are in full-time non-advanced education by construction; adults use educft, fted on earlier tapes); 19 and over is non-dependent whatever the education status - the FRS child tab runs to 19, ONS stops at 18, so the two definitions are translated here rather than assumed equal. Household type: one person (split at 65), no family present (two or more unrelated adults, which counts related non-family households such as two siblings), exactly one family classified by that family whatever other individuals live there (a couple plus a lodger is a couple household - the class the #757 person-count restrictions could not place), or two or more families. The ten values are the Chronicle ons-families-households-2025 ons.household_type value ids verbatim, so the frame value, this declaration, the contract row and the published fact share one string. The reciprocity tolerance is the 2024-25 tape's three ordered pairs (two households) where a child records a parent link the parent records as non-relative or sibling; either side's declaration establishes the link, and any other count refuses the build for review." - stage: frs_employment survey: Family Resources Survey 2024-25 source: Department for Work and Pensions Family Resources Survey 2024-25, UK Data Service SN 9563, DOI 10.5255/UKDA-SN-9563-1; local licensed 2024_25 tabs. diff --git a/packages/microcosm-build/src/microcosm/build/uk/uk_data_target_parity.json b/packages/microcosm-build/src/microcosm/build/uk/uk_data_target_parity.json index aecca0f0a..41e7b4fcb 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/uk_data_target_parity.json +++ b/packages/microcosm-build/src/microcosm/build/uk/uk_data_target_parity.json @@ -873,7 +873,7 @@ "covers": [ "policyengine_uk_data.targets.sources.ons_households" ], - "evidence": "uk-data targets/sources/ons_households.py; Microcosm ten-row ons.household_composition partition and UK_CROSS_GRAIN_BRIDGES declaration.", + "evidence": "uk-data targets/sources/ons_households.py; Microcosm ten-row ons.household_composition partition and UK_CROSS_GRAIN_BRIDGES declaration. Since microcosm#791 the ten cells bind on the frs_relationships stage's household.ons_household_type column (FRS household grid, ONS family definitions) rather than on the uk-data compute/households.py benefit-unit proxies, and the partition bridge to ons.census.households is bound.", "status": "ported_national" }, { diff --git a/packages/microcosm-build/src/microcosm/build/uk/uk_local_target_census.json b/packages/microcosm-build/src/microcosm/build/uk/uk_local_target_census.json index 6b373096b..46699babf 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/uk_local_target_census.json +++ b/packages/microcosm-build/src/microcosm/build/uk/uk_local_target_census.json @@ -98,7 +98,7 @@ "enforcement": "review_required_before_binding", "fence_id": "census_disclosure_control_noise", "fenced_fact_count": null, - "rule": "All three census household-count legs are disclosure-controlled (ONS/NRS cell-key perturbation; NISRA table-builder controls). Per-area dispersion of the retired OA-ladder sums against the published cells at review: England mean 7.4 / max 29, Wales 6.4 / 15, Scotland net \u2212557 (NRS applies disclosure control per output level; same shortfall at both grains), Northern Ireland mean 7 / max 16 after the NI constituency leg moved to NISRA's published DZ2021\u2192PARLCON24 lookup (the earlier postcode inference was a mapping defect of 10 Data Zones, max 694, not perturbation). When a national same-concept control is bound, the standing cross-grain rule declared in uk_runtime.ledger_targets rescales both grains; country wins. The census cells count the occupied-household universe and pair only through the household-composition bridge, never with dwelling stock; that cross-grain rescale applies once the bridge is bound. Today it is reviewed-unbound, so the cells bind as published after A15 uprating." + "rule": "All three census household-count legs are disclosure-controlled (ONS/NRS cell-key perturbation; NISRA table-builder controls). Per-area dispersion of the retired OA-ladder sums against the published cells at review: England mean 7.4 / max 29, Wales 6.4 / 15, Scotland net \u2212557 (NRS applies disclosure control per output level; same shortfall at both grains), Northern Ireland mean 7 / max 16 after the NI constituency leg moved to NISRA's published DZ2021\u2192PARLCON24 lookup (the earlier postcode inference was a mapping defect of 10 Data Zones, max 694, not perturbation). When a national same-concept control is bound, the standing cross-grain rule declared in uk_runtime.ledger_targets rescales both grains; country wins. The census cells count the occupied-household universe and pair only through the household-composition bridge, never with dwelling stock; that cross-grain rescale applies once the bridge is bound. Bound from microcosm#791 (2026-09-11): the three ONS household-composition cells that held the bridge reviewed-unbound now bind on the frs_relationships household type, so the cross-grain rescale runs on the A15-uprated cells; the ten-cell partition and the A15 control are both ons.households_total, so the declared factor is 1 by closure and the receipt records the bridge as bound." }, { "authority": "FRS background and methodology (private-household universe); ONS population estimates methodology (communal-establishment population); microcosm#495 scoping (cross-family review finding).", diff --git a/packages/microcosm-build/src/microcosm/build/uk/uk_population_targets.json b/packages/microcosm-build/src/microcosm/build/uk/uk_population_targets.json index 43e5afe0e..779e4eee7 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/uk_population_targets.json +++ b/packages/microcosm-build/src/microcosm/build/uk/uk_population_targets.json @@ -9833,36 +9833,13 @@ "reduce": "any", "household_conditions": [ { - "variable": "family_type", - "entity": "benunit", - "reduce": "any", - "operator": "==", - "value": "SINGLE" - }, - { - "variable": "is_child", - "entity": "person", - "reduce": "sum", + "variable": "ons_household_type", "operator": "==", - "value": 0 - }, - { - "variable": "age", - "entity": "person", - "reduce": "sum", - "operator": "<", - "value": 65 - }, - { - "variable": "age", - "entity": "person", - "reduce": "count", - "operator": "==", - "value": 1 + "value": "lone_households_under_65" } ], "value_variable": "household_count", - "notes": "ONS 'one person household': person count == 1 makes the category exact, and the age-sum reduction becomes the person's own age, so the head-age proxy note no longer applies. Without the restriction every all-adult SINGLE-benunit sharer household was also counted here (microcosm#757 audit partition, 2026-08-26)." + "notes": "Bound on the frame column household.ons_household_type == 'lone_households_under_65', written by the frs_relationships stage (microcosm#791) from the FRS household grid (relhrp, R01-R14); the value is Chronicle's ons.household_type dimension value id, so the contract row, the frame and the published fact share one string and no engine variable is involved. ONS dependency is under 16, or 16-18 in full-time education (the engine's is_child, age under 18, is not used). One-person household, aged under 65 on the frame's final (age_tail) age." }, "axiom": { "metric_name": "ons/lone_households_under_65", @@ -9897,36 +9874,13 @@ "reduce": "any", "household_conditions": [ { - "variable": "family_type", - "entity": "benunit", - "reduce": "any", + "variable": "ons_household_type", "operator": "==", - "value": "SINGLE" - }, - { - "variable": "is_child", - "entity": "person", - "reduce": "sum", - "operator": "==", - "value": 0 - }, - { - "variable": "age", - "entity": "person", - "reduce": "sum", - "operator": ">=", - "value": 65 - }, - { - "variable": "age", - "entity": "person", - "reduce": "count", - "operator": "==", - "value": 1 + "value": "lone_households_over_65" } ], "value_variable": "household_count", - "notes": "ONS 'one person household': person count == 1 makes the category exact, and the age-sum reduction becomes the person's own age, so the head-age proxy note no longer applies. Without the restriction every all-adult SINGLE-benunit sharer household was also counted here (microcosm#757 audit partition, 2026-08-26)." + "notes": "Bound on the frame column household.ons_household_type == 'lone_households_over_65', written by the frs_relationships stage (microcosm#791) from the FRS household grid (relhrp, R01-R14); the value is Chronicle's ons.household_type dimension value id, so the contract row, the frame and the published fact share one string and no engine variable is involved. ONS dependency is under 16, or 16-18 in full-time education (the engine's is_child, age under 18, is not used). One-person household, aged 65 or over on the frame's final (age_tail) age." }, "axiom": { "metric_name": "ons/lone_households_over_65", @@ -9961,28 +9915,13 @@ "reduce": "any", "household_conditions": [ { - "variable": "family_type", - "entity": "benunit", - "reduce": "any", + "variable": "ons_household_type", "operator": "==", - "value": "SINGLE" - }, - { - "variable": "is_child", - "entity": "person", - "reduce": "sum", - "operator": "==", - "value": 0 - }, - { - "variable": "age", - "entity": "person", - "reduce": "count", - "operator": ">", - "value": 1 + "value": "unrelated_adult_households" } ], - "value_variable": "household_count" + "value_variable": "household_count", + "notes": "Bound on the frame column household.ons_household_type == 'unrelated_adult_households', written by the frs_relationships stage (microcosm#791) from the FRS household grid (relhrp, R01-R14); the value is Chronicle's ons.household_type dimension value id, so the contract row, the frame and the published fact share one string and no engine variable is involved. ONS dependency is under 16, or 16-18 in full-time education (the engine's is_child, age under 18, is not used). ONS 'two or more unrelated adults' is any household of two or more people with no family present (no couple, no parent-child link), so related non-family households - two siblings, an adult with a foster child, a grandparent with a grandchild whose parent is absent - count here, as ONS counts them (ONS, Families and households statistics explained, 2021: \"a household with two or more people, none of whom are living as part of a family (that is, they do not contain either a couple or a parent with their child)\", https://www.ons.gov.uk/peoplepopulationandcommunity/birthsdeathsandmarriages/families/articles/familiesandhouseholdsstatisticsexplained/2021-03-02). Skip-generation households switch cell with the child's age by FRS coding: a grandparent raising a grandchild under 16 with no parent present is two unrelated adults here (codes 15/16 never form a family), while a 16-19 grandchild in full-time education is coded as the grandparents' legal dependent (7/3), so the same household becomes a lone-parent or couple family with a dependent child. The #757 SINGLE-benunit proxy, which could not tell this cell from the lone-parent-with-non-dependent-children cell, is retired." }, "axiom": { "metric_name": "ons/unrelated_adult_households", @@ -10017,22 +9956,13 @@ "reduce": "any", "household_conditions": [ { - "variable": "family_type", - "entity": "benunit", - "reduce": "any", + "variable": "ons_household_type", "operator": "==", - "value": "COUPLE_NO_CHILDREN" - }, - { - "variable": "age", - "entity": "person", - "reduce": "count", - "operator": "==", - "value": 2 + "value": "couple_no_children_households" } ], "value_variable": "household_count", - "notes": "ONS Table 7 'one family only: couple, no children' is the household being exactly one childless couple and nobody else; with the childless-couple benunit present, person count == 2 is equivalent to the one-family restriction. Without it the binding counted every household *containing* such a couple — a 1.84m overlap with the couple-non-dependent-children and multi-family categories (microcosm#757 audit partition, 2026-08-26)." + "notes": "Bound on the frame column household.ons_household_type == 'couple_no_children_households', written by the frs_relationships stage (microcosm#791) from the FRS household grid (relhrp, R01-R14); the value is Chronicle's ons.household_type dimension value id, so the contract row, the frame and the published fact share one string and no engine variable is involved. ONS dependency is under 16, or 16-18 in full-time education (the engine's is_child, age under 18, is not used). Exactly one family and it is a couple with no children in the household, whatever other individuals live there: a couple plus a lodger, or a couple plus an elderly parent, is this cell, as ONS classifies one-family households by the family. The #757 person-count == 2 restriction, which pushed those households into the multi-family and unrelated-adult proxies, is retired." }, "axiom": { "metric_name": "ons/couple_no_children_households", @@ -10067,28 +9997,13 @@ "reduce": "any", "household_conditions": [ { - "variable": "family_type", - "entity": "benunit", - "reduce": "any", + "variable": "ons_household_type", "operator": "==", - "value": "COUPLE_WITH_CHILDREN" - }, - { - "variable": "is_child", - "entity": "person", - "reduce": "sum", - "operator": ">=", - "value": 1 - }, - { - "variable": "is_child", - "entity": "person", - "reduce": "sum", - "operator": "<=", - "value": 2 + "value": "couple_under_3_children_households" } ], - "value_variable": "household_count" + "value_variable": "household_count", + "notes": "Bound on the frame column household.ons_household_type == 'couple_under_3_children_households', written by the frs_relationships stage (microcosm#791) from the FRS household grid (relhrp, R01-R14); the value is Chronicle's ons.household_type dimension value id, so the contract row, the frame and the published fact share one string and no engine variable is involved. ONS dependency is under 16, or 16-18 in full-time education (the engine's is_child, age under 18, is not used). Exactly one family, a couple with one or two dependent children (non-dependent children may also be present), whatever other individuals live there." }, "axiom": { "metric_name": "ons/couple_under_3_children_households", @@ -10123,21 +10038,13 @@ "reduce": "any", "household_conditions": [ { - "variable": "family_type", - "entity": "benunit", - "reduce": "any", + "variable": "ons_household_type", "operator": "==", - "value": "COUPLE_WITH_CHILDREN" - }, - { - "variable": "is_child", - "entity": "person", - "reduce": "sum", - "operator": ">=", - "value": 3 + "value": "couple_3_plus_children_households" } ], - "value_variable": "household_count" + "value_variable": "household_count", + "notes": "Bound on the frame column household.ons_household_type == 'couple_3_plus_children_households', written by the frs_relationships stage (microcosm#791) from the FRS household grid (relhrp, R01-R14); the value is Chronicle's ons.household_type dimension value id, so the contract row, the frame and the published fact share one string and no engine variable is involved. ONS dependency is under 16, or 16-18 in full-time education (the engine's is_child, age under 18, is not used). Exactly one family, a couple with three or more dependent children, whatever other individuals live there." }, "axiom": { "metric_name": "ons/couple_3_plus_children_households", @@ -10172,22 +10079,13 @@ "reduce": "any", "household_conditions": [ { - "variable": "family_type", - "entity": "benunit", - "reduce": "any", + "variable": "ons_household_type", "operator": "==", - "value": "COUPLE_NO_CHILDREN" - }, - { - "variable": "age", - "entity": "person", - "reduce": "count", - "operator": ">", - "value": 2 + "value": "couple_non_dependent_children_only_households" } ], "value_variable": "household_count", - "notes": "Proxied: couple benunit with additional non-dependent people (compute/households.py:40-42)." + "notes": "Bound on the frame column household.ons_household_type == 'couple_non_dependent_children_only_households', written by the frs_relationships stage (microcosm#791) from the FRS household grid (relhrp, R01-R14); the value is Chronicle's ons.household_type dimension value id, so the contract row, the frame and the published fact share one string and no engine variable is involved. ONS dependency is under 16, or 16-18 in full-time education (the engine's is_child, age under 18, is not used). Exactly one family, a couple whose children in the household are all non-dependent (19 and over, or 16-18 not in full-time education, with no partner or own child in the household), whatever other individuals live there. The uk-data compute/households.py proxy is retired." }, "axiom": { "metric_name": "ons/couple_non_dependent_children_only_households", @@ -10222,21 +10120,13 @@ "reduce": "any", "household_conditions": [ { - "variable": "family_type", - "entity": "benunit", - "reduce": "any", + "variable": "ons_household_type", "operator": "==", - "value": "LONE_PARENT" - }, - { - "variable": "is_child", - "entity": "person", - "reduce": "sum", - "operator": ">", - "value": 0 + "value": "lone_parent_dependent_children_households" } ], - "value_variable": "household_count" + "value_variable": "household_count", + "notes": "Bound on the frame column household.ons_household_type == 'lone_parent_dependent_children_households', written by the frs_relationships stage (microcosm#791) from the FRS household grid (relhrp, R01-R14); the value is Chronicle's ons.household_type dimension value id, so the contract row, the frame and the published fact share one string and no engine variable is involved. ONS dependency is under 16, or 16-18 in full-time education (the engine's is_child, age under 18, is not used). Exactly one family, a lone parent with at least one dependent child, whatever other individuals live there (a grandparent living with a lone-parent daughter and grandchild is this cell; the grandparent is an individual because the daughter has her own child). A 16-19 grandchild in full-time education living with grandparents and no parent lands here (or in the couple cell) because the FRS codes the grandparents as legal guardian (7/3); under 16 the same household is two unrelated adults." }, "axiom": { "metric_name": "ons/lone_parent_dependent_children_households", @@ -10271,36 +10161,13 @@ "reduce": "any", "household_conditions": [ { - "variable": "family_type", - "entity": "benunit", - "reduce": "any", + "variable": "ons_household_type", "operator": "==", - "value": "SINGLE" - }, - { - "variable": "is_child", - "entity": "person", - "reduce": "sum", - "operator": "==", - "value": 0 - }, - { - "variable": "age", - "entity": "person", - "reduce": "count", - "operator": ">", - "value": 1 - }, - { - "variable": "age", - "entity": "person", - "reduce": "sum", - "operator": ">=", - "value": 40 + "value": "lone_parent_non_dependent_children_households" } ], "value_variable": "household_count", - "notes": "Proxied: single benunit, no dependent children, more than one person, head aged 40+ (compute/households.py:45-52). uk-data reads ctx.pe('age') - person ages summed to household - as the head's age; exact only for single-person households (compute/households.py:12)." + "notes": "Bound on the frame column household.ons_household_type == 'lone_parent_non_dependent_children_households', written by the frs_relationships stage (microcosm#791) from the FRS household grid (relhrp, R01-R14); the value is Chronicle's ons.household_type dimension value id, so the contract row, the frame and the published fact share one string and no engine variable is involved. ONS dependency is under 16, or 16-18 in full-time education (the engine's is_child, age under 18, is not used). Exactly one family, a lone parent whose children in the household are all non-dependent. The summed-age head-age proxy inherited from uk-data compute/households.py:45-52 is retired; the relationship grid makes the cell exact." }, "axiom": { "metric_name": "ons/lone_parent_non_dependent_children_households", @@ -10335,12 +10202,13 @@ "reduce": "any", "household_conditions": [ { - "variable": "household_num_benunits", - "operator": ">", - "value": 1 + "variable": "ons_household_type", + "operator": "==", + "value": "multi_family_households" } ], - "value_variable": "household_count" + "value_variable": "household_count", + "notes": "Bound on the frame column household.ons_household_type == 'multi_family_households', written by the frs_relationships stage (microcosm#791) from the FRS household grid (relhrp, R01-R14); the value is Chronicle's ons.household_type dimension value id, so the contract row, the frame and the published fact share one string and no engine variable is involved. ONS dependency is under 16, or 16-18 in full-time education (the engine's is_child, age under 18, is not used). Two or more ONS families in the household, where a family is a couple with or without children or a lone parent with at least one child, and a child (of any age) with no partner and no own child belongs to the parent's family. The household_num_benunits > 1 proxy is retired: a non-dependent child is a separate benefit unit but the same ONS family, which is why the proxy read +1618% on the #757 rebind packet." }, "axiom": { "metric_name": "ons/multi_family_households", diff --git a/packages/microcosm-build/src/microcosm/build/uk_runtime/battery_bindings.py b/packages/microcosm-build/src/microcosm/build/uk_runtime/battery_bindings.py index f4e907507..5730b3cb7 100644 --- a/packages/microcosm-build/src/microcosm/build/uk_runtime/battery_bindings.py +++ b/packages/microcosm-build/src/microcosm/build/uk_runtime/battery_bindings.py @@ -1399,6 +1399,9 @@ def _ledger_compile_parity_required_artifacts( "minimum_signal_rows", "structural_zero_columns", "maximum_relative_deviation", + # #791 household_composition stage-health check. + "max_grid_reciprocity_mismatches", + "require_partition_closure", "support_bounds_resource", "minimum_band_rows", } diff --git a/packages/microcosm-build/src/microcosm/build/uk_runtime/calibration_run.py b/packages/microcosm-build/src/microcosm/build/uk_runtime/calibration_run.py index 7898ddc59..e5ddf40c2 100644 --- a/packages/microcosm-build/src/microcosm/build/uk_runtime/calibration_run.py +++ b/packages/microcosm-build/src/microcosm/build/uk_runtime/calibration_run.py @@ -123,6 +123,10 @@ class UKCalibrationRunResult: "uk_stage_salary_sacrifice_realization", "uk_stage_student_loans_realization", "uk_stage_age_tail_targets", + "uk_stage_frs_relationships_composition", + # Weight-independent like the BRMA enum below, and its column exists from + # frs_relationships onward (#791). + "uk_ons_household_type_enum_domain", # Weight-independent, and its column exists from frs_brma onward, so the # spine checks it at the assembled boundary instead of the release end. "uk_brma_enum_domain", diff --git a/packages/microcosm-build/src/microcosm/build/uk_runtime/data_target_parity.py b/packages/microcosm-build/src/microcosm/build/uk_runtime/data_target_parity.py index 96d22d57a..878108d23 100644 --- a/packages/microcosm-build/src/microcosm/build/uk_runtime/data_target_parity.py +++ b/packages/microcosm-build/src/microcosm/build/uk_runtime/data_target_parity.py @@ -250,7 +250,15 @@ def _fence(origin: str, purpose: str, verdict_basis: str) -> dict[str, str]: "concern_id": "national_ons_household_composition", "status": "ported_national", "classification": "national_registry_family", - "evidence": "uk-data targets/sources/ons_households.py; Microcosm ten-row ons.household_composition partition and UK_CROSS_GRAIN_BRIDGES declaration.", + "evidence": ( + "uk-data targets/sources/ons_households.py; Microcosm ten-row " + "ons.household_composition partition and UK_CROSS_GRAIN_BRIDGES " + "declaration. Since microcosm#791 the ten cells bind on the " + "frs_relationships stage's household.ons_household_type column " + "(FRS household grid, ONS family definitions) rather than on the " + "uk-data compute/households.py benefit-unit proxies, and the " + "partition bridge to ons.census.households is bound." + ), }, { "concern_id": "national_ons_england_tenure", diff --git a/packages/microcosm-build/src/microcosm/build/uk_runtime/frs_relationships.py b/packages/microcosm-build/src/microcosm/build/uk_runtime/frs_relationships.py new file mode 100644 index 000000000..768286b24 --- /dev/null +++ b/packages/microcosm-build/src/microcosm/build/uk_runtime/frs_relationships.py @@ -0,0 +1,768 @@ +"""FRS household-grid relationships and the ONS household-composition split. + +The stage (microcosm#791) reads the licensed FRS household grid — ``relhrp`` +(each person's relationship to the household reference person) and the +pairwise ``R01``-``R14`` matrix — and derives four frame columns: the +relationship to the head, each person's role inside an ONS family, the family +index within the household, and the household's ONS Families and households +Table 7 type. The ten household-type values are Chronicle's own category +identifiers for the ``ons.household_type`` dimension, so the frame value, the +manifest declaration, the contract row and the published fact share one +string. + +Three code lists, three owners, each named for its source: + +* ``FRS_HOUSEHOLD_GRID_RELATIONSHIP_CODES`` — DWP's FRS relationship codes + (UK Data Service SN 9563, FRS 2024-25 question instructions, Household + Grid: Relationship). +* ``ONS_FAMILY_LINK_CODES`` / ``ONS_DEPENDENT_CHILD_RULE`` / + ``ONS_ONE_PERSON_AGE_SPLIT`` — the ONS household-type definitions + (Families and households in the UK: 2025, Measuring the data / Glossary) + expressed over those FRS codes. +* ``CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS`` — the Chronicle + ``ons-families-households-2025`` package's ``ons.household_type`` value ids. + +The manifest declares the same lists as the ``derive_ons_household_composition`` +operation's parameters; :func:`assert_frs_relationships_stage_parameters` +refuses a build whose manifest and runtime disagree on any of them. +""" + +from __future__ import annotations + +from collections.abc import Mapping +from dataclasses import dataclass +from pathlib import Path +from typing import Any + +import numpy as np +import pandas as pd + +from microcosm.build.source_manifest import SourceStageSpec +from microcosm.build.uk_runtime.frs_spine import normalize_ids, read_pinned_tab +from microcosm.build.uk_runtime.national_frame import ( + uk_household_weight_kind, + uk_national_frame, + uk_time_period, + validate_uk_national_frame, +) +from microcosm.frame import Frame + +__all__ = [ + "CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS", + "FRS_HOUSEHOLD_GRID_RELATIONSHIP_CODES", + "FRS_RELATIONSHIPS_DERIVE_OPERATION_KIND", + "FRS_RELATIONSHIPS_DOCUMENTATION", + "FRS_RELATIONSHIPS_OUTPUT_COLUMNS", + "FRS_RELATIONSHIPS_RECIPROCITY_MISMATCH_TOLERANCE", + "FRS_RELATIONSHIPS_SOURCE_COLUMNS", + "FRS_RELATIONSHIPS_STAGE_NAME", + "FRS_RELATIONSHIPS_TABLES", + "ONS_DEPENDENT_CHILD_RULE", + "ONS_FAMILY_LINK_CODES", + "ONS_FAMILY_ROLE_VALUES", + "ONS_ONE_PERSON_AGE_SPLIT", + "RELATIONSHIP_TO_HEAD_HEAD_LABEL", + "RELATIONSHIP_TO_HEAD_VALUES", + "UKFRSRelationshipsResult", + "UKFRSRelationshipsStageTransform", + "add_frs_relationships", + "assert_frs_relationships_stage_parameters", + "derive_frs_relationships", + "frs_relationships_domains", + "frs_relationships_operation_parameters", +] + +FRS_RELATIONSHIPS_STAGE_NAME = "frs_relationships" +FRS_RELATIONSHIPS_DERIVE_OPERATION_KIND = "derive_ons_household_composition" +FRS_RELATIONSHIPS_TABLES = ("adult", "child", "househol") +FRS_RELATIONSHIPS_OUTPUT_COLUMNS = ( + "relationship_to_head", + "ons_family_role", + "ons_family_index", + "ons_household_type", +) +FRS_RELATIONSHIPS_PERSON_OUTPUT_COLUMNS = ( + "relationship_to_head", + "ons_family_role", + "ons_family_index", +) +FRS_RELATIONSHIPS_HOUSEHOLD_OUTPUT_COLUMNS = ("ons_household_type",) + +#: Raw FRS columns the stage reads. ``grid`` is the pairwise relationship +#: matrix keyed to the within-household person number (``person_id % 1000``); +#: ``full_time_education`` lists the adult-tab flag in fallback order (the +#: 2024-25 tape carries ``educft``; earlier tapes carried ``fted``). +FRS_RELATIONSHIPS_SOURCE_COLUMNS: Mapping[str, Any] = { + "head": "relhrp", + "head_flag": "hrpid", + "head_index": "hrpnum", + "grid": [f"r{index:02d}" for index in range(1, 15)], + "full_time_education": ["fted", "educft"], +} +FRS_HOUSEHOLD_GRID_MAX_PERSONS = 14 + +#: DWP FRS Household Grid relationship codes (UK Data Service SN 9563, FRS +#: 2024-25 question instructions, "Relationship"). Code 19 is not issued and +#: 97 is reserved; blank means the person is the household reference person. +FRS_HOUSEHOLD_GRID_RELATIONSHIP_CODES: Mapping[int, str] = { + 1: "SPOUSE", + 2: "COHABITEE", + 3: "CHILD", # son/daughter, including adopted and legal dependent + 4: "STEP_CHILD", + 5: "FOSTER_CHILD", + 6: "CHILD_IN_LAW", + 7: "PARENT", # father/mother or guardian + 8: "STEP_PARENT", + 9: "FOSTER_PARENT", + 10: "PARENT_IN_LAW", + 11: "SIBLING", # brother/sister, including adopted + 12: "STEP_SIBLING", # half-siblings are coded here per the instructions + 13: "FOSTER_SIBLING", + 14: "SIBLING_IN_LAW", + 15: "GRANDCHILD", + 16: "GRANDPARENT", + 17: "OTHER_RELATIVE", + 18: "OTHER_NON_RELATIVE", + 20: "CIVIL_PARTNER", +} +RELATIONSHIP_TO_HEAD_HEAD_LABEL = "HEAD" +RELATIONSHIP_TO_HEAD_VALUES: tuple[str, ...] = ( + RELATIONSHIP_TO_HEAD_HEAD_LABEL, + *FRS_HOUSEHOLD_GRID_RELATIONSHIP_CODES.values(), +) + +#: ONS "family" links over the FRS codes: a couple is any partner pair; a +#: child belongs to a parent's family through a natural/adopted or step link +#: (the parent's record carries the reciprocal parent code). Foster, in-law, +#: grandparent and sibling links never form a family (ONS treats foster +#: children and children living without a parent as one-person family units). +ONS_FAMILY_LINK_CODES: Mapping[str, tuple[int, ...]] = { + "partner": (1, 2, 20), + "child_of": (3, 4), + "parent_of": (7, 8), +} +#: ONS dependent child: under 16, or 16-18 and in full-time education, and +#: (by construction of the family assignment) with no partner or own child in +#: the household. 19+ is non-dependent whatever the education status. +ONS_DEPENDENT_CHILD_RULE: Mapping[str, int] = { + "unconditional_below_age": 16, + "full_time_education_through_age": 18, +} +#: ONS one-person households split at 65 ("65 or over"). +ONS_ONE_PERSON_AGE_SPLIT = 65 +ONS_FAMILY_ROLE_VALUES: tuple[str, ...] = ( + "COUPLE_PARTNER", + "LONE_PARENT", + "DEPENDENT_CHILD", + "NON_DEPENDENT_CHILD", + "INDIVIDUAL", +) +ONS_INDIVIDUAL_FAMILY_INDEX = 0 + +#: Chronicle ``ons-families-households-2025`` Table 7 ``ons.household_type`` +#: value ids, in the published row order. These are the frame values. +CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS: tuple[str, ...] = ( + "lone_households_under_65", + "lone_households_over_65", + "unrelated_adult_households", + "couple_no_children_households", + "couple_under_3_children_households", + "couple_3_plus_children_households", + "couple_non_dependent_children_only_households", + "lone_parent_dependent_children_households", + "lone_parent_non_dependent_children_households", + "multi_family_households", +) +#: Reviewed count of grid reciprocity mismatches on the pinned 2024-25 tape: +#: three ordered pairs in two households where a child records a parent link +#: the parent records as non-relative or sibling (step-0 probe, microcosm#791). +#: Either side's declaration establishes the link; any other count refuses. +FRS_RELATIONSHIPS_RECIPROCITY_MISMATCH_TOLERANCE = 3 +FRS_RELATIONSHIPS_DOCUMENTATION: Mapping[str, str] = { + "frs_codes": ( + "UK Data Service SN 9563 (DOI 10.5255/UKDA-SN-9563-1), FRS 2024-25 " + "question instructions, Household Grid: Relationship; HRP definition " + "in the FRS background information and methodology" + ), + "ons_definitions": ( + "ONS Families and households in the UK: 2025, Measuring the data and " + "Glossary (family, dependent and non-dependent children, one-family, " + "two or more unrelated adults, multi-family households)" + ), + "category_ids": ( + "chronicle package ons-families-households-2025, Table 7, dimension " + "ons.household_type value ids" + ), +} + + +def frs_relationships_operation_parameters() -> dict[str, Any]: + """The ``derive_ons_household_composition`` parameters the runtime implements.""" + + return { + "kind": FRS_RELATIONSHIPS_DERIVE_OPERATION_KIND, + "source_columns": { + "head": FRS_RELATIONSHIPS_SOURCE_COLUMNS["head"], + "head_flag": FRS_RELATIONSHIPS_SOURCE_COLUMNS["head_flag"], + "head_index": FRS_RELATIONSHIPS_SOURCE_COLUMNS["head_index"], + "grid": list(FRS_RELATIONSHIPS_SOURCE_COLUMNS["grid"]), + "full_time_education": list( + FRS_RELATIONSHIPS_SOURCE_COLUMNS["full_time_education"] + ), + }, + "frs_household_grid_relationship_codes": [ + {"code": code, "label": label} + for code, label in FRS_HOUSEHOLD_GRID_RELATIONSHIP_CODES.items() + ], + "head_label": RELATIONSHIP_TO_HEAD_HEAD_LABEL, + "family_link_codes": { + key: list(codes) for key, codes in ONS_FAMILY_LINK_CODES.items() + }, + "dependent_child": dict(ONS_DEPENDENT_CHILD_RULE), + "one_person_age_split": ONS_ONE_PERSON_AGE_SPLIT, + "family_role_values": list(ONS_FAMILY_ROLE_VALUES), + "household_type_values": list(CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS), + "reciprocity_mismatch_tolerance": ( + FRS_RELATIONSHIPS_RECIPROCITY_MISMATCH_TOLERANCE + ), + "documentation": dict(FRS_RELATIONSHIPS_DOCUMENTATION), + } + + +def assert_frs_relationships_stage_parameters(stage: SourceStageSpec) -> None: + """Closed-world drift assert: the manifest declares exactly this stage.""" + + if stage.stage != FRS_RELATIONSHIPS_STAGE_NAME: + raise ValueError(f"frs_relationships transform received stage {stage.stage!r}.") + operations = list(stage.operations) + kinds = [operation.kind for operation in operations] + if kinds != ["read_tables", FRS_RELATIONSHIPS_DERIVE_OPERATION_KIND]: + raise ValueError( + "frs_relationships stage must declare read_tables followed by " + f"{FRS_RELATIONSHIPS_DERIVE_OPERATION_KIND}, got {kinds}." + ) + declared = {"kind": operations[1].kind, **dict(operations[1].parameters)} + expected = frs_relationships_operation_parameters() + for key, value in expected.items(): + if _plain(declared.get(key)) != _plain(value): + raise ValueError( + f"frs_relationships stage parameter drift: {key!r} declares " + f"{declared.get(key)!r} but the runtime implements {value!r}." + ) + extra = set(declared) - set(expected) - {"reason"} + if extra: + raise ValueError( + f"frs_relationships stage declares parameter(s) {sorted(extra)} that " + "the runtime does not implement." + ) + if tuple(stage.outputs) != FRS_RELATIONSHIPS_OUTPUT_COLUMNS: + raise ValueError( + "frs_relationships stage outputs drift: manifest declares " + f"{tuple(stage.outputs)!r}, runtime writes " + f"{FRS_RELATIONSHIPS_OUTPUT_COLUMNS!r}." + ) + + +def _plain(value: Any) -> Any: + """Normalise tuples/lists and mapping proxies so JSON and Python compare.""" + + if isinstance(value, Mapping): + return {str(key): _plain(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [_plain(item) for item in value] + return value + + +def frs_relationships_domains() -> dict[str, tuple[str, ...]]: + """Enum domains of the three string outputs, for gates and tests.""" + + return { + "relationship_to_head": RELATIONSHIP_TO_HEAD_VALUES, + "ons_family_role": ONS_FAMILY_ROLE_VALUES, + "ons_household_type": CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS, + } + + +@dataclass(frozen=True) +class UKFRSRelationshipsResult: + """Derived person and household columns plus the stage evidence.""" + + person_values: pd.DataFrame + household_values: pd.DataFrame + evidence: Mapping[str, Any] + + +class UKFRSRelationshipsStageTransform: + """Whole-stage callable for the FRS relationship and composition derivation.""" + + def __init__(self, raw_dir: str | Path, *, stage: SourceStageSpec) -> None: + self.raw_dir = Path(raw_dir) + self.stage = stage + self.last_result: UKFRSRelationshipsResult | None = None + + def __call__(self, frame: Frame) -> Frame: + result, new_frame = add_frs_relationships(frame, self.raw_dir, stage=self.stage) + self.last_result = result + return new_frame + + @staticmethod + def output_columns() -> tuple[str, ...]: + return FRS_RELATIONSHIPS_OUTPUT_COLUMNS + + def checkpoint_metadata(self) -> dict[str, object]: + if self.last_result is None: + raise RuntimeError("checkpoint metadata requires a completed stage run.") + return {"evidence": dict(self.last_result.evidence)} + + +def add_frs_relationships( + frame: Frame, raw_dir: str | Path, *, stage: SourceStageSpec +) -> tuple[UKFRSRelationshipsResult, Frame]: + """Read the pinned FRS tabs and write the four relationship columns.""" + + assert_frs_relationships_stage_parameters(stage) + artifacts = _artifact_by_table(stage) + tables = { + table: normalize_ids( + read_pinned_tab( + Path(raw_dir) / str(artifacts[table]["locator"]), artifacts[table] + ) + ) + for table in FRS_RELATIONSHIPS_TABLES + } + person = frame.table("person").copy() + household = frame.table("household").copy() + weights = frame.weights_for("household").values + result = derive_frs_relationships( + person, + household, + raw_adult=tables["adult"], + raw_child=tables["child"], + raw_household=tables["househol"], + household_weights=weights, + ) + for column in FRS_RELATIONSHIPS_PERSON_OUTPUT_COLUMNS: + person[column] = result.person_values[column].to_numpy() + for column in FRS_RELATIONSHIPS_HOUSEHOLD_OUTPUT_COLUMNS: + household[column] = result.household_values[column].to_numpy() + new_frame = uk_national_frame( + person=person, + benunit=frame.table("benunit"), + household=household, + time_period=uk_time_period(frame), + weight_kind=uk_household_weight_kind(frame), + household_weights=weights, + mass_log=frame.mass_log, + ) + validate_uk_national_frame(new_frame) + return result, new_frame + + +def _artifact_by_table(stage: SourceStageSpec) -> dict[str, Mapping[str, Any]]: + by_table = {str(artifact.get("table")): artifact for artifact in stage.artifacts} + missing = sorted(set(FRS_RELATIONSHIPS_TABLES) - set(by_table)) + if missing: + raise ValueError( + f"frs_relationships manifest is missing tab artifact(s): {missing}." + ) + return by_table + + +class FRSRelationshipsError(ValueError): + """A licensed-tape defect the derivation refuses to paper over.""" + + +def derive_frs_relationships( + person: pd.DataFrame, + household: pd.DataFrame, + *, + raw_adult: pd.DataFrame, + raw_child: pd.DataFrame, + raw_household: pd.DataFrame | None = None, + household_weights: np.ndarray | pd.Series | None = None, + reciprocity_mismatch_tolerance: int = ( + FRS_RELATIONSHIPS_RECIPROCITY_MISMATCH_TOLERANCE + ), +) -> UKFRSRelationshipsResult: + """Derive the relationship, family and household-type columns. + + ``person`` and ``household`` are frame tables (``person_id``, + ``person_household_id``, ``age``, ``is_household_head``; + ``household_id``). ``raw_adult`` / ``raw_child`` / ``raw_household`` are + the id-normalised FRS tabs. Pure pandas/numpy; no engine. + """ + + raw = _aligned_raw_person(person, raw_adult, raw_child) + person_ids = person["person_id"].to_numpy(dtype="int64") + household_ids = person["person_household_id"].to_numpy(dtype="int64") + ages = pd.to_numeric(person["age"], errors="coerce").fillna(0).to_numpy() + frame_head = person["is_household_head"].to_numpy(dtype=bool) + person_index = person_ids % 1000 + grid_columns = list(FRS_RELATIONSHIPS_SOURCE_COLUMNS["grid"]) + grid = ( + raw[grid_columns] + .apply(pd.to_numeric, errors="coerce") + .fillna(0) + .to_numpy(dtype="int64") + ) + relhrp = pd.to_numeric( + raw[FRS_RELATIONSHIPS_SOURCE_COLUMNS["head"]], errors="coerce" + ) + hrpid = pd.to_numeric( + raw.get(FRS_RELATIONSHIPS_SOURCE_COLUMNS["head_flag"]), errors="coerce" + ) + hrpid = (pd.Series(hrpid, index=raw.index).fillna(0) == 1).to_numpy(dtype=bool) + fte_column = next( + ( + column + for column in FRS_RELATIONSHIPS_SOURCE_COLUMNS["full_time_education"] + if column in raw.columns + ), + None, + ) + fte_flag = ( + (pd.to_numeric(raw[fte_column], errors="coerce").fillna(0) == 1).to_numpy( + dtype=bool + ) + if fte_column is not None + else np.zeros(len(raw), dtype=bool) + ) + from_child_tab = (raw["_frs_table"] == "child").to_numpy(dtype=bool) + in_fte = from_child_tab | fte_flag + + relationship_to_head, unmapped = _relationship_to_head(relhrp, hrpid) + head_index_by_household = _head_index_by_household(raw_household) + + partner_codes = np.asarray(ONS_FAMILY_LINK_CODES["partner"]) + child_of_codes = np.asarray(ONS_FAMILY_LINK_CODES["child_of"]) + parent_of_codes = np.asarray(ONS_FAMILY_LINK_CODES["parent_of"]) + natural_child_code = int(ONS_FAMILY_LINK_CODES["child_of"][0]) + dep_rule = ONS_DEPENDENT_CHILD_RULE + + family_index = np.zeros(len(person), dtype="int64") + role = np.full(len(person), "INDIVIDUAL", dtype=object) + household_type: dict[int, str] = {} + + counters = { + "head_invariant_violations": 0, + "hrpnum_mismatches": 0, + "person_index_gaps": 0, + "grid_reciprocity_mismatches": 0, + "multi_partner_persons": 0, + "parent_tie_breaks": 0, + "one_family_plus_individuals": 0, + } + dependency_counts = { + "under_16": 0, + "16_18_fte": 0, + "16_18_not_fte": 0, + "19_plus": 0, + } + + order = np.argsort(household_ids, kind="stable") + boundaries = np.flatnonzero(np.diff(household_ids[order])) + 1 + for rows in np.split(order, boundaries): + household_id = int(household_ids[rows[0]]) + n = len(rows) + p = person_index[rows] + sort = np.argsort(p, kind="stable") + rows = rows[sort] + p = p[sort] + if p.max() > FRS_HOUSEHOLD_GRID_MAX_PERSONS or not np.array_equal( + p, np.arange(1, n + 1) + ): + counters["person_index_gaps"] += 1 + # M[i, j] = person i's relationship code toward person j. + matrix = grid[rows][:, np.minimum(p, FRS_HOUSEHOLD_GRID_MAX_PERSONS) - 1] + np.fill_diagonal(matrix, 0) + partner = np.isin(matrix, partner_codes) + child_of = np.isin(matrix, child_of_codes) + parent_of = np.isin(matrix, parent_of_codes) + counters["grid_reciprocity_mismatches"] += int( + np.triu(partner != partner.T, 1).sum() + ) + int((child_of != parent_of.T).sum()) + + heads = relationship_to_head[rows] == RELATIONSHIP_TO_HEAD_HEAD_LABEL + if heads.sum() != 1 or not np.array_equal(heads, frame_head[rows]): + counters["head_invariant_violations"] += 1 + expected_head_index = head_index_by_household.get(household_id) + if expected_head_index is not None and ( + heads.sum() != 1 or int(p[heads][0]) != expected_head_index + ): + counters["hrpnum_mismatches"] += 1 + + partner_any = partner | partner.T + partner_count = partner_any.sum(axis=1) + counters["multi_partner_persons"] += int((partner_count > 1).sum()) + has_partner = partner_count > 0 + child_of_any = child_of | parent_of.T + has_own_child = child_of_any.any(axis=0) + child_eligible = ~has_partner & ~has_own_child + + local_family = np.zeros(n, dtype="int64") + local_role = np.full(n, "INDIVIDUAL", dtype=object) + next_family = 1 + for i in range(n): + for j in range(i + 1, n): + if partner_any[i, j] and local_family[i] == 0 and local_family[j] == 0: + local_family[i] = local_family[j] = next_family + local_role[i] = local_role[j] = "COUPLE_PARTNER" + next_family += 1 + for i in range(n): + if not child_eligible[i]: + continue + parents = np.flatnonzero(child_of_any[i]) + if parents.size == 0: + continue + couple_families = sorted( + { + int(local_family[q]) + for q in parents + if local_role[q] == "COUPLE_PARTNER" + } + ) + if couple_families: + if len(couple_families) > 1: + counters["parent_tie_breaks"] += 1 + local_family[i] = couple_families[0] + local_role[i] = "CHILD" + continue + candidates = [ + q for q in parents if local_role[q] in ("INDIVIDUAL", "LONE_PARENT") + ] + if not candidates: + continue + ranked = sorted( + candidates, + key=lambda q: (0 if matrix[i, q] == natural_child_code else 1, q), + ) + if len({int(q) for q in ranked}) > 1: + counters["parent_tie_breaks"] += 1 + q = ranked[0] + if local_family[q] == 0: + local_family[q] = next_family + local_role[q] = "LONE_PARENT" + next_family += 1 + local_family[i] = local_family[q] + local_role[i] = "CHILD" + + local_ages = ages[rows] + local_fte = in_fte[rows] + for i in np.flatnonzero(local_role == "CHILD"): + age = int(local_ages[i]) + if age < dep_rule["unconditional_below_age"]: + dependent = True + dependency_counts["under_16"] += 1 + elif age <= dep_rule["full_time_education_through_age"]: + dependent = bool(local_fte[i]) + dependency_counts["16_18_fte" if dependent else "16_18_not_fte"] += 1 + else: + dependent = False + dependency_counts["19_plus"] += 1 + local_role[i] = "DEPENDENT_CHILD" if dependent else "NON_DEPENDENT_CHILD" + + families = next_family - 1 + if n == 1: + value = ( + "lone_households_over_65" + if int(local_ages[0]) >= ONS_ONE_PERSON_AGE_SPLIT + else "lone_households_under_65" + ) + elif families == 0: + value = "unrelated_adult_households" + elif families >= 2: + value = "multi_family_households" + else: + members = local_family == 1 + if members.sum() < n: + counters["one_family_plus_individuals"] += 1 + dependent = int((local_role[members] == "DEPENDENT_CHILD").sum()) + non_dependent = int((local_role[members] == "NON_DEPENDENT_CHILD").sum()) + if (local_role[members] == "COUPLE_PARTNER").any(): + if dependent >= 3: + value = "couple_3_plus_children_households" + elif dependent >= 1: + value = "couple_under_3_children_households" + elif non_dependent >= 1: + value = "couple_non_dependent_children_only_households" + else: + value = "couple_no_children_households" + elif dependent >= 1: + value = "lone_parent_dependent_children_households" + else: + value = "lone_parent_non_dependent_children_households" + household_type[household_id] = value + family_index[rows] = local_family + role[rows] = local_role + + household_table_ids = household["household_id"].to_numpy(dtype="int64") + missing_households = [ + int(identifier) + for identifier in household_table_ids + if int(identifier) not in household_type + ] + if missing_households: + raise FRSRelationshipsError( + f"{len(missing_households)} household(s) carry no persons on the " + f"frame and cannot be typed (first: {missing_households[:5]})." + ) + typed = np.asarray( + [household_type[int(identifier)] for identifier in household_table_ids], + dtype=object, + ) + if household_weights is None: + weights = np.ones(len(household_table_ids), dtype=float) + else: + weights = np.asarray(household_weights, dtype=float) + type_counts = { + value: int((typed == value).sum()) + for value in CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS + } + type_weighted = { + value: float(weights[typed == value].sum()) + for value in CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS + } + domain_violations = int( + (~np.isin(relationship_to_head, RELATIONSHIP_TO_HEAD_VALUES)).sum() + + (~np.isin(role, ONS_FAMILY_ROLE_VALUES)).sum() + + (~np.isin(typed, CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS)).sum() + ) + family_index_violations = int(((family_index == 0) != (role == "INDIVIDUAL")).sum()) + evidence: dict[str, Any] = { + "stage": FRS_RELATIONSHIPS_STAGE_NAME, + "households": int(len(household_table_ids)), + "persons": int(len(person)), + **counters, + "relhrp_unmapped_codes": unmapped, + "family_index_violations": family_index_violations, + "domain_violations": domain_violations, + "dependency_counts": dependency_counts, + "household_type_counts": type_counts, + "household_type_weighted": type_weighted, + "partition_closes": sum(type_counts.values()) == int(len(household_table_ids)), + "full_time_education_source": fte_column, + "reciprocity_mismatch_tolerance": int(reciprocity_mismatch_tolerance), + } + _refuse_defects(evidence, reciprocity_mismatch_tolerance) + person_values = pd.DataFrame( + { + "relationship_to_head": relationship_to_head, + "ons_family_role": role, + "ons_family_index": family_index, + }, + index=person.index, + ) + household_values = pd.DataFrame( + {"ons_household_type": typed}, index=household.index + ) + return UKFRSRelationshipsResult( + person_values=person_values, + household_values=household_values, + evidence=evidence, + ) + + +def _refuse_defects(evidence: Mapping[str, Any], tolerance: int) -> None: + failures: list[str] = [] + for key in ( + "head_invariant_violations", + "hrpnum_mismatches", + "person_index_gaps", + "multi_partner_persons", + "family_index_violations", + "domain_violations", + ): + if int(evidence[key]) != 0: + failures.append(f"{key}={evidence[key]}") + if int(evidence["grid_reciprocity_mismatches"]) > int(tolerance): + failures.append( + "grid_reciprocity_mismatches=" + f"{evidence['grid_reciprocity_mismatches']} exceeds tolerance {tolerance}" + ) + if evidence["relhrp_unmapped_codes"]: + failures.append(f"relhrp_unmapped_codes={evidence['relhrp_unmapped_codes']}") + if not evidence["partition_closes"]: + failures.append("household-type partition does not close") + if failures: + raise FRSRelationshipsError( + "FRS relationship derivation refused: " + "; ".join(failures) + "." + ) + + +def _aligned_raw_person( + person: pd.DataFrame, raw_adult: pd.DataFrame, raw_child: pd.DataFrame +) -> pd.DataFrame: + adult = raw_adult.copy() + adult["_frs_table"] = "adult" + child = raw_child.copy() + child["_frs_table"] = "child" + raw = pd.concat([adult, child], ignore_index=True, sort=False) + required = [ + "person_id", + FRS_RELATIONSHIPS_SOURCE_COLUMNS["head"], + *FRS_RELATIONSHIPS_SOURCE_COLUMNS["grid"], + ] + missing = [column for column in required if column not in raw.columns] + if missing: + raise FRSRelationshipsError( + f"FRS adult/child tabs are missing relationship column(s): {missing}." + ) + if FRS_RELATIONSHIPS_SOURCE_COLUMNS["head_flag"] not in adult.columns: + raise FRSRelationshipsError( + "FRS adult tab is missing the household reference person flag " + f"{FRS_RELATIONSHIPS_SOURCE_COLUMNS['head_flag']!r}." + ) + raw = raw.set_index(raw["person_id"].astype("int64")) + if raw.index.duplicated().any(): + raise FRSRelationshipsError("FRS adult/child tabs repeat a person_id.") + frame_ids = person["person_id"].astype("int64") + absent = frame_ids[~frame_ids.isin(raw.index)] + if len(absent): + raise FRSRelationshipsError( + f"{len(absent)} frame person(s) are absent from the FRS adult/child " + f"tabs (first: {absent.head().tolist()})." + ) + return raw.reindex(frame_ids.to_numpy()).reset_index(drop=True) + + +def _relationship_to_head( + relhrp: pd.Series, hrpid: np.ndarray +) -> tuple[np.ndarray, dict[str, int]]: + codes = relhrp.to_numpy(dtype=float) + blank = np.isnan(codes) | (codes == 0) + labels = np.full(len(codes), "", dtype=object) + unmapped: dict[str, int] = {} + labels[blank & hrpid] = RELATIONSHIP_TO_HEAD_HEAD_LABEL + blank_non_head = int((blank & ~hrpid).sum()) + if blank_non_head: + unmapped["blank_non_head"] = blank_non_head + coded = ~blank + for code, label in FRS_HOUSEHOLD_GRID_RELATIONSHIP_CODES.items(): + labels[coded & (codes == code)] = label + for code in np.unique(codes[coded]): + if int(code) not in FRS_HOUSEHOLD_GRID_RELATIONSHIP_CODES: + unmapped[str(int(code))] = int((codes == code).sum()) + coded_head = int((coded & hrpid).sum()) + if coded_head: + unmapped["coded_head"] = coded_head + return labels, unmapped + + +def _head_index_by_household(raw_household: pd.DataFrame | None) -> dict[int, int]: + if raw_household is None: + return {} + column = FRS_RELATIONSHIPS_SOURCE_COLUMNS["head_index"] + if ( + column not in raw_household.columns + or "household_id" not in raw_household.columns + ): + raise FRSRelationshipsError( + f"FRS househol tab is missing {column!r} or household_id." + ) + values = pd.to_numeric(raw_household[column], errors="coerce") + ids = raw_household["household_id"].astype("int64") + return { + int(identifier): int(value) + for identifier, value in zip(ids, values, strict=True) + if pd.notna(value) + } diff --git a/packages/microcosm-build/src/microcosm/build/uk_runtime/graph.py b/packages/microcosm-build/src/microcosm/build/uk_runtime/graph.py index a00abb0ad..18892d872 100644 --- a/packages/microcosm-build/src/microcosm/build/uk_runtime/graph.py +++ b/packages/microcosm-build/src/microcosm/build/uk_runtime/graph.py @@ -101,6 +101,7 @@ _SPLIT_STAGE_SOURCES: Mapping[str, tuple[str, ...]] = { "frs_spine": ("frs",), + "frs_relationships": ("frs",), "frs_employment": ("frs",), "frs_council_tax": ("frs",), "frs_education": ("frs",), @@ -131,6 +132,12 @@ # memberships, weights, and strata are executor-carried context rather than # ordinary owned cells. _STAGE_CONSUMES: Mapping[str, frozenset[tuple[str, str]] | None] = { + # The relationship grid is re-read from the pinned adult/child tabs; the + # frame reads are the disaggregated age (#785 contract) and the HRP flag + # the derivation must agree with. + "frs_relationships": frozenset( + {("person", "age"), ("person", "is_household_head")} + ), "frs_employment": frozenset(), "frs_council_tax": frozenset(), "frs_disability": frozenset( @@ -351,6 +358,12 @@ def _cells( _STAGE_CELLS: Mapping[str, tuple[_Cell, ...]] = { + "frs_relationships": ( + _Cell("person", "relationship_to_head", "string"), + _Cell("person", "ons_family_role", "string"), + _Cell("person", "ons_family_index", "int64"), + _Cell("household", "ons_household_type", "string"), + ), "frs_employment": ( _Cell("person", "employment_status", "string"), _Cell("person", "employment_sector", "string"), diff --git a/packages/microcosm-build/src/microcosm/build/uk_runtime/graph_kernels.py b/packages/microcosm-build/src/microcosm/build/uk_runtime/graph_kernels.py index 530e61470..a24296e0f 100644 --- a/packages/microcosm-build/src/microcosm/build/uk_runtime/graph_kernels.py +++ b/packages/microcosm-build/src/microcosm/build/uk_runtime/graph_kernels.py @@ -64,6 +64,7 @@ _STAGE_MODULES = { "frs_spine": "frs_spine", + "frs_relationships": "frs_relationships", "frs_employment": "frs_employment", "frs_council_tax": "frs_council_tax", "frs_disability": "frs_disability", @@ -319,7 +320,7 @@ def _fixture_descriptor( missing = sorted(set(_STAGE_MODULES) - set(stages)) extra = sorted(set(stages) - set(_STAGE_MODULES)) raise ValueError( - "UK parity fixture must describe the current 28-stage spine " + "UK parity fixture must describe the current 29-stage spine " f"(missing={missing}, extra={extra})." ) return descriptor, stages @@ -347,6 +348,7 @@ def _fixture_implementations(source: Path) -> Mapping[str, object]: from .frs_household_draws import UKFRSHouseholdDrawsStageTransform from .frs_legacy_proxies import UKFRSLegacyProxiesStageTransform from .frs_person_draws import UKFRSPersonDrawsStageTransform + from .frs_relationships import UKFRSRelationshipsStageTransform from .frs_take_up import UKFRSTakeUpStageTransform from .lcfs_consumption import UKLCFSConsumptionStageTransform from .regional_uprating import UKRegionalPropertyUpratingStageTransform @@ -401,6 +403,9 @@ def _fixture_implementations(source: Path) -> Mapping[str, object]: calibration_year = int(config["student_loans_calibration_year"]) return MappingProxyType( { + "frs_relationships": UKFRSRelationshipsStageTransform( + raw_dir, stage=stages["frs_relationships"] + ), "frs_employment": UKFRSEmploymentStageTransform( raw_dir, stage=stages["frs_employment"] ), diff --git a/packages/microcosm-build/src/microcosm/build/uk_runtime/ledger_targets.py b/packages/microcosm-build/src/microcosm/build/uk_runtime/ledger_targets.py index cbeae2215..1c1dd6adf 100644 --- a/packages/microcosm-build/src/microcosm/build/uk_runtime/ledger_targets.py +++ b/packages/microcosm-build/src/microcosm/build/uk_runtime/ledger_targets.py @@ -246,6 +246,7 @@ def compile_uk_target_registry( fact_rows = tuple(facts) spec = load_country_spec("uk") + _assert_household_type_bindings_declared(_uk_contract_targets()) compiled = [] unsupported: list[dict[str, str]] = [] for reference in spec.target_references: @@ -639,6 +640,54 @@ def _local_crosswalk_rosters( return rosters +def _assert_household_type_bindings_declared( + contract: Mapping[str, Mapping[str, Any]], +) -> None: + """Every ``ons_household_type`` condition names a declared frame value. + + The ten ONS household-composition rows bind on the frs_relationships + stage's household column (microcosm#791), whose domain is Chronicle's + ``ons.household_type`` value ids. A condition value outside that domain + would match no household and surface only as a zero-support refusal deep + in the solve; refusing at compile time names the row instead. The ten + rows must also cover the domain exactly once, or the partition the + census bridge reconciles against is no longer a partition. + """ + + from microcosm.build.uk_runtime.frs_relationships import ( + CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS, + ) + + domain = set(CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS) + covered: dict[str, str] = {} + for target_id, target in contract.items(): + binding = target.get("bindings", {}).get("policyengine", {}) + for field in ("filters", "household_conditions"): + for predicate in binding.get(field, ()): + if predicate.get("variable") != "ons_household_type": + continue + value = predicate.get("value") + if predicate.get("operator", "==") != "==" or value not in domain: + raise ValueError( + f"UK target {target_id!r} conditions on ons_household_type " + f"with {predicate!r}; the declared values are " + f"{sorted(domain)} under '=='." + ) + if target.get("family") == "ons_household_composition": + if value in covered: + raise ValueError( + f"UK targets {covered[value]!r} and {target_id!r} both " + f"bind ons_household_type == {value!r}." + ) + covered[value] = target_id + missing = domain - set(covered) + if covered and missing: + raise ValueError( + "UK ons_household_composition rows leave declared household-type " + f"value(s) unbound: {sorted(missing)}." + ) + + def _assert_local_reference_in_crosswalk( reference: LedgerTargetReference, rosters: Mapping[str, Mapping[str, Any]], diff --git a/packages/microcosm-build/src/microcosm/build/uk_runtime/local_target_census.py b/packages/microcosm-build/src/microcosm/build/uk_runtime/local_target_census.py index c31a5528e..7377df956 100644 --- a/packages/microcosm-build/src/microcosm/build/uk_runtime/local_target_census.py +++ b/packages/microcosm-build/src/microcosm/build/uk_runtime/local_target_census.py @@ -611,8 +611,13 @@ "country wins. The census cells count the occupied-household " "universe and pair only through the household-composition bridge, " "never with dwelling stock; that cross-grain rescale applies once " - "the bridge is bound. Today it is reviewed-unbound, so the cells " - "bind as published after A15 uprating." + "the bridge is bound. Bound from microcosm#791 (2026-09-11): the " + "three ONS household-composition cells that held the bridge " + "reviewed-unbound now bind on the frs_relationships household " + "type, so the cross-grain rescale runs on the A15-uprated cells; " + "the ten-cell partition and the A15 control are both " + "ons.households_total, so the declared factor is 1 by closure and " + "the receipt records the bridge as bound." ), "authority": ( "ONS/NRS/NISRA statistical disclosure control documentation; " diff --git a/packages/microcosm-build/src/microcosm/build/uk_runtime/source_runtime.py b/packages/microcosm-build/src/microcosm/build/uk_runtime/source_runtime.py index c36abf6cb..8e98ea9b3 100644 --- a/packages/microcosm-build/src/microcosm/build/uk_runtime/source_runtime.py +++ b/packages/microcosm-build/src/microcosm/build/uk_runtime/source_runtime.py @@ -52,6 +52,7 @@ def uk_stage_implementations( retained_leaves_transform: Callable[[Frame], Frame], hmrc_income_transform: Callable[[Frame], Frame], frs_spine_transform: Callable[[Frame], Frame] | None = None, + frs_relationships_transform: Callable[[Frame], Frame] | None = None, frs_employment_transform: Callable[[Frame], Frame] | None = None, frs_council_tax_transform: Callable[[Frame], Frame] | None = None, frs_disability_transform: Callable[[Frame], Frame] | None = None, @@ -85,6 +86,7 @@ def uk_stage_implementations( } optional = { "frs_spine": frs_spine_transform, + "frs_relationships": frs_relationships_transform, "frs_employment": frs_employment_transform, "frs_council_tax": frs_council_tax_transform, "frs_disability": frs_disability_transform, diff --git a/packages/microcosm-build/src/microcosm/build/uk_runtime/stage_health.py b/packages/microcosm-build/src/microcosm/build/uk_runtime/stage_health.py index 3a91e0f74..b60c9eaf9 100644 --- a/packages/microcosm-build/src/microcosm/build/uk_runtime/stage_health.py +++ b/packages/microcosm-build/src/microcosm/build/uk_runtime/stage_health.py @@ -54,6 +54,8 @@ def uk_stage_health_gate( return _cgt_imputation_summary_gate(stage, evidence, parameters) if check == "latent_attribute_realization": return _latent_attribute_realization_gate(stage, evidence) + if check == "household_composition": + return _household_composition_gate(stage, evidence, parameters) return GateResult( name="stage_health", passed=False, @@ -168,7 +170,11 @@ def _support_clip_gate( "columns_checked": len(expected_columns) - len(exempt_columns), "exempt_columns": sorted(exempt_columns), } - return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) + return ( + _fail(stage, check, failures, details) + if failures + else _pass(stage, check, details) + ) def _realization_target_gate( @@ -202,7 +208,11 @@ def _realization_target_gate( if bool(receipt.get("cap_bound")) and not bool(parameters.get("allow_cap_bound")): failures.append(f"{stage}: cap_bound is true but not allowed.") details = {"target": target, "abs_realization_deviation": deviation} - return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) + return ( + _fail(stage, check, failures, details) + if failures + else _pass(stage, check, details) + ) def _student_loan_plans_gate( @@ -225,7 +235,9 @@ def _student_loan_plans_gate( failures.append(f"{stage}: missing receipt for {plan}.") continue stock = _finite_number(receipt.get("stock"), label=f"{stage}.{plan}.stock") - expected = _finite_number(declared_stock, label=f"{stage}.{plan}.declared_stock") + expected = _finite_number( + declared_stock, label=f"{stage}.{plan}.declared_stock" + ) if stock != expected: failures.append(f"{stage}: {plan} stock {stock} != declared {expected}.") final = _finite_number( @@ -246,7 +258,11 @@ def _student_loan_plans_gate( f"{stage}: {plan} realization_deviation {deviation} exceeds {max_deviation}." ) details = {"plans_checked": len(declared_stocks), "worst_abs_deviation": worst} - return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) + return ( + _fail(stage, check, failures, details) + if failures + else _pass(stage, check, details) + ) def _cgt_incidence_mass_gate( @@ -255,7 +271,9 @@ def _cgt_incidence_mass_gate( parameters: Mapping[str, object], ) -> GateResult: check = "cgt_incidence_mass" - mass = _mapping(evidence.get("mass_by_clone_flag"), label=f"{stage}.mass_by_clone_flag") + mass = _mapping( + evidence.get("mass_by_clone_flag"), label=f"{stage}.mass_by_clone_flag" + ) original = _finite_number(mass.get("false"), label=f"{stage}.mass.false") clone = _finite_number(mass.get("true"), label=f"{stage}.mass.true") tolerance = _finite_number( @@ -268,9 +286,19 @@ def _cgt_incidence_mass_gate( if original <= 0.0 or clone <= 0.0: failures.append(f"{stage}: clone and original mass must both be positive.") if imbalance > tolerance: - failures.append(f"{stage}: clone/original mass imbalance {imbalance} exceeds {tolerance}.") - details = {"original_mass": original, "clone_mass": clone, "relative_imbalance": imbalance} - return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) + failures.append( + f"{stage}: clone/original mass imbalance {imbalance} exceeds {tolerance}." + ) + details = { + "original_mass": original, + "clone_mass": clone, + "relative_imbalance": imbalance, + } + return ( + _fail(stage, check, failures, details) + if failures + else _pass(stage, check, details) + ) def _spi_support_channel_gate( @@ -289,13 +317,24 @@ def _spi_support_channel_gate( if abs(share - expected_share) > _finite_number( parameters.get("absolute_tolerance", 0.0), label=f"{stage}.absolute_tolerance" ): - failures.append(f"{stage}: spi_prior_mass_share {share} != declared {expected_share}.") + failures.append( + f"{stage}: spi_prior_mass_share {share} != declared {expected_share}." + ) if evidence.get("household_weight_kind") != parameters.get("household_weight_kind"): failures.append(f"{stage}: household_weight_kind drifted.") - if int(evidence.get("spi_households", 0)) < int(parameters["minimum_spi_households"]): + if int(evidence.get("spi_households", 0)) < int( + parameters["minimum_spi_households"] + ): failures.append(f"{stage}: spi_households below declared minimum.") - details = {"spi_prior_mass_share": share, "spi_households": evidence.get("spi_households")} - return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) + details = { + "spi_prior_mass_share": share, + "spi_households": evidence.get("spi_households"), + } + return ( + _fail(stage, check, failures, details) + if failures + else _pass(stage, check, details) + ) def _spi_income_spine_gate( @@ -317,15 +356,26 @@ def _spi_income_spine_gate( expected_share = _finite_number( parameters["spi_prior_mass_share"], label=f"{stage}.spi_prior_mass_share" ) - share = _finite_number(prior.get("mass_share"), label=f"{stage}.spi_prior.mass_share") + share = _finite_number( + prior.get("mass_share"), label=f"{stage}.spi_prior.mass_share" + ) if abs(share - expected_share) > _finite_number( parameters.get("absolute_tolerance", 0.0), label=f"{stage}.absolute_tolerance" ): - failures.append(f"{stage}: spi prior mass share {share} != declared {expected_share}.") + failures.append( + f"{stage}: spi prior mass share {share} != declared {expected_share}." + ) if int(targets.get("count", 0)) < int(parameters["minimum_target_count"]): failures.append(f"{stage}: target count below declared minimum.") - details = {"identity_rows": identity.get("rows_checked"), "target_count": targets.get("count")} - return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) + details = { + "identity_rows": identity.get("rows_checked"), + "target_count": targets.get("count"), + } + return ( + _fail(stage, check, failures, details) + if failures + else _pass(stage, check, details) + ) def _source_signal_gate( @@ -334,20 +384,37 @@ def _source_signal_gate( parameters: Mapping[str, object], ) -> GateResult: check = "source_signal" - rows = _mapping(evidence.get("source_signal_rows"), label=f"{stage}.source_signal_rows") - allowed_zero = {str(column) for column in parameters.get("structural_zero_columns", ())} - reported_zero = {str(column) for column in evidence.get("structural_zero_columns", ())} + rows = _mapping( + evidence.get("source_signal_rows"), label=f"{stage}.source_signal_rows" + ) + allowed_zero = { + str(column) for column in parameters.get("structural_zero_columns", ()) + } + reported_zero = { + str(column) for column in evidence.get("structural_zero_columns", ()) + } minimum = int(parameters["minimum_signal_rows"]) failures: list[str] = [] if reported_zero - allowed_zero: - failures.append(f"{stage}: unreviewed structural zero columns {sorted(reported_zero - allowed_zero)}.") + failures.append( + f"{stage}: unreviewed structural zero columns {sorted(reported_zero - allowed_zero)}." + ) for column, value in rows.items(): if str(column) in allowed_zero: continue if int(value) < minimum: - failures.append(f"{stage}: {column} has {value} source-signal row(s), below {minimum}.") - details = {"columns_checked": len(rows), "structural_zero_columns": sorted(reported_zero)} - return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) + failures.append( + f"{stage}: {column} has {value} source-signal row(s), below {minimum}." + ) + details = { + "columns_checked": len(rows), + "structural_zero_columns": sorted(reported_zero), + } + return ( + _fail(stage, check, failures, details) + if failures + else _pass(stage, check, details) + ) def _age_tail_targets_gate( @@ -356,8 +423,12 @@ def _age_tail_targets_gate( parameters: Mapping[str, object], ) -> GateResult: check = "age_tail_targets" - achieved = _mapping(evidence.get("achieved_weighted"), label=f"{stage}.achieved_weighted") - targets = _mapping(evidence.get("band_populations"), label=f"{stage}.band_populations") + achieved = _mapping( + evidence.get("achieved_weighted"), label=f"{stage}.achieved_weighted" + ) + targets = _mapping( + evidence.get("band_populations"), label=f"{stage}.band_populations" + ) max_relative = _finite_number( parameters["maximum_relative_deviation"], label=f"{stage}.maximum_relative_deviation", @@ -377,9 +448,15 @@ def _age_tail_targets_gate( relative = abs(value - target) / max(abs(target), 1.0) worst = max(worst, relative) if relative > max_relative: - failures.append(f"{stage}: {key} relative deviation {relative} exceeds {max_relative}.") + failures.append( + f"{stage}: {key} relative deviation {relative} exceeds {max_relative}." + ) details = {"bands_checked": len(targets), "worst_relative_deviation": worst} - return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) + return ( + _fail(stage, check, failures, details) + if failures + else _pass(stage, check, details) + ) def _cgt_band_donor_support_gate( @@ -401,16 +478,32 @@ def _cgt_band_donor_support_gate( if not isinstance(row, Mapping): failures.append(f"{stage}: band row is not an object.") continue - realized_min = _finite_number(row.get("realized_min_gain"), label=f"{stage}.realized_min_gain") - realized_max = _finite_number(row.get("realized_max_gain"), label=f"{stage}.realized_max_gain") - lower_limit = _finite_number(row.get("lower_limit"), label=f"{stage}.lower_limit") + realized_min = _finite_number( + row.get("realized_min_gain"), label=f"{stage}.realized_min_gain" + ) + realized_max = _finite_number( + row.get("realized_max_gain"), label=f"{stage}.realized_max_gain" + ) + lower_limit = _finite_number( + row.get("lower_limit"), label=f"{stage}.lower_limit" + ) band_floor = max(global_lower, lower_limit) if realized_min < band_floor: - failures.append(f"{stage}: realized gain {realized_min} falls below {band_floor}.") - if upper is not None and realized_max >= _finite_number(upper, label="capital_gains.upper"): - failures.append(f"{stage}: realized gain {realized_max} exceeds open upper bound.") + failures.append( + f"{stage}: realized gain {realized_min} falls below {band_floor}." + ) + if upper is not None and realized_max >= _finite_number( + upper, label="capital_gains.upper" + ): + failures.append( + f"{stage}: realized gain {realized_max} exceeds open upper bound." + ) details = {"bands_checked": len(bands), "minimum_lower_limit": global_lower} - return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) + return ( + _fail(stage, check, failures, details) + if failures + else _pass(stage, check, details) + ) def _cgt_imputation_summary_gate( @@ -431,7 +524,11 @@ def _cgt_imputation_summary_gate( if value < 0.0: failures.append(f"{stage}: {key} is negative.") details = {"band_rows": len(rows), "taxpayer_mass": evidence.get("taxpayer_mass")} - return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) + return ( + _fail(stage, check, failures, details) + if failures + else _pass(stage, check, details) + ) def _latent_attribute_realization_gate( @@ -539,3 +636,88 @@ def latent_attribute_tolerance(*, target: float, rows: int) -> float: def _binomial_tolerance(*, target: float, rows: int) -> float: return latent_attribute_tolerance(target=target, rows=rows) + + +def _household_composition_gate( + stage: str, + evidence: Mapping[str, object], + parameters: Mapping[str, object], +) -> GateResult: + """The #791 relationship derivation left no tape defect unrefused. + + The stage refuses head, index, partner and domain defects itself; this + gate re-reads the receipt so the battery, not only the transform, holds + the invariants, and it pins the reviewed reciprocity tolerance and the + partition closure (every household typed exactly once). + """ + + check = "household_composition" + failures: list[str] = [] + zero_keys = ( + "head_invariant_violations", + "hrpnum_mismatches", + "person_index_gaps", + "multi_partner_persons", + "family_index_violations", + "domain_violations", + ) + details: dict[str, object] = {} + for key in zero_keys: + value = evidence.get(key) + if not isinstance(value, int | float): + failures.append(f"{stage}: receipt is missing {key}.") + continue + details[key] = int(value) + if int(value) != 0: + failures.append(f"{stage}: {key} is {int(value)}, expected 0.") + tolerance = int( + _finite_number( + parameters["max_grid_reciprocity_mismatches"], + label=f"{stage}.max_grid_reciprocity_mismatches", + ) + ) + mismatches = evidence.get("grid_reciprocity_mismatches") + if not isinstance(mismatches, int | float): + failures.append(f"{stage}: receipt is missing grid_reciprocity_mismatches.") + else: + details["grid_reciprocity_mismatches"] = int(mismatches) + details["max_grid_reciprocity_mismatches"] = tolerance + if int(mismatches) > tolerance: + failures.append( + f"{stage}: grid_reciprocity_mismatches {int(mismatches)} exceeds " + f"the reviewed tolerance {tolerance}." + ) + unmapped = evidence.get("relhrp_unmapped_codes") + if not isinstance(unmapped, Mapping): + failures.append(f"{stage}: receipt is missing relhrp_unmapped_codes.") + elif unmapped: + failures.append(f"{stage}: unmapped relhrp codes {dict(unmapped)!r}.") + details["relhrp_unmapped_codes"] = ( + dict(unmapped) if isinstance(unmapped, Mapping) else None + ) + if bool(parameters.get("require_partition_closure", True)): + counts = evidence.get("household_type_counts") + households = evidence.get("households") + if not isinstance(counts, Mapping) or not isinstance(households, int | float): + failures.append( + f"{stage}: receipt is missing household_type_counts or households." + ) + else: + total = int(sum(int(value) for value in counts.values())) + details["household_type_counts"] = { + str(key): int(value) for key, value in counts.items() + } + details["households"] = int(households) + if total != int(households) or evidence.get("partition_closes") is not True: + failures.append( + f"{stage}: household-type partition covers {total} of " + f"{int(households)} households." + ) + weighted = evidence.get("household_type_weighted") + if isinstance(weighted, Mapping): + details["household_type_weighted"] = { + str(key): float(value) for key, value in weighted.items() + } + if failures: + return _fail(stage, check, failures, details) + return _pass(stage, check, details) diff --git a/packages/microcosm-build/src/microcosm/build/uk_runtime/terminal_gates.py b/packages/microcosm-build/src/microcosm/build/uk_runtime/terminal_gates.py index eb387d85e..9ca574f75 100644 --- a/packages/microcosm-build/src/microcosm/build/uk_runtime/terminal_gates.py +++ b/packages/microcosm-build/src/microcosm/build/uk_runtime/terminal_gates.py @@ -186,6 +186,7 @@ def __post_init__(self) -> None: "household.msoa_code", "household.num_vehicles", "household.oa_code", + "household.ons_household_type", "household.private_pension_wealth", "household.property_purchased", "household.rail_usage", @@ -209,11 +210,14 @@ def __post_init__(self) -> None: "person.is_parent", "person.is_uc_claimant", "person.legacy_jobseeker_proxy", + "person.ons_family_index", + "person.ons_family_role", "person.outpatient_visits", "person.pension_contributions_via_salary_sacrifice", "person.pip_dl_category", "person.pip_m_category", "person.receives_benefits_in_own_right", + "person.relationship_to_head", "person.salary_sacrifice_asked", "person.salary_sacrifice_reported", "person.sic_industry_division", diff --git a/packages/microcosm-build/tests/test_country_spec.py b/packages/microcosm-build/tests/test_country_spec.py index 90276da1f..2e4da7732 100644 --- a/packages/microcosm-build/tests/test_country_spec.py +++ b/packages/microcosm-build/tests/test_country_spec.py @@ -981,10 +981,10 @@ def test_uk_source_manifest_loads_thirty_stages(self) -> None: spec = load_country_spec("uk") assert spec.sources is not None - # 28 spine stages (uc_reporter_redraw #832, then uc_deduction_attributes - # #685 as the newest) plus the + # 29 spine stages (uc_reporter_redraw #832, uc_deduction_attributes + # #685, then frs_relationships #791 as the newest) plus the # two certified-pair stages the June path still uses. - assert len(spec.sources.stages) == 30 + assert len(spec.sources.stages) == 31 class TestExistingPackagesGeneralize: @@ -1322,6 +1322,7 @@ def test_declares_the_full_june_battery(self, manifest) -> None: "uk_stage_salary_sacrifice_realization", "uk_stage_student_loans_realization", "uk_stage_age_tail_targets", + "uk_stage_frs_relationships_composition", "uk_release_input_coverage", "uk_degenerate_release_surface", "uk_zero_weight_strata", @@ -1335,6 +1336,7 @@ def test_declares_the_full_june_battery(self, manifest) -> None: "uk_export_surface", "uk_take_up_signal", "uk_brma_enum_domain", + "uk_ons_household_type_enum_domain", "uk_uc_deduction_combination_enum_domain", "uk_student_loan_plan_enum_domain", "uk_calibration_reference_coverage", @@ -1411,6 +1413,7 @@ def test_strict_absent_evidence_entries_are_declared(self, manifest) -> None: "uk_stage_salary_sacrifice_realization", "uk_stage_student_loans_realization", "uk_stage_age_tail_targets", + "uk_stage_frs_relationships_composition", "uk_weights_audit", ] assert all(g.not_applicable is None for g in manifest.gates) diff --git a/packages/microcosm-build/tests/test_spec_engine_country_bundles.py b/packages/microcosm-build/tests/test_spec_engine_country_bundles.py index 1169547c3..a826e90db 100644 --- a/packages/microcosm-build/tests/test_spec_engine_country_bundles.py +++ b/packages/microcosm-build/tests/test_spec_engine_country_bundles.py @@ -55,7 +55,7 @@ ), ( "uk", - "2269bc281ada99dce077730657e3868972e025b48be5f9db8c11b3cc63285bac", + "c396ee51ab029ed780ec25b69d34b128f53b08c673dc87a7f600f74264e755e3", { "benunit.benunit_id", "household.household_id", diff --git a/packages/microcosm-build/tests/test_uk_frs_relationships.py b/packages/microcosm-build/tests/test_uk_frs_relationships.py new file mode 100644 index 000000000..e9f5c0309 --- /dev/null +++ b/packages/microcosm-build/tests/test_uk_frs_relationships.py @@ -0,0 +1,841 @@ +"""Tests for the #791 FRS relationship-grid stage and its manifest lockstep.""" + +from __future__ import annotations + +import hashlib +import json +from pathlib import Path + +import numpy as np +import pandas as pd +import pytest + +from microcosm.build.source_manifest import SourceManifest, SourceStageSpec +from microcosm.build.uk_runtime.frs_relationships import ( + CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS, + FRS_HOUSEHOLD_GRID_RELATIONSHIP_CODES, + FRS_RELATIONSHIPS_OUTPUT_COLUMNS, + FRS_RELATIONSHIPS_RECIPROCITY_MISMATCH_TOLERANCE, + FRSRelationshipsError, + UKFRSRelationshipsStageTransform, + assert_frs_relationships_stage_parameters, + derive_frs_relationships, + frs_relationships_domains, + frs_relationships_operation_parameters, +) +from microcosm.build.uk_runtime.national_frame import uk_national_frame +from microcosm.build.uk_runtime.stage_health import uk_stage_health_gate + +REPO_ROOT = Path(__file__).resolve().parents[3] +UK_PACKAGE = REPO_ROOT / "packages/microcosm-build/src/microcosm/build/uk" +GRID = [f"r{index:02d}" for index in range(1, 15)] + +SPOUSE, COHABITEE, CHILD, STEP_CHILD, FOSTER_CHILD = 1, 2, 3, 4, 5 +CHILD_IN_LAW, PARENT, STEP_PARENT, FOSTER_PARENT, PARENT_IN_LAW = 6, 7, 8, 9, 10 +SIBLING, GRANDCHILD, GRANDPARENT, NON_RELATIVE, CIVIL_PARTNER = 11, 15, 16, 18, 20 + + +def _person( + number: int, + *, + age: int, + table: str = "adult", + hrp: bool = False, + fte: bool | None = None, + rel: dict[int, int] | None = None, +) -> dict: + return { + "number": number, + "age": age, + "table": table, + "hrp": hrp, + "fte": fte, + "rel": dict(rel or {}), + } + + +def _tables(*households: list[dict]): + """Raw (id-normalised) adult/child/househol tabs plus frame tables.""" + + adult_rows, child_rows, hh_rows, person_rows = [], [], [], [] + for sernum, persons in enumerate(households, start=1): + head = ( + next(p["number"] for p in persons if p["hrp"]) + if any(p["hrp"] for p in persons) + else None + ) + if head is not None: + hh_rows.append({"household_id": sernum, "hrpnum": head}) + for p in persons: + row = { + "household_id": sernum, + "person_id": sernum * 1000 + p["number"], + "relhrp": ( + np.nan + if p["hrp"] or head is None + else float(p["rel"].get(head, NON_RELATIVE)) + ), + **{column: np.nan for column in GRID}, + } + for other, code in p["rel"].items(): + row[f"r{other:02d}"] = float(code) + if p["table"] == "adult": + row["hrpid"] = 1.0 if p["hrp"] else 2.0 + row["educft"] = 1.0 if p["fte"] else 2.0 + adult_rows.append(row) + else: + row["educft"] = 1.0 + child_rows.append(row) + person_rows.append( + { + "person_id": sernum * 1000 + p["number"], + "person_benunit_id": sernum * 100 + 1, + "person_household_id": sernum, + "age": p["age"], + "is_household_head": bool(p["hrp"]), + } + ) + person = pd.DataFrame(person_rows).sort_values("person_id").reset_index(drop=True) + household = pd.DataFrame({"household_id": list(range(1, len(households) + 1))}) + adult = ( + pd.DataFrame(adult_rows) + if adult_rows + else pd.DataFrame( + columns=["household_id", "person_id", "relhrp", "hrpid", "educft", *GRID] + ) + ) + child = ( + pd.DataFrame(child_rows) + if child_rows + else pd.DataFrame( + columns=["household_id", "person_id", "relhrp", "educft", *GRID] + ) + ) + return person, household, adult, child, pd.DataFrame(hh_rows) + + +def _derive(*households: list[dict], **kwargs): + person, household, adult, child, raw_household = _tables(*households) + return derive_frs_relationships( + person, + household, + raw_adult=adult, + raw_child=child, + raw_household=raw_household, + **kwargs, + ) + + +def _couple(a: int = 1, b: int = 2, code: int = SPOUSE) -> tuple[dict, dict]: + return {b: code}, {a: code} + + +def _types(result) -> list[str]: + return result.household_values["ons_household_type"].tolist() + + +def _roles(result) -> list[str]: + return result.person_values["ons_family_role"].tolist() + + +# --- household types ------------------------------------------------------- + + +def test_couple_plus_lodger_is_a_couple_household_with_an_individual() -> None: + result = _derive( + [ + _person(1, age=40, hrp=True, rel={2: SPOUSE, 3: NON_RELATIVE}), + _person(2, age=39, rel={1: SPOUSE, 3: NON_RELATIVE}), + _person(3, age=30, rel={1: NON_RELATIVE, 2: NON_RELATIVE}), + ] + ) + assert _types(result) == ["couple_no_children_households"] + assert _roles(result) == ["COUPLE_PARTNER", "COUPLE_PARTNER", "INDIVIDUAL"] + assert result.person_values["ons_family_index"].tolist() == [1, 1, 0] + assert result.evidence["one_family_plus_individuals"] == 1 + assert result.person_values["relationship_to_head"].tolist() == [ + "HEAD", + "SPOUSE", + "OTHER_NON_RELATIVE", + ] + + +def test_couple_with_an_adult_child_is_non_dependent_children_only() -> None: + result = _derive( + [ + _person(1, age=55, hrp=True, rel={2: COHABITEE, 3: PARENT}), + _person(2, age=54, rel={1: COHABITEE, 3: PARENT}), + _person(3, age=22, fte=True, rel={1: CHILD, 2: CHILD}), + ] + ) + assert _types(result) == ["couple_non_dependent_children_only_households"] + assert _roles(result) == [ + "COUPLE_PARTNER", + "COUPLE_PARTNER", + "NON_DEPENDENT_CHILD", + ] + # 22 in full-time education is still non-dependent: ONS stops at 18. + assert result.evidence["dependency_counts"]["19_plus"] == 1 + + +def test_grandparent_couple_with_a_partnered_child_are_two_families() -> None: + result = _derive( + [ + _person( + 1, + age=70, + hrp=True, + rel={2: SPOUSE, 3: PARENT, 4: PARENT_IN_LAW, 5: GRANDPARENT}, + ), + _person( + 2, age=69, rel={1: SPOUSE, 3: PARENT, 4: PARENT_IN_LAW, 5: GRANDPARENT} + ), + _person(3, age=40, rel={1: CHILD, 2: CHILD, 4: SPOUSE, 5: PARENT}), + _person( + 4, age=41, rel={1: CHILD_IN_LAW, 2: CHILD_IN_LAW, 3: SPOUSE, 5: PARENT} + ), + _person( + 5, + age=5, + table="child", + rel={1: GRANDCHILD, 2: GRANDCHILD, 3: CHILD, 4: CHILD}, + ), + ] + ) + assert _types(result) == ["multi_family_households"] + # The partnered child is not a child of the grandparents' family: two couples. + assert _roles(result) == [ + "COUPLE_PARTNER", + "COUPLE_PARTNER", + "COUPLE_PARTNER", + "COUPLE_PARTNER", + "DEPENDENT_CHILD", + ] + assert result.person_values["ons_family_index"].tolist() == [1, 1, 2, 2, 2] + + +def test_couple_elderly_parent_and_grandchild_is_one_family_plus_individual() -> None: + result = _derive( + [ + _person(1, age=40, hrp=True, rel={2: SPOUSE, 3: CHILD, 4: PARENT}), + _person(2, age=41, rel={1: SPOUSE, 3: CHILD_IN_LAW, 4: PARENT}), + _person(3, age=70, rel={1: PARENT, 2: PARENT_IN_LAW, 4: GRANDPARENT}), + _person(4, age=5, table="child", rel={1: CHILD, 2: CHILD, 3: GRANDCHILD}), + ] + ) + # ONS: "a married couple with one elderly parent" is a one-family household. + assert _types(result) == ["couple_under_3_children_households"] + assert _roles(result) == [ + "COUPLE_PARTNER", + "COUPLE_PARTNER", + "INDIVIDUAL", + "DEPENDENT_CHILD", + ] + + +def test_lone_parent_with_a_19_year_old_in_education_is_non_dependent_only() -> None: + result = _derive( + [ + _person(1, age=45, hrp=True, rel={2: PARENT}), + _person(2, age=19, table="child", rel={1: CHILD}), + ] + ) + assert _types(result) == ["lone_parent_non_dependent_children_households"] + assert _roles(result) == ["LONE_PARENT", "NON_DEPENDENT_CHILD"] + + +def test_sixteen_to_eighteen_dependency_follows_full_time_education() -> None: + not_in_education = _derive( + [ + _person(1, age=45, hrp=True, rel={2: PARENT}), + _person(2, age=17, fte=False, rel={1: CHILD}), + ] + ) + in_education = _derive( + [ + _person(1, age=45, hrp=True, rel={2: PARENT}), + _person(2, age=17, fte=True, rel={1: CHILD}), + ] + ) + assert _types(not_in_education) == ["lone_parent_non_dependent_children_households"] + assert _types(in_education) == ["lone_parent_dependent_children_households"] + assert in_education.evidence["dependency_counts"]["16_18_fte"] == 1 + assert not_in_education.evidence["dependency_counts"]["16_18_not_fte"] == 1 + + +def test_households_with_no_family_are_unrelated_adults() -> None: + sharers = _derive( + [ + _person(1, age=30, hrp=True, rel={2: NON_RELATIVE}), + _person(2, age=31, rel={1: NON_RELATIVE}), + ] + ) + siblings = _derive( + [ + _person(1, age=60, hrp=True, rel={2: SIBLING}), + _person(2, age=58, rel={1: SIBLING}), + ] + ) + foster = _derive( + [ + _person(1, age=50, hrp=True, rel={2: FOSTER_PARENT}), + _person(2, age=10, table="child", rel={1: FOSTER_CHILD}), + ] + ) + for result in (sharers, siblings, foster): + assert _types(result) == ["unrelated_adult_households"] + assert _roles(result) == ["INDIVIDUAL", "INDIVIDUAL"] + + +def test_grandparent_with_a_lone_parent_daughter_is_one_lone_parent_family() -> None: + result = _derive( + [ + _person(1, age=70, hrp=True, rel={2: PARENT, 3: GRANDPARENT}), + _person(2, age=35, rel={1: CHILD, 3: PARENT}), + _person(3, age=8, table="child", rel={1: GRANDCHILD, 2: CHILD}), + ] + ) + assert _types(result) == ["lone_parent_dependent_children_households"] + # The daughter has her own child, so she is not the grandparent's child. + assert _roles(result) == ["INDIVIDUAL", "LONE_PARENT", "DEPENDENT_CHILD"] + + +def test_grandparent_with_an_unpartnered_childless_adult_child_is_a_lone_parent() -> ( + None +): + result = _derive( + [ + _person(1, age=70, hrp=True, rel={2: PARENT}), + _person(2, age=35, rel={1: CHILD}), + ] + ) + assert _types(result) == ["lone_parent_non_dependent_children_households"] + assert _roles(result) == ["LONE_PARENT", "NON_DEPENDENT_CHILD"] + + +def test_two_lone_parents_who_are_not_a_couple_are_multi_family() -> None: + result = _derive( + [ + _person( + 1, age=40, hrp=True, rel={2: NON_RELATIVE, 3: PARENT, 4: NON_RELATIVE} + ), + _person(2, age=38, rel={1: NON_RELATIVE, 3: NON_RELATIVE, 4: PARENT}), + _person( + 3, + age=6, + table="child", + rel={1: CHILD, 2: NON_RELATIVE, 4: NON_RELATIVE}, + ), + _person( + 4, + age=7, + table="child", + rel={1: NON_RELATIVE, 2: CHILD, 3: NON_RELATIVE}, + ), + ] + ) + assert _types(result) == ["multi_family_households"] + assert _roles(result) == [ + "LONE_PARENT", + "LONE_PARENT", + "DEPENDENT_CHILD", + "DEPENDENT_CHILD", + ] + assert result.person_values["ons_family_index"].tolist() == [1, 2, 1, 2] + + +def test_one_person_households_split_at_sixty_five() -> None: + result = _derive( + [_person(1, age=64, hrp=True)], + [_person(1, age=65, hrp=True)], + ) + assert _types(result) == ["lone_households_under_65", "lone_households_over_65"] + assert _roles(result) == ["INDIVIDUAL", "INDIVIDUAL"] + + +def test_couples_split_on_the_count_of_dependent_children() -> None: + def couple_with(children: int, ages: list[int]) -> list[dict]: + rel1 = {2: SPOUSE, **{3 + i: PARENT for i in range(children)}} + rel2 = {1: SPOUSE, **{3 + i: PARENT for i in range(children)}} + kids = [ + _person(3 + i, age=ages[i], table="child", rel={1: CHILD, 2: CHILD}) + for i in range(children) + ] + return [ + _person(1, age=40, hrp=True, rel=rel1), + _person(2, age=39, rel=rel2), + *kids, + ] + + result = _derive(couple_with(2, [3, 9]), couple_with(3, [3, 9, 12])) + assert _types(result) == [ + "couple_under_3_children_households", + "couple_3_plus_children_households", + ] + assert result.evidence["partition_closes"] is True + assert sum(result.evidence["household_type_counts"].values()) == 2 + + +def test_civil_partners_and_step_children_form_one_family() -> None: + result = _derive( + [ + _person(1, age=45, hrp=True, rel={2: CIVIL_PARTNER, 3: STEP_PARENT}), + _person(2, age=44, rel={1: CIVIL_PARTNER, 3: PARENT}), + _person(3, age=12, table="child", rel={1: STEP_CHILD, 2: CHILD}), + ] + ) + assert _types(result) == ["couple_under_3_children_households"] + assert result.person_values["relationship_to_head"].tolist() == [ + "HEAD", + "CIVIL_PARTNER", + "STEP_CHILD", + ] + + +def test_weighted_cells_and_domains_in_evidence() -> None: + person, household, adult, child, raw_household = _tables( + [_person(1, age=30, hrp=True)], + [_person(1, age=80, hrp=True)], + ) + result = derive_frs_relationships( + person, + household, + raw_adult=adult, + raw_child=child, + raw_household=raw_household, + household_weights=np.array([2.5, 4.0]), + ) + weighted = result.evidence["household_type_weighted"] + assert weighted["lone_households_under_65"] == 2.5 + assert weighted["lone_households_over_65"] == 4.0 + assert set(weighted) == set(CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS) + assert result.evidence["stage"] == "frs_relationships" + assert result.evidence["domain_violations"] == 0 + assert result.evidence["hrpnum_mismatches"] == 0 + + +# --- fail-closed ----------------------------------------------------------- + + +def test_two_household_reference_persons_refuse() -> None: + with pytest.raises(FRSRelationshipsError, match="head_invariant_violations=1"): + _derive( + [ + _person(1, age=30, hrp=True, rel={2: NON_RELATIVE}), + _person(2, age=31, hrp=True, rel={1: NON_RELATIVE}), + ] + ) + + +def test_hrpnum_disagreeing_with_hrpid_refuses() -> None: + person, household, adult, child, raw_household = _tables( + [ + _person(1, age=30, hrp=True, rel={2: NON_RELATIVE}), + _person(2, age=31, rel={1: NON_RELATIVE}), + ] + ) + raw_household["hrpnum"] = 2 + with pytest.raises(FRSRelationshipsError, match="hrpnum_mismatches=1"): + derive_frs_relationships( + person, + household, + raw_adult=adult, + raw_child=child, + raw_household=raw_household, + ) + + +def test_unmapped_relhrp_code_refuses() -> None: + person, household, adult, child, raw_household = _tables( + [ + _person(1, age=30, hrp=True, rel={2: NON_RELATIVE}), + _person(2, age=31, rel={1: NON_RELATIVE}), + ] + ) + adult.loc[adult["person_id"] == 1002, "relhrp"] = 99 + with pytest.raises(FRSRelationshipsError, match="relhrp_unmapped_codes"): + derive_frs_relationships( + person, + household, + raw_adult=adult, + raw_child=child, + raw_household=raw_household, + ) + + +def test_a_person_with_two_partners_refuses() -> None: + with pytest.raises(FRSRelationshipsError, match="multi_partner_persons=1"): + _derive( + [ + _person(1, age=30, hrp=True, rel={2: SPOUSE, 3: COHABITEE}), + _person(2, age=31, rel={1: SPOUSE, 3: NON_RELATIVE}), + _person(3, age=29, rel={1: COHABITEE, 2: NON_RELATIVE}), + ] + ) + + +def test_non_contiguous_person_numbers_refuse() -> None: + with pytest.raises(FRSRelationshipsError, match="person_index_gaps=1"): + _derive( + [ + _person(1, age=30, hrp=True, rel={3: NON_RELATIVE}), + _person(3, age=31, rel={1: NON_RELATIVE}), + ] + ) + + +def test_reciprocity_mismatches_are_counted_and_fenced() -> None: + # The child records a parent link; the parent records a non-relative. + household = [ + _person(1, age=45, hrp=True, rel={2: NON_RELATIVE}), + _person(2, age=10, table="child", rel={1: CHILD}), + ] + with pytest.raises(FRSRelationshipsError, match="grid_reciprocity_mismatches=1"): + _derive(household, reciprocity_mismatch_tolerance=0) + tolerated = _derive(household, reciprocity_mismatch_tolerance=1) + assert tolerated.evidence["grid_reciprocity_mismatches"] == 1 + # Either side's declaration establishes the link. + assert _types(tolerated) == ["lone_parent_dependent_children_households"] + + +def test_a_frame_person_missing_from_the_tabs_refuses() -> None: + person, household, adult, child, raw_household = _tables( + [_person(1, age=30, hrp=True)] + ) + person = pd.concat( + [ + person, + pd.DataFrame( + { + "person_id": [1002], + "person_benunit_id": [101], + "person_household_id": [1], + "age": [20], + "is_household_head": [False], + } + ), + ], + ignore_index=True, + ) + with pytest.raises(FRSRelationshipsError, match="absent from the FRS"): + derive_frs_relationships( + person, + household, + raw_adult=adult, + raw_child=child, + raw_household=raw_household, + ) + + +# --- manifest lockstep and declared domains ---------------------------------- + + +def _committed_stage() -> SourceStageSpec: + manifest = SourceManifest.from_mapping( + json.loads((UK_PACKAGE / "source_stages.json").read_text(encoding="utf-8")) + ) + return next( + stage for stage in manifest.stages if stage.stage == "frs_relationships" + ) + + +def _stage_mapping() -> dict: + payload = json.loads( + (UK_PACKAGE / "source_stages.json").read_text(encoding="utf-8") + ) + return next( + stage for stage in payload["stages"] if stage["stage"] == "frs_relationships" + ) + + +def test_committed_manifest_matches_the_runtime_parameters() -> None: + stage = _committed_stage() + assert_frs_relationships_stage_parameters(stage) + assert stage.outputs == FRS_RELATIONSHIPS_OUTPUT_COLUMNS + declared = dict(stage.operations[1].parameters) + assert declared["household_type_values"] == list( + CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS + ) + assert declared["reciprocity_mismatch_tolerance"] == ( + FRS_RELATIONSHIPS_RECIPROCITY_MISMATCH_TOLERANCE + ) + assert { + item["code"]: item["label"] + for item in declared["frs_household_grid_relationship_codes"] + } == dict(FRS_HOUSEHOLD_GRID_RELATIONSHIP_CODES) + + +@pytest.mark.parametrize( + ("mutate", "message"), + [ + ( + lambda op: op.__setitem__("reciprocity_mismatch_tolerance", 99), + "reciprocity_mismatch_tolerance", + ), + ( + lambda op: op["family_link_codes"].__setitem__("partner", [1, 2]), + "family_link_codes", + ), + ( + lambda op: op.__setitem__( + "household_type_values", op["household_type_values"][::-1] + ), + "household_type_values", + ), + (lambda op: op.__setitem__("unreviewed", 1), "unreviewed"), + ], +) +def test_manifest_drift_refuses_with_the_key_named(mutate, message) -> None: + mapping = _stage_mapping() + mutate(mapping["operations"][1]) + with pytest.raises(ValueError, match=message): + assert_frs_relationships_stage_parameters(SourceStageSpec.from_mapping(mapping)) + + +def test_manifest_operation_order_is_enforced() -> None: + mapping = _stage_mapping() + mapping["operations"] = mapping["operations"][::-1] + with pytest.raises(ValueError, match="read_tables followed by"): + assert_frs_relationships_stage_parameters(SourceStageSpec.from_mapping(mapping)) + + +def test_raw_tab_pins_match_the_spine_artifacts() -> None: + manifest = SourceManifest.from_mapping( + json.loads((UK_PACKAGE / "source_stages.json").read_text(encoding="utf-8")) + ) + stages = {stage.stage: stage for stage in manifest.stages} + spine = { + artifact["table"]: ( + artifact["locator"], + artifact["sha256"], + artifact["size_bytes"], + ) + for artifact in stages["frs_spine"].artifacts + } + for artifact in stages["frs_relationships"].artifacts: + assert spine[artifact["table"]] == ( + artifact["locator"], + artifact["sha256"], + artifact["size_bytes"], + ) + assert { + artifact["table"] for artifact in stages["frs_relationships"].artifacts + } == { + "adult", + "child", + "househol", + } + names = [stage.stage for stage in manifest.stages] + assert names.index("frs_relationships") == names.index("age_tail") + 1 + + +def test_household_type_values_are_the_ten_contract_cells_in_order() -> None: + contract = json.loads( + (UK_PACKAGE / "uk_population_targets.json").read_text(encoding="utf-8") + ) + rows = [ + target + for target in contract["targets"] + if target["family"] == "ons_household_composition" + ] + dimension_values = [ + target["ledger_selector"]["dimension_values"]["household_type"] + for target in rows + ] + assert dimension_values == list(CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS) + assert frs_relationships_domains()["ons_household_type"] == ( + CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS + ) + assert len(set(CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS)) == 10 + + +def test_operation_parameters_carry_their_source_documentation() -> None: + parameters = frs_relationships_operation_parameters() + assert "SN 9563" in parameters["documentation"]["frs_codes"] + assert "Families and households" in parameters["documentation"]["ons_definitions"] + assert "ons-families-households-2025" in parameters["documentation"]["category_ids"] + assert parameters["head_label"] == "HEAD" + assert parameters["source_columns"]["grid"] == GRID + + +def test_gates_declare_the_stage_health_and_enum_gates_and_export_columns() -> None: + gates = json.loads((UK_PACKAGE / "gates.json").read_text(encoding="utf-8")) + by_id = {gate["id"]: gate for gate in gates["gates"]} + health = by_id["uk_stage_frs_relationships_composition"] + assert (health["gate"], health["phase"]) == ("stage_health", "assembled") + assert health["parameters"]["check"] == "household_composition" + assert health["parameters"]["max_grid_reciprocity_mismatches"] == ( + FRS_RELATIONSHIPS_RECIPROCITY_MISMATCH_TOLERANCE + ) + enum = by_id["uk_ons_household_type_enum_domain"] + assert (enum["gate"], enum["phase"]) == ("enum_domain", "assembled") + assert enum["parameters"]["columns"] == ["ons_household_type"] + exported = set(by_id["uk_export_surface"]["parameters"]["allowed_extra_columns"]) + assert { + "person.relationship_to_head", + "person.ons_family_role", + "person.ons_family_index", + "household.ons_household_type", + } <= exported + + +# --- stage health ----------------------------------------------------------- + + +def _health_parameters() -> dict: + return { + "stage": "frs_relationships", + "check": "household_composition", + "parameters": { + "stage": "frs_relationships", + "check": "household_composition", + "max_grid_reciprocity_mismatches": ( + FRS_RELATIONSHIPS_RECIPROCITY_MISMATCH_TOLERANCE + ), + "require_partition_closure": True, + }, + } + + +def test_stage_health_passes_on_a_clean_receipt() -> None: + result = _derive([_person(1, age=30, hrp=True)]) + gate = uk_stage_health_gate(evidence=result.evidence, **_health_parameters()) + assert gate.passed, gate.failures + assert gate.details["households"] == 1 + + +def test_stage_health_refuses_a_partition_gap_and_excess_mismatches() -> None: + result = _derive([_person(1, age=30, hrp=True)]) + evidence = dict(result.evidence) + evidence["households"] = 2 + gate = uk_stage_health_gate(evidence=evidence, **_health_parameters()) + assert not gate.passed + assert any("partition covers 1 of 2" in failure for failure in gate.failures) + evidence = dict(result.evidence) + evidence["grid_reciprocity_mismatches"] = ( + FRS_RELATIONSHIPS_RECIPROCITY_MISMATCH_TOLERANCE + 1 + ) + gate = uk_stage_health_gate(evidence=evidence, **_health_parameters()) + assert not gate.passed + assert any("exceeds the reviewed tolerance" in failure for failure in gate.failures) + + +# --- the transform end to end ------------------------------------------------ + + +def _write_tab(path: Path, rows: list[dict]) -> dict: + frame = pd.DataFrame(rows) + frame.to_csv(path, sep="\t", index=False) + return { + "locator": path.name, + "sha256": hashlib.sha256(path.read_bytes()).hexdigest(), + "size_bytes": path.stat().st_size, + } + + +def test_transform_writes_the_four_columns_and_receipts(tmp_path: Path) -> None: + grid_blank = {f"R{index:02d}": "" for index in range(1, 15)} + adult = _write_tab( + tmp_path / "adult.tab", + [ + { + "SERNUM": 1, + "BENUNIT": 1, + "PERSON": 1, + "HRPID": 1, + "EDUCFT": 2, + "RELHRP": "", + **grid_blank, + "R02": PARENT, + }, + { + "SERNUM": 2, + "BENUNIT": 1, + "PERSON": 1, + "HRPID": 1, + "EDUCFT": 2, + "RELHRP": "", + **grid_blank, + "R02": SPOUSE, + }, + { + "SERNUM": 2, + "BENUNIT": 1, + "PERSON": 2, + "HRPID": 2, + "EDUCFT": 2, + "RELHRP": SPOUSE, + **grid_blank, + "R01": SPOUSE, + }, + ], + ) + child = _write_tab( + tmp_path / "child.tab", + [ + { + "SERNUM": 1, + "BENUNIT": 1, + "PERSON": 2, + "EDUCFT": 1, + "RELHRP": CHILD, + **grid_blank, + "R01": CHILD, + } + ], + ) + househol = _write_tab( + tmp_path / "househol.tab", + [{"SERNUM": 1, "HRPNUM": 1}, {"SERNUM": 2, "HRPNUM": 1}], + ) + mapping = _stage_mapping() + pins = {"adult": adult, "child": child, "househol": househol} + for artifact in mapping["artifacts"]: + artifact.update(pins[artifact["table"]]) + stage = SourceStageSpec.from_mapping(mapping) + + person = pd.DataFrame( + { + "person_id": [1001, 1002, 2001, 2002], + "person_benunit_id": [101, 101, 201, 201], + "person_household_id": [1, 1, 2, 2], + "age": [40, 9, 66, 64], + "gender": ["FEMALE", "MALE", "MALE", "FEMALE"], + "is_household_head": [True, False, True, False], + } + ) + benunit = pd.DataFrame({"benunit_id": [101, 201]}) + household = pd.DataFrame({"household_id": [1, 2], "household_weight": [3.0, 5.0]}) + frame = uk_national_frame( + person=person, benunit=benunit, household=household, time_period="2024" + ) + + transform = UKFRSRelationshipsStageTransform(tmp_path, stage=stage) + assert transform.output_columns() == FRS_RELATIONSHIPS_OUTPUT_COLUMNS + returned = transform(frame) + assert returned.table("person")["relationship_to_head"].tolist() == [ + "HEAD", + "CHILD", + "HEAD", + "SPOUSE", + ] + assert returned.table("person")["ons_family_role"].tolist() == [ + "LONE_PARENT", + "DEPENDENT_CHILD", + "COUPLE_PARTNER", + "COUPLE_PARTNER", + ] + assert returned.table("person")["ons_family_index"].tolist() == [1, 1, 1, 1] + assert returned.table("household")["ons_household_type"].tolist() == [ + "lone_parent_dependent_children_households", + "couple_no_children_households", + ] + assert list(returned.weights_for("household").values) == [3.0, 5.0] + metadata = transform.checkpoint_metadata() + assert metadata["evidence"]["stage"] == "frs_relationships" + assert metadata["evidence"]["household_type_weighted"] == { + **{value: 0.0 for value in CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS}, + "lone_parent_dependent_children_households": 3.0, + "couple_no_children_households": 5.0, + } + assert metadata["evidence"]["full_time_education_source"] == "educft" diff --git a/packages/microcosm-build/tests/test_uk_frs_spine.py b/packages/microcosm-build/tests/test_uk_frs_spine.py index 18e35e77c..041e8a87e 100644 --- a/packages/microcosm-build/tests/test_uk_frs_spine.py +++ b/packages/microcosm-build/tests/test_uk_frs_spine.py @@ -21,6 +21,10 @@ frs_legacy_proxies, ) from microcosm.build.uk_runtime.content_identity import uk_frame_content_identity +from microcosm.build.uk_runtime.frs_relationships import ( + FRS_RELATIONSHIPS_OUTPUT_COLUMNS, + frs_relationships_operation_parameters, +) from microcosm.build.uk_runtime.frs_spine import ( FRS_SPINE_TABLES, REGION_MAP, @@ -62,6 +66,7 @@ def _fixture_tables() -> dict[str, list[dict[str, object]]]: "SERNUM": 2, "GROSS4": 20.0, "GVTREGNO": 1, + "HRPNUM": 1, "PTENTYP2": 5, "TYPEACC": 1, "BEDROOM6": 3, @@ -91,6 +96,7 @@ def _fixture_tables() -> dict[str, list[dict[str, object]]]: "SERNUM": 1, "GROSS4": 10.0, "GVTREGNO": 12, + "HRPNUM": 1, "PTENTYP2": 6, "TYPEACC": 4, "BEDROOM6": 2, @@ -119,6 +125,11 @@ def _fixture_tables() -> dict[str, list[dict[str, object]]]: "TOTHOURS": 40, "HRPID": 1, "UPERSON": 1, + # #791 household grid: the HRP carries a blank relhrp and the parent + # code toward person 2 (the child). + "RELHRP": "", + **{f"R{index:02d}": "" for index in range(1, 15)}, + "R02": 7, "MARITAL": 1, "EMPSTATI": 5, "MJOBSECT": 1, @@ -159,7 +170,7 @@ def _fixture_tables() -> dict[str, list[dict[str, object]]]: # heartval is on the adult tape too; the three school columns are not. "HEARTVAL": 5.0, } - adult_2 = {**adult_1, "SERNUM": 2, "PERSON": 1, "SEX": 2, "HRPID": 1} + adult_2 = {**adult_1, "SERNUM": 2, "PERSON": 1, "SEX": 2, "HRPID": 1, "R02": ""} child_1 = { "SERNUM": 1, "BENUNIT": 1, @@ -170,6 +181,9 @@ def _fixture_tables() -> dict[str, list[dict[str, object]]]: "TOTHOURS": np.nan, "HRPID": 0, "UPERSON": 0, + "RELHRP": 3, + **{f"R{index:02d}": "" for index in range(1, 15)}, + "R01": 3, "MARITAL": 2, "FTED": 1, "TYPEED2": 2, @@ -415,6 +429,20 @@ def source_stage( policy="Synthetic FRS spine spec.", stages=( stage, + # #791: the relationship-grid stage runs right after the root + # (age_tail sits later in this synthetic roster) and declares + # the same operation parameters the runtime lockstep-asserts. + source_stage( + "frs_relationships", + tables=("adult", "child", "househol"), + operations=[ + {"kind": "read_tables"}, + frs_relationships_operation_parameters(), + ], + outputs=FRS_RELATIONSHIPS_OUTPUT_COLUMNS, + nonnegative_outputs=("ons_family_index",), + grain="household+person", + ), source_stage( "frs_employment", tables=("adult",), @@ -959,14 +987,20 @@ def test_uc_claimant_input_uses_frs_membership_not_age_or_marriage( "HRPID": 0, "AGE": 17, "MARITAL": 2, + "RELHRP": 2, + "R01": 2, + "R02": "", } ) + tables["adult"][0]["R02"] = 2 tables["benunit"][0]["FAMTYPB2"] = 6 if couple_has_children: tables["benunit"][0]["DEPCHLDB"] = 1 tables["child"].append( - {**tables["child"][0], "SERNUM": 2, "PERSON": 3, "AGE": 18} + {**tables["child"][0], "SERNUM": 2, "PERSON": 3, "AGE": 18, "R02": 3} ) + tables["adult"][0]["R03"] = 7 + tables["adult"][-1]["R03"] = 7 stage = _write_fixture(tmp_path, tables) frame = build_uk_frs_spine_frame(tmp_path, stage=stage) person = frame.table("person").set_index("person_id") diff --git a/packages/microcosm-build/tests/test_uk_graph.py b/packages/microcosm-build/tests/test_uk_graph.py index 80a39f041..fd208ca52 100644 --- a/packages/microcosm-build/tests/test_uk_graph.py +++ b/packages/microcosm-build/tests/test_uk_graph.py @@ -163,10 +163,10 @@ def test_uk_spine_graph_contains_manifest_stages_and_named_exclusions() -> None: graph = uk_spine_graph(spec) ids = {node.id for node in graph.nodes} - # 28 with the #832 uc_reporter_redraw and #685 uc_deduction_attributes - # stages; the two named exclusions are the certified-pair alternatives, - # not steps of this pipeline. - assert len(expected) == 28 + # 29 with the #832 uc_reporter_redraw, #685 uc_deduction_attributes and + # #791 frs_relationships stages; the two named exclusions are the + # certified-pair alternatives, not steps of this pipeline. + assert len(expected) == 29 assert UK_SPINE_EXCLUSIONS == { "frs_hmrc_retained_leaves", "hmrc_spi_income", diff --git a/packages/microcosm-build/tests/test_uk_ledger_targets.py b/packages/microcosm-build/tests/test_uk_ledger_targets.py index 737909109..b298dc7a8 100644 --- a/packages/microcosm-build/tests/test_uk_ledger_targets.py +++ b/packages/microcosm-build/tests/test_uk_ledger_targets.py @@ -1323,7 +1323,10 @@ def test_real_uk_bridges_resolve_contract_lower_sides(): assert reconciled.loc[1:, "value"].tolist() == [60.0, 30.0] -def test_reviewed_household_composition_gap_leaves_census_contract_unbound(): +def test_partially_bound_household_composition_bridge_stays_unbound_with_reviewed_records(): + # Synthetic partial bridge: the production register no longer carries these + # three exclusions (microcosm#791), so this exercises the reviewed-record + # path on a hand-built surface only. household_bridge = UK_CROSS_GRAIN_BRIDGES[0] missing = { "ons.household_composition.unrelated_adult_households", @@ -1388,6 +1391,59 @@ def test_reviewed_household_composition_gap_leaves_census_contract_unbound(): ] +def test_fully_bound_household_composition_bridge_reconciles_census_cells(): + # microcosm#791: with the three composition exclusions retired, the ten-cell + # partition binds and the census household cells rescale to its total. + household_bridge = UK_CROSS_GRAIN_BRIDGES[0] + surface = pd.DataFrame( + [ + *[ + { + "grain": "country", + "geography_id": "K02000001", + "target_id": target_id, + "value": 10.0, + } + for target_id in household_bridge.higher_target_ids + ], + { + "grain": "constituency", + "geography_id": "E14000001", + "target_id": "ons.census.households", + "value": 40.0, + }, + { + "grain": "constituency", + "geography_id": "S14000001", + "target_id": "ons.census.households", + "value": 10.0, + }, + ] + ) + + reconciled, receipt = apply_uk_cross_grain_reconciliation( + surface, + household_bridge.higher_target_ids, + reviewed_unbound_higher_targets={}, + ) + + assert receipt["unbound_bridges"] == [] + groups = [ + group + for group in receipt["groups"] + if group["bridge_id"] == household_bridge.bridge_id + ] + assert len(groups) == 1 + assert groups[0]["winning_grain"] == "country" + legs = groups[0]["legs"] + assert len(legs) == 1 + assert legs[0]["parent_geography_id"] == "K02000001" + assert legs[0]["declared_factor"] == pytest.approx(2.0) + assert legs[0]["new_total"] == pytest.approx(100.0) + census = reconciled.loc[reconciled["target_id"] == "ons.census.households", "value"] + assert census.tolist() == pytest.approx([80.0, 20.0]) + + def test_uk_front_door_reconciles_per_country_legs_and_builds_uniform_surface(): surface = pd.DataFrame( [ diff --git a/packages/microcosm-build/tests/test_uk_measure_simulation.py b/packages/microcosm-build/tests/test_uk_measure_simulation.py index 75b724c8f..2aaaf6259 100644 --- a/packages/microcosm-build/tests/test_uk_measure_simulation.py +++ b/packages/microcosm-build/tests/test_uk_measure_simulation.py @@ -575,7 +575,6 @@ def test_exclusion_applier_warns_within_week_of_expiry(): "slc.": 5, "dwp/uc_payment_dist/": 18, "obr.universal_credit_": 2, - "ons.household_composition.": 3, "obr.fuel_duties": 1, # microcosm#762 A16 (2026-09-03): the rows the spine cannot reach by # reweighting — savings interest, housing benefit, the two plan-2 @@ -600,7 +599,7 @@ def test_exclusion_applier_warns_within_week_of_expiry(): def test_packaged_exclusions_load(): exclusions = load_uk_calibration_measure_exclusions() names = [entry["name"] for entry in exclusions] - assert len(names) == len(set(names)) == 51 + assert len(names) == len(set(names)) == 48 for marker, expected in _PACKAGED_EXCLUSION_CENSUS.items(): matched = [name for name in names if marker in name] @@ -620,16 +619,17 @@ def test_packaged_exclusions_load(): ], sparse # The 2026-08-26 tranche carries the uk_target_fit disposition - # adjudication and a uniform three-month window; the ONS composition - # cells track the relationship-to-head successor issue. + # adjudication and a uniform three-month window. Its three ONS + # household-composition cells were retired by microcosm#791 (the + # relationship-to-head successor): the ten cells now bind on the + # frs_relationships stage's household type column, so no composition + # entry may remain on the register. tranche = [e for e in exclusions if e["approved_on"] == "2026-08-26"] - assert len(tranche) == 39 + assert len(tranche) == 36 for entry in tranche: assert "5427936411" in entry["adjudication"], entry["name"] assert entry["expires_on"] == "2026-11-26", entry["name"] - for entry in exclusions: - if entry["name"].startswith("ons.household_composition."): - assert entry["tracking"] == "microcosm#791", entry["name"] + assert not [n for n in names if n.startswith("ons.household_composition.")] # The 2026-09-03 tranche is #762's A16: five unreachable national rows, # a one-month window, each row tracked on its spine-defect issue. @@ -662,6 +662,9 @@ def test_packaged_exclusions_load(): "dwp.uc.households_single_no_children", "dwp.uc.two_child_limit.children_disabled_child_element", "ons.household_composition.couple_no_children_households", + "ons.household_composition.multi_family_households", + "ons.household_composition.unrelated_adult_households", + "ons.household_composition.lone_parent_non_dependent_children_households", "hmrc/state_pension_income_band_40_000_to_50_000", "hmrc/state_pension_income_band_50_000_to_70_000", "hmrc/self_employment_income_income_band_50_000_to_70_000", diff --git a/packages/microcosm-build/tests/test_uk_population_targets.py b/packages/microcosm-build/tests/test_uk_population_targets.py index 92650b85c..9aa05f5b0 100644 --- a/packages/microcosm-build/tests/test_uk_population_targets.py +++ b/packages/microcosm-build/tests/test_uk_population_targets.py @@ -884,3 +884,37 @@ def _valid_dimension_values(value: object) -> bool: def _is_dimension_scalar(value: object) -> bool: return isinstance(value, str | int | float | bool) + + +def test_household_composition_rows_bind_on_the_frs_relationships_column() -> None: + # microcosm#791: the ten ONS Table 7 cells bind on one frame column whose + # values are Chronicle's ons.household_type value ids, so each row's + # condition value is its own selector dimension value and the ten cover + # the declared domain exactly once. + from microcosm.build.uk_runtime.frs_relationships import ( + CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS, + ) + + resource = _load() + rows = [ + target + for target in resource["targets"] + if target["family"] == "ons_household_composition" + ] + assert len(rows) == 10 + seen = [] + for target in rows: + binding = target["bindings"]["policyengine"] + conditions = binding["household_conditions"] + assert len(conditions) == 1, target["target_id"] + (condition,) = conditions + assert condition == { + "variable": "ons_household_type", + "operator": "==", + "value": target["ledger_selector"]["dimension_values"]["household_type"], + }, target["target_id"] + assert "reduce" not in condition and "entity" not in condition + assert binding["value_variable"] == "household_count" + assert "microcosm#791" in binding["notes"], target["target_id"] + seen.append(condition["value"]) + assert seen == list(CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS) diff --git a/packages/microcosm-build/tests/test_uk_source_stages.py b/packages/microcosm-build/tests/test_uk_source_stages.py index 56786b7fe..22bcb9004 100644 --- a/packages/microcosm-build/tests/test_uk_source_stages.py +++ b/packages/microcosm-build/tests/test_uk_source_stages.py @@ -30,6 +30,8 @@ ] POST_FRS_SPINE_STAGE_NAMES = [ "age_tail", + # #791: the relationship grid runs right after the final age is fixed. + "frs_relationships", ] E4_STAGE_NAMES = [ "frs_take_up", @@ -323,6 +325,7 @@ def test_country_stage_plan_assembles_spine_plan(self) -> None: "salary_sacrifice": _identity, "student_loans": _identity, "age_tail": _identity, + "frs_relationships": _identity, "frs_hmrc_retained_leaves": _identity, "hmrc_spi_income": _identity, "hmrc_spi_income_fallback": _identity, diff --git a/packages/microcosm-build/tests/test_uk_spine_acceptance_receipt.py b/packages/microcosm-build/tests/test_uk_spine_acceptance_receipt.py index 2c57fbb70..be784bb03 100644 --- a/packages/microcosm-build/tests/test_uk_spine_acceptance_receipt.py +++ b/packages/microcosm-build/tests/test_uk_spine_acceptance_receipt.py @@ -64,6 +64,11 @@ def _apply_pending_roster_transformations( assert roster[-1] == "age_tail" roster.remove("age_tail") roster.insert(1, "age_tail") + + # #791 re-mint pending: the relationship-grid stage runs right after the + # final age is fixed. + assert "frs_relationships" not in roster + roster.insert(roster.index("age_tail") + 1, "frs_relationships") return tuple(roster) diff --git a/packages/microcosm-data/src/microcosm/data/contract.py b/packages/microcosm-data/src/microcosm/data/contract.py index 989697621..fcbeb96bb 100644 --- a/packages/microcosm-data/src/microcosm/data/contract.py +++ b/packages/microcosm-data/src/microcosm/data/contract.py @@ -385,13 +385,13 @@ # fingerprint derives from the manifest digest. Editing the spec moves all # three here in the same reviewed change. _UK_GATE_BATTERY_POLICY_SHA256 = ( - "8deb610d25fced25e27be58989311efa217f49e6d644f37268cf0f7efd122193" + "38a8a01467e372c87d845e3aacef67c5cc67d90dbc86fa5325408296be00afab" ) _UK_GATE_BATTERY_GATES_MANIFEST_SHA256 = ( - "cd90537532e1800a76d4414a7d7454f5dedb4dfd574aca2dfca4ec1e1fe6cff3" + "49e86be979d5a266c88ea3091b295f8efe2fa96c85fddeb153c6d6083be6c72b" ) _UK_GATE_BATTERY_SPEC_FINGERPRINT = ( - "8b28c7d23b9e8ebc9e7436abd7309e59f0ef14fb582506f874147a5c1c4f44ef" + "25049e61956b1f4145c1915f0e9a0b9523ec86da428f2a378c6ed8dce5cd2793" ) #: Spec entry id -> the legacy gate name whose observable detail checks #: apply unchanged (the battery re-keys the report by entry id; the gate @@ -410,6 +410,7 @@ "uk_export_surface": "export_surface", "uk_take_up_signal": "take_up_signal", "uk_brma_enum_domain": "enum_domain", + "uk_ons_household_type_enum_domain": "enum_domain", "uk_uc_deduction_combination_enum_domain": "enum_domain", "uk_student_loan_plan_enum_domain": "enum_domain", "uk_target_surface": "target_surface", @@ -459,6 +460,7 @@ ), "uk_stage_student_loans_realization": ("stage_health", "transferred"), "uk_stage_age_tail_targets": ("stage_health", "assembled"), + "uk_stage_frs_relationships_composition": ("stage_health", "assembled"), "uk_ledger_compile_parity_local_incumbent_2025": ( "ledger_compile_parity", "preflight", @@ -477,6 +479,7 @@ "uk_export_surface": ("export_surface", "terminal"), "uk_take_up_signal": ("take_up_signal", "terminal"), "uk_brma_enum_domain": ("enum_domain", "assembled"), + "uk_ons_household_type_enum_domain": ("enum_domain", "assembled"), "uk_uc_deduction_combination_enum_domain": ("enum_domain", "terminal"), "uk_student_loan_plan_enum_domain": ("enum_domain", "terminal"), "uk_calibration_reference_coverage": ( @@ -525,6 +528,7 @@ "uk_stage_salary_sacrifice_realization", "uk_stage_student_loans_realization", "uk_stage_age_tail_targets", + "uk_stage_frs_relationships_composition", } ) # The input-mass binding's evidence payload wraps the reviewed reference @@ -656,12 +660,14 @@ "spine": frozenset( { "uk_brma_enum_domain", + "uk_ons_household_type_enum_domain", "uk_stage_age_tail_targets", "uk_stage_cgt_band_donors_support", "uk_stage_cgt_incidence_clone_mass", "uk_stage_etb_services_support", "uk_stage_etb_vat_support", "uk_stage_frs_hmrc_spine_leaves_signal", + "uk_stage_frs_relationships_composition", "uk_stage_hmrc_cgt_gains_spine_summary", "uk_stage_hmrc_spi_income_spine_identity", "uk_stage_lcfs_consumption_support", @@ -710,10 +716,10 @@ _UK_CERTIFICATION_PART_DIGESTS: Mapping[str, Mapping[str, str]] = { "spine": { "gates_manifest_sha256": ( - "70a47a57039a236ae67df7d019fc7f8d43cbffab14a47d00a1e3e28dbc83a5a3" + "7f9f07e60ba300cc39cbc22d7df60804374664827a803856bf6d6b11d9045287" ), "policy_sha256": ( - "21e6b68e013cfc33a5bf96e141c42fd6fb23a34a237ae71a9e5f806a958552c8" + "7058df03511284046d89932747012908d731198359f2b779be9e478e33703364" ), }, "calibration_seam": { @@ -726,10 +732,10 @@ }, "release_cut": { "gates_manifest_sha256": ( - "79a1bd35f18ced387d988a1285aa26afb9404c635f69f32204aa020559d4a0e3" + "1aaf29c5e95e70cdbd499fec3a06098478a925caf32e3f09f6fcf3b0ac32f436" ), "policy_sha256": ( - "e9cdea8c7dad2ee582a6b71df0d5f25eed142f52bd352e29683a4977f6ac69d9" + "4a93792fb9d03da4401f1aa58d261af19677ead0afb56d93ae9f195203f68307" ), }, } diff --git a/packages/microcosm-data/tests/test_contract.py b/packages/microcosm-data/tests/test_contract.py index cafceadac..78c3a2c91 100644 --- a/packages/microcosm-data/tests/test_contract.py +++ b/packages/microcosm-data/tests/test_contract.py @@ -137,13 +137,13 @@ def _trusted_terminal_gate_signing_key(monkeypatch) -> None: UK_GATE_BATTERY_PRODUCER = "microcosm.build.gate_battery" UK_GATE_BATTERY_SIGNING_KEY_ENV = "MICROCOSM_UK_TERMINAL_GATE_SIGNING_KEY" UK_GATE_BATTERY_POLICY_SHA256 = ( - "8deb610d25fced25e27be58989311efa217f49e6d644f37268cf0f7efd122193" + "38a8a01467e372c87d845e3aacef67c5cc67d90dbc86fa5325408296be00afab" ) UK_GATE_BATTERY_GATES_MANIFEST_SHA256 = ( - "cd90537532e1800a76d4414a7d7454f5dedb4dfd574aca2dfca4ec1e1fe6cff3" + "49e86be979d5a266c88ea3091b295f8efe2fa96c85fddeb153c6d6083be6c72b" ) UK_GATE_BATTERY_SPEC_FINGERPRINT = ( - "8b28c7d23b9e8ebc9e7436abd7309e59f0ef14fb582506f874147a5c1c4f44ef" + "25049e61956b1f4145c1915f0e9a0b9523ec86da428f2a378c6ed8dce5cd2793" ) UK_GATE_BATTERY_DEGENERATE_EVIDENCE_SHA256 = ( "6f0243bcda09dad26945376230c44ec3cf55d4e417c3a25e29bae8c59bc1a69d" @@ -219,6 +219,7 @@ def _trusted_terminal_gate_signing_key(monkeypatch) -> None: None, ), "uk_stage_age_tail_targets": ("stage_health", "assembled", None), + "uk_stage_frs_relationships_composition": ("stage_health", "assembled", None), "uk_ledger_compile_parity_local_incumbent_2025": ( "ledger_compile_parity", "preflight", @@ -258,6 +259,7 @@ def _trusted_terminal_gate_signing_key(monkeypatch) -> None: "uk_export_surface": ("export_surface", "terminal", "export_surface"), "uk_take_up_signal": ("take_up_signal", "terminal", "take_up_signal"), "uk_brma_enum_domain": ("enum_domain", "assembled", "enum_domain"), + "uk_ons_household_type_enum_domain": ("enum_domain", "assembled", "enum_domain"), "uk_uc_deduction_combination_enum_domain": ( "enum_domain", "terminal", @@ -1190,6 +1192,7 @@ def _gate_battery_payload( "uk_stage_salary_sacrifice_realization": "salary_sacrifice", "uk_stage_student_loans_realization": "student_loans", "uk_stage_age_tail_targets": "age_tail", + "uk_stage_frs_relationships_composition": "frs_relationships", } gates: dict[str, dict] = {} for entry_id, (gate, phase, detail_name) in UK_GATE_BATTERY_ENTRIES.items(): diff --git a/packages/microcosm-graph/src/microcosm/graph/population.py b/packages/microcosm-graph/src/microcosm/graph/population.py index 1a52baf3f..b5561f1d1 100644 --- a/packages/microcosm-graph/src/microcosm/graph/population.py +++ b/packages/microcosm-graph/src/microcosm/graph/population.py @@ -1799,7 +1799,12 @@ def _patch_columns( owners[(owned.entity, owned.column)] = node.id continue else: + # The placeholder is built positionally; bind it to the table's own + # index before insertion. A filtered population (a sampled rung) + # carries a non-contiguous index, and a label-aligned insert would + # NaN-fill the gaps and silently widen an int64 or bool column. incumbent = _empty_column(len(table), owned.dtype, owned_mask) + incumbent.index = table.index table[owned.column] = incumbent positions = pd.Series( diff --git a/packages/microcosm-graph/tests/fixtures/parity/uk_spine/NORMALIZATION.md b/packages/microcosm-graph/tests/fixtures/parity/uk_spine/NORMALIZATION.md index fa46b4edf..bf65a68d3 100644 --- a/packages/microcosm-graph/tests/fixtures/parity/uk_spine/NORMALIZATION.md +++ b/packages/microcosm-graph/tests/fixtures/parity/uk_spine/NORMALIZATION.md @@ -1,6 +1,6 @@ # UK spine parity string normalization -The unchanged legacy transforms retain these 22 textual table columns as +The unchanged legacy transforms retain these 25 textual table columns as pandas `object`. The frozen graph dtype token `string` is specified by interface-freeze amendment 10 as pandas `StringDtype(storage="python")`. Before computing the legacy oracle's `uk_frame_content_identity` (live, @@ -8,6 +8,6 @@ in `legacy_oracle_identity`), exactly this audited surface is cast to that dtype. No values, row order, column order, weights, strata, mass records, or metadata change. -- `person`: `gender`, `marital_status`, `employment_status`, `employment_sector`, `aa_category`, `dla_sc_category`, `dla_m_category`, `pip_m_category`, `pip_dl_category`, `current_education`, `highest_education`, `person_support_channel`, `student_loan_plan` +- `person`: `gender`, `marital_status`, `employment_status`, `employment_sector`, `aa_category`, `dla_sc_category`, `dla_m_category`, `pip_m_category`, `pip_dl_category`, `current_education`, `highest_education`, `person_support_channel`, `student_loan_plan`, `relationship_to_head`, `ons_family_role` - `benunit`: `benunit_support_channel`, `uc_deduction_combination` -- `household`: `region`, `tenure_type`, `accommodation_type`, `council_tax_band`, `brma`, `household_support_channel`, `source_household_key` +- `household`: `region`, `tenure_type`, `accommodation_type`, `council_tax_band`, `brma`, `household_support_channel`, `source_household_key`, `ons_household_type` diff --git a/packages/microcosm-graph/tests/fixtures/parity/uk_spine/PRODUCED_BY.txt b/packages/microcosm-graph/tests/fixtures/parity/uk_spine/PRODUCED_BY.txt index b036ca7d1..b591b8f42 100644 --- a/packages/microcosm-graph/tests/fixtures/parity/uk_spine/PRODUCED_BY.txt +++ b/packages/microcosm-graph/tests/fixtures/parity/uk_spine/PRODUCED_BY.txt @@ -1 +1 @@ -tools/graph_uk_spine_fixture.py; current 28-transform legacy StagePlan oracle with parsed private-source seams. The acceptance test runs both sides from frs_raw in-process (root weights differ by one ulp between machines); the captured root tables serve the unbound registry's data-only CREATE path. +tools/graph_uk_spine_fixture.py; current 29-transform legacy StagePlan oracle with parsed private-source seams. The acceptance test runs both sides from frs_raw in-process (root weights differ by one ulp between machines); the captured root tables serve the unbound registry's data-only CREATE path. diff --git a/packages/microcosm-graph/tests/fixtures/parity/uk_spine/sources/fixture.json b/packages/microcosm-graph/tests/fixtures/parity/uk_spine/sources/fixture.json index 38dd16be6..7cf09ca2b 100644 --- a/packages/microcosm-graph/tests/fixtures/parity/uk_spine/sources/fixture.json +++ b/packages/microcosm-graph/tests/fixtures/parity/uk_spine/sources/fixture.json @@ -13,7 +13,7 @@ "spi_sample_fraction": 0.0135, "student_loans_calibration_year": 2025 }, - "description": "Data-only inputs for reconstructing the same 28 current UK stage transform classes used by the legacy StagePlan oracle.", + "description": "Data-only inputs for reconstructing the same 29 current UK stage transform classes used by the legacy StagePlan oracle.", "inputs": { "cgt_distribution": "cgt_distribution.json", "etb": "etb.csv", @@ -442,8 +442,8 @@ "locator": "househol.tab", "role": "frs_table", "runtime_sha256_required": true, - "sha256": "5dce5c323681a5dd77b366fc52da49326d7626b6bbe99c34aee0808e21a81829", - "size_bytes": 14896, + "sha256": "c56d5f75ee60027e6ff74f54889f6880ade9f6deb0bace0f27d21f8e5976c6a1", + "size_bytes": 15173, "table": "househol", "vintage": "synthetic-h2" } @@ -522,8 +522,8 @@ "locator": "adult.tab", "role": "frs_table", "runtime_sha256_required": true, - "sha256": "2738aa2d7357f8bc560de607f9c3a5add38856e96015b7b1e9f85d3ab80d73ba", - "size_bytes": 22851, + "sha256": "79801434b27f0b0b2f82af0f4d0750688c53aabda049bc2c30994fc35b338a5f", + "size_bytes": 24966, "table": "adult", "vintage": "synthetic-h2" }, @@ -533,8 +533,8 @@ "locator": "child.tab", "role": "frs_table", "runtime_sha256_required": true, - "sha256": "30f9fcabb0c54673e14c368e46627010b0b239c4305b2c4e4c46803d089c6fac", - "size_bytes": 1601, + "sha256": "fd24138e8c97aa641b126ed03b867e6ea177d22cbcc8c1e53b44530ba045724a", + "size_bytes": 2123, "table": "child", "vintage": "synthetic-h2" } @@ -638,8 +638,8 @@ "locator": "adult.tab", "role": "frs_table", "runtime_sha256_required": true, - "sha256": "2738aa2d7357f8bc560de607f9c3a5add38856e96015b7b1e9f85d3ab80d73ba", - "size_bytes": 22851, + "sha256": "79801434b27f0b0b2f82af0f4d0750688c53aabda049bc2c30994fc35b338a5f", + "size_bytes": 24966, "table": "adult", "vintage": "synthetic-h2" } @@ -681,8 +681,8 @@ "locator": "adult.tab", "role": "frs_table", "runtime_sha256_required": true, - "sha256": "2738aa2d7357f8bc560de607f9c3a5add38856e96015b7b1e9f85d3ab80d73ba", - "size_bytes": 22851, + "sha256": "79801434b27f0b0b2f82af0f4d0750688c53aabda049bc2c30994fc35b338a5f", + "size_bytes": 24966, "table": "adult", "vintage": "synthetic-h2" }, @@ -860,8 +860,8 @@ "locator": "adult.tab", "role": "frs_table", "runtime_sha256_required": true, - "sha256": "2738aa2d7357f8bc560de607f9c3a5add38856e96015b7b1e9f85d3ab80d73ba", - "size_bytes": 22851, + "sha256": "79801434b27f0b0b2f82af0f4d0750688c53aabda049bc2c30994fc35b338a5f", + "size_bytes": 24966, "table": "adult", "vintage": "synthetic-h2" } @@ -963,6 +963,220 @@ "stage": "frs_person_draws", "survey": "Family Resources Survey 2024-25" }, + "frs_relationships": { + "artifacts": [ + { + "format": "tab", + "kind": "licensed_microdata", + "locator": "adult.tab", + "role": "frs_table", + "runtime_sha256_required": true, + "sha256": "79801434b27f0b0b2f82af0f4d0750688c53aabda049bc2c30994fc35b338a5f", + "size_bytes": 24966, + "table": "adult", + "vintage": "synthetic-h2" + }, + { + "format": "tab", + "kind": "licensed_microdata", + "locator": "child.tab", + "role": "frs_table", + "runtime_sha256_required": true, + "sha256": "fd24138e8c97aa641b126ed03b867e6ea177d22cbcc8c1e53b44530ba045724a", + "size_bytes": 2123, + "table": "child", + "vintage": "synthetic-h2" + }, + { + "format": "tab", + "kind": "licensed_microdata", + "locator": "househol.tab", + "role": "frs_table", + "runtime_sha256_required": true, + "sha256": "c56d5f75ee60027e6ff74f54889f6880ade9f6deb0bace0f27d21f8e5976c6a1", + "size_bytes": 15173, + "table": "househol", + "vintage": "synthetic-h2" + } + ], + "grain": "household+person", + "nonnegative_outputs": [ + "ons_family_index" + ], + "notes": "Derives the ONS Families and households Table 7 household type from the FRS household grid (microcosm#791). Every person's relhrp code becomes relationship_to_head (HEAD for the household reference person, whose relhrp is blank and whose hrpid is 1; hrpnum on the househol tab is the independent check). The pairwise R01-R14 matrix builds ONS families: any partner pair (spouse, cohabitee, civil partner) is a couple; a person with no partner and no own child in the household joins a parent's family through a natural/adopted or step child link (natural before step, then the lowest person number, on ties); foster, in-law, grandparent and sibling links never form a family, so foster children and grandchildren without a parent present stay individuals, as ONS treats them. A child is dependent under 16, or 16-18 in full-time education (child-tab members are in full-time non-advanced education by construction; adults use educft, fted on earlier tapes); 19 and over is non-dependent whatever the education status - the FRS child tab runs to 19, ONS stops at 18, so the two definitions are translated here rather than assumed equal. Household type: one person (split at 65), no family present (two or more unrelated adults, which counts related non-family households such as two siblings), exactly one family classified by that family whatever other individuals live there (a couple plus a lodger is a couple household - the class the #757 person-count restrictions could not place), or two or more families. The ten values are the Chronicle ons-families-households-2025 ons.household_type value ids verbatim, so the frame value, this declaration, the contract row and the published fact share one string. The reciprocity tolerance is the 2024-25 tape's three ordered pairs (two households) where a child records a parent link the parent records as non-relative or sibling; either side's declaration establishes the link, and any other count refuses the build for review.", + "operations": [ + { + "delimiter": "\t", + "format": "tab", + "kind": "read_tables", + "lowercase_columns": true, + "numeric_errors": "coerce", + "runtime_sha256_required": true + }, + { + "dependent_child": { + "full_time_education_through_age": 18, + "unconditional_below_age": 16 + }, + "documentation": { + "category_ids": "chronicle package ons-families-households-2025, Table 7, dimension ons.household_type value ids", + "frs_codes": "UK Data Service SN 9563 (DOI 10.5255/UKDA-SN-9563-1), FRS 2024-25 question instructions, Household Grid: Relationship; HRP definition in the FRS background information and methodology", + "ons_definitions": "ONS Families and households in the UK: 2025, Measuring the data and Glossary (family, dependent and non-dependent children, one-family, two or more unrelated adults, multi-family households)" + }, + "family_link_codes": { + "child_of": [ + 3, + 4 + ], + "parent_of": [ + 7, + 8 + ], + "partner": [ + 1, + 2, + 20 + ] + }, + "family_role_values": [ + "COUPLE_PARTNER", + "LONE_PARENT", + "DEPENDENT_CHILD", + "NON_DEPENDENT_CHILD", + "INDIVIDUAL" + ], + "frs_household_grid_relationship_codes": [ + { + "code": 1, + "label": "SPOUSE" + }, + { + "code": 2, + "label": "COHABITEE" + }, + { + "code": 3, + "label": "CHILD" + }, + { + "code": 4, + "label": "STEP_CHILD" + }, + { + "code": 5, + "label": "FOSTER_CHILD" + }, + { + "code": 6, + "label": "CHILD_IN_LAW" + }, + { + "code": 7, + "label": "PARENT" + }, + { + "code": 8, + "label": "STEP_PARENT" + }, + { + "code": 9, + "label": "FOSTER_PARENT" + }, + { + "code": 10, + "label": "PARENT_IN_LAW" + }, + { + "code": 11, + "label": "SIBLING" + }, + { + "code": 12, + "label": "STEP_SIBLING" + }, + { + "code": 13, + "label": "FOSTER_SIBLING" + }, + { + "code": 14, + "label": "SIBLING_IN_LAW" + }, + { + "code": 15, + "label": "GRANDCHILD" + }, + { + "code": 16, + "label": "GRANDPARENT" + }, + { + "code": 17, + "label": "OTHER_RELATIVE" + }, + { + "code": 18, + "label": "OTHER_NON_RELATIVE" + }, + { + "code": 20, + "label": "CIVIL_PARTNER" + } + ], + "head_label": "HEAD", + "household_type_values": [ + "lone_households_under_65", + "lone_households_over_65", + "unrelated_adult_households", + "couple_no_children_households", + "couple_under_3_children_households", + "couple_3_plus_children_households", + "couple_non_dependent_children_only_households", + "lone_parent_dependent_children_households", + "lone_parent_non_dependent_children_households", + "multi_family_households" + ], + "kind": "derive_ons_household_composition", + "one_person_age_split": 65, + "reciprocity_mismatch_tolerance": 3, + "source_columns": { + "full_time_education": [ + "fted", + "educft" + ], + "grid": [ + "r01", + "r02", + "r03", + "r04", + "r05", + "r06", + "r07", + "r08", + "r09", + "r10", + "r11", + "r12", + "r13", + "r14" + ], + "head": "relhrp", + "head_flag": "hrpid", + "head_index": "hrpnum" + } + } + ], + "outputs": [ + "relationship_to_head", + "ons_family_role", + "ons_family_index", + "ons_household_type" + ], + "rewrites": [], + "source": "Department for Work and Pensions Family Resources Survey 2024-25, UK Data Service SN 9563, DOI 10.5255/UKDA-SN-9563-1; local licensed 2024_25 tabs (household grid, relhrp and R01-R14).", + "stage": "frs_relationships", + "survey": "Family Resources Survey 2024-25" + }, "frs_spine": { "artifacts": [ { @@ -982,8 +1196,8 @@ "locator": "adult.tab", "role": "frs_table", "runtime_sha256_required": true, - "sha256": "2738aa2d7357f8bc560de607f9c3a5add38856e96015b7b1e9f85d3ab80d73ba", - "size_bytes": 22851, + "sha256": "79801434b27f0b0b2f82af0f4d0750688c53aabda049bc2c30994fc35b338a5f", + "size_bytes": 24966, "table": "adult", "vintage": "synthetic-h2" }, @@ -1015,8 +1229,8 @@ "locator": "child.tab", "role": "frs_table", "runtime_sha256_required": true, - "sha256": "30f9fcabb0c54673e14c368e46627010b0b239c4305b2c4e4c46803d089c6fac", - "size_bytes": 1601, + "sha256": "fd24138e8c97aa641b126ed03b867e6ea177d22cbcc8c1e53b44530ba045724a", + "size_bytes": 2123, "table": "child", "vintage": "synthetic-h2" }, @@ -1048,8 +1262,8 @@ "locator": "househol.tab", "role": "frs_table", "runtime_sha256_required": true, - "sha256": "5dce5c323681a5dd77b366fc52da49326d7626b6bbe99c34aee0808e21a81829", - "size_bytes": 14896, + "sha256": "c56d5f75ee60027e6ff74f54889f6880ade9f6deb0bace0f27d21f8e5976c6a1", + "size_bytes": 15173, "table": "househol", "vintage": "synthetic-h2" }, diff --git a/packages/microcosm-graph/tests/fixtures/parity/uk_spine/sources/frs_raw/adult.tab b/packages/microcosm-graph/tests/fixtures/parity/uk_spine/sources/frs_raw/adult.tab index d78c9cb12..c5833093a 100644 --- a/packages/microcosm-graph/tests/fixtures/parity/uk_spine/sources/frs_raw/adult.tab +++ b/packages/microcosm-graph/tests/fixtures/parity/uk_spine/sources/frs_raw/adult.tab @@ -1,136 +1,136 @@ -SERNUM BENUNIT PERSON AGE80 AGE SEX TOTHOURS HRPID UPERSON MARITAL EMPSTATI MJOBSECT SIC FTED TYPEED2 EDUCQUAL TRAIN EMAAMT CHEMAAMT INEARNS SEINCAM2 MNTUS1 MNTUSAM1 MNTAMT1 MNTAMT2 CVPAY ROYYR1 ROYYR2 ROYYR3 ROYYR4 ALLPAY2 ALLPAY3 ALLPAY4 CHAMTERN CHAMTTST APAMT APDAMT PAREAMT REDAMT SLREPAMT SSPADJ SMPADJ TUBORR ACCSSAMT GRTDIR1 GRTDIR2 HEARTVAL -1 1 1 0 80 2 21 1 1 2 2 2 11 2 0 2 10 0.0 0.0 101.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -2 1 1 0 22 1 22 1 1 3 3 1 12 2 0 3 10 0.0 0.0 102.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -3 1 1 0 23 2 23 1 1 1 4 2 13 2 0 4 10 0.0 0.0 103.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -4 1 1 0 24 1 24 1 1 2 5 1 14 2 0 5 10 0.0 0.0 104.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -5 1 1 0 25 2 25 1 1 3 6 2 15 2 0 6 10 0.0 0.0 105.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -6 1 1 0 26 1 26 1 1 1 7 1 16 2 0 7 10 0.0 0.0 106.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -7 1 1 0 27 2 27 1 1 2 8 2 17 2 0 8 10 0.0 0.0 107.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -8 1 1 0 28 1 28 1 1 3 1 1 18 2 0 9 10 0.0 0.0 108.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -9 1 1 0 29 2 29 1 1 1 2 2 19 2 0 10 10 0.0 0.0 109.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -10 1 1 0 30 1 30 1 1 2 3 1 20 2 0 11 10 0.0 0.0 110.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -11 1 1 0 31 2 31 1 1 3 4 2 21 2 0 12 10 0.0 0.0 111.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -12 1 1 0 32 1 32 1 1 1 5 1 22 2 0 13 10 0.0 0.0 112.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -13 1 1 0 33 2 33 1 1 2 6 2 23 2 0 14 10 0.0 0.0 113.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -14 1 1 0 34 1 34 1 1 3 7 1 24 2 0 15 10 0.0 0.0 114.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -15 1 1 0 35 2 35 1 1 1 8 2 25 2 0 16 10 0.0 0.0 115.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -16 1 1 0 36 1 36 1 1 2 1 1 26 2 0 17 10 0.0 0.0 116.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -17 1 1 0 37 2 37 1 1 3 2 2 27 2 0 18 10 0.0 0.0 117.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -18 1 1 0 38 1 38 1 1 1 3 1 28 2 0 1 10 0.0 0.0 118.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -19 1 1 0 39 2 39 1 1 2 4 2 29 2 0 2 10 0.0 0.0 119.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -20 1 1 0 40 1 40 1 1 3 5 1 30 2 0 3 10 0.0 0.0 120.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -21 1 1 0 41 2 41 1 1 1 6 2 31 2 0 4 10 0.0 0.0 121.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -22 1 1 0 42 1 42 1 1 2 7 1 32 2 0 5 10 0.0 0.0 122.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -23 1 1 0 43 2 43 1 1 3 8 2 33 2 0 6 10 0.0 0.0 123.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -24 1 1 0 44 1 44 1 1 1 1 1 34 2 0 7 10 0.0 0.0 124.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -25 1 1 0 45 2 20 1 1 2 2 2 35 2 0 8 10 0.0 0.0 125.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -26 1 1 0 46 1 21 1 1 3 3 1 36 2 0 9 10 0.0 0.0 126.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -27 1 1 0 47 2 22 1 1 1 4 2 37 2 0 10 10 0.0 0.0 127.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -28 1 1 0 48 1 23 1 1 2 5 1 38 2 0 11 10 0.0 0.0 128.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -29 1 1 0 49 2 24 1 1 3 6 2 39 2 0 12 10 0.0 0.0 129.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -30 1 1 0 50 1 25 1 1 1 7 1 40 2 0 13 10 0.0 0.0 130.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -31 1 1 0 51 2 26 1 1 2 8 2 41 2 0 14 10 0.0 0.0 131.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -32 1 1 0 52 1 27 1 1 3 1 1 42 2 0 15 10 0.0 0.0 132.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -33 1 1 0 53 2 28 1 1 1 2 2 43 2 0 16 10 0.0 0.0 133.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -34 1 1 0 54 1 29 1 1 2 3 1 44 2 0 17 10 0.0 0.0 134.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -35 1 1 0 55 2 30 1 1 3 4 2 45 2 0 18 10 0.0 0.0 135.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -36 1 1 0 56 1 31 1 1 1 5 1 46 2 0 1 10 0.0 0.0 136.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -37 1 1 0 57 2 32 1 1 2 6 2 47 2 0 2 10 0.0 0.0 137.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -38 1 1 0 58 1 33 1 1 3 7 1 48 2 0 3 10 0.0 0.0 138.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -39 1 1 0 59 2 34 1 1 1 8 2 49 2 0 4 10 0.0 0.0 139.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -40 1 1 0 60 1 35 1 1 2 1 1 50 2 0 5 10 0.0 0.0 140.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -41 1 1 0 61 2 36 1 1 3 2 2 51 2 0 6 10 0.0 0.0 141.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -42 1 1 0 62 1 37 1 1 1 3 1 52 2 0 7 10 0.0 0.0 142.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -43 1 1 0 63 2 38 1 1 2 4 2 53 2 0 8 10 0.0 0.0 143.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -44 1 1 0 64 1 39 1 1 3 5 1 54 2 0 9 10 0.0 0.0 144.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -45 1 1 0 65 2 40 1 1 1 6 2 55 2 0 10 10 0.0 0.0 145.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -46 1 1 0 66 1 41 1 1 2 7 1 56 2 0 11 10 0.0 0.0 146.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -47 1 1 0 67 2 42 1 1 3 8 2 57 2 0 12 10 0.0 0.0 147.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -48 1 1 0 68 1 43 1 1 1 1 1 58 2 0 13 10 0.0 0.0 148.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -49 1 1 0 69 2 44 1 1 2 2 2 59 2 0 14 10 0.0 0.0 149.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -50 1 1 0 70 1 20 1 1 3 3 1 60 2 0 15 10 0.0 0.0 150.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -51 1 1 0 71 2 21 1 1 1 4 2 61 2 0 16 10 0.0 0.0 151.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -52 1 1 0 72 1 22 1 1 2 5 1 62 2 0 17 10 0.0 0.0 152.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -53 1 1 0 73 2 23 1 1 3 6 2 63 2 0 18 10 0.0 0.0 153.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -54 1 1 0 74 1 24 1 1 1 7 1 64 2 0 1 10 0.0 0.0 154.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -55 1 1 0 20 2 25 1 1 2 8 2 65 2 0 2 10 0.0 0.0 155.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -56 1 1 0 21 1 26 1 1 3 1 1 66 2 0 3 10 0.0 0.0 156.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -57 1 1 0 22 2 27 1 1 1 2 2 67 2 0 4 10 0.0 0.0 157.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -58 1 1 0 23 1 28 1 1 2 3 1 68 2 0 5 10 0.0 0.0 158.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -59 1 1 0 24 2 29 1 1 3 4 2 69 2 0 6 10 0.0 0.0 159.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -60 1 1 0 25 1 30 1 1 1 5 1 70 2 0 7 10 0.0 0.0 160.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -61 1 1 0 26 2 31 1 1 2 6 2 71 2 0 8 10 0.0 0.0 161.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -62 1 1 0 27 1 32 1 1 3 7 1 72 2 0 9 10 0.0 0.0 162.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -63 1 1 0 28 2 33 1 1 1 8 2 73 2 0 10 10 0.0 0.0 163.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -64 1 1 0 29 1 34 1 1 2 1 1 74 2 0 11 10 0.0 0.0 164.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -65 1 1 0 30 2 35 1 1 3 2 2 75 2 0 12 10 0.0 0.0 165.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -66 1 1 0 31 1 36 1 1 1 3 1 76 2 0 13 10 0.0 0.0 166.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -67 1 1 0 32 2 37 1 1 2 4 2 77 2 0 14 10 0.0 0.0 167.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -68 1 1 0 33 1 38 1 1 3 5 1 78 2 0 15 10 0.0 0.0 168.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -69 1 1 0 34 2 39 1 1 1 6 2 79 2 0 16 10 0.0 0.0 169.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -70 1 1 0 35 1 40 1 1 2 7 1 80 2 0 17 10 0.0 0.0 170.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -71 1 1 0 36 2 41 1 1 3 8 2 81 2 0 18 10 0.0 0.0 171.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -72 1 1 0 37 1 42 1 1 1 1 1 82 2 0 1 10 0.0 0.0 172.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -73 1 1 0 38 2 43 1 1 2 2 2 83 2 0 2 10 0.0 0.0 173.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -74 1 1 0 39 1 44 1 1 3 3 1 84 2 0 3 10 0.0 0.0 174.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -75 1 1 0 40 2 20 1 1 1 4 2 85 2 0 4 10 0.0 0.0 175.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -76 1 1 0 41 1 21 1 1 2 5 1 86 2 0 5 10 0.0 0.0 176.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -77 1 1 0 42 2 22 1 1 3 6 2 87 2 0 6 10 0.0 0.0 177.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -78 1 1 0 43 1 23 1 1 1 7 1 88 2 0 7 10 0.0 0.0 178.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -79 1 1 0 44 2 24 1 1 2 8 2 89 2 0 8 10 0.0 0.0 179.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -80 1 1 0 45 1 25 1 1 3 1 1 10 2 0 9 10 0.0 0.0 180.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -81 1 1 0 46 2 26 1 1 1 2 2 11 2 0 10 10 0.0 0.0 181.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -82 1 1 0 47 1 27 1 1 2 3 1 12 2 0 11 10 0.0 0.0 182.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -83 1 1 0 48 2 28 1 1 3 4 2 13 2 0 12 10 0.0 0.0 183.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -84 1 1 0 49 1 29 1 1 1 5 1 14 2 0 13 10 0.0 0.0 184.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -85 1 1 0 50 2 30 1 1 2 6 2 15 2 0 14 10 0.0 0.0 185.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -86 1 1 0 51 1 31 1 1 3 7 1 16 2 0 15 10 0.0 0.0 186.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -87 1 1 0 52 2 32 1 1 1 8 2 17 2 0 16 10 0.0 0.0 187.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -88 1 1 0 53 1 33 1 1 2 1 1 18 2 0 17 10 0.0 0.0 188.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -89 1 1 0 54 2 34 1 1 3 2 2 19 2 0 18 10 0.0 0.0 189.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -90 1 1 0 55 1 35 1 1 1 3 1 20 2 0 1 10 0.0 0.0 190.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -91 1 1 0 56 2 36 1 1 2 4 2 21 2 0 2 10 0.0 0.0 191.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -92 1 1 0 57 1 37 1 1 3 5 1 22 2 0 3 10 0.0 0.0 192.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -93 1 1 0 58 2 38 1 1 1 6 2 23 2 0 4 10 0.0 0.0 193.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -94 1 1 0 59 1 39 1 1 2 7 1 24 2 0 5 10 0.0 0.0 194.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -95 1 1 0 60 2 40 1 1 3 8 2 25 2 0 6 10 0.0 0.0 195.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -96 1 1 0 61 1 41 1 1 1 1 1 26 2 0 7 10 0.0 0.0 196.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -97 1 1 0 62 2 42 1 1 2 2 2 27 2 0 8 10 0.0 0.0 197.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -98 1 1 0 63 1 43 1 1 3 3 1 28 2 0 9 10 0.0 0.0 198.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -99 1 1 0 64 2 44 1 1 1 4 2 29 2 0 10 10 0.0 0.0 199.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -100 1 1 0 65 1 20 1 1 2 5 1 30 2 0 11 10 0.0 0.0 200.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -101 1 1 0 66 2 21 1 1 3 6 2 31 2 0 12 10 0.0 0.0 201.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -102 1 1 0 67 1 22 1 1 1 7 1 32 2 0 13 10 0.0 0.0 202.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -103 1 1 0 68 2 23 1 1 2 8 2 33 2 0 14 10 0.0 0.0 203.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -104 1 1 0 69 1 24 1 1 3 1 1 34 2 0 15 10 0.0 0.0 204.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -105 1 1 0 70 2 25 1 1 1 2 2 35 2 0 16 10 0.0 0.0 205.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -106 1 1 0 71 1 26 1 1 2 3 1 36 2 0 17 10 0.0 0.0 206.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -107 1 1 0 72 2 27 1 1 3 4 2 37 2 0 18 10 0.0 0.0 207.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -108 1 1 0 73 1 28 1 1 1 5 1 38 2 0 1 10 0.0 0.0 208.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -109 1 1 0 74 2 29 1 1 2 6 2 39 2 0 2 10 0.0 0.0 209.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -110 1 1 0 20 1 30 1 1 3 7 1 40 2 0 3 10 0.0 0.0 210.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -111 1 1 0 21 2 31 1 1 1 8 2 41 2 0 4 10 0.0 0.0 211.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -112 1 1 0 22 1 32 1 1 2 1 1 42 2 0 5 10 0.0 0.0 212.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -113 1 1 0 23 2 33 1 1 3 2 2 43 2 0 6 10 0.0 0.0 213.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -114 1 1 0 24 1 34 1 1 1 3 1 44 2 0 7 10 0.0 0.0 214.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -115 1 1 0 25 2 35 1 1 2 4 2 45 2 0 8 10 0.0 0.0 215.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -116 1 1 0 26 1 36 1 1 3 5 1 46 2 0 9 10 0.0 0.0 216.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -117 1 1 0 27 2 37 1 1 1 6 2 47 2 0 10 10 0.0 0.0 217.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -118 1 1 0 28 1 38 1 1 2 7 1 48 2 0 11 10 0.0 0.0 218.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -119 1 1 0 29 2 39 1 1 3 8 2 49 2 0 12 10 0.0 0.0 219.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -120 1 1 0 30 1 40 1 1 1 1 1 50 2 0 13 10 0.0 0.0 220.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -121 1 1 0 31 2 41 1 1 2 2 2 51 2 0 14 10 0.0 0.0 221.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -122 1 1 0 32 1 42 1 1 3 3 1 52 2 0 15 10 0.0 0.0 222.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -123 1 1 0 33 2 43 1 1 1 4 2 53 2 0 16 10 0.0 0.0 223.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -124 1 1 0 34 1 44 1 1 2 5 1 54 2 0 17 10 0.0 0.0 224.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -125 1 1 0 35 2 20 1 1 3 6 2 55 2 0 18 10 0.0 0.0 225.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -126 1 1 0 36 1 21 1 1 1 7 1 56 2 0 1 10 0.0 0.0 226.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -127 1 1 0 37 2 22 1 1 2 8 2 57 2 0 2 10 0.0 0.0 227.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -128 1 1 0 38 1 23 1 1 3 1 1 58 2 0 3 10 0.0 0.0 228.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -129 1 1 0 39 2 24 1 1 1 2 2 59 2 0 4 10 0.0 0.0 229.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -130 1 1 0 40 1 25 1 1 2 3 1 60 2 0 5 10 0.0 0.0 230.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -131 1 1 0 41 2 26 1 1 3 4 2 61 2 0 6 10 0.0 0.0 231.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -132 1 1 0 42 1 27 1 1 1 5 1 62 2 0 7 10 0.0 0.0 232.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -133 1 1 0 43 2 28 1 1 2 6 2 63 2 0 8 10 0.0 0.0 233.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -134 1 1 0 44 1 29 1 1 3 7 1 64 2 0 9 10 0.0 0.0 234.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 -135 1 1 0 45 2 30 1 1 1 8 2 65 2 0 10 10 0.0 0.0 235.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +SERNUM BENUNIT PERSON AGE80 AGE SEX TOTHOURS HRPID UPERSON RELHRP R01 R02 R03 R04 R05 R06 R07 R08 R09 R10 R11 R12 R13 R14 MARITAL EMPSTATI MJOBSECT SIC FTED TYPEED2 EDUCQUAL TRAIN EMAAMT CHEMAAMT INEARNS SEINCAM2 MNTUS1 MNTUSAM1 MNTAMT1 MNTAMT2 CVPAY ROYYR1 ROYYR2 ROYYR3 ROYYR4 ALLPAY2 ALLPAY3 ALLPAY4 CHAMTERN CHAMTTST APAMT APDAMT PAREAMT REDAMT SLREPAMT SSPADJ SMPADJ TUBORR ACCSSAMT GRTDIR1 GRTDIR2 HEARTVAL +1 1 1 0 80 2 21 1 1 2 2 2 11 2 0 2 10 0.0 0.0 101.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +2 1 1 0 22 1 22 1 1 3 3 1 12 2 0 3 10 0.0 0.0 102.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +3 1 1 0 23 2 23 1 1 1 4 2 13 2 0 4 10 0.0 0.0 103.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +4 1 1 0 24 1 24 1 1 2 5 1 14 2 0 5 10 0.0 0.0 104.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +5 1 1 0 25 2 25 1 1 7 3 6 2 15 2 0 6 10 0.0 0.0 105.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +6 1 1 0 26 1 26 1 1 1 7 1 16 2 0 7 10 0.0 0.0 106.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +7 1 1 0 27 2 27 1 1 2 8 2 17 2 0 8 10 0.0 0.0 107.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +8 1 1 0 28 1 28 1 1 3 1 1 18 2 0 9 10 0.0 0.0 108.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +9 1 1 0 29 2 29 1 1 1 2 2 19 2 0 10 10 0.0 0.0 109.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +10 1 1 0 30 1 30 1 1 7 2 3 1 20 2 0 11 10 0.0 0.0 110.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +11 1 1 0 31 2 31 1 1 3 4 2 21 2 0 12 10 0.0 0.0 111.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +12 1 1 0 32 1 32 1 1 1 5 1 22 2 0 13 10 0.0 0.0 112.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +13 1 1 0 33 2 33 1 1 2 6 2 23 2 0 14 10 0.0 0.0 113.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +14 1 1 0 34 1 34 1 1 3 7 1 24 2 0 15 10 0.0 0.0 114.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +15 1 1 0 35 2 35 1 1 7 1 8 2 25 2 0 16 10 0.0 0.0 115.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +16 1 1 0 36 1 36 1 1 2 1 1 26 2 0 17 10 0.0 0.0 116.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +17 1 1 0 37 2 37 1 1 3 2 2 27 2 0 18 10 0.0 0.0 117.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +18 1 1 0 38 1 38 1 1 1 3 1 28 2 0 1 10 0.0 0.0 118.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +19 1 1 0 39 2 39 1 1 2 4 2 29 2 0 2 10 0.0 0.0 119.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +20 1 1 0 40 1 40 1 1 7 3 5 1 30 2 0 3 10 0.0 0.0 120.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +21 1 1 0 41 2 41 1 1 1 6 2 31 2 0 4 10 0.0 0.0 121.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +22 1 1 0 42 1 42 1 1 2 7 1 32 2 0 5 10 0.0 0.0 122.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +23 1 1 0 43 2 43 1 1 3 8 2 33 2 0 6 10 0.0 0.0 123.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +24 1 1 0 44 1 44 1 1 1 1 1 34 2 0 7 10 0.0 0.0 124.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +25 1 1 0 45 2 20 1 1 7 2 2 2 35 2 0 8 10 0.0 0.0 125.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +26 1 1 0 46 1 21 1 1 3 3 1 36 2 0 9 10 0.0 0.0 126.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +27 1 1 0 47 2 22 1 1 1 4 2 37 2 0 10 10 0.0 0.0 127.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +28 1 1 0 48 1 23 1 1 2 5 1 38 2 0 11 10 0.0 0.0 128.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +29 1 1 0 49 2 24 1 1 3 6 2 39 2 0 12 10 0.0 0.0 129.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +30 1 1 0 50 1 25 1 1 7 1 7 1 40 2 0 13 10 0.0 0.0 130.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +31 1 1 0 51 2 26 1 1 2 8 2 41 2 0 14 10 0.0 0.0 131.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +32 1 1 0 52 1 27 1 1 3 1 1 42 2 0 15 10 0.0 0.0 132.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +33 1 1 0 53 2 28 1 1 1 2 2 43 2 0 16 10 0.0 0.0 133.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +34 1 1 0 54 1 29 1 1 2 3 1 44 2 0 17 10 0.0 0.0 134.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +35 1 1 0 55 2 30 1 1 7 3 4 2 45 2 0 18 10 0.0 0.0 135.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +36 1 1 0 56 1 31 1 1 1 5 1 46 2 0 1 10 0.0 0.0 136.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +37 1 1 0 57 2 32 1 1 2 6 2 47 2 0 2 10 0.0 0.0 137.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +38 1 1 0 58 1 33 1 1 3 7 1 48 2 0 3 10 0.0 0.0 138.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +39 1 1 0 59 2 34 1 1 1 8 2 49 2 0 4 10 0.0 0.0 139.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +40 1 1 0 60 1 35 1 1 7 2 1 1 50 2 0 5 10 0.0 0.0 140.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +41 1 1 0 61 2 36 1 1 3 2 2 51 2 0 6 10 0.0 0.0 141.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +42 1 1 0 62 1 37 1 1 1 3 1 52 2 0 7 10 0.0 0.0 142.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +43 1 1 0 63 2 38 1 1 2 4 2 53 2 0 8 10 0.0 0.0 143.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +44 1 1 0 64 1 39 1 1 3 5 1 54 2 0 9 10 0.0 0.0 144.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +45 1 1 0 65 2 40 1 1 7 1 6 2 55 2 0 10 10 0.0 0.0 145.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +46 1 1 0 66 1 41 1 1 2 7 1 56 2 0 11 10 0.0 0.0 146.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +47 1 1 0 67 2 42 1 1 3 8 2 57 2 0 12 10 0.0 0.0 147.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +48 1 1 0 68 1 43 1 1 1 1 1 58 2 0 13 10 0.0 0.0 148.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +49 1 1 0 69 2 44 1 1 2 2 2 59 2 0 14 10 0.0 0.0 149.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +50 1 1 0 70 1 20 1 1 7 3 3 1 60 2 0 15 10 0.0 0.0 150.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +51 1 1 0 71 2 21 1 1 1 4 2 61 2 0 16 10 0.0 0.0 151.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +52 1 1 0 72 1 22 1 1 2 5 1 62 2 0 17 10 0.0 0.0 152.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +53 1 1 0 73 2 23 1 1 3 6 2 63 2 0 18 10 0.0 0.0 153.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +54 1 1 0 74 1 24 1 1 1 7 1 64 2 0 1 10 0.0 0.0 154.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +55 1 1 0 20 2 25 1 1 7 2 8 2 65 2 0 2 10 0.0 0.0 155.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +56 1 1 0 21 1 26 1 1 3 1 1 66 2 0 3 10 0.0 0.0 156.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +57 1 1 0 22 2 27 1 1 1 2 2 67 2 0 4 10 0.0 0.0 157.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +58 1 1 0 23 1 28 1 1 2 3 1 68 2 0 5 10 0.0 0.0 158.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +59 1 1 0 24 2 29 1 1 3 4 2 69 2 0 6 10 0.0 0.0 159.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +60 1 1 0 25 1 30 1 1 7 1 5 1 70 2 0 7 10 0.0 0.0 160.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +61 1 1 0 26 2 31 1 1 2 6 2 71 2 0 8 10 0.0 0.0 161.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +62 1 1 0 27 1 32 1 1 3 7 1 72 2 0 9 10 0.0 0.0 162.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +63 1 1 0 28 2 33 1 1 1 8 2 73 2 0 10 10 0.0 0.0 163.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +64 1 1 0 29 1 34 1 1 2 1 1 74 2 0 11 10 0.0 0.0 164.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +65 1 1 0 30 2 35 1 1 7 3 2 2 75 2 0 12 10 0.0 0.0 165.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +66 1 1 0 31 1 36 1 1 1 3 1 76 2 0 13 10 0.0 0.0 166.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +67 1 1 0 32 2 37 1 1 2 4 2 77 2 0 14 10 0.0 0.0 167.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +68 1 1 0 33 1 38 1 1 3 5 1 78 2 0 15 10 0.0 0.0 168.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +69 1 1 0 34 2 39 1 1 1 6 2 79 2 0 16 10 0.0 0.0 169.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +70 1 1 0 35 1 40 1 1 7 2 7 1 80 2 0 17 10 0.0 0.0 170.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +71 1 1 0 36 2 41 1 1 3 8 2 81 2 0 18 10 0.0 0.0 171.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +72 1 1 0 37 1 42 1 1 1 1 1 82 2 0 1 10 0.0 0.0 172.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +73 1 1 0 38 2 43 1 1 2 2 2 83 2 0 2 10 0.0 0.0 173.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +74 1 1 0 39 1 44 1 1 3 3 1 84 2 0 3 10 0.0 0.0 174.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +75 1 1 0 40 2 20 1 1 7 1 4 2 85 2 0 4 10 0.0 0.0 175.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +76 1 1 0 41 1 21 1 1 2 5 1 86 2 0 5 10 0.0 0.0 176.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +77 1 1 0 42 2 22 1 1 3 6 2 87 2 0 6 10 0.0 0.0 177.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +78 1 1 0 43 1 23 1 1 1 7 1 88 2 0 7 10 0.0 0.0 178.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +79 1 1 0 44 2 24 1 1 2 8 2 89 2 0 8 10 0.0 0.0 179.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +80 1 1 0 45 1 25 1 1 7 3 1 1 10 2 0 9 10 0.0 0.0 180.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +81 1 1 0 46 2 26 1 1 1 2 2 11 2 0 10 10 0.0 0.0 181.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +82 1 1 0 47 1 27 1 1 2 3 1 12 2 0 11 10 0.0 0.0 182.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +83 1 1 0 48 2 28 1 1 3 4 2 13 2 0 12 10 0.0 0.0 183.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +84 1 1 0 49 1 29 1 1 1 5 1 14 2 0 13 10 0.0 0.0 184.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +85 1 1 0 50 2 30 1 1 7 2 6 2 15 2 0 14 10 0.0 0.0 185.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +86 1 1 0 51 1 31 1 1 3 7 1 16 2 0 15 10 0.0 0.0 186.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +87 1 1 0 52 2 32 1 1 1 8 2 17 2 0 16 10 0.0 0.0 187.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +88 1 1 0 53 1 33 1 1 2 1 1 18 2 0 17 10 0.0 0.0 188.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +89 1 1 0 54 2 34 1 1 3 2 2 19 2 0 18 10 0.0 0.0 189.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +90 1 1 0 55 1 35 1 1 7 1 3 1 20 2 0 1 10 0.0 0.0 190.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +91 1 1 0 56 2 36 1 1 2 4 2 21 2 0 2 10 0.0 0.0 191.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +92 1 1 0 57 1 37 1 1 3 5 1 22 2 0 3 10 0.0 0.0 192.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +93 1 1 0 58 2 38 1 1 1 6 2 23 2 0 4 10 0.0 0.0 193.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +94 1 1 0 59 1 39 1 1 2 7 1 24 2 0 5 10 0.0 0.0 194.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +95 1 1 0 60 2 40 1 1 7 3 8 2 25 2 0 6 10 0.0 0.0 195.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +96 1 1 0 61 1 41 1 1 1 1 1 26 2 0 7 10 0.0 0.0 196.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +97 1 1 0 62 2 42 1 1 2 2 2 27 2 0 8 10 0.0 0.0 197.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +98 1 1 0 63 1 43 1 1 3 3 1 28 2 0 9 10 0.0 0.0 198.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +99 1 1 0 64 2 44 1 1 1 4 2 29 2 0 10 10 0.0 0.0 199.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +100 1 1 0 65 1 20 1 1 7 2 5 1 30 2 0 11 10 0.0 0.0 200.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +101 1 1 0 66 2 21 1 1 3 6 2 31 2 0 12 10 0.0 0.0 201.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +102 1 1 0 67 1 22 1 1 1 7 1 32 2 0 13 10 0.0 0.0 202.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +103 1 1 0 68 2 23 1 1 2 8 2 33 2 0 14 10 0.0 0.0 203.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +104 1 1 0 69 1 24 1 1 3 1 1 34 2 0 15 10 0.0 0.0 204.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +105 1 1 0 70 2 25 1 1 7 1 2 2 35 2 0 16 10 0.0 0.0 205.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +106 1 1 0 71 1 26 1 1 2 3 1 36 2 0 17 10 0.0 0.0 206.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +107 1 1 0 72 2 27 1 1 3 4 2 37 2 0 18 10 0.0 0.0 207.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +108 1 1 0 73 1 28 1 1 1 5 1 38 2 0 1 10 0.0 0.0 208.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +109 1 1 0 74 2 29 1 1 2 6 2 39 2 0 2 10 0.0 0.0 209.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +110 1 1 0 20 1 30 1 1 7 3 7 1 40 2 0 3 10 0.0 0.0 210.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +111 1 1 0 21 2 31 1 1 1 8 2 41 2 0 4 10 0.0 0.0 211.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +112 1 1 0 22 1 32 1 1 2 1 1 42 2 0 5 10 0.0 0.0 212.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +113 1 1 0 23 2 33 1 1 3 2 2 43 2 0 6 10 0.0 0.0 213.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +114 1 1 0 24 1 34 1 1 1 3 1 44 2 0 7 10 0.0 0.0 214.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +115 1 1 0 25 2 35 1 1 7 2 4 2 45 2 0 8 10 0.0 0.0 215.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +116 1 1 0 26 1 36 1 1 3 5 1 46 2 0 9 10 0.0 0.0 216.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +117 1 1 0 27 2 37 1 1 1 6 2 47 2 0 10 10 0.0 0.0 217.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +118 1 1 0 28 1 38 1 1 2 7 1 48 2 0 11 10 0.0 0.0 218.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +119 1 1 0 29 2 39 1 1 3 8 2 49 2 0 12 10 0.0 0.0 219.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +120 1 1 0 30 1 40 1 1 7 1 1 1 50 2 0 13 10 0.0 0.0 220.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +121 1 1 0 31 2 41 1 1 2 2 2 51 2 0 14 10 0.0 0.0 221.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +122 1 1 0 32 1 42 1 1 3 3 1 52 2 0 15 10 0.0 0.0 222.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +123 1 1 0 33 2 43 1 1 1 4 2 53 2 0 16 10 0.0 0.0 223.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +124 1 1 0 34 1 44 1 1 2 5 1 54 2 0 17 10 0.0 0.0 224.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +125 1 1 0 35 2 20 1 1 7 3 6 2 55 2 0 18 10 0.0 0.0 225.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +126 1 1 0 36 1 21 1 1 1 7 1 56 2 0 1 10 0.0 0.0 226.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +127 1 1 0 37 2 22 1 1 2 8 2 57 2 0 2 10 0.0 0.0 227.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +128 1 1 0 38 1 23 1 1 3 1 1 58 2 0 3 10 0.0 0.0 228.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +129 1 1 0 39 2 24 1 1 1 2 2 59 2 0 4 10 0.0 0.0 229.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +130 1 1 0 40 1 25 1 1 7 2 3 1 60 2 0 5 10 0.0 0.0 230.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +131 1 1 0 41 2 26 1 1 3 4 2 61 2 0 6 10 0.0 0.0 231.0 1.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +132 1 1 0 42 1 27 1 1 1 5 1 62 2 0 7 10 0.0 0.0 232.0 2.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +133 1 1 0 43 2 28 1 1 2 6 2 63 2 0 8 10 0.0 0.0 233.0 3.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +134 1 1 0 44 1 29 1 1 3 7 1 64 2 0 9 10 0.0 0.0 234.0 4.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 +135 1 1 0 45 2 30 1 1 7 1 8 2 65 2 0 10 10 0.0 0.0 235.0 0.0 2 1.0 2.0 1.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 20.0 2.0 1.0 0.5 500.0 1.0 2.0 3.0 5.0 diff --git a/packages/microcosm-graph/tests/fixtures/parity/uk_spine/sources/frs_raw/child.tab b/packages/microcosm-graph/tests/fixtures/parity/uk_spine/sources/frs_raw/child.tab index ae1b07c2e..f2c60ca0b 100644 --- a/packages/microcosm-graph/tests/fixtures/parity/uk_spine/sources/frs_raw/child.tab +++ b/packages/microcosm-graph/tests/fixtures/parity/uk_spine/sources/frs_raw/child.tab @@ -1,28 +1,28 @@ -SERNUM BENUNIT PERSON AGE80 AGE SEX TOTHOURS HRPID UPERSON MARITAL FTED TYPEED2 EDUCQUAL TRAIN EMAAMT CHEMAAMT FSMVAL FSFVVAL FSBVAL HEARTVAL -5 1 2 0 13 2 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -10 1 2 0 10 1 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -15 1 2 0 15 2 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -20 1 2 0 12 1 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -25 1 2 0 9 2 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -30 1 2 0 14 1 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -35 1 2 0 11 2 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -40 1 2 0 8 1 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -45 1 2 0 13 2 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -50 1 2 0 10 1 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -55 1 2 0 15 2 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -60 1 2 0 12 1 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -65 1 2 0 9 2 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -70 1 2 0 14 1 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -75 1 2 0 11 2 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -80 1 2 0 8 1 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -85 1 2 0 13 2 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -90 1 2 0 10 1 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -95 1 2 0 15 2 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -100 1 2 0 12 1 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -105 1 2 0 9 2 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -110 1 2 0 14 1 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -115 1 2 0 11 2 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -120 1 2 0 8 1 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -125 1 2 0 13 2 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -130 1 2 0 10 1 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 -135 1 2 0 15 2 0 0 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +SERNUM BENUNIT PERSON AGE80 AGE SEX TOTHOURS HRPID UPERSON RELHRP R01 R02 R03 R04 R05 R06 R07 R08 R09 R10 R11 R12 R13 R14 MARITAL FTED TYPEED2 EDUCQUAL TRAIN EMAAMT CHEMAAMT FSMVAL FSFVVAL FSBVAL HEARTVAL +5 1 2 0 13 2 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +10 1 2 0 10 1 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +15 1 2 0 15 2 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +20 1 2 0 12 1 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +25 1 2 0 9 2 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +30 1 2 0 14 1 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +35 1 2 0 11 2 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +40 1 2 0 8 1 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +45 1 2 0 13 2 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +50 1 2 0 10 1 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +55 1 2 0 15 2 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +60 1 2 0 12 1 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +65 1 2 0 9 2 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +70 1 2 0 14 1 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +75 1 2 0 11 2 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +80 1 2 0 8 1 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +85 1 2 0 13 2 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +90 1 2 0 10 1 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +95 1 2 0 15 2 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +100 1 2 0 12 1 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +105 1 2 0 9 2 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +110 1 2 0 14 1 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +115 1 2 0 11 2 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +120 1 2 0 8 1 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +125 1 2 0 13 2 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +130 1 2 0 10 1 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 +135 1 2 0 15 2 0 0 3 3 2 1 2 86 9 0.0 1.0 3.0 1.0 2.0 4.0 diff --git a/packages/microcosm-graph/tests/fixtures/parity/uk_spine/sources/frs_raw/househol.tab b/packages/microcosm-graph/tests/fixtures/parity/uk_spine/sources/frs_raw/househol.tab index d23e625c1..2a4c08784 100644 --- a/packages/microcosm-graph/tests/fixtures/parity/uk_spine/sources/frs_raw/househol.tab +++ b/packages/microcosm-graph/tests/fixtures/parity/uk_spine/sources/frs_raw/househol.tab @@ -1,136 +1,136 @@ -SERNUM GROSS4 GVTREGNO PTENTYP2 TYPEACC BEDROOM6 CTANNUAL CTBAND CTREBAMT ADULTH CSEWAMT CWATAMTD CWATAMT1 CSEWAMT1 WATSEWRT NIRATLIA RT2REBAM HHRENT SUBRENT TENTYP2 MORTINT STRUINS CHRGAMT1 CHRGAMT2 CHRGAMT3 CHRGAMT4 CHRGAMT5 CHRGAMT6 CHRGAMT7 CHRGAMT8 CHRGAMT9 -1 1.01 11 6 2 2 910.0 2 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -2 1.02 12 5 3 3 920.0 3 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -3 1.03 1 6 4 4 930.0 4 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -4 1.04 8 5 1 1 940.0 5 1.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -5 1.05 11 6 2 2 950.0 6 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -6 1.06 12 5 3 3 960.0 7 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -7 1.07 1 6 4 4 970.0 1 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -8 1.08 8 5 1 1 980.0 2 2.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -9 1.09 11 6 2 2 990.0 3 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -10 1.1 12 5 3 3 1000.0 4 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -11 1.11 1 6 4 4 1010.0 5 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -12 1.12 8 5 1 1 1020.0 6 0.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -13 1.13 11 6 2 2 1030.0 7 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -14 1.1400000000000001 12 5 3 3 1040.0 1 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -15 1.15 1 6 4 4 1050.0 2 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -16 1.16 8 5 1 1 1060.0 3 1.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -17 1.17 11 6 2 2 1070.0 4 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -18 1.18 12 5 3 3 1080.0 5 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -19 1.19 1 6 4 4 1090.0 6 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -20 1.2 8 5 1 1 1100.0 7 2.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -21 1.21 11 6 2 2 1110.0 1 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -22 1.22 12 5 3 3 1120.0 2 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -23 1.23 1 6 4 4 1130.0 3 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -24 1.24 8 5 1 1 1140.0 4 0.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -25 1.25 11 6 2 2 1150.0 5 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -26 1.26 12 5 3 3 1160.0 6 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -27 1.27 1 6 4 4 1170.0 7 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -28 1.28 8 5 1 1 1180.0 1 1.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -29 1.29 11 6 2 2 1190.0 2 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -30 1.3 12 5 3 3 1200.0 3 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -31 1.31 1 6 4 4 1210.0 4 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -32 1.32 8 5 1 1 1220.0 5 2.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -33 1.33 11 6 2 2 1230.0 6 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -34 1.34 12 5 3 3 1240.0 7 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -35 1.35 1 6 4 4 1250.0 1 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -36 1.3599999999999999 8 5 1 1 1260.0 2 0.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -37 1.37 11 6 2 2 1270.0 3 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -38 1.38 12 5 3 3 1280.0 4 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -39 1.3900000000000001 1 6 4 4 1290.0 5 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -40 1.4 8 5 1 1 1300.0 6 1.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -41 1.41 11 6 2 2 1310.0 7 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -42 1.42 12 5 3 3 1320.0 1 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -43 1.43 1 6 4 4 1330.0 2 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -44 1.44 8 5 1 1 1340.0 3 2.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -45 1.45 11 6 2 2 1350.0 4 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -46 1.46 12 5 3 3 1360.0 5 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -47 1.47 1 6 4 4 1370.0 6 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -48 1.48 8 5 1 1 1380.0 7 0.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -49 1.49 11 6 2 2 1390.0 1 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -50 1.5 12 5 3 3 1400.0 2 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -51 1.51 1 6 4 4 1410.0 3 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -52 1.52 8 5 1 1 1420.0 4 1.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -53 1.53 11 6 2 2 1430.0 5 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -54 1.54 12 5 3 3 1440.0 6 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -55 1.55 1 6 4 4 1450.0 7 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -56 1.56 8 5 1 1 1460.0 1 2.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -57 1.5699999999999998 11 6 2 2 1470.0 2 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -58 1.58 12 5 3 3 1480.0 3 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -59 1.5899999999999999 1 6 4 4 1490.0 4 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -60 1.6 8 5 1 1 1500.0 5 0.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -61 1.6099999999999999 11 6 2 2 1510.0 6 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -62 1.62 12 5 3 3 1520.0 7 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -63 1.63 1 6 4 4 1530.0 1 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -64 1.6400000000000001 8 5 1 1 1540.0 2 1.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -65 1.65 11 6 2 2 1550.0 3 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -66 1.6600000000000001 12 5 3 3 1560.0 4 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -67 1.67 1 6 4 4 1570.0 5 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -68 1.6800000000000002 8 5 1 1 1580.0 6 2.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -69 1.69 11 6 2 2 1590.0 7 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -70 1.7 12 5 3 3 1600.0 1 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -71 1.71 1 6 4 4 1610.0 2 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -72 1.72 8 5 1 1 1620.0 3 0.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -73 1.73 11 6 2 2 1630.0 4 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -74 1.74 12 5 3 3 1640.0 5 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -75 1.75 1 6 4 4 1650.0 6 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -76 1.76 8 5 1 1 1660.0 7 1.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -77 1.77 11 6 2 2 1670.0 1 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -78 1.78 12 5 3 3 1680.0 2 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -79 1.79 1 6 4 4 1690.0 3 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -80 1.8 8 5 1 1 1700.0 4 2.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -81 1.81 11 6 2 2 1710.0 5 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -82 1.8199999999999998 12 5 3 3 1720.0 6 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -83 1.83 1 6 4 4 1730.0 7 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -84 1.8399999999999999 8 5 1 1 1740.0 1 0.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -85 1.85 11 6 2 2 1750.0 2 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -86 1.8599999999999999 12 5 3 3 1760.0 3 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -87 1.87 1 6 4 4 1770.0 4 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -88 1.88 8 5 1 1 1780.0 5 1.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -89 1.8900000000000001 11 6 2 2 1790.0 6 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -90 1.9 12 5 3 3 1800.0 7 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -91 1.9100000000000001 1 6 4 4 1810.0 1 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -92 1.92 8 5 1 1 1820.0 2 2.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -93 1.9300000000000002 11 6 2 2 1830.0 3 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -94 1.94 12 5 3 3 1840.0 4 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -95 1.95 1 6 4 4 1850.0 5 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -96 1.96 8 5 1 1 1860.0 6 0.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -97 1.97 11 6 2 2 1870.0 7 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -98 1.98 12 5 3 3 1880.0 1 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -99 1.99 1 6 4 4 1890.0 2 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -100 2.0 8 5 1 1 1900.0 3 1.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -101 2.01 11 6 2 2 1910.0 4 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -102 2.02 12 5 3 3 1920.0 5 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -103 2.0300000000000002 1 6 4 4 1930.0 6 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -104 2.04 8 5 1 1 1940.0 7 2.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -105 2.05 11 6 2 2 1950.0 1 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -106 2.06 12 5 3 3 1960.0 2 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -107 2.0700000000000003 1 6 4 4 1970.0 3 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -108 2.08 8 5 1 1 1980.0 4 0.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -109 2.09 11 6 2 2 1990.0 5 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -110 2.1 12 5 3 3 2000.0 6 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -111 2.1100000000000003 1 6 4 4 2010.0 7 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -112 2.12 8 5 1 1 2020.0 1 1.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -113 2.13 11 6 2 2 2030.0 2 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -114 2.1399999999999997 12 5 3 3 2040.0 3 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -115 2.15 1 6 4 4 2050.0 4 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -116 2.16 8 5 1 1 2060.0 5 2.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -117 2.17 11 6 2 2 2070.0 6 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -118 2.1799999999999997 12 5 3 3 2080.0 7 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -119 2.19 1 6 4 4 2090.0 1 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -120 2.2 8 5 1 1 2100.0 2 0.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -121 2.21 11 6 2 2 2110.0 3 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -122 2.2199999999999998 12 5 3 3 2120.0 4 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -123 2.23 1 6 4 4 2130.0 5 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -124 2.24 8 5 1 1 2140.0 6 1.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -125 2.25 11 6 2 2 2150.0 7 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -126 2.26 12 5 3 3 2160.0 1 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -127 2.27 1 6 4 4 2170.0 2 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -128 2.2800000000000002 8 5 1 1 2180.0 3 2.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -129 2.29 11 6 2 2 2190.0 4 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -130 2.3 12 5 3 3 2200.0 5 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -131 2.31 1 6 4 4 2210.0 6 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -132 2.3200000000000003 8 5 1 1 2220.0 7 0.0 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -133 2.33 11 6 2 2 2230.0 1 1.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -134 2.34 12 5 3 3 2240.0 2 2.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 -135 2.35 1 6 4 4 2250.0 3 0.0 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +SERNUM GROSS4 GVTREGNO PTENTYP2 TYPEACC BEDROOM6 CTANNUAL CTBAND CTREBAMT ADULTH HRPNUM CSEWAMT CWATAMTD CWATAMT1 CSEWAMT1 WATSEWRT NIRATLIA RT2REBAM HHRENT SUBRENT TENTYP2 MORTINT STRUINS CHRGAMT1 CHRGAMT2 CHRGAMT3 CHRGAMT4 CHRGAMT5 CHRGAMT6 CHRGAMT7 CHRGAMT8 CHRGAMT9 +1 1.01 11 6 2 2 910.0 2 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +2 1.02 12 5 3 3 920.0 3 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +3 1.03 1 6 4 4 930.0 4 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +4 1.04 8 5 1 1 940.0 5 1.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +5 1.05 11 6 2 2 950.0 6 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +6 1.06 12 5 3 3 960.0 7 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +7 1.07 1 6 4 4 970.0 1 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +8 1.08 8 5 1 1 980.0 2 2.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +9 1.09 11 6 2 2 990.0 3 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +10 1.1 12 5 3 3 1000.0 4 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +11 1.11 1 6 4 4 1010.0 5 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +12 1.12 8 5 1 1 1020.0 6 0.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +13 1.13 11 6 2 2 1030.0 7 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +14 1.1400000000000001 12 5 3 3 1040.0 1 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +15 1.15 1 6 4 4 1050.0 2 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +16 1.16 8 5 1 1 1060.0 3 1.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +17 1.17 11 6 2 2 1070.0 4 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +18 1.18 12 5 3 3 1080.0 5 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +19 1.19 1 6 4 4 1090.0 6 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +20 1.2 8 5 1 1 1100.0 7 2.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +21 1.21 11 6 2 2 1110.0 1 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +22 1.22 12 5 3 3 1120.0 2 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +23 1.23 1 6 4 4 1130.0 3 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +24 1.24 8 5 1 1 1140.0 4 0.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +25 1.25 11 6 2 2 1150.0 5 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +26 1.26 12 5 3 3 1160.0 6 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +27 1.27 1 6 4 4 1170.0 7 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +28 1.28 8 5 1 1 1180.0 1 1.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +29 1.29 11 6 2 2 1190.0 2 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +30 1.3 12 5 3 3 1200.0 3 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +31 1.31 1 6 4 4 1210.0 4 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +32 1.32 8 5 1 1 1220.0 5 2.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +33 1.33 11 6 2 2 1230.0 6 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +34 1.34 12 5 3 3 1240.0 7 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +35 1.35 1 6 4 4 1250.0 1 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +36 1.3599999999999999 8 5 1 1 1260.0 2 0.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +37 1.37 11 6 2 2 1270.0 3 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +38 1.38 12 5 3 3 1280.0 4 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +39 1.3900000000000001 1 6 4 4 1290.0 5 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +40 1.4 8 5 1 1 1300.0 6 1.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +41 1.41 11 6 2 2 1310.0 7 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +42 1.42 12 5 3 3 1320.0 1 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +43 1.43 1 6 4 4 1330.0 2 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +44 1.44 8 5 1 1 1340.0 3 2.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +45 1.45 11 6 2 2 1350.0 4 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +46 1.46 12 5 3 3 1360.0 5 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +47 1.47 1 6 4 4 1370.0 6 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +48 1.48 8 5 1 1 1380.0 7 0.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +49 1.49 11 6 2 2 1390.0 1 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +50 1.5 12 5 3 3 1400.0 2 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +51 1.51 1 6 4 4 1410.0 3 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +52 1.52 8 5 1 1 1420.0 4 1.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +53 1.53 11 6 2 2 1430.0 5 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +54 1.54 12 5 3 3 1440.0 6 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +55 1.55 1 6 4 4 1450.0 7 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +56 1.56 8 5 1 1 1460.0 1 2.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +57 1.5699999999999998 11 6 2 2 1470.0 2 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +58 1.58 12 5 3 3 1480.0 3 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +59 1.5899999999999999 1 6 4 4 1490.0 4 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +60 1.6 8 5 1 1 1500.0 5 0.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +61 1.6099999999999999 11 6 2 2 1510.0 6 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +62 1.62 12 5 3 3 1520.0 7 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +63 1.63 1 6 4 4 1530.0 1 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +64 1.6400000000000001 8 5 1 1 1540.0 2 1.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +65 1.65 11 6 2 2 1550.0 3 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +66 1.6600000000000001 12 5 3 3 1560.0 4 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +67 1.67 1 6 4 4 1570.0 5 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +68 1.6800000000000002 8 5 1 1 1580.0 6 2.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +69 1.69 11 6 2 2 1590.0 7 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +70 1.7 12 5 3 3 1600.0 1 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +71 1.71 1 6 4 4 1610.0 2 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +72 1.72 8 5 1 1 1620.0 3 0.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +73 1.73 11 6 2 2 1630.0 4 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +74 1.74 12 5 3 3 1640.0 5 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +75 1.75 1 6 4 4 1650.0 6 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +76 1.76 8 5 1 1 1660.0 7 1.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +77 1.77 11 6 2 2 1670.0 1 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +78 1.78 12 5 3 3 1680.0 2 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +79 1.79 1 6 4 4 1690.0 3 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +80 1.8 8 5 1 1 1700.0 4 2.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +81 1.81 11 6 2 2 1710.0 5 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +82 1.8199999999999998 12 5 3 3 1720.0 6 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +83 1.83 1 6 4 4 1730.0 7 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +84 1.8399999999999999 8 5 1 1 1740.0 1 0.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +85 1.85 11 6 2 2 1750.0 2 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +86 1.8599999999999999 12 5 3 3 1760.0 3 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +87 1.87 1 6 4 4 1770.0 4 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +88 1.88 8 5 1 1 1780.0 5 1.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +89 1.8900000000000001 11 6 2 2 1790.0 6 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +90 1.9 12 5 3 3 1800.0 7 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +91 1.9100000000000001 1 6 4 4 1810.0 1 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +92 1.92 8 5 1 1 1820.0 2 2.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +93 1.9300000000000002 11 6 2 2 1830.0 3 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +94 1.94 12 5 3 3 1840.0 4 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +95 1.95 1 6 4 4 1850.0 5 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +96 1.96 8 5 1 1 1860.0 6 0.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +97 1.97 11 6 2 2 1870.0 7 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +98 1.98 12 5 3 3 1880.0 1 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +99 1.99 1 6 4 4 1890.0 2 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +100 2.0 8 5 1 1 1900.0 3 1.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +101 2.01 11 6 2 2 1910.0 4 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +102 2.02 12 5 3 3 1920.0 5 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +103 2.0300000000000002 1 6 4 4 1930.0 6 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +104 2.04 8 5 1 1 1940.0 7 2.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +105 2.05 11 6 2 2 1950.0 1 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +106 2.06 12 5 3 3 1960.0 2 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +107 2.0700000000000003 1 6 4 4 1970.0 3 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +108 2.08 8 5 1 1 1980.0 4 0.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +109 2.09 11 6 2 2 1990.0 5 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +110 2.1 12 5 3 3 2000.0 6 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +111 2.1100000000000003 1 6 4 4 2010.0 7 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +112 2.12 8 5 1 1 2020.0 1 1.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +113 2.13 11 6 2 2 2030.0 2 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +114 2.1399999999999997 12 5 3 3 2040.0 3 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +115 2.15 1 6 4 4 2050.0 4 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +116 2.16 8 5 1 1 2060.0 5 2.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +117 2.17 11 6 2 2 2070.0 6 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +118 2.1799999999999997 12 5 3 3 2080.0 7 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +119 2.19 1 6 4 4 2090.0 1 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +120 2.2 8 5 1 1 2100.0 2 0.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +121 2.21 11 6 2 2 2110.0 3 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +122 2.2199999999999998 12 5 3 3 2120.0 4 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +123 2.23 1 6 4 4 2130.0 5 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +124 2.24 8 5 1 1 2140.0 6 1.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +125 2.25 11 6 2 2 2150.0 7 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +126 2.26 12 5 3 3 2160.0 1 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +127 2.27 1 6 4 4 2170.0 2 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +128 2.2800000000000002 8 5 1 1 2180.0 3 2.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +129 2.29 11 6 2 2 2190.0 4 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +130 2.3 12 5 3 3 2200.0 5 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +131 2.31 1 6 4 4 2210.0 6 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +132 2.3200000000000003 8 5 1 1 2220.0 7 0.0 1 1 0.0 4.0 5.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +133 2.33 11 6 2 2 2230.0 1 1.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +134 2.34 12 5 3 3 2240.0 2 2.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 +135 2.35 1 6 4 4 2250.0 3 0.0 1 1 0.0 3.0 0.0 0.0 5.0 0.0 5 7.0 8.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 diff --git a/packages/microcosm-graph/tests/fixtures/parity/uk_spine/uk_spine.json b/packages/microcosm-graph/tests/fixtures/parity/uk_spine/uk_spine.json index 1a3698802..038de62e0 100644 --- a/packages/microcosm-graph/tests/fixtures/parity/uk_spine/uk_spine.json +++ b/packages/microcosm-graph/tests/fixtures/parity/uk_spine/uk_spine.json @@ -1 +1 @@ -{"country":"uk","nodes":[{"base":null,"citation":"","description":"Load the source-bound UK FRS root population.","id":"create_uk_frs","inputs":[],"kernel":"uk.create@1","mass":"conserve","outputs":[{"column":"age","dtype":"int64","entity":"person","ownership":"produced","rows":"all"},{"column":"gender","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"marital_status","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"hours_worked","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"is_household_head","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"is_benunit_head","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"is_parent","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"is_uc_claimant","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"employment_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"self_employment_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"private_pension_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"tax_free_savings_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"savings_interest_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"dividend_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"property_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"maintenance_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"miscellaneous_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"private_transfer_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"lump_sum_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"student_loan_repayments","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"statutory_sick_pay","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"statutory_maternity_pay","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"student_loans","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"access_fund","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"education_grants","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"healthy_start_vouchers","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"free_school_breakfasts","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"free_school_fruit_veg","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"free_school_meals","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"council_tax_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"maintenance_expenses","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"childcare_expenses","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"personal_pension_contributions","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"employee_pension_contributions","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"pension_contributions_via_salary_sacrifice","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"salary_sacrifice_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"salary_sacrifice_asked","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"child_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"income_support_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"housing_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"attendance_allowance_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"dla_sc_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"dla_m_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"iidb_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"carers_allowance_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"sda_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"afcs_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"ssmg_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"pension_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"child_tax_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"working_tax_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"state_pension_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"winter_fuel_allowance_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"incapacity_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"universal_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"pip_m_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"pip_dl_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"jsa_contrib_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"jsa_income_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"esa_contrib_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"esa_income_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"bsp_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"frs_benunit_capital","dtype":"float64","entity":"benunit","ownership":"produced","rows":"all"},{"column":"is_married","dtype":"bool","entity":"benunit","ownership":"produced","rows":"all"},{"column":"dependent_children","dtype":"int64","entity":"benunit","ownership":"produced","rows":"all"},{"column":"region","dtype":"string","entity":"household","ownership":"produced","rows":"all"},{"column":"tenure_type","dtype":"string","entity":"household","ownership":"produced","rows":"all"},{"column":"accommodation_type","dtype":"string","entity":"household","ownership":"produced","rows":"all"},{"column":"num_bedrooms","dtype":"int64","entity":"household","ownership":"produced","rows":"all"},{"column":"council_tax_reported","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"council_tax_band","dtype":"string","entity":"household","ownership":"produced","rows":"all"},{"column":"council_tax_rebate","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"council_tax_single_adult_raw","dtype":"int64","entity":"household","ownership":"produced","rows":"all"},{"column":"water_and_sewerage_charges","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"domestic_rates","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"rent","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"subrent","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"mortgage_interest_repayment","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"mortgage_capital_repayment","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"structural_insurance_payments","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"housing_service_charges","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"external_child_payments","dtype":"float64","entity":"household","ownership":"produced","rows":"all"}],"params":{"sample_fraction":1.0,"sample_seed":578,"stage_contract_sha256":"7ed918cd9dfa27874110bececf0c2513e7348df10b79ed55ea432e0e9ed70f3f","time_period":"2024"},"population":null,"sources":["frs"],"structural":"create","weights":null},{"base":"create_uk_frs","citation":"","description":"Ownership boundary for the source-assembling root stage.","id":"frs_spine.boundary","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported"],"entity":"person","rows":"all"}],"kernel":"uk.identity@1","mass":"conserve","outputs":[],"params":{},"population":null,"sources":[],"structural":"filter","weights":null},{"base":null,"citation":"","description":"Claim the cells assembled by the UK FRS root transform.","id":"frs_spine","inputs":[],"kernel":"uk.claim@1","mass":"conserve","outputs":[{"column":"age","dtype":"int64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"gender","dtype":"string","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"marital_status","dtype":"string","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"hours_worked","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"is_household_head","dtype":"bool","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"is_benunit_head","dtype":"bool","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"is_parent","dtype":"bool","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"is_uc_claimant","dtype":"bool","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"employment_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"self_employment_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"private_pension_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"tax_free_savings_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"savings_interest_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"dividend_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"property_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"maintenance_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"miscellaneous_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"private_transfer_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"lump_sum_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"student_loan_repayments","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"statutory_sick_pay","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"statutory_maternity_pay","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"student_loans","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"access_fund","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"education_grants","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"healthy_start_vouchers","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"free_school_breakfasts","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"free_school_fruit_veg","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"free_school_meals","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"council_tax_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"maintenance_expenses","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"childcare_expenses","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"personal_pension_contributions","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"employee_pension_contributions","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pension_contributions_via_salary_sacrifice","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"salary_sacrifice_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"salary_sacrifice_asked","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"child_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"income_support_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"housing_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"attendance_allowance_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"dla_sc_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"dla_m_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"iidb_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"carers_allowance_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"sda_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"afcs_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"ssmg_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pension_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"child_tax_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"working_tax_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"state_pension_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"winter_fuel_allowance_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"incapacity_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"universal_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pip_m_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pip_dl_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"jsa_contrib_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"jsa_income_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"esa_contrib_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"esa_income_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"bsp_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"frs_benunit_capital","dtype":"float64","entity":"benunit","ownership":"produced","rewrite":true,"rows":"all"},{"column":"is_married","dtype":"bool","entity":"benunit","ownership":"produced","rewrite":true,"rows":"all"},{"column":"dependent_children","dtype":"int64","entity":"benunit","ownership":"produced","rewrite":true,"rows":"all"},{"column":"region","dtype":"string","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"tenure_type","dtype":"string","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"accommodation_type","dtype":"string","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"num_bedrooms","dtype":"int64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"council_tax_reported","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"council_tax_band","dtype":"string","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"council_tax_rebate","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"council_tax_single_adult_raw","dtype":"int64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"water_and_sewerage_charges","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"domestic_rates","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"rent","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"subrent","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"mortgage_interest_repayment","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"mortgage_capital_repayment","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"structural_insurance_payments","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"housing_service_charges","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"external_child_payments","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"}],"params":{},"population":"frs_spine.boundary","sources":[],"structural":"none","weights":null},{"base":"frs_spine.boundary","citation":"","description":"Ownership boundary before age_tail rewrites.","id":"age_tail.boundary","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported"],"entity":"person","rows":"all"}],"kernel":"uk.identity@1","mass":"conserve","outputs":[],"params":{},"population":null,"sources":[],"structural":"filter","weights":null},{"base":null,"citation":"","description":"Run UK spine stage age_tail.","id":"age_tail","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["external_child_payments","region"],"entity":"household","rows":"all"},{"columns":["gender"],"entity":"person","rows":"all"}],"kernel":"uk.stage.age_tail@1","mass":"conserve","outputs":[{"column":"age","dtype":"int64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"}],"params":{"stage":"age_tail","stage_contract_sha256":"963a34f38caede2525e3b8735f904bb70a1bbef5a272f0eefd4346343444484f","time_period":"2024"},"population":"age_tail.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_employment.","id":"frs_employment","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_employment@1","mass":"conserve","outputs":[{"column":"employment_status","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"employment_sector","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"sic_industry_division","dtype":"int64","entity":"person","ownership":"produced","rows":"all"}],"params":{"stage":"frs_employment","stage_contract_sha256":"ddbefaf05b44788d794a6e4b0e8926c14318d66e50d2f11f50ca549538bbf60c","time_period":"2024"},"population":"age_tail.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_council_tax.","id":"frs_council_tax","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age","sic_industry_division"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_council_tax@1","mass":"conserve","outputs":[{"column":"council_tax","dtype":"float64","entity":"household","ownership":"produced","rows":"all"}],"params":{"stage":"frs_council_tax","stage_contract_sha256":"3381cd9f7a736514d5073c57480e07f5098890f3ca9ed3865392043594771eb9","time_period":"2024"},"population":"age_tail.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_disability.","id":"frs_disability","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["council_tax","region"],"entity":"household","rows":"all"},{"columns":["afcs_reported","age","attendance_allowance_reported","dla_m_reported","dla_sc_reported","esa_contrib_reported","esa_income_reported","iidb_reported","incapacity_benefit_reported","pip_dl_reported","pip_m_reported","sda_reported"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_disability@1","mass":"conserve","outputs":[{"column":"aa_category","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"dla_sc_category","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"dla_m_category","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"pip_m_category","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"pip_dl_category","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"is_disabled_for_benefits","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"is_enhanced_disabled_for_benefits","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"is_severely_disabled_for_benefits","dtype":"bool","entity":"person","ownership":"produced","rows":"all"}],"params":{"stage":"frs_disability","stage_contract_sha256":"ac500b4cb1bc04d4fb72d198592dd376d61da8c150921a6ac53914ac18be0508","time_period":"2024"},"population":"age_tail.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_education.","id":"frs_education","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age","esa_contrib_reported","esa_income_reported","is_severely_disabled_for_benefits","jsa_contrib_reported","jsa_income_reported","universal_credit_reported"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_education@1","mass":"conserve","outputs":[{"column":"current_education","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"highest_education","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"is_in_non_advanced_education","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"is_in_approved_training","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"age_started_or_accepted_current_education_or_training","dtype":"int64","entity":"person","ownership":"produced","rows":"all"},{"column":"is_before_universal_credit_qualifying_young_person_terminal_date","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"adult_ema","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"child_ema","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"receives_benefits_in_own_right","dtype":"bool","entity":"person","ownership":"produced","rows":"all"}],"params":{"stage":"frs_education","stage_contract_sha256":"836cb0f5a582fee1425190e96c9cb81bdef859bd236c8b6bc27660b6e3d0c2f8","time_period":"2024"},"population":"age_tail.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_legacy_proxies.","id":"frs_legacy_proxies","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","council_tax"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_legacy_proxies@1","mass":"conserve","outputs":[{"column":"legacy_jobseeker_proxy","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"esa_health_condition_proxy","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"esa_support_group_proxy","dtype":"bool","entity":"person","ownership":"produced","rows":"all"}],"params":{"stage":"frs_legacy_proxies","stage_contract_sha256":"1ecf761cf3fa7180da15659e138e67a8654e58272b4fde28344aa27a874ad0aa","time_period":"2024"},"population":"age_tail.boundary","sources":["frs"],"structural":"none","weights":null},{"base":"age_tail.boundary","citation":"","description":"Ownership boundary before frs_education_grant_split rewrites.","id":"frs_education_grant_split.boundary","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","council_tax"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy"],"entity":"person","rows":"all"}],"kernel":"uk.identity@1","mass":"conserve","outputs":[],"params":{},"population":null,"sources":[],"structural":"filter","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_education_grant_split.","id":"frs_education_grant_split","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","council_tax"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_education_grant_split@1","mass":"conserve","outputs":[{"column":"disabled_students_allowance_eligible_expenses","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"education_grants","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"}],"params":{"stage":"frs_education_grant_split","stage_contract_sha256":"8718f014b90498c2cc7c754289775ca4a41452d9b978d8cbc5f34b64cbdc7df2","time_period":"2024"},"population":"frs_education_grant_split.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_take_up.","id":"frs_take_up","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age","child_benefit_reported","education_grants","pension_credit_reported","universal_credit_reported"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_take_up@1","mass":"conserve","outputs":[{"column":"would_claim_child_benefit","dtype":"bool","entity":"benunit","ownership":"produced","rows":"all"},{"column":"child_benefit_opts_out","dtype":"bool","entity":"benunit","ownership":"produced","rows":"all"},{"column":"would_claim_pc","dtype":"bool","entity":"benunit","ownership":"produced","rows":"all"},{"column":"would_claim_uc","dtype":"bool","entity":"benunit","ownership":"produced","rows":"all"},{"column":"would_claim_tfc","dtype":"bool","entity":"benunit","ownership":"produced","rows":"all"},{"column":"would_claim_extended_childcare","dtype":"bool","entity":"benunit","ownership":"produced","rows":"all"},{"column":"would_claim_universal_childcare","dtype":"bool","entity":"benunit","ownership":"produced","rows":"all"},{"column":"would_claim_targeted_childcare","dtype":"bool","entity":"benunit","ownership":"produced","rows":"all"},{"column":"maximum_extended_childcare_hours_usage","dtype":"float64","entity":"benunit","ownership":"produced","rows":"all"}],"params":{"stage":"frs_take_up","stage_contract_sha256":"d10ca01bfa5d719640ded8e62196b0692236d3be0a2417899deeefd241088abf","time_period":"2024"},"population":"frs_education_grant_split.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_person_draws.","id":"frs_person_draws","inputs":[{"columns":["frs_benunit_capital","maximum_extended_childcare_hours_usage"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_person_draws@1","mass":"conserve","outputs":[{"column":"would_claim_marriage_allowance","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"would_claim_scp","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"attends_private_school_random_draw","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"tax_free_childcare_spend_routed_share","dtype":"float64","entity":"person","ownership":"produced","rows":"all"}],"params":{"stage":"frs_person_draws","stage_contract_sha256":"e87b779c3977aa520c298f9bca54b675a8cacb8baed0b58412a1f783b42968ff","time_period":"2024"},"population":"frs_education_grant_split.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_household_draws.","id":"frs_household_draws","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age","tax_free_childcare_spend_routed_share"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_household_draws@1","mass":"conserve","outputs":[{"column":"household_owns_tv","dtype":"bool","entity":"household","ownership":"produced","rows":"all"},{"column":"would_evade_tv_licence_fee","dtype":"bool","entity":"household","ownership":"produced","rows":"all"},{"column":"main_residential_property_purchased_is_first_home","dtype":"bool","entity":"household","ownership":"produced","rows":"all"},{"column":"property_purchased","dtype":"bool","entity":"household","ownership":"produced","rows":"all"}],"params":{"stage":"frs_household_draws","stage_contract_sha256":"c74c63b09264319c4bf0049dabba00ecd0ce660beb7b53d6dae71518434bc949","time_period":"2024"},"population":"frs_education_grant_split.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_brma.","id":"frs_brma","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_brma@1","mass":"conserve","outputs":[{"column":"brma","dtype":"string","entity":"household","ownership":"produced","rows":"all"}],"params":{"stage":"frs_brma","stage_contract_sha256":"5b8f0b361310c7cd3efbaae3762b347649b7d4afb9e9943131d9bef9266fc3c8","time_period":"2024"},"population":"frs_education_grant_split.boundary","sources":["frs"],"structural":"none","weights":null},{"base":"frs_education_grant_split.boundary","citation":"","description":"Freeze the assembled-spine gate population.","id":"frs_brma.checkpoint","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share"],"entity":"person","rows":"all"}],"kernel":"uk.identity@1","mass":"conserve","outputs":[],"params":{},"population":null,"sources":[],"structural":"filter","weights":null},{"base":null,"citation":"","description":"Run UK spine stage was_wealth.","id":"was_wealth","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share"],"entity":"person","rows":"all"}],"kernel":"uk.stage.was_wealth@1","mass":"conserve","outputs":[{"column":"owned_land","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"property_wealth","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"corporate_wealth","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"private_pension_wealth","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"gross_financial_wealth","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"net_financial_wealth","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"main_residence_value","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"other_residential_property_value","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"non_residential_property_value","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"savings","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"num_vehicles","dtype":"int64","entity":"household","ownership":"produced","rows":"all"},{"column":"cash_isa","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"stocks_and_shares_isa","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"mortgage_debt","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"consumer_debt","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"student_loan_balance","dtype":"float64","entity":"person","ownership":"produced","rows":"all"}],"params":{"stage":"was_wealth","stage_contract_sha256":"c499dcb7c49a0176229dbc363b400415cb5c1da44af266ba2155f9a62a0bd2ed","time_period":"2024"},"population":"frs_brma.checkpoint","sources":["frs"],"structural":"none","weights":null},{"base":"frs_brma.checkpoint","citation":"","description":"Ownership boundary before regional_property_uprating rewrites.","id":"regional_property_uprating.boundary","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance"],"entity":"person","rows":"all"}],"kernel":"uk.identity@1","mass":"conserve","outputs":[],"params":{},"population":null,"sources":[],"structural":"filter","weights":null},{"base":null,"citation":"","description":"Run UK spine stage regional_property_uprating.","id":"regional_property_uprating","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age","student_loan_balance"],"entity":"person","rows":"all"}],"kernel":"uk.stage.regional_property_uprating@1","mass":"conserve","outputs":[{"column":"main_residence_value","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"property_wealth","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"}],"params":{"stage":"regional_property_uprating","stage_contract_sha256":"4304356c6c5ba91a04883148cbf9078761ee926c8387aadb6c15b6b70ebb31f6","time_period":"2024"},"population":"regional_property_uprating.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage lcfs_consumption.","id":"lcfs_consumption","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance"],"entity":"person","rows":"all"}],"kernel":"uk.stage.lcfs_consumption@1","mass":"conserve","outputs":[{"column":"food_and_non_alcoholic_beverages_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"alcohol_and_tobacco_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"clothing_and_footwear_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"housing_water_and_electricity_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"household_furnishings_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"health_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"transport_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"communication_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"recreation_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"education_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"restaurants_and_hotels_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"miscellaneous_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"petrol_spending","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"diesel_spending","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"bus_fare_spending","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"domestic_energy_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"electricity_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"gas_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"has_fuel_consumption","dtype":"bool","entity":"household","ownership":"produced","rows":"all"}],"params":{"stage":"lcfs_consumption","stage_contract_sha256":"eb0a529c357c84290a001209a18c5a43b0a0310553c77963d6842fd0111b73ad","time_period":"2024"},"population":"regional_property_uprating.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage etb_vat.","id":"etb_vat","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance"],"entity":"person","rows":"all"}],"kernel":"uk.stage.etb_vat@1","mass":"conserve","outputs":[{"column":"full_rate_vat_expenditure_rate","dtype":"float64","entity":"household","ownership":"produced","rows":"all"}],"params":{"stage":"etb_vat","stage_contract_sha256":"99a6756256adfe8255672fafda89710c08ae56bd2b8f011b20c3b8381eabfa1e","time_period":"2024"},"population":"regional_property_uprating.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage etb_services.","id":"etb_services","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance"],"entity":"person","rows":"all"}],"kernel":"uk.stage.etb_services@1","mass":"conserve","outputs":[{"column":"dfe_education_spending","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"rail_subsidy_spending","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"bus_subsidy_spending","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"rail_usage","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"a_and_e_visits","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"admitted_patient_visits","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"outpatient_visits","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"nhs_a_and_e_spending","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"nhs_admitted_patient_spending","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"nhs_outpatient_spending","dtype":"float64","entity":"person","ownership":"produced","rows":"all"}],"params":{"stage":"etb_services","stage_contract_sha256":"48294c9d86dd422238a723aca5845e9ceb9eda2903a3bb87bb32a86092447e19","time_period":"2024"},"population":"regional_property_uprating.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_hmrc_spine_leaves.","id":"frs_hmrc_spine_leaves","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age","employee_pension_contributions","nhs_outpatient_spending"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_hmrc_spine_leaves@1","mass":"conserve","outputs":[{"column":"hmrc_spi_pay","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_unemployment_benefit_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_incapacity_benefit_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"ossben_identifiable_subset","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"srp_regular_code5","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"employer_pension_contributions","dtype":"float64","entity":"person","ownership":"produced","rows":"all"}],"params":{"stage":"frs_hmrc_spine_leaves","stage_contract_sha256":"2bb3d068003489b47cc8676ac26c203ce3c39a9b6e92f3ecd0a3c06acd6addc4","time_period":"2024"},"population":"regional_property_uprating.boundary","sources":["frs"],"structural":"none","weights":null},{"base":"regional_property_uprating.boundary","citation":"","description":"Run structural UK stage spi_support_channel.","id":"spi_support_channel","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate","dfe_education_spending","rail_subsidy_spending","bus_subsidy_spending","rail_usage"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance","a_and_e_visits","admitted_patient_visits","outpatient_visits","nhs_a_and_e_spending","nhs_admitted_patient_spending","nhs_outpatient_spending","hmrc_spi_pay","hmrc_spi_unemployment_benefit_income","hmrc_spi_incapacity_benefit_income","ossben_identifiable_subset","srp_regular_code5","employer_pension_contributions"],"entity":"person","rows":"all"}],"kernel":"uk.stage.expand.spi_support_channel@1","mass":"declared","outputs":[],"params":{"expand_cells":[["person","person_source_id","int64"],["person","person_support_channel","string"],["person","person_support_clone_index","int64"],["benunit","benunit_source_id","int64"],["benunit","benunit_support_channel","string"],["benunit","benunit_support_clone_index","int64"],["household","source_household_id","int64"],["household","source_year","int64"],["household","source_household_key","string"],["household","household_source_id","int64"],["household","household_support_channel","string"],["household","household_support_clone_index","int64"],["household","household_is_spi_synthetic","bool"]],"expand_weight_entity":"household","expand_weight_kind":"importance","stage":"spi_support_channel","stage_contract_sha256":"4b10f1a4a215cdf2c406c9974de2d1e580eb3cd3a25ed34973c1b63abf4a54bb","time_period":"2024"},"population":null,"sources":["frs"],"structural":"expand","weights":null},{"base":null,"citation":"","description":"Own the cells materialized by spi_support_channel.","id":"spi_support_channel.owned","inputs":[],"kernel":"uk.claim@1","mass":"conserve","outputs":[{"column":"person_source_id","dtype":"int64","entity":"person","ownership":"produced","rows":"all"},{"column":"person_support_channel","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"person_support_clone_index","dtype":"int64","entity":"person","ownership":"produced","rows":"all"},{"column":"benunit_source_id","dtype":"int64","entity":"benunit","ownership":"produced","rows":"all"},{"column":"benunit_support_channel","dtype":"string","entity":"benunit","ownership":"produced","rows":"all"},{"column":"benunit_support_clone_index","dtype":"int64","entity":"benunit","ownership":"produced","rows":"all"},{"column":"source_household_id","dtype":"int64","entity":"household","ownership":"produced","rows":"all"},{"column":"source_year","dtype":"int64","entity":"household","ownership":"produced","rows":"all"},{"column":"source_household_key","dtype":"string","entity":"household","ownership":"produced","rows":"all"},{"column":"household_source_id","dtype":"int64","entity":"household","ownership":"produced","rows":"all"},{"column":"household_support_channel","dtype":"string","entity":"household","ownership":"produced","rows":"all"},{"column":"household_support_clone_index","dtype":"int64","entity":"household","ownership":"produced","rows":"all"},{"column":"household_is_spi_synthetic","dtype":"bool","entity":"household","ownership":"produced","rows":"all"}],"params":{"materialized_expand_outputs":["person.person_source_id","person.person_support_channel","person.person_support_clone_index","benunit.benunit_source_id","benunit.benunit_support_channel","benunit.benunit_support_clone_index","household.source_household_id","household.source_year","household.source_household_key","household.household_source_id","household.household_support_channel","household.household_support_clone_index","household.household_is_spi_synthetic"]},"population":"spi_support_channel","sources":[],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage hmrc_spi_income_spine.","id":"hmrc_spi_income_spine","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage","benunit_source_id","benunit_support_channel","benunit_support_clone_index"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate","dfe_education_spending","rail_subsidy_spending","bus_subsidy_spending","rail_usage","source_household_id","source_year","source_household_key","household_source_id","household_support_channel","household_support_clone_index","household_is_spi_synthetic"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","maintenance_expenses","childcare_expenses","salary_sacrifice_reported","salary_sacrifice_asked","ssmg_reported","incapacity_benefit_reported","employment_status","employment_sector","sic_industry_division","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance","a_and_e_visits","admitted_patient_visits","outpatient_visits","nhs_a_and_e_spending","nhs_admitted_patient_spending","nhs_outpatient_spending","ossben_identifiable_subset","srp_regular_code5","person_source_id","person_support_channel","person_support_clone_index"],"entity":"person","rows":"all"}],"kernel":"uk.stage.hmrc_spi_income_spine@1","mass":"conserve","outputs":[{"column":"charitable_investment_gifts","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"gift_aid","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"other_investment_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_employment_benefits","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_employment_expenses","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_other_social_security_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_taxable_termination_pay","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_miscellaneous_employment_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_other_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_state_pension_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_employed_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_total_earned_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_total_investment_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_assessable_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"employment_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"self_employment_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"savings_interest_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"dividend_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"private_pension_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"property_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"employee_pension_contributions","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"employer_pension_contributions","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"personal_pension_contributions","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pension_contributions_via_salary_sacrifice","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"tax_free_savings_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"universal_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pension_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"child_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"housing_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"income_support_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"working_tax_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"child_tax_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"attendance_allowance_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"state_pension_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"dla_sc_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"dla_m_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pip_m_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pip_dl_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"sda_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"carers_allowance_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"iidb_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"afcs_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"bsp_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"winter_fuel_allowance_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"council_tax_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"jsa_contrib_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"jsa_income_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"esa_contrib_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"esa_income_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"hmrc_spi_pay","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"hmrc_spi_unemployment_benefit_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"hmrc_spi_incapacity_benefit_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"aa_category","dtype":"string","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"dla_sc_category","dtype":"string","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"dla_m_category","dtype":"string","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pip_m_category","dtype":"string","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pip_dl_category","dtype":"string","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"is_disabled_for_benefits","dtype":"bool","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"is_enhanced_disabled_for_benefits","dtype":"bool","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"is_severely_disabled_for_benefits","dtype":"bool","entity":"person","ownership":"produced","rewrite":true,"rows":"all"}],"params":{"stage":"hmrc_spi_income_spine","stage_contract_sha256":"4c2edca1f77416a00cff10c7e9d0a9da50e332a2bb6a995ef9ac1bdd00ff97a9","time_period":"2024"},"population":"spi_support_channel","sources":["frs"],"structural":"none","weights":null},{"base":"spi_support_channel","citation":"","description":"Ownership boundary before uc_reporter_redraw rewrites.","id":"uc_reporter_redraw.boundary","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage","benunit_source_id","benunit_support_channel","benunit_support_clone_index"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate","dfe_education_spending","rail_subsidy_spending","bus_subsidy_spending","rail_usage","source_household_id","source_year","source_household_key","household_source_id","household_support_channel","household_support_clone_index","household_is_spi_synthetic"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance","a_and_e_visits","admitted_patient_visits","outpatient_visits","nhs_a_and_e_spending","nhs_admitted_patient_spending","nhs_outpatient_spending","hmrc_spi_pay","hmrc_spi_unemployment_benefit_income","hmrc_spi_incapacity_benefit_income","ossben_identifiable_subset","srp_regular_code5","employer_pension_contributions","person_source_id","person_support_channel","person_support_clone_index","charitable_investment_gifts","gift_aid","other_investment_income","hmrc_spi_employment_benefits","hmrc_spi_employment_expenses","hmrc_spi_other_social_security_income","hmrc_spi_taxable_termination_pay","hmrc_spi_miscellaneous_employment_income","hmrc_spi_other_income","hmrc_spi_state_pension_income","hmrc_spi_employed_income","hmrc_spi_total_earned_income","hmrc_spi_total_investment_income","hmrc_spi_assessable_income"],"entity":"person","rows":"all"}],"kernel":"uk.identity@1","mass":"conserve","outputs":[],"params":{},"population":null,"sources":[],"structural":"filter","weights":null},{"base":null,"citation":"","description":"Run UK spine stage uc_reporter_redraw.","id":"uc_reporter_redraw","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage","benunit_source_id","benunit_support_channel","benunit_support_clone_index"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate","dfe_education_spending","rail_subsidy_spending","bus_subsidy_spending","rail_usage","source_household_id","source_year","source_household_key","household_source_id","household_support_channel","household_support_clone_index","household_is_spi_synthetic"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance","a_and_e_visits","admitted_patient_visits","outpatient_visits","nhs_a_and_e_spending","nhs_admitted_patient_spending","nhs_outpatient_spending","hmrc_spi_pay","hmrc_spi_unemployment_benefit_income","hmrc_spi_incapacity_benefit_income","ossben_identifiable_subset","srp_regular_code5","employer_pension_contributions","person_source_id","person_support_channel","person_support_clone_index","charitable_investment_gifts","gift_aid","other_investment_income","hmrc_spi_employment_benefits","hmrc_spi_employment_expenses","hmrc_spi_other_social_security_income","hmrc_spi_taxable_termination_pay","hmrc_spi_miscellaneous_employment_income","hmrc_spi_other_income","hmrc_spi_state_pension_income","hmrc_spi_employed_income","hmrc_spi_total_earned_income","hmrc_spi_total_investment_income","hmrc_spi_assessable_income"],"entity":"person","rows":"all"}],"kernel":"uk.stage.uc_reporter_redraw@1","mass":"conserve","outputs":[{"column":"universal_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"}],"params":{"stage":"uc_reporter_redraw","stage_contract_sha256":"7e94e034cad29c5bae566ffb875c42cddf3a1025c15496907e783ceff1144f8b","time_period":"2024"},"population":"uc_reporter_redraw.boundary","sources":["frs"],"structural":"none","weights":null},{"base":"uc_reporter_redraw.boundary","citation":"","description":"Ownership boundary before uc_capital_coherence rewrites.","id":"uc_capital_coherence.boundary","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage","benunit_source_id","benunit_support_channel","benunit_support_clone_index"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate","dfe_education_spending","rail_subsidy_spending","bus_subsidy_spending","rail_usage","source_household_id","source_year","source_household_key","household_source_id","household_support_channel","household_support_clone_index","household_is_spi_synthetic"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance","a_and_e_visits","admitted_patient_visits","outpatient_visits","nhs_a_and_e_spending","nhs_admitted_patient_spending","nhs_outpatient_spending","hmrc_spi_pay","hmrc_spi_unemployment_benefit_income","hmrc_spi_incapacity_benefit_income","ossben_identifiable_subset","srp_regular_code5","employer_pension_contributions","person_source_id","person_support_channel","person_support_clone_index","charitable_investment_gifts","gift_aid","other_investment_income","hmrc_spi_employment_benefits","hmrc_spi_employment_expenses","hmrc_spi_other_social_security_income","hmrc_spi_taxable_termination_pay","hmrc_spi_miscellaneous_employment_income","hmrc_spi_other_income","hmrc_spi_state_pension_income","hmrc_spi_employed_income","hmrc_spi_total_earned_income","hmrc_spi_total_investment_income","hmrc_spi_assessable_income"],"entity":"person","rows":"all"}],"kernel":"uk.identity@1","mass":"conserve","outputs":[],"params":{},"population":null,"sources":[],"structural":"filter","weights":null},{"base":null,"citation":"","description":"Run UK spine stage uc_capital_coherence.","id":"uc_capital_coherence","inputs":[{"columns":["benunit_support_channel","dependent_children","is_married"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age","is_benunit_head","is_parent","person_support_channel","universal_credit_reported"],"entity":"person","rows":"all"}],"kernel":"uk.stage.uc_capital_coherence@1","mass":"conserve","outputs":[{"column":"uc_reported_capital","dtype":"float64","entity":"benunit","ownership":"produced","rows":"all"},{"column":"frs_benunit_capital","dtype":"float64","entity":"benunit","ownership":"produced","rewrite":true,"rows":"all"},{"column":"would_claim_uc","dtype":"bool","entity":"benunit","ownership":"produced","rewrite":true,"rows":"all"}],"params":{"stage":"uc_capital_coherence","stage_contract_sha256":"059f27ee687ee15385b246d43068b17aeecbe3645ccc41fd52fcad06a006a081","time_period":"2024"},"population":"uc_capital_coherence.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage uc_deduction_attributes.","id":"uc_deduction_attributes","inputs":[{"columns":["frs_benunit_capital","would_claim_uc"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age"],"entity":"person","rows":"all"}],"kernel":"uk.stage.uc_deduction_attributes@1","mass":"conserve","outputs":[{"column":"uc_deduction_random_draw","dtype":"float64","entity":"benunit","ownership":"produced","rows":"all"},{"column":"uc_deduction_type_random_draw","dtype":"float64","entity":"benunit","ownership":"produced","rows":"all"},{"column":"uc_latent_deduction_rate","dtype":"float64","entity":"benunit","ownership":"produced","rows":"all"},{"column":"uc_deduction_combination","dtype":"string","entity":"benunit","ownership":"produced","rows":"all"}],"params":{"stage":"uc_deduction_attributes","stage_contract_sha256":"6bc7e3ec1a5712e23ca1b7d2956e8b17f2526b94431ba3e5a9294b04658e4fe0","time_period":"2024"},"population":"uc_capital_coherence.boundary","sources":["frs"],"structural":"none","weights":null},{"base":"uc_capital_coherence.boundary","citation":"","description":"Run structural UK stage cgt_incidence_clone.","id":"cgt_incidence_clone","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage","benunit_source_id","benunit_support_channel","benunit_support_clone_index","uc_reported_capital","uc_deduction_random_draw","uc_deduction_type_random_draw","uc_latent_deduction_rate","uc_deduction_combination"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate","dfe_education_spending","rail_subsidy_spending","bus_subsidy_spending","rail_usage","source_household_id","source_year","source_household_key","household_source_id","household_support_channel","household_support_clone_index","household_is_spi_synthetic"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance","a_and_e_visits","admitted_patient_visits","outpatient_visits","nhs_a_and_e_spending","nhs_admitted_patient_spending","nhs_outpatient_spending","hmrc_spi_pay","hmrc_spi_unemployment_benefit_income","hmrc_spi_incapacity_benefit_income","ossben_identifiable_subset","srp_regular_code5","employer_pension_contributions","person_source_id","person_support_channel","person_support_clone_index","charitable_investment_gifts","gift_aid","other_investment_income","hmrc_spi_employment_benefits","hmrc_spi_employment_expenses","hmrc_spi_other_social_security_income","hmrc_spi_taxable_termination_pay","hmrc_spi_miscellaneous_employment_income","hmrc_spi_other_income","hmrc_spi_state_pension_income","hmrc_spi_employed_income","hmrc_spi_total_earned_income","hmrc_spi_total_investment_income","hmrc_spi_assessable_income"],"entity":"person","rows":"all"}],"kernel":"uk.stage.expand.cgt_incidence_clone@1","mass":"conserve","outputs":[],"params":{"expand_cells":[["household","household_is_capital_gains_clone","bool"],["person","capital_gains","float64"]],"expand_weight_entity":"household","expand_weight_kind":"importance","stage":"cgt_incidence_clone","stage_contract_sha256":"ee30278543cc0297a5366d855b7753aa04af5518971594c193c52be36bf8a7b4","time_period":"2024"},"population":null,"sources":["frs"],"structural":"expand","weights":null},{"base":null,"citation":"","description":"Own the cells materialized by cgt_incidence_clone.","id":"cgt_incidence_clone.owned","inputs":[],"kernel":"uk.claim@1","mass":"conserve","outputs":[{"column":"household_is_capital_gains_clone","dtype":"bool","entity":"household","ownership":"produced","rows":"all"},{"column":"capital_gains","dtype":"float64","entity":"person","ownership":"produced","rows":"all"}],"params":{"materialized_expand_outputs":["household.household_is_capital_gains_clone","person.capital_gains"]},"population":"cgt_incidence_clone","sources":[],"structural":"none","weights":null},{"base":"cgt_incidence_clone","citation":"","description":"Run structural UK stage cgt_band_donors.","id":"cgt_band_donors","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage","benunit_source_id","benunit_support_channel","benunit_support_clone_index","uc_reported_capital","uc_deduction_random_draw","uc_deduction_type_random_draw","uc_latent_deduction_rate","uc_deduction_combination"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate","dfe_education_spending","rail_subsidy_spending","bus_subsidy_spending","rail_usage","source_household_id","source_year","source_household_key","household_source_id","household_support_channel","household_support_clone_index","household_is_spi_synthetic","household_is_capital_gains_clone"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance","a_and_e_visits","admitted_patient_visits","outpatient_visits","nhs_a_and_e_spending","nhs_admitted_patient_spending","nhs_outpatient_spending","hmrc_spi_pay","hmrc_spi_unemployment_benefit_income","hmrc_spi_incapacity_benefit_income","ossben_identifiable_subset","srp_regular_code5","employer_pension_contributions","person_source_id","person_support_channel","person_support_clone_index","charitable_investment_gifts","gift_aid","other_investment_income","hmrc_spi_employment_benefits","hmrc_spi_employment_expenses","hmrc_spi_other_social_security_income","hmrc_spi_taxable_termination_pay","hmrc_spi_miscellaneous_employment_income","hmrc_spi_other_income","hmrc_spi_state_pension_income","hmrc_spi_employed_income","hmrc_spi_total_earned_income","hmrc_spi_total_investment_income","hmrc_spi_assessable_income","capital_gains"],"entity":"person","rows":"all"}],"kernel":"uk.stage.expand.cgt_band_donors@1","mass":"free","outputs":[],"params":{"expand_cells":[["household","household_is_cgt_band_donor","bool"],["person","capital_gains","float64"]],"expand_weight_entity":"household","expand_weight_kind":"importance","stage":"cgt_band_donors","stage_contract_sha256":"e10e10c49c0ca2a6a65048c91b683f818e8b6e207a6c6f57a20d76ea299160b0","time_period":"2024"},"population":null,"sources":["frs"],"structural":"expand","weights":null},{"base":null,"citation":"","description":"Own the cells materialized by cgt_band_donors.","id":"cgt_band_donors.owned","inputs":[],"kernel":"uk.claim@1","mass":"conserve","outputs":[{"column":"household_is_cgt_band_donor","dtype":"bool","entity":"household","ownership":"produced","rows":"all"},{"column":"capital_gains","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"}],"params":{"materialized_expand_outputs":["household.household_is_cgt_band_donor"]},"population":"cgt_band_donors","sources":[],"structural":"none","weights":null},{"base":"cgt_band_donors","citation":"","description":"Ownership boundary before hmrc_cgt_gains_spine rewrites.","id":"hmrc_cgt_gains_spine.boundary","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage","benunit_source_id","benunit_support_channel","benunit_support_clone_index","uc_reported_capital","uc_deduction_random_draw","uc_deduction_type_random_draw","uc_latent_deduction_rate","uc_deduction_combination"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate","dfe_education_spending","rail_subsidy_spending","bus_subsidy_spending","rail_usage","source_household_id","source_year","source_household_key","household_source_id","household_support_channel","household_support_clone_index","household_is_spi_synthetic","household_is_capital_gains_clone","household_is_cgt_band_donor"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance","a_and_e_visits","admitted_patient_visits","outpatient_visits","nhs_a_and_e_spending","nhs_admitted_patient_spending","nhs_outpatient_spending","hmrc_spi_pay","hmrc_spi_unemployment_benefit_income","hmrc_spi_incapacity_benefit_income","ossben_identifiable_subset","srp_regular_code5","employer_pension_contributions","person_source_id","person_support_channel","person_support_clone_index","charitable_investment_gifts","gift_aid","other_investment_income","hmrc_spi_employment_benefits","hmrc_spi_employment_expenses","hmrc_spi_other_social_security_income","hmrc_spi_taxable_termination_pay","hmrc_spi_miscellaneous_employment_income","hmrc_spi_other_income","hmrc_spi_state_pension_income","hmrc_spi_employed_income","hmrc_spi_total_earned_income","hmrc_spi_total_investment_income","hmrc_spi_assessable_income","capital_gains"],"entity":"person","rows":"all"}],"kernel":"uk.identity@1","mass":"conserve","outputs":[],"params":{},"population":null,"sources":[],"structural":"filter","weights":null},{"base":null,"citation":"","description":"Run UK spine stage hmrc_cgt_gains_spine.","id":"hmrc_cgt_gains_spine","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age","dividend_income","employment_income","miscellaneous_income","private_pension_income","property_income","savings_interest_income","self_employment_income","state_pension_reported","tax_free_savings_income"],"entity":"person","rows":"all"}],"kernel":"uk.stage.hmrc_cgt_gains_spine@1","mass":"conserve","outputs":[{"column":"capital_gains","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"}],"params":{"stage":"hmrc_cgt_gains_spine","stage_contract_sha256":"20ada8d8ee94400bd160223e865a910db7aff9c40a7f0c8ee8ca8c40ed901b72","time_period":"2024"},"population":"hmrc_cgt_gains_spine.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage salary_sacrifice.","id":"salary_sacrifice","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage","benunit_source_id","benunit_support_channel","benunit_support_clone_index","uc_reported_capital","uc_deduction_random_draw","uc_deduction_type_random_draw","uc_latent_deduction_rate","uc_deduction_combination"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate","dfe_education_spending","rail_subsidy_spending","bus_subsidy_spending","rail_usage","source_household_id","source_year","source_household_key","household_source_id","household_support_channel","household_support_clone_index","household_is_spi_synthetic","household_is_capital_gains_clone","household_is_cgt_band_donor"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance","a_and_e_visits","admitted_patient_visits","outpatient_visits","nhs_a_and_e_spending","nhs_admitted_patient_spending","nhs_outpatient_spending","hmrc_spi_pay","hmrc_spi_unemployment_benefit_income","hmrc_spi_incapacity_benefit_income","ossben_identifiable_subset","srp_regular_code5","employer_pension_contributions","person_source_id","person_support_channel","person_support_clone_index","charitable_investment_gifts","gift_aid","other_investment_income","hmrc_spi_employment_benefits","hmrc_spi_employment_expenses","hmrc_spi_other_social_security_income","hmrc_spi_taxable_termination_pay","hmrc_spi_miscellaneous_employment_income","hmrc_spi_other_income","hmrc_spi_state_pension_income","hmrc_spi_employed_income","hmrc_spi_total_earned_income","hmrc_spi_total_investment_income","hmrc_spi_assessable_income","capital_gains"],"entity":"person","rows":"all"}],"kernel":"uk.stage.salary_sacrifice@1","mass":"conserve","outputs":[{"column":"pension_contributions_via_salary_sacrifice","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"employee_pension_contributions","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"}],"params":{"stage":"salary_sacrifice","stage_contract_sha256":"a4af925af21cc6766eb7c8855b6743a3aa4eeeb38df12cfc83063d7ad6890539","time_period":"2024"},"population":"hmrc_cgt_gains_spine.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage student_loans.","id":"student_loans","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age","current_education","employee_pension_contributions","highest_education","student_loan_repayments","student_loans"],"entity":"person","rows":"all"}],"kernel":"uk.stage.student_loans@1","mass":"conserve","outputs":[{"column":"student_loan_plan","dtype":"string","entity":"person","ownership":"produced","rows":"all"}],"params":{"stage":"student_loans","stage_contract_sha256":"7c4c76398c2e80b41c7f941a5f06246b57d89b5eb0c36d42e3116ac35e82e203","time_period":"2024"},"population":"hmrc_cgt_gains_spine.boundary","sources":["frs"],"structural":"none","weights":null}],"sources":[{"codec":"csv-tables","description":"Content-bound UK FRS and donor fixture/source bundle.","name":"frs"}]} +{"country":"uk","nodes":[{"base":null,"citation":"","description":"Load the source-bound UK FRS root population.","id":"create_uk_frs","inputs":[],"kernel":"uk.create@1","mass":"conserve","outputs":[{"column":"age","dtype":"int64","entity":"person","ownership":"produced","rows":"all"},{"column":"gender","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"marital_status","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"hours_worked","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"is_household_head","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"is_benunit_head","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"is_parent","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"is_uc_claimant","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"employment_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"self_employment_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"private_pension_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"tax_free_savings_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"savings_interest_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"dividend_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"property_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"maintenance_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"miscellaneous_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"private_transfer_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"lump_sum_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"student_loan_repayments","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"statutory_sick_pay","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"statutory_maternity_pay","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"student_loans","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"access_fund","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"education_grants","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"healthy_start_vouchers","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"free_school_breakfasts","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"free_school_fruit_veg","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"free_school_meals","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"council_tax_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"maintenance_expenses","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"childcare_expenses","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"personal_pension_contributions","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"employee_pension_contributions","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"pension_contributions_via_salary_sacrifice","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"salary_sacrifice_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"salary_sacrifice_asked","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"child_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"income_support_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"housing_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"attendance_allowance_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"dla_sc_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"dla_m_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"iidb_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"carers_allowance_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"sda_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"afcs_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"ssmg_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"pension_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"child_tax_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"working_tax_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"state_pension_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"winter_fuel_allowance_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"incapacity_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"universal_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"pip_m_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"pip_dl_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"jsa_contrib_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"jsa_income_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"esa_contrib_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"esa_income_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"bsp_reported","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"frs_benunit_capital","dtype":"float64","entity":"benunit","ownership":"produced","rows":"all"},{"column":"is_married","dtype":"bool","entity":"benunit","ownership":"produced","rows":"all"},{"column":"dependent_children","dtype":"int64","entity":"benunit","ownership":"produced","rows":"all"},{"column":"region","dtype":"string","entity":"household","ownership":"produced","rows":"all"},{"column":"tenure_type","dtype":"string","entity":"household","ownership":"produced","rows":"all"},{"column":"accommodation_type","dtype":"string","entity":"household","ownership":"produced","rows":"all"},{"column":"num_bedrooms","dtype":"int64","entity":"household","ownership":"produced","rows":"all"},{"column":"council_tax_reported","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"council_tax_band","dtype":"string","entity":"household","ownership":"produced","rows":"all"},{"column":"council_tax_rebate","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"council_tax_single_adult_raw","dtype":"int64","entity":"household","ownership":"produced","rows":"all"},{"column":"water_and_sewerage_charges","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"domestic_rates","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"rent","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"subrent","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"mortgage_interest_repayment","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"mortgage_capital_repayment","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"structural_insurance_payments","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"housing_service_charges","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"external_child_payments","dtype":"float64","entity":"household","ownership":"produced","rows":"all"}],"params":{"sample_fraction":1.0,"sample_seed":578,"stage_contract_sha256":"7ed918cd9dfa27874110bececf0c2513e7348df10b79ed55ea432e0e9ed70f3f","time_period":"2024"},"population":null,"sources":["frs"],"structural":"create","weights":null},{"base":"create_uk_frs","citation":"","description":"Ownership boundary for the source-assembling root stage.","id":"frs_spine.boundary","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported"],"entity":"person","rows":"all"}],"kernel":"uk.identity@1","mass":"conserve","outputs":[],"params":{},"population":null,"sources":[],"structural":"filter","weights":null},{"base":null,"citation":"","description":"Claim the cells assembled by the UK FRS root transform.","id":"frs_spine","inputs":[],"kernel":"uk.claim@1","mass":"conserve","outputs":[{"column":"age","dtype":"int64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"gender","dtype":"string","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"marital_status","dtype":"string","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"hours_worked","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"is_household_head","dtype":"bool","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"is_benunit_head","dtype":"bool","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"is_parent","dtype":"bool","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"is_uc_claimant","dtype":"bool","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"employment_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"self_employment_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"private_pension_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"tax_free_savings_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"savings_interest_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"dividend_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"property_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"maintenance_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"miscellaneous_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"private_transfer_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"lump_sum_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"student_loan_repayments","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"statutory_sick_pay","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"statutory_maternity_pay","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"student_loans","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"access_fund","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"education_grants","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"healthy_start_vouchers","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"free_school_breakfasts","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"free_school_fruit_veg","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"free_school_meals","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"council_tax_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"maintenance_expenses","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"childcare_expenses","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"personal_pension_contributions","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"employee_pension_contributions","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pension_contributions_via_salary_sacrifice","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"salary_sacrifice_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"salary_sacrifice_asked","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"child_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"income_support_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"housing_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"attendance_allowance_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"dla_sc_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"dla_m_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"iidb_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"carers_allowance_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"sda_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"afcs_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"ssmg_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pension_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"child_tax_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"working_tax_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"state_pension_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"winter_fuel_allowance_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"incapacity_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"universal_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pip_m_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pip_dl_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"jsa_contrib_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"jsa_income_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"esa_contrib_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"esa_income_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"bsp_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"frs_benunit_capital","dtype":"float64","entity":"benunit","ownership":"produced","rewrite":true,"rows":"all"},{"column":"is_married","dtype":"bool","entity":"benunit","ownership":"produced","rewrite":true,"rows":"all"},{"column":"dependent_children","dtype":"int64","entity":"benunit","ownership":"produced","rewrite":true,"rows":"all"},{"column":"region","dtype":"string","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"tenure_type","dtype":"string","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"accommodation_type","dtype":"string","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"num_bedrooms","dtype":"int64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"council_tax_reported","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"council_tax_band","dtype":"string","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"council_tax_rebate","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"council_tax_single_adult_raw","dtype":"int64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"water_and_sewerage_charges","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"domestic_rates","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"rent","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"subrent","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"mortgage_interest_repayment","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"mortgage_capital_repayment","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"structural_insurance_payments","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"housing_service_charges","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"external_child_payments","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"}],"params":{},"population":"frs_spine.boundary","sources":[],"structural":"none","weights":null},{"base":"frs_spine.boundary","citation":"","description":"Ownership boundary before age_tail rewrites.","id":"age_tail.boundary","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported"],"entity":"person","rows":"all"}],"kernel":"uk.identity@1","mass":"conserve","outputs":[],"params":{},"population":null,"sources":[],"structural":"filter","weights":null},{"base":null,"citation":"","description":"Run UK spine stage age_tail.","id":"age_tail","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["external_child_payments","region"],"entity":"household","rows":"all"},{"columns":["gender"],"entity":"person","rows":"all"}],"kernel":"uk.stage.age_tail@1","mass":"conserve","outputs":[{"column":"age","dtype":"int64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"}],"params":{"stage":"age_tail","stage_contract_sha256":"963a34f38caede2525e3b8735f904bb70a1bbef5a272f0eefd4346343444484f","time_period":"2024"},"population":"age_tail.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_relationships.","id":"frs_relationships","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age","is_household_head"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_relationships@1","mass":"conserve","outputs":[{"column":"relationship_to_head","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"ons_family_role","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"ons_family_index","dtype":"int64","entity":"person","ownership":"produced","rows":"all"},{"column":"ons_household_type","dtype":"string","entity":"household","ownership":"produced","rows":"all"}],"params":{"stage":"frs_relationships","stage_contract_sha256":"30628808d06d9829ebcbcf460cd355a01261e78c7c73e6006c75bec2e3d60c33","time_period":"2024"},"population":"age_tail.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_employment.","id":"frs_employment","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["ons_household_type","region"],"entity":"household","rows":"all"},{"columns":["age"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_employment@1","mass":"conserve","outputs":[{"column":"employment_status","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"employment_sector","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"sic_industry_division","dtype":"int64","entity":"person","ownership":"produced","rows":"all"}],"params":{"stage":"frs_employment","stage_contract_sha256":"ddbefaf05b44788d794a6e4b0e8926c14318d66e50d2f11f50ca549538bbf60c","time_period":"2024"},"population":"age_tail.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_council_tax.","id":"frs_council_tax","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age","sic_industry_division"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_council_tax@1","mass":"conserve","outputs":[{"column":"council_tax","dtype":"float64","entity":"household","ownership":"produced","rows":"all"}],"params":{"stage":"frs_council_tax","stage_contract_sha256":"3381cd9f7a736514d5073c57480e07f5098890f3ca9ed3865392043594771eb9","time_period":"2024"},"population":"age_tail.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_disability.","id":"frs_disability","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["council_tax","region"],"entity":"household","rows":"all"},{"columns":["afcs_reported","age","attendance_allowance_reported","dla_m_reported","dla_sc_reported","esa_contrib_reported","esa_income_reported","iidb_reported","incapacity_benefit_reported","pip_dl_reported","pip_m_reported","sda_reported"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_disability@1","mass":"conserve","outputs":[{"column":"aa_category","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"dla_sc_category","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"dla_m_category","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"pip_m_category","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"pip_dl_category","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"is_disabled_for_benefits","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"is_enhanced_disabled_for_benefits","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"is_severely_disabled_for_benefits","dtype":"bool","entity":"person","ownership":"produced","rows":"all"}],"params":{"stage":"frs_disability","stage_contract_sha256":"ac500b4cb1bc04d4fb72d198592dd376d61da8c150921a6ac53914ac18be0508","time_period":"2024"},"population":"age_tail.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_education.","id":"frs_education","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age","esa_contrib_reported","esa_income_reported","is_severely_disabled_for_benefits","jsa_contrib_reported","jsa_income_reported","universal_credit_reported"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_education@1","mass":"conserve","outputs":[{"column":"current_education","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"highest_education","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"is_in_non_advanced_education","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"is_in_approved_training","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"age_started_or_accepted_current_education_or_training","dtype":"int64","entity":"person","ownership":"produced","rows":"all"},{"column":"is_before_universal_credit_qualifying_young_person_terminal_date","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"adult_ema","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"child_ema","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"receives_benefits_in_own_right","dtype":"bool","entity":"person","ownership":"produced","rows":"all"}],"params":{"stage":"frs_education","stage_contract_sha256":"836cb0f5a582fee1425190e96c9cb81bdef859bd236c8b6bc27660b6e3d0c2f8","time_period":"2024"},"population":"age_tail.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_legacy_proxies.","id":"frs_legacy_proxies","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","ons_household_type","council_tax"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","relationship_to_head","ons_family_role","ons_family_index","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_legacy_proxies@1","mass":"conserve","outputs":[{"column":"legacy_jobseeker_proxy","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"esa_health_condition_proxy","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"esa_support_group_proxy","dtype":"bool","entity":"person","ownership":"produced","rows":"all"}],"params":{"stage":"frs_legacy_proxies","stage_contract_sha256":"1ecf761cf3fa7180da15659e138e67a8654e58272b4fde28344aa27a874ad0aa","time_period":"2024"},"population":"age_tail.boundary","sources":["frs"],"structural":"none","weights":null},{"base":"age_tail.boundary","citation":"","description":"Ownership boundary before frs_education_grant_split rewrites.","id":"frs_education_grant_split.boundary","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","ons_household_type","council_tax"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","relationship_to_head","ons_family_role","ons_family_index","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy"],"entity":"person","rows":"all"}],"kernel":"uk.identity@1","mass":"conserve","outputs":[],"params":{},"population":null,"sources":[],"structural":"filter","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_education_grant_split.","id":"frs_education_grant_split","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","ons_household_type","council_tax"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","relationship_to_head","ons_family_role","ons_family_index","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_education_grant_split@1","mass":"conserve","outputs":[{"column":"disabled_students_allowance_eligible_expenses","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"education_grants","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"}],"params":{"stage":"frs_education_grant_split","stage_contract_sha256":"8718f014b90498c2cc7c754289775ca4a41452d9b978d8cbc5f34b64cbdc7df2","time_period":"2024"},"population":"frs_education_grant_split.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_take_up.","id":"frs_take_up","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age","child_benefit_reported","education_grants","pension_credit_reported","universal_credit_reported"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_take_up@1","mass":"conserve","outputs":[{"column":"would_claim_child_benefit","dtype":"bool","entity":"benunit","ownership":"produced","rows":"all"},{"column":"child_benefit_opts_out","dtype":"bool","entity":"benunit","ownership":"produced","rows":"all"},{"column":"would_claim_pc","dtype":"bool","entity":"benunit","ownership":"produced","rows":"all"},{"column":"would_claim_uc","dtype":"bool","entity":"benunit","ownership":"produced","rows":"all"},{"column":"would_claim_tfc","dtype":"bool","entity":"benunit","ownership":"produced","rows":"all"},{"column":"would_claim_extended_childcare","dtype":"bool","entity":"benunit","ownership":"produced","rows":"all"},{"column":"would_claim_universal_childcare","dtype":"bool","entity":"benunit","ownership":"produced","rows":"all"},{"column":"would_claim_targeted_childcare","dtype":"bool","entity":"benunit","ownership":"produced","rows":"all"},{"column":"maximum_extended_childcare_hours_usage","dtype":"float64","entity":"benunit","ownership":"produced","rows":"all"}],"params":{"stage":"frs_take_up","stage_contract_sha256":"d10ca01bfa5d719640ded8e62196b0692236d3be0a2417899deeefd241088abf","time_period":"2024"},"population":"frs_education_grant_split.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_person_draws.","id":"frs_person_draws","inputs":[{"columns":["frs_benunit_capital","maximum_extended_childcare_hours_usage"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_person_draws@1","mass":"conserve","outputs":[{"column":"would_claim_marriage_allowance","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"would_claim_scp","dtype":"bool","entity":"person","ownership":"produced","rows":"all"},{"column":"attends_private_school_random_draw","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"tax_free_childcare_spend_routed_share","dtype":"float64","entity":"person","ownership":"produced","rows":"all"}],"params":{"stage":"frs_person_draws","stage_contract_sha256":"e87b779c3977aa520c298f9bca54b675a8cacb8baed0b58412a1f783b42968ff","time_period":"2024"},"population":"frs_education_grant_split.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_household_draws.","id":"frs_household_draws","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age","tax_free_childcare_spend_routed_share"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_household_draws@1","mass":"conserve","outputs":[{"column":"household_owns_tv","dtype":"bool","entity":"household","ownership":"produced","rows":"all"},{"column":"would_evade_tv_licence_fee","dtype":"bool","entity":"household","ownership":"produced","rows":"all"},{"column":"main_residential_property_purchased_is_first_home","dtype":"bool","entity":"household","ownership":"produced","rows":"all"},{"column":"property_purchased","dtype":"bool","entity":"household","ownership":"produced","rows":"all"}],"params":{"stage":"frs_household_draws","stage_contract_sha256":"c74c63b09264319c4bf0049dabba00ecd0ce660beb7b53d6dae71518434bc949","time_period":"2024"},"population":"frs_education_grant_split.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_brma.","id":"frs_brma","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","ons_household_type","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","relationship_to_head","ons_family_role","ons_family_index","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_brma@1","mass":"conserve","outputs":[{"column":"brma","dtype":"string","entity":"household","ownership":"produced","rows":"all"}],"params":{"stage":"frs_brma","stage_contract_sha256":"5b8f0b361310c7cd3efbaae3762b347649b7d4afb9e9943131d9bef9266fc3c8","time_period":"2024"},"population":"frs_education_grant_split.boundary","sources":["frs"],"structural":"none","weights":null},{"base":"frs_education_grant_split.boundary","citation":"","description":"Freeze the assembled-spine gate population.","id":"frs_brma.checkpoint","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","ons_household_type","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","relationship_to_head","ons_family_role","ons_family_index","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share"],"entity":"person","rows":"all"}],"kernel":"uk.identity@1","mass":"conserve","outputs":[],"params":{},"population":null,"sources":[],"structural":"filter","weights":null},{"base":null,"citation":"","description":"Run UK spine stage was_wealth.","id":"was_wealth","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","ons_household_type","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","relationship_to_head","ons_family_role","ons_family_index","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share"],"entity":"person","rows":"all"}],"kernel":"uk.stage.was_wealth@1","mass":"conserve","outputs":[{"column":"owned_land","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"property_wealth","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"corporate_wealth","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"private_pension_wealth","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"gross_financial_wealth","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"net_financial_wealth","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"main_residence_value","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"other_residential_property_value","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"non_residential_property_value","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"savings","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"num_vehicles","dtype":"int64","entity":"household","ownership":"produced","rows":"all"},{"column":"cash_isa","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"stocks_and_shares_isa","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"mortgage_debt","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"consumer_debt","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"student_loan_balance","dtype":"float64","entity":"person","ownership":"produced","rows":"all"}],"params":{"stage":"was_wealth","stage_contract_sha256":"c499dcb7c49a0176229dbc363b400415cb5c1da44af266ba2155f9a62a0bd2ed","time_period":"2024"},"population":"frs_brma.checkpoint","sources":["frs"],"structural":"none","weights":null},{"base":"frs_brma.checkpoint","citation":"","description":"Ownership boundary before regional_property_uprating rewrites.","id":"regional_property_uprating.boundary","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","ons_household_type","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","relationship_to_head","ons_family_role","ons_family_index","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance"],"entity":"person","rows":"all"}],"kernel":"uk.identity@1","mass":"conserve","outputs":[],"params":{},"population":null,"sources":[],"structural":"filter","weights":null},{"base":null,"citation":"","description":"Run UK spine stage regional_property_uprating.","id":"regional_property_uprating","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age","student_loan_balance"],"entity":"person","rows":"all"}],"kernel":"uk.stage.regional_property_uprating@1","mass":"conserve","outputs":[{"column":"main_residence_value","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"},{"column":"property_wealth","dtype":"float64","entity":"household","ownership":"produced","rewrite":true,"rows":"all"}],"params":{"stage":"regional_property_uprating","stage_contract_sha256":"4304356c6c5ba91a04883148cbf9078761ee926c8387aadb6c15b6b70ebb31f6","time_period":"2024"},"population":"regional_property_uprating.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage lcfs_consumption.","id":"lcfs_consumption","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","ons_household_type","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","relationship_to_head","ons_family_role","ons_family_index","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance"],"entity":"person","rows":"all"}],"kernel":"uk.stage.lcfs_consumption@1","mass":"conserve","outputs":[{"column":"food_and_non_alcoholic_beverages_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"alcohol_and_tobacco_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"clothing_and_footwear_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"housing_water_and_electricity_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"household_furnishings_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"health_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"transport_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"communication_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"recreation_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"education_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"restaurants_and_hotels_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"miscellaneous_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"petrol_spending","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"diesel_spending","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"bus_fare_spending","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"domestic_energy_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"electricity_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"gas_consumption","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"has_fuel_consumption","dtype":"bool","entity":"household","ownership":"produced","rows":"all"}],"params":{"stage":"lcfs_consumption","stage_contract_sha256":"eb0a529c357c84290a001209a18c5a43b0a0310553c77963d6842fd0111b73ad","time_period":"2024"},"population":"regional_property_uprating.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage etb_vat.","id":"etb_vat","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","ons_household_type","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","relationship_to_head","ons_family_role","ons_family_index","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance"],"entity":"person","rows":"all"}],"kernel":"uk.stage.etb_vat@1","mass":"conserve","outputs":[{"column":"full_rate_vat_expenditure_rate","dtype":"float64","entity":"household","ownership":"produced","rows":"all"}],"params":{"stage":"etb_vat","stage_contract_sha256":"99a6756256adfe8255672fafda89710c08ae56bd2b8f011b20c3b8381eabfa1e","time_period":"2024"},"population":"regional_property_uprating.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage etb_services.","id":"etb_services","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","ons_household_type","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","relationship_to_head","ons_family_role","ons_family_index","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance"],"entity":"person","rows":"all"}],"kernel":"uk.stage.etb_services@1","mass":"conserve","outputs":[{"column":"dfe_education_spending","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"rail_subsidy_spending","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"bus_subsidy_spending","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"rail_usage","dtype":"float64","entity":"household","ownership":"produced","rows":"all"},{"column":"a_and_e_visits","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"admitted_patient_visits","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"outpatient_visits","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"nhs_a_and_e_spending","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"nhs_admitted_patient_spending","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"nhs_outpatient_spending","dtype":"float64","entity":"person","ownership":"produced","rows":"all"}],"params":{"stage":"etb_services","stage_contract_sha256":"48294c9d86dd422238a723aca5845e9ceb9eda2903a3bb87bb32a86092447e19","time_period":"2024"},"population":"regional_property_uprating.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage frs_hmrc_spine_leaves.","id":"frs_hmrc_spine_leaves","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age","employee_pension_contributions","nhs_outpatient_spending"],"entity":"person","rows":"all"}],"kernel":"uk.stage.frs_hmrc_spine_leaves@1","mass":"conserve","outputs":[{"column":"hmrc_spi_pay","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_unemployment_benefit_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_incapacity_benefit_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"ossben_identifiable_subset","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"srp_regular_code5","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"employer_pension_contributions","dtype":"float64","entity":"person","ownership":"produced","rows":"all"}],"params":{"stage":"frs_hmrc_spine_leaves","stage_contract_sha256":"2bb3d068003489b47cc8676ac26c203ce3c39a9b6e92f3ecd0a3c06acd6addc4","time_period":"2024"},"population":"regional_property_uprating.boundary","sources":["frs"],"structural":"none","weights":null},{"base":"regional_property_uprating.boundary","citation":"","description":"Run structural UK stage spi_support_channel.","id":"spi_support_channel","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","ons_household_type","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate","dfe_education_spending","rail_subsidy_spending","bus_subsidy_spending","rail_usage"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","relationship_to_head","ons_family_role","ons_family_index","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance","a_and_e_visits","admitted_patient_visits","outpatient_visits","nhs_a_and_e_spending","nhs_admitted_patient_spending","nhs_outpatient_spending","hmrc_spi_pay","hmrc_spi_unemployment_benefit_income","hmrc_spi_incapacity_benefit_income","ossben_identifiable_subset","srp_regular_code5","employer_pension_contributions"],"entity":"person","rows":"all"}],"kernel":"uk.stage.expand.spi_support_channel@1","mass":"declared","outputs":[],"params":{"expand_cells":[["person","person_source_id","int64"],["person","person_support_channel","string"],["person","person_support_clone_index","int64"],["benunit","benunit_source_id","int64"],["benunit","benunit_support_channel","string"],["benunit","benunit_support_clone_index","int64"],["household","source_household_id","int64"],["household","source_year","int64"],["household","source_household_key","string"],["household","household_source_id","int64"],["household","household_support_channel","string"],["household","household_support_clone_index","int64"],["household","household_is_spi_synthetic","bool"]],"expand_weight_entity":"household","expand_weight_kind":"importance","stage":"spi_support_channel","stage_contract_sha256":"4b10f1a4a215cdf2c406c9974de2d1e580eb3cd3a25ed34973c1b63abf4a54bb","time_period":"2024"},"population":null,"sources":["frs"],"structural":"expand","weights":null},{"base":null,"citation":"","description":"Own the cells materialized by spi_support_channel.","id":"spi_support_channel.owned","inputs":[],"kernel":"uk.claim@1","mass":"conserve","outputs":[{"column":"person_source_id","dtype":"int64","entity":"person","ownership":"produced","rows":"all"},{"column":"person_support_channel","dtype":"string","entity":"person","ownership":"produced","rows":"all"},{"column":"person_support_clone_index","dtype":"int64","entity":"person","ownership":"produced","rows":"all"},{"column":"benunit_source_id","dtype":"int64","entity":"benunit","ownership":"produced","rows":"all"},{"column":"benunit_support_channel","dtype":"string","entity":"benunit","ownership":"produced","rows":"all"},{"column":"benunit_support_clone_index","dtype":"int64","entity":"benunit","ownership":"produced","rows":"all"},{"column":"source_household_id","dtype":"int64","entity":"household","ownership":"produced","rows":"all"},{"column":"source_year","dtype":"int64","entity":"household","ownership":"produced","rows":"all"},{"column":"source_household_key","dtype":"string","entity":"household","ownership":"produced","rows":"all"},{"column":"household_source_id","dtype":"int64","entity":"household","ownership":"produced","rows":"all"},{"column":"household_support_channel","dtype":"string","entity":"household","ownership":"produced","rows":"all"},{"column":"household_support_clone_index","dtype":"int64","entity":"household","ownership":"produced","rows":"all"},{"column":"household_is_spi_synthetic","dtype":"bool","entity":"household","ownership":"produced","rows":"all"}],"params":{"materialized_expand_outputs":["person.person_source_id","person.person_support_channel","person.person_support_clone_index","benunit.benunit_source_id","benunit.benunit_support_channel","benunit.benunit_support_clone_index","household.source_household_id","household.source_year","household.source_household_key","household.household_source_id","household.household_support_channel","household.household_support_clone_index","household.household_is_spi_synthetic"]},"population":"spi_support_channel","sources":[],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage hmrc_spi_income_spine.","id":"hmrc_spi_income_spine","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage","benunit_source_id","benunit_support_channel","benunit_support_clone_index"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","ons_household_type","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate","dfe_education_spending","rail_subsidy_spending","bus_subsidy_spending","rail_usage","source_household_id","source_year","source_household_key","household_source_id","household_support_channel","household_support_clone_index","household_is_spi_synthetic"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","maintenance_expenses","childcare_expenses","salary_sacrifice_reported","salary_sacrifice_asked","ssmg_reported","incapacity_benefit_reported","relationship_to_head","ons_family_role","ons_family_index","employment_status","employment_sector","sic_industry_division","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance","a_and_e_visits","admitted_patient_visits","outpatient_visits","nhs_a_and_e_spending","nhs_admitted_patient_spending","nhs_outpatient_spending","ossben_identifiable_subset","srp_regular_code5","person_source_id","person_support_channel","person_support_clone_index"],"entity":"person","rows":"all"}],"kernel":"uk.stage.hmrc_spi_income_spine@1","mass":"conserve","outputs":[{"column":"charitable_investment_gifts","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"gift_aid","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"other_investment_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_employment_benefits","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_employment_expenses","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_other_social_security_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_taxable_termination_pay","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_miscellaneous_employment_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_other_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_state_pension_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_employed_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_total_earned_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_total_investment_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"hmrc_spi_assessable_income","dtype":"float64","entity":"person","ownership":"produced","rows":"all"},{"column":"employment_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"self_employment_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"savings_interest_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"dividend_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"private_pension_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"property_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"employee_pension_contributions","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"employer_pension_contributions","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"personal_pension_contributions","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pension_contributions_via_salary_sacrifice","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"tax_free_savings_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"universal_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pension_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"child_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"housing_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"income_support_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"working_tax_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"child_tax_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"attendance_allowance_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"state_pension_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"dla_sc_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"dla_m_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pip_m_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pip_dl_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"sda_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"carers_allowance_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"iidb_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"afcs_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"bsp_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"winter_fuel_allowance_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"council_tax_benefit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"jsa_contrib_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"jsa_income_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"esa_contrib_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"esa_income_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"hmrc_spi_pay","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"hmrc_spi_unemployment_benefit_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"hmrc_spi_incapacity_benefit_income","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"aa_category","dtype":"string","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"dla_sc_category","dtype":"string","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"dla_m_category","dtype":"string","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pip_m_category","dtype":"string","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"pip_dl_category","dtype":"string","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"is_disabled_for_benefits","dtype":"bool","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"is_enhanced_disabled_for_benefits","dtype":"bool","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"is_severely_disabled_for_benefits","dtype":"bool","entity":"person","ownership":"produced","rewrite":true,"rows":"all"}],"params":{"stage":"hmrc_spi_income_spine","stage_contract_sha256":"4c2edca1f77416a00cff10c7e9d0a9da50e332a2bb6a995ef9ac1bdd00ff97a9","time_period":"2024"},"population":"spi_support_channel","sources":["frs"],"structural":"none","weights":null},{"base":"spi_support_channel","citation":"","description":"Ownership boundary before uc_reporter_redraw rewrites.","id":"uc_reporter_redraw.boundary","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage","benunit_source_id","benunit_support_channel","benunit_support_clone_index"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","ons_household_type","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate","dfe_education_spending","rail_subsidy_spending","bus_subsidy_spending","rail_usage","source_household_id","source_year","source_household_key","household_source_id","household_support_channel","household_support_clone_index","household_is_spi_synthetic"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","relationship_to_head","ons_family_role","ons_family_index","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance","a_and_e_visits","admitted_patient_visits","outpatient_visits","nhs_a_and_e_spending","nhs_admitted_patient_spending","nhs_outpatient_spending","hmrc_spi_pay","hmrc_spi_unemployment_benefit_income","hmrc_spi_incapacity_benefit_income","ossben_identifiable_subset","srp_regular_code5","employer_pension_contributions","person_source_id","person_support_channel","person_support_clone_index","charitable_investment_gifts","gift_aid","other_investment_income","hmrc_spi_employment_benefits","hmrc_spi_employment_expenses","hmrc_spi_other_social_security_income","hmrc_spi_taxable_termination_pay","hmrc_spi_miscellaneous_employment_income","hmrc_spi_other_income","hmrc_spi_state_pension_income","hmrc_spi_employed_income","hmrc_spi_total_earned_income","hmrc_spi_total_investment_income","hmrc_spi_assessable_income"],"entity":"person","rows":"all"}],"kernel":"uk.identity@1","mass":"conserve","outputs":[],"params":{},"population":null,"sources":[],"structural":"filter","weights":null},{"base":null,"citation":"","description":"Run UK spine stage uc_reporter_redraw.","id":"uc_reporter_redraw","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage","benunit_source_id","benunit_support_channel","benunit_support_clone_index"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","ons_household_type","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate","dfe_education_spending","rail_subsidy_spending","bus_subsidy_spending","rail_usage","source_household_id","source_year","source_household_key","household_source_id","household_support_channel","household_support_clone_index","household_is_spi_synthetic"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","relationship_to_head","ons_family_role","ons_family_index","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance","a_and_e_visits","admitted_patient_visits","outpatient_visits","nhs_a_and_e_spending","nhs_admitted_patient_spending","nhs_outpatient_spending","hmrc_spi_pay","hmrc_spi_unemployment_benefit_income","hmrc_spi_incapacity_benefit_income","ossben_identifiable_subset","srp_regular_code5","employer_pension_contributions","person_source_id","person_support_channel","person_support_clone_index","charitable_investment_gifts","gift_aid","other_investment_income","hmrc_spi_employment_benefits","hmrc_spi_employment_expenses","hmrc_spi_other_social_security_income","hmrc_spi_taxable_termination_pay","hmrc_spi_miscellaneous_employment_income","hmrc_spi_other_income","hmrc_spi_state_pension_income","hmrc_spi_employed_income","hmrc_spi_total_earned_income","hmrc_spi_total_investment_income","hmrc_spi_assessable_income"],"entity":"person","rows":"all"}],"kernel":"uk.stage.uc_reporter_redraw@1","mass":"conserve","outputs":[{"column":"universal_credit_reported","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"}],"params":{"stage":"uc_reporter_redraw","stage_contract_sha256":"7e94e034cad29c5bae566ffb875c42cddf3a1025c15496907e783ceff1144f8b","time_period":"2024"},"population":"uc_reporter_redraw.boundary","sources":["frs"],"structural":"none","weights":null},{"base":"uc_reporter_redraw.boundary","citation":"","description":"Ownership boundary before uc_capital_coherence rewrites.","id":"uc_capital_coherence.boundary","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage","benunit_source_id","benunit_support_channel","benunit_support_clone_index"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","ons_household_type","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate","dfe_education_spending","rail_subsidy_spending","bus_subsidy_spending","rail_usage","source_household_id","source_year","source_household_key","household_source_id","household_support_channel","household_support_clone_index","household_is_spi_synthetic"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","relationship_to_head","ons_family_role","ons_family_index","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance","a_and_e_visits","admitted_patient_visits","outpatient_visits","nhs_a_and_e_spending","nhs_admitted_patient_spending","nhs_outpatient_spending","hmrc_spi_pay","hmrc_spi_unemployment_benefit_income","hmrc_spi_incapacity_benefit_income","ossben_identifiable_subset","srp_regular_code5","employer_pension_contributions","person_source_id","person_support_channel","person_support_clone_index","charitable_investment_gifts","gift_aid","other_investment_income","hmrc_spi_employment_benefits","hmrc_spi_employment_expenses","hmrc_spi_other_social_security_income","hmrc_spi_taxable_termination_pay","hmrc_spi_miscellaneous_employment_income","hmrc_spi_other_income","hmrc_spi_state_pension_income","hmrc_spi_employed_income","hmrc_spi_total_earned_income","hmrc_spi_total_investment_income","hmrc_spi_assessable_income"],"entity":"person","rows":"all"}],"kernel":"uk.identity@1","mass":"conserve","outputs":[],"params":{},"population":null,"sources":[],"structural":"filter","weights":null},{"base":null,"citation":"","description":"Run UK spine stage uc_capital_coherence.","id":"uc_capital_coherence","inputs":[{"columns":["benunit_support_channel","dependent_children","is_married"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age","is_benunit_head","is_parent","person_support_channel","universal_credit_reported"],"entity":"person","rows":"all"}],"kernel":"uk.stage.uc_capital_coherence@1","mass":"conserve","outputs":[{"column":"uc_reported_capital","dtype":"float64","entity":"benunit","ownership":"produced","rows":"all"},{"column":"frs_benunit_capital","dtype":"float64","entity":"benunit","ownership":"produced","rewrite":true,"rows":"all"},{"column":"would_claim_uc","dtype":"bool","entity":"benunit","ownership":"produced","rewrite":true,"rows":"all"}],"params":{"stage":"uc_capital_coherence","stage_contract_sha256":"059f27ee687ee15385b246d43068b17aeecbe3645ccc41fd52fcad06a006a081","time_period":"2024"},"population":"uc_capital_coherence.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage uc_deduction_attributes.","id":"uc_deduction_attributes","inputs":[{"columns":["frs_benunit_capital","would_claim_uc"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age"],"entity":"person","rows":"all"}],"kernel":"uk.stage.uc_deduction_attributes@1","mass":"conserve","outputs":[{"column":"uc_deduction_random_draw","dtype":"float64","entity":"benunit","ownership":"produced","rows":"all"},{"column":"uc_deduction_type_random_draw","dtype":"float64","entity":"benunit","ownership":"produced","rows":"all"},{"column":"uc_latent_deduction_rate","dtype":"float64","entity":"benunit","ownership":"produced","rows":"all"},{"column":"uc_deduction_combination","dtype":"string","entity":"benunit","ownership":"produced","rows":"all"}],"params":{"stage":"uc_deduction_attributes","stage_contract_sha256":"6bc7e3ec1a5712e23ca1b7d2956e8b17f2526b94431ba3e5a9294b04658e4fe0","time_period":"2024"},"population":"uc_capital_coherence.boundary","sources":["frs"],"structural":"none","weights":null},{"base":"uc_capital_coherence.boundary","citation":"","description":"Run structural UK stage cgt_incidence_clone.","id":"cgt_incidence_clone","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage","benunit_source_id","benunit_support_channel","benunit_support_clone_index","uc_reported_capital","uc_deduction_random_draw","uc_deduction_type_random_draw","uc_latent_deduction_rate","uc_deduction_combination"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","ons_household_type","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate","dfe_education_spending","rail_subsidy_spending","bus_subsidy_spending","rail_usage","source_household_id","source_year","source_household_key","household_source_id","household_support_channel","household_support_clone_index","household_is_spi_synthetic"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","relationship_to_head","ons_family_role","ons_family_index","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance","a_and_e_visits","admitted_patient_visits","outpatient_visits","nhs_a_and_e_spending","nhs_admitted_patient_spending","nhs_outpatient_spending","hmrc_spi_pay","hmrc_spi_unemployment_benefit_income","hmrc_spi_incapacity_benefit_income","ossben_identifiable_subset","srp_regular_code5","employer_pension_contributions","person_source_id","person_support_channel","person_support_clone_index","charitable_investment_gifts","gift_aid","other_investment_income","hmrc_spi_employment_benefits","hmrc_spi_employment_expenses","hmrc_spi_other_social_security_income","hmrc_spi_taxable_termination_pay","hmrc_spi_miscellaneous_employment_income","hmrc_spi_other_income","hmrc_spi_state_pension_income","hmrc_spi_employed_income","hmrc_spi_total_earned_income","hmrc_spi_total_investment_income","hmrc_spi_assessable_income"],"entity":"person","rows":"all"}],"kernel":"uk.stage.expand.cgt_incidence_clone@1","mass":"conserve","outputs":[],"params":{"expand_cells":[["household","household_is_capital_gains_clone","bool"],["person","capital_gains","float64"]],"expand_weight_entity":"household","expand_weight_kind":"importance","stage":"cgt_incidence_clone","stage_contract_sha256":"ee30278543cc0297a5366d855b7753aa04af5518971594c193c52be36bf8a7b4","time_period":"2024"},"population":null,"sources":["frs"],"structural":"expand","weights":null},{"base":null,"citation":"","description":"Own the cells materialized by cgt_incidence_clone.","id":"cgt_incidence_clone.owned","inputs":[],"kernel":"uk.claim@1","mass":"conserve","outputs":[{"column":"household_is_capital_gains_clone","dtype":"bool","entity":"household","ownership":"produced","rows":"all"},{"column":"capital_gains","dtype":"float64","entity":"person","ownership":"produced","rows":"all"}],"params":{"materialized_expand_outputs":["household.household_is_capital_gains_clone","person.capital_gains"]},"population":"cgt_incidence_clone","sources":[],"structural":"none","weights":null},{"base":"cgt_incidence_clone","citation":"","description":"Run structural UK stage cgt_band_donors.","id":"cgt_band_donors","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage","benunit_source_id","benunit_support_channel","benunit_support_clone_index","uc_reported_capital","uc_deduction_random_draw","uc_deduction_type_random_draw","uc_latent_deduction_rate","uc_deduction_combination"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","ons_household_type","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate","dfe_education_spending","rail_subsidy_spending","bus_subsidy_spending","rail_usage","source_household_id","source_year","source_household_key","household_source_id","household_support_channel","household_support_clone_index","household_is_spi_synthetic","household_is_capital_gains_clone"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","relationship_to_head","ons_family_role","ons_family_index","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance","a_and_e_visits","admitted_patient_visits","outpatient_visits","nhs_a_and_e_spending","nhs_admitted_patient_spending","nhs_outpatient_spending","hmrc_spi_pay","hmrc_spi_unemployment_benefit_income","hmrc_spi_incapacity_benefit_income","ossben_identifiable_subset","srp_regular_code5","employer_pension_contributions","person_source_id","person_support_channel","person_support_clone_index","charitable_investment_gifts","gift_aid","other_investment_income","hmrc_spi_employment_benefits","hmrc_spi_employment_expenses","hmrc_spi_other_social_security_income","hmrc_spi_taxable_termination_pay","hmrc_spi_miscellaneous_employment_income","hmrc_spi_other_income","hmrc_spi_state_pension_income","hmrc_spi_employed_income","hmrc_spi_total_earned_income","hmrc_spi_total_investment_income","hmrc_spi_assessable_income","capital_gains"],"entity":"person","rows":"all"}],"kernel":"uk.stage.expand.cgt_band_donors@1","mass":"free","outputs":[],"params":{"expand_cells":[["household","household_is_cgt_band_donor","bool"],["person","capital_gains","float64"]],"expand_weight_entity":"household","expand_weight_kind":"importance","stage":"cgt_band_donors","stage_contract_sha256":"e10e10c49c0ca2a6a65048c91b683f818e8b6e207a6c6f57a20d76ea299160b0","time_period":"2024"},"population":null,"sources":["frs"],"structural":"expand","weights":null},{"base":null,"citation":"","description":"Own the cells materialized by cgt_band_donors.","id":"cgt_band_donors.owned","inputs":[],"kernel":"uk.claim@1","mass":"conserve","outputs":[{"column":"household_is_cgt_band_donor","dtype":"bool","entity":"household","ownership":"produced","rows":"all"},{"column":"capital_gains","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"}],"params":{"materialized_expand_outputs":["household.household_is_cgt_band_donor"]},"population":"cgt_band_donors","sources":[],"structural":"none","weights":null},{"base":"cgt_band_donors","citation":"","description":"Ownership boundary before hmrc_cgt_gains_spine rewrites.","id":"hmrc_cgt_gains_spine.boundary","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage","benunit_source_id","benunit_support_channel","benunit_support_clone_index","uc_reported_capital","uc_deduction_random_draw","uc_deduction_type_random_draw","uc_latent_deduction_rate","uc_deduction_combination"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","ons_household_type","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate","dfe_education_spending","rail_subsidy_spending","bus_subsidy_spending","rail_usage","source_household_id","source_year","source_household_key","household_source_id","household_support_channel","household_support_clone_index","household_is_spi_synthetic","household_is_capital_gains_clone","household_is_cgt_band_donor"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","employee_pension_contributions","pension_contributions_via_salary_sacrifice","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","relationship_to_head","ons_family_role","ons_family_index","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance","a_and_e_visits","admitted_patient_visits","outpatient_visits","nhs_a_and_e_spending","nhs_admitted_patient_spending","nhs_outpatient_spending","hmrc_spi_pay","hmrc_spi_unemployment_benefit_income","hmrc_spi_incapacity_benefit_income","ossben_identifiable_subset","srp_regular_code5","employer_pension_contributions","person_source_id","person_support_channel","person_support_clone_index","charitable_investment_gifts","gift_aid","other_investment_income","hmrc_spi_employment_benefits","hmrc_spi_employment_expenses","hmrc_spi_other_social_security_income","hmrc_spi_taxable_termination_pay","hmrc_spi_miscellaneous_employment_income","hmrc_spi_other_income","hmrc_spi_state_pension_income","hmrc_spi_employed_income","hmrc_spi_total_earned_income","hmrc_spi_total_investment_income","hmrc_spi_assessable_income","capital_gains"],"entity":"person","rows":"all"}],"kernel":"uk.identity@1","mass":"conserve","outputs":[],"params":{},"population":null,"sources":[],"structural":"filter","weights":null},{"base":null,"citation":"","description":"Run UK spine stage hmrc_cgt_gains_spine.","id":"hmrc_cgt_gains_spine","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age","dividend_income","employment_income","miscellaneous_income","private_pension_income","property_income","savings_interest_income","self_employment_income","state_pension_reported","tax_free_savings_income"],"entity":"person","rows":"all"}],"kernel":"uk.stage.hmrc_cgt_gains_spine@1","mass":"conserve","outputs":[{"column":"capital_gains","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"}],"params":{"stage":"hmrc_cgt_gains_spine","stage_contract_sha256":"20ada8d8ee94400bd160223e865a910db7aff9c40a7f0c8ee8ca8c40ed901b72","time_period":"2024"},"population":"hmrc_cgt_gains_spine.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage salary_sacrifice.","id":"salary_sacrifice","inputs":[{"columns":["frs_benunit_capital","is_married","dependent_children","would_claim_child_benefit","child_benefit_opts_out","would_claim_pc","would_claim_uc","would_claim_tfc","would_claim_extended_childcare","would_claim_universal_childcare","would_claim_targeted_childcare","maximum_extended_childcare_hours_usage","benunit_source_id","benunit_support_channel","benunit_support_clone_index","uc_reported_capital","uc_deduction_random_draw","uc_deduction_type_random_draw","uc_latent_deduction_rate","uc_deduction_combination"],"entity":"benunit","rows":"all"},{"columns":["region","tenure_type","accommodation_type","num_bedrooms","council_tax_reported","council_tax_band","council_tax_rebate","council_tax_single_adult_raw","water_and_sewerage_charges","domestic_rates","rent","subrent","mortgage_interest_repayment","mortgage_capital_repayment","structural_insurance_payments","housing_service_charges","external_child_payments","ons_household_type","council_tax","household_owns_tv","would_evade_tv_licence_fee","main_residential_property_purchased_is_first_home","property_purchased","brma","owned_land","property_wealth","corporate_wealth","private_pension_wealth","gross_financial_wealth","net_financial_wealth","main_residence_value","other_residential_property_value","non_residential_property_value","savings","num_vehicles","cash_isa","stocks_and_shares_isa","mortgage_debt","consumer_debt","food_and_non_alcoholic_beverages_consumption","alcohol_and_tobacco_consumption","clothing_and_footwear_consumption","housing_water_and_electricity_consumption","household_furnishings_consumption","health_consumption","transport_consumption","communication_consumption","recreation_consumption","education_consumption","restaurants_and_hotels_consumption","miscellaneous_consumption","petrol_spending","diesel_spending","bus_fare_spending","domestic_energy_consumption","electricity_consumption","gas_consumption","has_fuel_consumption","full_rate_vat_expenditure_rate","dfe_education_spending","rail_subsidy_spending","bus_subsidy_spending","rail_usage","source_household_id","source_year","source_household_key","household_source_id","household_support_channel","household_support_clone_index","household_is_spi_synthetic","household_is_capital_gains_clone","household_is_cgt_band_donor"],"entity":"household","rows":"all"},{"columns":["age","gender","marital_status","hours_worked","is_household_head","is_benunit_head","is_parent","is_uc_claimant","employment_income","self_employment_income","private_pension_income","tax_free_savings_income","savings_interest_income","dividend_income","property_income","maintenance_income","miscellaneous_income","private_transfer_income","lump_sum_income","student_loan_repayments","statutory_sick_pay","statutory_maternity_pay","student_loans","access_fund","education_grants","healthy_start_vouchers","free_school_breakfasts","free_school_fruit_veg","free_school_meals","council_tax_benefit_reported","maintenance_expenses","childcare_expenses","personal_pension_contributions","salary_sacrifice_reported","salary_sacrifice_asked","child_benefit_reported","income_support_reported","housing_benefit_reported","attendance_allowance_reported","dla_sc_reported","dla_m_reported","iidb_reported","carers_allowance_reported","sda_reported","afcs_reported","ssmg_reported","pension_credit_reported","child_tax_credit_reported","working_tax_credit_reported","state_pension_reported","winter_fuel_allowance_reported","incapacity_benefit_reported","universal_credit_reported","pip_m_reported","pip_dl_reported","jsa_contrib_reported","jsa_income_reported","esa_contrib_reported","esa_income_reported","bsp_reported","relationship_to_head","ons_family_role","ons_family_index","employment_status","employment_sector","sic_industry_division","aa_category","dla_sc_category","dla_m_category","pip_m_category","pip_dl_category","is_disabled_for_benefits","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","current_education","highest_education","is_in_non_advanced_education","is_in_approved_training","age_started_or_accepted_current_education_or_training","is_before_universal_credit_qualifying_young_person_terminal_date","adult_ema","child_ema","receives_benefits_in_own_right","legacy_jobseeker_proxy","esa_health_condition_proxy","esa_support_group_proxy","disabled_students_allowance_eligible_expenses","would_claim_marriage_allowance","would_claim_scp","attends_private_school_random_draw","tax_free_childcare_spend_routed_share","student_loan_balance","a_and_e_visits","admitted_patient_visits","outpatient_visits","nhs_a_and_e_spending","nhs_admitted_patient_spending","nhs_outpatient_spending","hmrc_spi_pay","hmrc_spi_unemployment_benefit_income","hmrc_spi_incapacity_benefit_income","ossben_identifiable_subset","srp_regular_code5","employer_pension_contributions","person_source_id","person_support_channel","person_support_clone_index","charitable_investment_gifts","gift_aid","other_investment_income","hmrc_spi_employment_benefits","hmrc_spi_employment_expenses","hmrc_spi_other_social_security_income","hmrc_spi_taxable_termination_pay","hmrc_spi_miscellaneous_employment_income","hmrc_spi_other_income","hmrc_spi_state_pension_income","hmrc_spi_employed_income","hmrc_spi_total_earned_income","hmrc_spi_total_investment_income","hmrc_spi_assessable_income","capital_gains"],"entity":"person","rows":"all"}],"kernel":"uk.stage.salary_sacrifice@1","mass":"conserve","outputs":[{"column":"pension_contributions_via_salary_sacrifice","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"},{"column":"employee_pension_contributions","dtype":"float64","entity":"person","ownership":"produced","rewrite":true,"rows":"all"}],"params":{"stage":"salary_sacrifice","stage_contract_sha256":"a4af925af21cc6766eb7c8855b6743a3aa4eeeb38df12cfc83063d7ad6890539","time_period":"2024"},"population":"hmrc_cgt_gains_spine.boundary","sources":["frs"],"structural":"none","weights":null},{"base":null,"citation":"","description":"Run UK spine stage student_loans.","id":"student_loans","inputs":[{"columns":["frs_benunit_capital"],"entity":"benunit","rows":"all"},{"columns":["region"],"entity":"household","rows":"all"},{"columns":["age","current_education","employee_pension_contributions","highest_education","student_loan_repayments","student_loans"],"entity":"person","rows":"all"}],"kernel":"uk.stage.student_loans@1","mass":"conserve","outputs":[{"column":"student_loan_plan","dtype":"string","entity":"person","ownership":"produced","rows":"all"}],"params":{"stage":"student_loans","stage_contract_sha256":"7c4c76398c2e80b41c7f941a5f06246b57d89b5eb0c36d42e3116ac35e82e203","time_period":"2024"},"population":"hmrc_cgt_gains_spine.boundary","sources":["frs"],"structural":"none","weights":null}],"sources":[{"codec":"csv-tables","description":"Content-bound UK FRS and donor fixture/source bundle.","name":"frs"}]} diff --git a/packages/microcosm-graph/tests/test_acceptance_h_parity.py b/packages/microcosm-graph/tests/test_acceptance_h_parity.py index 44698f765..34522c4ec 100644 --- a/packages/microcosm-graph/tests/test_acceptance_h_parity.py +++ b/packages/microcosm-graph/tests/test_acceptance_h_parity.py @@ -43,7 +43,7 @@ #: was taken under). KERNEL_PARITY = PARITY / "kernels" -#: H2: ``uk_spine.json`` — the 28-stage FRS spine expressed as a graph — plus +#: H2: ``uk_spine.json`` — the 29-stage FRS spine expressed as a graph — plus #: ``sources/``, the data-only bundle both the graph and the legacy oracle #: rebuild their transforms from. The root transform's weights differ at the #: last bit between machines, so both sides recompute the root from the raw @@ -250,13 +250,13 @@ def test_h2_uk_spine_parity(tmp_path: Path) -> None: engine tier (``requires_uk``) and skips in the engine-free fast lane. Expects ``packages/microcosm-graph/tests/fixtures/parity/uk_spine/`` with - ``uk_spine.json`` and ``sources/``; both sides run the 28 transforms from + ``uk_spine.json`` and ``sources/``; both sides run the 29 transforms from those sources in this process, root included, because the root weights differ at the last bit between machines. Stage order comes from declared ``consumes``: the assertion below is that the compiled topological order is derived, so the hand-maintained ``_STAGE_NAMES`` tuple - in ``tools/build_uk_frs_spine.py`` — the 28 names intersected with a - 28-stage packaged manifest, kept in step by hand — can be deleted. + in ``tools/build_uk_frs_spine.py`` — the 29 names intersected with a + 29-stage packaged manifest, kept in step by hand — can be deleted. """ _require(UK_SPINE_PARITY, "the UK migration lane (charter H2, María reviews)") @@ -280,7 +280,7 @@ def test_h2_uk_spine_parity(tmp_path: Path) -> None: graph = uk_spine_graph() assert graph_from_json((UK_SPINE_PARITY / "uk_spine.json").read_text()) == graph compiled = compile_graph(graph) - assert len(compiled.order) >= 29, "a CREATE node plus the 28 spine stages" + assert len(compiled.order) >= 30, "a CREATE node plus the 29 spine stages" assert all( set(compiled.predecessors[node_id]) <= set(compiled.order[:index]) for index, node_id in enumerate(compiled.order) diff --git a/packages/microcosm-graph/tests/test_graph_population.py b/packages/microcosm-graph/tests/test_graph_population.py index a96562d88..e08aac0f8 100644 --- a/packages/microcosm-graph/tests/test_graph_population.py +++ b/packages/microcosm-graph/tests/test_graph_population.py @@ -1434,3 +1434,46 @@ def test_reweight_can_synthesize_frame_but_must_not_change_ids() -> None: ) with pytest.raises(PopulationError, match="changed 'person' ids"): patch(population, node, KernelResult(frame=reordered)) + + +def test_new_dense_column_on_a_filtered_population_keeps_its_dtype() -> None: + # A filtered population (a sampled spine rung) carries a non-contiguous + # table index. The zero-filled placeholder for a new dense column is + # built positionally; inserting it label-aligned NaN-filled the gaps and + # silently widened person.int64 to float64 (found by the microcosm#791 + # sampled build). The placeholder must bind to the table's own index. + frame = _frame() + person = frame.table("person").copy() + person.index = pd.Index([243, 244, 1099, 1250]) + strata = frame.strata.copy() + strata.index = person.index + population = Population.from_frame( + _replace_person_table(frame, person, strata), "source" + ) + node = Node( + "new_dense_all_rows", + "test@1", + inputs=(Slice("person", ("amount",)),), + outputs=( + Owned("person", "count", "int64"), + Owned("person", "flag", "bool"), + ), + ) + result = KernelResult( + columns={ + ("person", "count"): pd.Series( + [3, 1, 2, 4], index=[1, 2, 3, 4], dtype="int64" + ), + ("person", "flag"): pd.Series( + [True, False, True, False], index=[1, 2, 3, 4], dtype=bool + ), + } + ) + + updated = patch(population, node, result) + + table = updated.frame.table("person") + assert table["count"].dtype == np.dtype("int64") + assert table["count"].tolist() == [3, 1, 2, 4] + assert table["flag"].dtype == np.dtype("bool") + assert table["flag"].tolist() == [True, False, True, False] diff --git a/tools/build_uk_frs_spine.py b/tools/build_uk_frs_spine.py index 3512a79e2..8ca3d484c 100644 --- a/tools/build_uk_frs_spine.py +++ b/tools/build_uk_frs_spine.py @@ -68,6 +68,10 @@ UKFRSLegacyProxiesStageTransform, ) from microcosm.build.uk_runtime.frs_person_draws import UKFRSPersonDrawsStageTransform +from microcosm.build.uk_runtime.frs_relationships import ( + CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS, + UKFRSRelationshipsStageTransform, +) from microcosm.build.uk_runtime.frs_release import load_uk_frs_release from microcosm.build.uk_runtime.frs_spine import ( UKFRSSpineStageTransform, @@ -885,6 +889,17 @@ def _run_plan_with_spine_sampling( return frame, (*spine_records, *assembled_records, *tail_records), sampling +def _spine_gate_artifacts(engine: object) -> dict[str, object]: + """Evidence artifacts for spine-phase gates: the engine plus frame-only enum domains.""" + + return { + "rules_engine": engine, + # #791: ons_household_type is a frame column, not an engine variable, + # so its enum_domain gate takes the declared domain as an artifact. + "ons_household_type_enum_domain": CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS, + } + + def _run_spine_gate_phase( battery: GateBatteryRun, phase: str, @@ -1106,6 +1121,12 @@ def main(argv: list[str] | None = None) -> int: "frs_disability": UKFRSDisabilityStageTransform( stage=stages_by_name["frs_disability"], ), + "frs_relationships": _GraphSourceTransform( + lambda sources: UKFRSRelationshipsStageTransform( + sources["frs"], + stage=stages_by_name["frs_relationships"], + ) + ), "frs_education": _GraphSourceTransform( lambda sources: UKFRSEducationStageTransform( sources["frs"], @@ -1310,7 +1331,7 @@ def main(argv: list[str] | None = None) -> int: stage_names=stage_names[:assembled_index], implementations=implementations, ), - gate_artifacts={"rules_engine": engine}, + gate_artifacts=_spine_gate_artifacts(engine), ) if assembled_index < len(stage_names): _run_spine_gate_phase( @@ -1321,7 +1342,7 @@ def main(argv: list[str] | None = None) -> int: stage_names=stage_names, implementations=implementations, ), - gate_artifacts={"rules_engine": engine}, + gate_artifacts=_spine_gate_artifacts(engine), ) if spine_battery is not None: append_phase(state, "spine_gates_evaluated") diff --git a/tools/graph_uk_spine_fixture.py b/tools/graph_uk_spine_fixture.py index 16dcc9266..e6b2fde64 100644 --- a/tools/graph_uk_spine_fixture.py +++ b/tools/graph_uk_spine_fixture.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """Regenerate the hermetic charter-H2 UK spine parity fixture. -The oracle is the legacy :class:`microcosm.build.plan.StagePlan`: all 28 +The oracle is the legacy :class:`microcosm.build.plan.StagePlan`: all 29 stages are the current production transform classes. Private source files are replaced only through their supported parsed-input seams. The bundle's ``fixture.json`` is deliberately data-only so the graph's unbound UK registry @@ -54,6 +54,9 @@ UKFRSLegacyProxiesStageTransform, ) from microcosm.build.uk_runtime.frs_person_draws import UKFRSPersonDrawsStageTransform +from microcosm.build.uk_runtime.frs_relationships import ( + UKFRSRelationshipsStageTransform, +) from microcosm.build.uk_runtime.frs_spine import ( FRS_SPINE_TABLES, UKFRSSpineStageTransform, @@ -126,11 +129,11 @@ _SPI_DONOR_SAMPLE_SIZE = 64 #: The packaged FRS spine roster the fixture exercises (manifest minus the #: certified-pair exclusions); moves whenever a spine stage is added. -UK_FIXTURE_STAGE_COUNT = 28 +UK_FIXTURE_STAGE_COUNT = 29 _QRF_ESTIMATORS = 4 # These are the complete object-string surface observed in the unchanged -# legacy 28-stage output. Graph storage uses pandas StringDtype/python. +# legacy 29-stage output. Graph storage uses pandas StringDtype/python. _NORMALIZED_STRING_COLUMNS: Mapping[str, tuple[str, ...]] = { "person": ( "gender", @@ -146,6 +149,8 @@ "highest_education", "person_support_channel", "student_loan_plan", + "relationship_to_head", + "ons_family_role", ), "benunit": ("benunit_support_channel", "uc_deduction_combination"), "household": ( @@ -156,6 +161,7 @@ "brma", "household_support_channel", "source_household_key", + "ons_household_type", ), } @@ -304,6 +310,7 @@ def _frs_tables() -> dict[str, pd.DataFrame]: "CTBAND": 1 + household_id % 7, "CTREBAMT": float(household_id % 3), "ADULTH": 1, + "HRPNUM": 1, "CSEWAMT": "", "CWATAMTD": 0.0, "CWATAMT1": 4.0 if scotland else "", @@ -338,6 +345,11 @@ def _frs_tables() -> dict[str, pd.DataFrame]: "TOTHOURS": 20 + household_id % 25, "HRPID": 1, "UPERSON": 1, + # #791 household grid: the HRP carries a blank relhrp and, when a + # child is present, the parent code toward person 2. + "RELHRP": "", + **{f"R{index:02d}": "" for index in range(1, 15)}, + **({"R02": 7} if has_child else {}), "MARITAL": 1 + household_id % 3, "EMPSTATI": 1 + household_id % 8, "MJOBSECT": 1 + household_id % 2, @@ -390,6 +402,9 @@ def _frs_tables() -> dict[str, pd.DataFrame]: "TOTHOURS": np.nan, "HRPID": 0, "UPERSON": 0, + "RELHRP": 3, + **{f"R{index:02d}": "" for index in range(1, 15)}, + "R01": 3, "MARITAL": 2, "FTED": 1, "TYPEED2": 2, @@ -866,7 +881,7 @@ def _normalization_markdown() -> str: lines = [ "# UK spine parity string normalization", "", - "The unchanged legacy transforms retain these 22 textual table columns as", + "The unchanged legacy transforms retain these 25 textual table columns as", "pandas `object`. The frozen graph dtype token `string` is specified by", 'interface-freeze amendment 10 as pandas `StringDtype(storage="python")`.', "Before computing the legacy oracle's `uk_frame_content_identity` (live,", @@ -922,8 +937,8 @@ def _normalize_legacy_strings(frame: Frame) -> Frame: for entity, columns in _NORMALIZED_STRING_COLUMNS.items() for column in columns ] - if observed != expected_order or len(observed) != 22: - raise RuntimeError("The legacy normalization audit is not exactly 22 cells.") + if observed != expected_order or len(observed) != 25: + raise RuntimeError("The legacy normalization audit is not exactly 25 cells.") return Frame( tables, frame.schema, @@ -1026,6 +1041,9 @@ def capture_root(frame: Frame) -> Frame: implementations: dict[str, object] = { "frs_spine": capture_root, + "frs_relationships": UKFRSRelationshipsStageTransform( + raw_dir, stage=stages["frs_relationships"] + ), "frs_employment": UKFRSEmploymentStageTransform( raw_dir, stage=stages["frs_employment"] ), @@ -1126,7 +1144,7 @@ def _run_legacy_plan( stages: Iterable[SourceStageSpec], implementations: Mapping[str, object], ) -> Frame: - """Run the legacy 28-stage StagePlan oracle and return its final frame.""" + """Run the legacy 29-stage StagePlan oracle and return its final frame.""" stages = tuple(stages) committed = load_country_spec("uk") @@ -1159,7 +1177,7 @@ def _run_legacy_plan( def legacy_oracle_frame(fixture: Path) -> Frame: """The legacy oracle's final frame on the fixture, computed live. - Rebuilds the same 28 transforms the graph's UK registry reconstructs from + Rebuilds the same 29 transforms the graph's UK registry reconstructs from ``fixture/sources``, runs them through the legacy StagePlan in this process, root included, and applies the one string normalization the fixture documents. The content identity is a byte-exact fingerprint of @@ -1238,7 +1256,7 @@ def generate(output: Path) -> None: descriptor = { "schema_version": "uk-spine-parity-fixture.v1", "description": ( - "Data-only inputs for reconstructing the same 28 current UK stage " + "Data-only inputs for reconstructing the same 29 current UK stage " "transform classes used by the legacy StagePlan oracle." ), "stages": {stage.stage: _stage_payload(stage) for stage in stages}, @@ -1274,7 +1292,7 @@ def generate(output: Path) -> None: _normalization_markdown(), encoding="utf-8" ) (output / "PRODUCED_BY.txt").write_text( - "tools/graph_uk_spine_fixture.py; current 28-transform legacy " + "tools/graph_uk_spine_fixture.py; current 29-transform legacy " "StagePlan oracle with parsed private-source seams. The acceptance " "test runs both sides from frs_raw in-process (root weights differ " "by one ulp between machines); the captured root tables serve the " From 34f0691dcf6926f3ddd11ad468d910a92d10dbbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Fri, 11 Sep 2026 15:42:20 +0200 Subject: [PATCH 2/4] Address Vahid's review round 1 on #903 and retire the eFRS reference regeneration test (#791) Should-fixes: the census_disclosure_control_noise adjudication reason carries a dated re-wording trailer for the bound bridge beside the #887 one; the plan of record is committed as docs/uk-relationship-to-head-plan-791.md and the receipts and PR body point at it. Questions: the unrelated-adults and lone-parent contract notes record the skip-generation age switch (under 16 with no parent present: two unrelated adults; 16-19 in full-time education: the FRS codes the grandparents as legal guardian, so a family with a dependent child) and cite the ONS "Families and households statistics explained" definition by URL. Nits: a non-numeric age refuses instead of reading as 0; stage_health.py is the main text plus the composition hunks only. Retire test_cached_reference_regeneration_matches_committed_surface (Maria's call): it regenerated the pinned eFRS parity reference under the installed engine, was skipped in CI and has failed on main since the 2.97.0 lock; the other thirteen reference integrity tests stay. Co-Authored-By: Claude Fable 5.1 (cherry picked from commit 12462fb046aa27e31d84a0c99296e1ef5b248ef9) --- ...frs-reference-regeneration-test.removed.md | 1 + docs/uk-relationship-to-head-plan-791.md | 111 ++++++++++++ .../791-household-composition-receipts.md | 8 +- .../build/uk/local_binding_adjudications.json | 2 +- .../build/uk_runtime/frs_relationships.py | 9 +- .../build/uk_runtime/stage_health.py | 165 ++++-------------- .../tests/test_uk_frs_relationships.py | 18 ++ .../tests/test_uk_parity_reference.py | 25 --- 8 files changed, 180 insertions(+), 159 deletions(-) create mode 100644 changelog.d/791-efrs-reference-regeneration-test.removed.md create mode 100644 docs/uk-relationship-to-head-plan-791.md diff --git a/changelog.d/791-efrs-reference-regeneration-test.removed.md b/changelog.d/791-efrs-reference-regeneration-test.removed.md new file mode 100644 index 000000000..380f7bb66 --- /dev/null +++ b/changelog.d/791-efrs-reference-regeneration-test.removed.md @@ -0,0 +1 @@ +Retire `test_uk_parity_reference.py::test_cached_reference_regeneration_matches_committed_surface`. It regenerated the pinned enhanced-FRS parity reference from the cached licensed artifact under whichever policyengine-uk the lock installs and asserted byte-equality with the committed file, so every engine bump broke it until the reference was re-pinned (the committed reference carries 2.89.0, the lock 2.97.0), and it was skipped in CI, where the licensed artifact is absent. The thirteen other integrity tests on the reference remain, including the check that the recorded sha256 matches the cached artifact's bytes. diff --git a/docs/uk-relationship-to-head-plan-791.md b/docs/uk-relationship-to-head-plan-791.md new file mode 100644 index 000000000..181a61539 --- /dev/null +++ b/docs/uk-relationship-to-head-plan-791.md @@ -0,0 +1,111 @@ +# Implementation plan for microcosm#791 (relationship-to-head frame column; ONS household-composition split measurable) + +Plan file of record (approved 2026-09-11 in plan mode; María’s rulings the same day: rebind all ten cells, one PR, #791 lands before her #901, all four new columns exported). Committed here as the plan of record for PR #903; María’s working copy is `repos/uk-791-relationship-to-head-plan.md`. + +## Context + +Issue #791 (successor to the #757 `uk_target_fit` dispositions, comment 5427936411): three ONS household-composition targets are unmeasurable because the UK spine carries no relationship-to-head column, so the household-type derivation cannot tell a second family from unrelated adults or from the head's non-dependent children. The three cells (`ons.household_composition.multi_family_households` +1618 %, `unrelated_adult_households` +48 %, `lone_parent_non_dependent_children_households` −0.03 % but the wrong concept) carry signed measure exclusions (`packages/microcosm-build/src/microcosm/build/uk/calibration_measure_exclusions.json:336-364`, approved 2026-08-26, **expires 2026-11-26**, tracking microcosm#791). Closing the issue = derive the column on the spine, re-derive the categories per the ONS definitions, retire the three exclusions. + +### What exploration established (verified on origin/main 6f7571e1; the `populace-887` worktree is byte-identical to it) + +- **There is no classifier function.** The ten `ons.household_composition.*` rows (`uk/uk_population_targets.json:9544-10068`, family `ons_household_composition`, ONS Families and households Table 7, UK, period 2025, `value_variable: household_count`; dimension values `lone_households_under_65`, `lone_households_over_65`, `unrelated_adult_households`, `couple_no_children_households`, `couple_under_3_children_households`, `couple_3_plus_children_households`, `couple_non_dependent_children_only_households`, `lone_parent_dependent_children_households`, `lone_parent_non_dependent_children_households`, `multi_family_households`) derive their category declaratively through `household_conditions` over the engine variables `family_type`, `is_child` (= age < 18), `age`, `household_num_benunits`. Conditions with `reduce` go to `UKFrameTargetAdapter.household_condition` (`uk_runtime/ledger_targets.py:812-857`); reduce-less household conditions (the `multi_family` row today) go through `_predicate_mask` → `_column` → plain `==` (`build/target_materialization.py:675-694`). The conditions were ported from uk-data `targets/compute/households.py`, including its summed-ages "head age" proxy (admitted in the rows' `notes`). +- **The defect is partition-wide.** The seven "exact" cells were tightened in the #757 audit with person-count restrictions (e.g. couple_no_children = couple benunit AND person count == 2). ONS classifies a household with one family plus other individuals (couple + lodger, couple + elderly parent) by that family; today such households fall into no exact cell and were absorbed by `multi_family` (`household_num_benunits > 1`) and `unrelated_adult`. The ten published 2025 values sum exactly to `ons.households_total` (29,003,000; vendored in `uk/registry_parity_fixture_2025.json:6171-6320`) and form the higher side of cross-grain bridge `national_household_composition_partition_vs_census_households` (`ledger_targets.py:78-96`; lower side `ons.census.households`, 1,011 constituency/LA cells), unbound while any member is excluded (`cross_grain.py:516-548`). Hence María's ruling: all ten rows move to one derivation. +- **No new raw input is needed.** `frs_spine.py:334-357` reads every column of the 14 pinned FRS 2024-25 tabs (SN 9563, `uk/frs_release.json`). The local release at `/Users/mariajuaristi/Desktop/PolicyEngine/data/ukds/frs_2024_25/` (per-tab digests match `uk/source_stages.json`) carries on `adult.tab` and `child.tab`: `R01..R14` (on person i's record, `R0j` = i's relationship to within-household person j; j = `person_id % 1000` since `person_id = sernum*1000 + person`, `frs_spine.py:368-371`), `relhrp` (relationship to the household reference person; blank for the HRP; 16,288 blanks = 16,288 households = exactly one HRP, coinciding with `hrpid == 1` = `is_household_head`), `educft` (adult and child; there is no `fted` on the 2024-25 tape, `frs_education.py:157` already falls back `fted → educft`, "in FTE" = `educft == 1`), and `DEPEND` on child (not to be relied on: FRS dependency runs to 19). `househol.tab` carries `hrpnum` and `hhcomps`; `hhcomps` is fully determined by (`adulth`, `depchldh`, sex/pension age), verified by cross-tab, so it carries no family structure. +- **FRS relationship codes** (FRS 2023-24 question instructions, Household Grid "Relationship"; step 0 re-verifies them against the SN 9563 2024-25 documentation): 1 spouse, 2 cohabitee, 3 son/daughter (incl adopted/legal dependent), 4 step-son/daughter, 5 foster child, 6 son/daughter-in-law, 7 father/mother/guardian, 8 step-parent, 9 foster parent, 10 parent-in-law, 11 brother/sister (incl adopted), 12 step-sibling (half-siblings here), 13 foster sibling, 14 sibling-in-law, 15 grandchild, 16 grandparent, 17 other relative, 18 other non-relative, 20 civil partner; 97 unused. Relatives of cohabitees are coded as if married. A 16–19 in FTE living with grandparents has the grandparent coded as guardian (7/3). HRP = highest-income householder, elder on ties (FRS BIM 2023-24). +- **ONS definitions** (Families and households 2024 bulletin; "Families and households statistics explained"): family = married/civil-partnered/cohabiting couple with or without children, or a lone parent with ≥ 1 child, at the same address; children dependent or non-dependent. Dependent child = under 16, or 16–18 in full-time education, excluding 16–18s with a partner or own child in the household. Non-dependent child = living with parent(s), aged 19+ with no partner/child in the household, or 16–18 not in FTE with no partner/child. One-family household = couple (no children / dependent children / non-dependent children only) or lone parent (dependent / non-dependent only); one family plus other individuals is still one-family, classified by the family. "Two or more unrelated adults" = 2+ people none of whom is in a family (no couple, no parent–child; two siblings count here). Multi-family = 2+ families. Foster children and children living with someone other than their parents are separate one-person family units. Source is the LFS; the FRS grid translates the same relationship concept, and the residual differences are translation notes on the rows, not fences. +- **Frame typing, export and parity are fail-closed.** Stage-owned cells are declared in `_STAGE_CELLS` (`uk_runtime/graph.py:353+`; household string cells already exist: `brma`, `household_support_channel`); the export allowlist `UK_ALLOWED_EXTRA_EXPORT_COLUMNS` (`uk_runtime/terminal_gates.py:163-231`, mirrored in `uk/gates.json` gate `uk_export_surface`) must list each non-engine column; `tools/verify_uk_spine_parity.py:396-434` treats an unsigned `only_in_candidate` column as a defect (`uk/spine_swap_signed_differences.json`). Non-engine string columns already ride the H5 into `Microsimulation` (`person_support_channel`, `source_household_key`). +- **Seam side is ready.** `resolve_target_measures` (`target_materialization.py:132-262`) materialises from the frame tables first; a missing column is routed to `UKMeasureResolver.knows` (`measure_simulation.py:367-395`), which refuses non-engine names, so the household column must be on the spine H5 (no engine fallback, no engine change). `_compare_series`/`_compare` handle string `==`. +- **US precedent**: `us_runtime/relationship_inputs.py` (stage `relationship_inputs`, fail-closed on missing/invalid codes, signal gate `:279-300`, tests `tests/test_us_relationship_inputs.py`). UK stage template: `uk_runtime/frs_education.py` (re-reads pinned adult+child tabs; manifest ops `read_tables` + `derive`, `uk/source_stages.json:537-612`). +- **Generated target surfaces do not carry bindings** (`tools/generate_uk_target_references.py:341-366` copies only observation basis/period fields), so rebinding moves none of `target_references.json`, `target_reference_membership.json`, the parity fixtures; it moves the spec digest (`tests/test_spec_engine_country_bundles.py:54`) and the field-usage ledger (`tests/test_spec_engine_field_usage.py`). +- **Binding the bridge is receipt-level, not numeric**: A15 already uprates each census grain to `ons.households_total` (`experiments/887-census-households-receipts.md:155-165`), the ten cells sum to the same total, so `factor = parent_value / raw_sum` (`cross_grain.py:377`) is 1.0 to float precision; what changes is `receipt["groups"]` gaining the bridge, `unbound_bridges == []`, and the dense assembler dropping the `unbound_bridge:` limitation (`tools/assemble_uk_dense_release_dir.py:164-171,515-523`). Deleting all three register entries is what binds it; a partial deletion raises (`cross_grain.py:530-535`). +- **Pinned to the exclusions**: `tests/test_uk_measure_simulation.py:562-680` (`_PACKAGED_EXCLUSION_CENSUS` has `"ons.household_composition.": 3`; 51 names; 2026-08-26 tranche 39; composition entries must track #791); synthetic bridge fixtures in `tests/test_uk_ledger_targets.py:1326-1385`, `tests/test_uk_rowwise_candidate.py:1155-1170`, `tests/test_cross_grain.py:278-325`, `tests/test_uk_dense_release_assembler.py:198-204`; wording in `uk/local_binding_adjudications.json:6` and `uk/uk_local_target_census.json:101`. The release fence `uk_target_fit` (`uk/gates.json:706-715`, 25 %; `target_fit_reviewed_exclusions.json` empty) covers the three cells with no cover once re-bound. +- **Conflict surface**: María's draft #901 (stacked on Max's #893) edits `sources.yaml`, `source_stages.json`, `graph.py`, `graph_kernels.py`, `calibration_run.py` and the spec digest pin; Max's draft #749 edits `spine_swap_signed_differences.json` and the parity pins. Ruling: #791 lands first on main; #901 and #749 rebase. +- **Publisher side (Chronicle, `origin/main` ca727a2; the local `fork/main` is stale)**: package `ons-families-households-2025` (`packages/ons/families_households_2025/source_package.yaml`), Table 7 sheet `7` of `familiesandhouseholdsuk2025.xlsx` (sha `a89eaa3d…`), record sets `cy2018..cy2025`, ten `detail` rows per year with `groupby_dimension ons.household_type`, no total row, no CI, and **no Table 7 note text** (notes 4/5/6/7/10/11 survive only as markers in the row labels; the ONS definitions above come from the bulletin and the "statistics explained" article and are recorded in the contract notes and receipts; a Chronicle follow-up to carry the note text as `definition` fields is optional, María's call). The 2025 values bound today resolve on feed `ec7169b5` (`ledger_source_record_id ons.families_households_2025.table7.cy2025..households`). Sibling census packages (`ons/census2021_ts003_household_composition_country`, NRS UV113, NISRA; chronicle#237) are the independent census benchmark for the LFS-based Table 7 rows; Chronicle states that the map onto Table 7 categories is a consumer declaration, i.e. Microcosm's job (`docs/chronicle-governance.md:10-45`). +- **Evidence on disk**: the rebind packet the register reasons cite is `~/Desktop/PolicyEngine/data/ukds/acceptance/757-swap/calibration_diagnostics_rebind.json` (build `uk-frs-calibration-attempt-20260826T160611Z-f83004f0`, loss 0.1362; multi_family 4,191,850 vs 244,000 = +1617.97 %, unrelated_adult +48.05 %, lone_parent_non_dep −0.03 %, couple_no_children +34.23 %). The latest 55k candidate run (spine-q Q50f, 2026-09-10) fits the seven bound cells within ±0.6 % **except `lone_parent_dependent_children_households` at +21.94 %** (was +0.08 % on the rebind packet): collateral of the three exclusions, the solver parking misclassified households in the nearest bound sibling. The incumbent eFRS carries the same defect (multi_family +1093 %, `uk-dataset-evaluation/reports/55k-rebuild-2026-09-10/inputs/incumbent_national_loss_2025.json`). `uk-candidate-eval/config/assessment_fences.json:17-18` already diagnoses the benunit-vs-family mis-binding in the same terms as this plan. +- **Doctrine**: `DESIGN.md:274-288` permits raw survey structure as calibration input (the holdout rule is for tax-benefit quantities); `uc_relationships.py:16-30` is the precedent for persisting a raw FRS role as a frame column rather than inferring it from age. The retirement mechanism for a measure exclusion is executable (`measure_simulation.py:527-571`: a stale entry hard-fails), but the evidence bar for removing one is written nowhere; the test comment at `test_uk_measure_simulation.py:566-571` says a drifting count "must be re-adjudicated, never absorbed", so the PR description carries the re-adjudication (delta receipt + calibration receipt) and María's review is the adjudication. + +## Design decisions + +1. **New stage `frs_relationships`, positioned after `age_tail` and before `frs_employment`** (roster 28 → 29 executed, manifest 30 → 31). Not `frs_spine` outputs: that would move the CREATE node's root cells and hash (invalidating every downstream cache and the H2 oracle), read top-coded `age` before `age_tail` rewrites it (the #785 rule that every later age reader binds to the disaggregated cell, `graph.py:96-99`), and leave the derivation without a stage receipt. `age_tail` only moves people piled at 80 (`age_tail.py:70`), so the 65 split and the 16–18 window are unaffected either way; no later stage owns `age`. The stage re-reads the pinned `adult`, `child` and `househol` tabs (same artifact pins as `frs_spine`; `househol` only for the `hrpnum` cross-check of HEAD, the one independent check available), joins on `person_id`, and consumes `("person","age")`, `("person","is_household_head")`, `("person","person_household_id")`. +2. **Three code lists, three sources of truth, named for where they come from** (no invented third spelling anywhere): + - *FRS relationship codes* (integers 1–18, 20 in `relhrp` and `r01..r14`): owned by DWP, published in the UKDS SN 9563 FRS 2024-25 documentation (Household Grid, "Relationship"). In the repo they appear once, as the manifest parameter `frs_household_grid_relationship_codes` (code → Microcosm label, e.g. `1: SPOUSE`, `3: CHILD`, `20: CIVIL_PARTNER`), with the documentation reference recorded beside them. The person column `relationship_to_head` carries those labels (`HEAD` for the HRP, which is not a code but the blank + `hrpid == 1` condition). + - *ONS household-type definitions* (family, dependent/non-dependent child, one-family vs multi-family, unrelated adults): owned by ONS, published in the Families and households bulletin and QMI. In the repo they appear as the manifest's rule parameters (`family_link_codes`, `dependent_child`, `one_person_age_split`) plus the ONS reference, and as the translation notes on the ten contract rows. + - *The ten category identifiers*: owned by Chronicle's `ons-families-households-2025` package (`groupby_dimension ons.household_type`, the `value_id`s `lone_households_under_65` … `multi_family_households`). The household column `ons_household_type` takes these value ids **verbatim**, so the frame value, the manifest's `household_type_values`, the contract row's `dimension_values.household_type`, and the Chronicle fact's dimension value are the same string. No map between frame enum and ledger dimension exists to drift. A test pins the manifest list against the pinned feed's `ons.household_type` values for `ons.families_households_table7` (reading the vendored feed as `test_uk_target_references.py::test_committed_surfaces_regenerate_from_pinned_feed` does) and against the ten contract rows. + Columns (all four exported): person `relationship_to_head` (str), person `ons_family_role` (str; `COUPLE_PARTNER, LONE_PARENT, DEPENDENT_CHILD, NON_DEPENDENT_CHILD, INDIVIDUAL`, Microcosm labels declared in the manifest), person `ons_family_index` (int64; 0 = individual, 1..F within household, numbered by lowest member index), household `ons_household_type` (str; the ten Chronicle value ids). No new column is named `household_*` (`graph.py:305-308`). +3. **Derivation** (per household; `p = person_id % 1000`; `Rel[i][j]` = code in `r0j` on i's record = "i is the of j"): + - Partner links = codes {1, 2, 20}. Child-of links = codes {3, 4} on the child's record toward the parent (reciprocal {7, 8} on the parent's record). Foster (5/9/13), in-law (6/10/14), grandchild (15/16), sibling and other codes never form a family link, so foster children and grandchildren with no parent present stay `INDIVIDUAL` (ONS rule). + - Child-eligible(i) = no partner link and nobody has a child-of link toward i (no own child in the household). + - Families: each couple is a family and takes every child-eligible person with a child-of link to either partner; each remaining child-eligible person with a child-of link to an uncoupled person q joins q's lone-parent family (q has an own child, so q is never a child elsewhere). Ties (child-of links to two uncoupled people): natural (3) before step (4), then lowest person index; counted in evidence. Everyone else `INDIVIDUAL`. + - Dependency (children in families only): `age < 16`, or `16 ≤ age ≤ 18` and in FTE (child-tab member, or adult `educft == 1`, `fted` first if present); `age ≥ 19` is non-dependent regardless of FTE. + - Household type: n == 1 → `ONE_PERSON_*` split at `age >= 65` (matches the current `age < 65` / `age >= 65` rows); n ≥ 2 with zero families → `UNRELATED_ADULTS`; exactly one family → by that family regardless of extra individuals (couple: no children → `COUPLE_NO_CHILDREN`; 1–2 dependent → `COUPLE_1_2_…`; 3+ dependent → `COUPLE_3_PLUS_…`; only non-dependent → `COUPLE_NON_DEPENDENT_…`; lone parent: any dependent → `LONE_PARENT_DEPENDENT_…`, else `LONE_PARENT_NON_DEPENDENT_…`); ≥ 2 families → `MULTI_FAMILY`. + - HEAD: `relhrp` NaN after numeric coercion AND `hrpid == 1`; invariants: HEAD ⇔ `is_household_head`, exactly one per household, `hrpnum` equals the HEAD's person index. + - Fail closed (SourceRuntimeError) on: missing tab or required column; a household without exactly one HEAD or HEAD disagreeing with `is_household_head`; unmapped `relhrp` code; person index > 14 or non-contiguous; two partner links on one person; grid reciprocity mismatches above the declared tolerance (default 0; set from the step-0 probe); a household typed outside the domain; partition not closing (household-type counts ≠ household count). +4. **Manifest operations: `read_tables` + a structured kind `derive_ons_household_composition`** (María's lean, 2026-09-11). A prose `derive.scope` guarantees nothing: it is documentation that no code reads. The guarantee comes from three layers that already exist for `disaggregate_top_coded_ages`: (i) a JSON-schema branch in `spec_engine/schema/sources.schema.json` (`additionalProperties: false`, every parameter `required`, closed `enum`s for the label and value-id lists, integer code keys) so a malformed or unknown code cannot load; (ii) the runtime lockstep assert in the `age_tail.py:258-292` pattern (`_assert_frs_relationships_stage_parameters(stage)`: the runtime's pinned constants must equal the manifest's declared parameters key by key, extra keys refuse, drift either way refuses the build with the offending key named); (iii) the spec digest pin (`test_spec_engine_country_bundles.py:54`), so any change to the codes is a reviewed digest move. Parameters: `source_columns` (`head: relhrp`, `head_flag: hrpid`, `head_index: hrpnum`, `grid: [r01..r14]`, `full_time_education: [fted, educft]` in fallback order), `frs_household_grid_relationship_codes` (the 19 code → label pairs), `family_link_codes` (`partner: [1, 2, 20]`, `child_of: [3, 4]`, `parent_of: [7, 8]`), `dependent_child` (`unconditional_below_age: 16`, `full_time_education_through_age: 18`), `one_person_age_split: 65`, `household_type_values` (the ten Chronicle value ids, in Table 7 order), `family_role_values`, `reciprocity_mismatch_tolerance: 0`, `documentation` (`frs_codes`: "UKDS SN 9563, FRS 2024-25 question instructions, Household Grid: Relationship"; `ons_definitions`: "ONS Families and households in the UK: 2025, Measuring the data / Glossary"; `category_ids`: "chronicle ons-families-households-2025, dimension ons.household_type"). Cost accepted: `source_manifest.py:60-135` allowlist entry, the schema branch, field-usage ledger re-pin. +5. **Gates**: `uk_ons_household_type_enum_domain` (`enum_domain`, phase `assembled`, spine scope; the enum domain is passed as `gate_artifacts["ons_household_type_enum_domain"]` next to `rules_engine` at `tools/build_uk_frs_spine.py:1313` and `:883`, the `_evaluate_enum_domain` artifact-first path at `battery_bindings.py:465-488`) and `uk_stage_frs_relationships_composition` (`stage_health`, phase `assembled`, `evidence_absent_blocks: true`, check `household_composition`: head-invariant and hrpnum mismatches = 0, reciprocity ≤ tolerance, person-enum domains, partition closes). Stage evidence keys: `households`, `persons`, `head_invariant_violations`, `hrpnum_mismatches`, `relhrp_unmapped_codes`, `person_index_gaps`, `grid_reciprocity_mismatches`, `multi_partner_persons`, `parent_tie_breaks`, `family_index_violations`, `domain_violations`, `one_family_plus_individuals`, `dependency_counts` (`under_16`, `16_18_fte`, `16_18_not_fte`, `19_plus`), `household_type_counts`, `household_type_weighted` (design weights), `partition_closes`. The weighted ten-cell shares versus the published 2025 values are a diagnostic receipt, not a gate. +6. **Contract**: every one of the ten rows gets the single condition `{"variable": "ons_household_type", "operator": "==", "value": ""}` (household entity, no `entity`, no `reduce`; binding-level `reduce: "any"` dropped), `value_variable: household_count` kept. `notes` rewritten on all ten: source column and stage, the two translation notes (ONS dependency 16–18 in FTE vs the engine's `is_child` age < 18; "unrelated adults" = no family present, so related non-family households count there), the #757 person-count prose and the "Proxied" prose removed. `tools/generate_uk_target_references.py` in check mode must report no diff. +7. **Registers**: delete the three #791 entries (51 → 48); two `column_missing_in_reference` entries in `spine_swap_signed_differences.json` (template `:474-500`), added only with the build because `--strict` refuses unused entries; `uk/local_binding_adjudications.json:6` and `uk/uk_local_target_census.json:101` re-worded and dated ("bound from microcosm#791: the cross-grain rescale runs on the A15-uprated cells with factor 1 by closure"); `uk/uk_data_target_parity.json:870-877` evidence string updated (the derivation no longer mirrors uk-data's proxies). `target_fit_reviewed_exclusions.json` untouched. +8. **If a re-derived cell misses the 25 % `uk_target_fit` fence after calibration: stop and report to María** with the delta receipt; do not pre-sign a reviewed target-fit exclusion (schema-2 entry keyed by the contract target id, `terminal_gates.py:85-140`; it suppresses the fence only, the cell stays in the solve, and stale entries fail). Two outcomes the calibration receipt must speak to explicitly: `lone_parent_dependent_children_households` should return inside the band once its siblings are correctly bound (it is +21.94 % on Q50f as collateral of the exclusions), and the cross-grain receipt must show the bridge factor ≈ 1.0 by closure; if it does not (the 887 plan §52-56 flagged that the 1,011 census cells escape rescaling only while the bridge is unbound), that is a separate adjudication for María, not something this PR absorbs. +9. **Other consumers pick the new derivation up unchanged**: the incumbent-surface evaluator (`tools/evaluate_uk_incumbent_surface.py:118-152`) measures all ten; the dense assembler and data contract (`contract.py:5576-5600, 5879-5887`) see 48 exclusions and no unbound bridge; the data-contract gate mirrors (`contract.py:400-415, 455-480, 515-527`) gain the two new gate ids. + +## How the columns are stored, read, and turned into calibration rows + +1. **Build.** The stage returns a Frame with the four new columns added to the person and household tables through `uk_national_frame` (`national_frame.py:317`; dtype kinds `str` and `int` are first-class in `microcosm-frame/schema.py:24`) and validated by `validate_uk_national_frame`. The graph declares them as stage-owned cells with dtypes in `graph.py:_STAGE_CELLS` (string household cells already exist: `brma`, `household_support_channel`). `write_uk_national_frame` (`national_frame.py:436`) persists the tables to the staging H5 next to `region` and `tenure_type`, so the H5 that calibration and the release read carries them. +2. **Gates at `assembled`.** `uk_ons_household_type_enum_domain` refuses any household value outside the manifest's `household_type_values` (`_evaluate_enum_domain`, `battery_bindings.py:465-488`, artifact-first); `uk_stage_frs_relationships_composition` refuses head-invariant violations, unmapped codes, reciprocity mismatches above tolerance, and a partition that does not close (every household typed exactly once). A wrong code cannot leave the build. +3. **Calibration read path.** `tools/calibrate_uk_national_dataset.py --input-h5` → `load_uk_national_frame` (`national_frame.py:299`) → `CalibrationFrameAdapter(frame)` (`national_calibration.py:365`, a `UKFrameTargetAdapter` whose `tables` are copies of the entity tables) → `materialize_target_bindings` (`target_materialization.py:472-546`). For each of the ten rows, `_prepared_column_values` (`:640-660`) takes `household_count` (ones per household, `ledger_targets.py:722-731`), ANDs in `_predicate_mask` (`:675-689`), which for the reduce-less condition reads `_column(adapter, "household", "ons_household_type")` and compares `== ""` (`_compare`, `:692`), and returns a 0/1 column over households. That column is the target's row of the loss matrix; the row's value is the weighted household count under the current weights and its target is the Chronicle fact. No engine variable is involved: `resolve_target_measures` only consults `UKMeasureResolver` for columns the frame lacks, so a present frame column is used as-is. +4. **Fail-closed on a wrong code downstream.** Contract compile: a new check in `compile_uk_target_registry`'s roster passes (next to `_assert_local_reference_in_crosswalk`) that every `ons_household_type` condition value is in the manifest's `household_type_values` and that the ten rows cover them exactly once, plus the population-targets test. Calibration initialisation: `microcosm-calibrate/initialization.py:55` raises "nonzero target at row has no support" if a condition matches no household, so a typo cannot silently become a zero row. Partition: the cross-grain bridge closure check (`cross_grain.py:396`) refuses if the ten rows do not sum to the household control. Each of these names the offending target id. +5. **Release.** The four columns ride into the release H5 through the export allowlist and are visible to the incumbent-surface evaluator and the dense/local assemblers unchanged. + +## Files to change + +Runtime (`packages/microcosm-build/src/microcosm/build/`): +- New `uk_runtime/frs_relationships.py`: `FRS_RELATIONSHIPS_STAGE_NAME`, `FRS_RELATIONSHIPS_OUTPUT_COLUMNS`, the runtime's pinned constants named for their source (`FRS_HOUSEHOLD_GRID_RELATIONSHIP_CODES`, `ONS_FAMILY_LINK_CODES`, `ONS_DEPENDENT_CHILD_RULE`, `ONS_ONE_PERSON_AGE_SPLIT`, `CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS`), `_assert_frs_relationships_stage_parameters(stage)` (age_tail lockstep pattern), `UKFRSRelationshipsStageTransform` (mirrors `UKFRSEducationStageTransform`, `frs_education.py:112-128`; `checkpoint_metadata` returns `{"evidence": …}` as `uc_deduction_attributes.py:148-151`), `add_frs_relationships(frame, raw_dir, *, stage)` (reads via `frs_spine.read_pinned_tab`/`_normalize_ids` as `frs_education.py:130-140`, writes person + household columns through `uk_national_frame`, validates with `validate_uk_national_frame`, `national_frame.py:488`), pure `derive_frs_relationships(person, household, raw_adult, raw_child, raw_household)` returning person values, household values and evidence, helpers `_relationship_grid`, `_assign_families`, `_household_type`, `frs_relationships_domains()`. +- `uk_runtime/__init__.py` exports; `uk_runtime/graph.py` (`_SPLIT_STAGE_SOURCES:104` add `"frs_relationships": ("frs",)`; `_STAGE_CONSUMES:133-243`; `_STAGE_CELLS:353+` four cells); `uk_runtime/graph_kernels.py` (`_STAGE_MODULES:65-94`, fixture implementations `:335-520`, "28-stage" string `:322`); `uk_runtime/source_runtime.py:50-121` (`frs_relationships_transform` kwarg); `uk_runtime/stage_health.py:17-62` (`household_composition` check); `uk_runtime/calibration_run.py:120-135` (`UK_SPINE_GATE_SCOPE` + the two gate ids); `uk_runtime/terminal_gates.py:163-231` (four allowlist rows). +- `tools/build_uk_frs_spine.py` (import block `:57-59`; wiring next to `frs_education` at `:1109-1114`; `gate_artifacts` at `:883` and `:1313`). + +Spec, manifest, gates, registers (`packages/microcosm-build/src/microcosm/build/uk/`): +- `spec/sources.yaml` and `source_stages.json` in lockstep (new stage block after `age_tail`, before `frs_employment`: `survey`/`source` as `frs_education`, artifacts = the `adult`, `child`, `househol` pins from `frs_spine`, ops `read_tables` + `derive_ons_household_composition` with the parameters of design 4, `outputs` = the four columns, mixed person/household `grain` as `was_wealth`, `notes`). +- `build/spec_engine/schema/sources.schema.json`: the `derive_ons_household_composition` branch (template: the `disaggregate_top_coded_ages` branch at `:2264-2304`; closed enums for labels and the ten value ids, integer-keyed code map, `additionalProperties: false`); `build/source_manifest.py:60-135`: allowlist entry. +- `uk_runtime/ledger_targets.py` / `compile_uk_target_registry`: the compile-time roster check that `ons_household_type` condition values are declared manifest values, covered exactly once. +- `gates.json`: stage-health gate after `uk_stage_age_tail_targets` (`:395-406`), enum gate near `uk_brma_enum_domain` (`:654-665`), four `uk_export_surface.allowed_extra_columns` rows (`:575+`). +- `calibration_measure_exclusions.json:336-364` (delete three); `spine_swap_signed_differences.json` (two entries, with the build); `local_binding_adjudications.json:6`; `uk_local_target_census.json:101`; `uk_data_target_parity.json:870-877`. +- `uk_population_targets.json:9544-10068` (ten rebound rows + notes). +- `packages/microcosm-data/src/microcosm/data/contract.py:400-415, 455-480, 515-527` (gate mirrors). + +Tests (`packages/microcosm-build/tests/` unless noted): +- New `test_uk_frs_relationships.py`: manifest-parameter lockstep (schema validation of the stage block; `_assert_frs_relationships_stage_parameters` passes on the committed manifest and refuses a mutated copy with the key named); `household_type_values` equals the pinned feed's `ons.household_type` value ids and the ten contract rows' dimension values; hand-built raw tabs + frame fixtures (couple + lodger → `COUPLE_NO_CHILDREN` with one individual; couple + 22-year-old child → `COUPLE_NON_DEPENDENT_CHILDREN_ONLY`; couple + adult child + child-in-law + grandchild → `MULTI_FAMILY`; lone parent + 19-year-old in FTE → `LONE_PARENT_NON_DEPENDENT_CHILDREN_ONLY`; lone parent + 17-year-old not in FTE → same; two sharers and two siblings → `UNRELATED_ADULTS`; grandparent + lone-parent daughter + grandchild → `LONE_PARENT_DEPENDENT_CHILDREN` with the grandparent an individual; grandparent + unpartnered childless adult daughter → `LONE_PARENT_NON_DEPENDENT_CHILDREN_ONLY`; adult + foster child → `UNRELATED_ADULTS`; two lone parents not a couple → `MULTI_FAMILY`; one person aged 64 / 65 → the split), domain pins, the ledger map covers exactly the ten contract cells, fail-closed cases, `checkpoint_metadata` shape, the stage-health check pass/fail, manifest lockstep (outputs == constant; artifact pins equal `frs_spine`'s, as `test_uk_source_stages.py:540`). +- Re-pins: `test_uk_source_stages.py:23-81` (roster) and outputs-backing test `:367+`; `test_uk_graph.py:169` 28 → 29 plus a consumes/cells assertion; `test_country_spec.py:970` 30 → 31; `test_spec_engine_country_bundles.py:54` (new uk sha); `test_spec_engine_field_usage.py` counts; `test_uk_spine_acceptance_receipt.py:45-70` pending-roster transformation until the receipt is re-minted; `test_uk_battery_bindings.py:80-86` and `test_country_spec.py:1463` (allowlist mirror); `packages/microcosm-graph/tests/test_acceptance_h_parity.py:46,259` comments. +- `test_uk_measure_simulation.py:562-620`: census entry removed, 51 → 48, tranche 39 → 36, the #791 tracking loop replaced by "no composition entry remains", the three lifted cells added to the not-excluded list. +- `test_uk_population_targets.py` (~`:475-490`): each of the ten rows carries one reduce-less `ons_household_type` condition whose value is in the domain and maps to its own `dimension_values.household_type`. +- `test_uk_ledger_targets.py:1326-1385`: keep as the synthetic partial-bridge case (renamed), add `test_fully_bound_household_composition_bridge_reconciles_census_cells` (ten K02000001 rows summing to a control, two census rows, expect `unbound_bridges == []` and one group with `declared_factor`). The other synthetic fixtures do not read the register and stay. + +Fixture and generated surfaces (regenerate, never hand-edit): `tools/graph_uk_spine_fixture.py` (`_frs_tables:272-400` add `RELHRP`, `R01..R14`, keep `FTED`; `_NORMALIZED_STRING_COLUMNS:134-158`; `UK_FIXTURE_STAGE_COUNT:131` 28 → 29; `_build_implementations`) then regenerate `packages/microcosm-graph/tests/fixtures/parity/uk_spine/` (`uk_spine.json`, `sources/fixture.json`, `sources/frs_raw/adult.tab`, `child.tab`, `PRODUCED_BY.txt`); `tools/spec_envelope_digests.py uk`; `tools/build_uk_release_input_coverage_manifest.py --check` (expected unchanged); `tools/generate_uk_target_references.py` check mode (expected no diff); `tools/ci_test_groups.py --verify`. + +Changelog and receipts: `changelog.d/uk-household-composition-791.added.md` (stage, gates, export columns) and `…791.changed.md` (rebind, exclusions lifted, bridge bound); `experiments/791-household-composition-receipts.md`. + +## Implementation steps (one PR, branch `uk-household-composition-791` off main, worktree `populace-791`) + +0. **Probe and verify vintage docs** (read-only scratchpad script, results into the receipts file): re-verify the relationship code list and HRP definition in the SN 9563 (FRS 2024-25) documentation; on the licensed tape tabulate `relhrp` codes on adult/child, HRP uniqueness and `hrpnum` agreement, PERSON contiguity, grid reciprocity rate, partner-link multiplicity, the share of households with one family plus individuals, and a first pass of the ten-cell weighted shares versus the published 2025 values. Sets the reciprocity tolerance (default 0). +1. Write `frs_relationships.py` + `test_uk_frs_relationships.py`; unit tests green. +2. Wire manifest/spec/graph/kernels/runtime/gates/allowlist/data-contract mirrors; re-pin the moved surfaces (spec sha, field-usage counts, roster and count pins, acceptance-receipt pending transformation); regenerate the H2 fixture; run the build shard. +3. Rebind the ten rows and rewrite their notes; the contract test; generator check mode. +4. Delete the three exclusions; re-pin `test_uk_measure_simulation.py`; adjudication wording; parity-register evidence; bridge test. +5. Sampled spine build (1 %), then the full licensed build (spine-q; spine-p took 424 s, 3.84 GB peak); expect 29 stages, both new gates green; sign the two parity-register entries; twin-build diff and parity verification. +6. Derivation-delta receipt on the new spine: the old ten bindings (copy of the pre-change rows) versus the new column through `UKFrameTargetAdapter`, a 10×10 design-weighted crosstab, and each cell's design-weight total against the published 2025 values, the rebind packet (`data/ukds/acceptance/757-swap/calibration_diagnostics_rebind.json`) and the Q50f run. Optional diagnostic, not a target: the E&W census TS003 "other household types" and "other family composition" leaves from the Chronicle census package as a second-source sanity check on the multi-family and unrelated-adults magnitudes (their map onto Table 7 is a consumer declaration and stays a note). +7. National calibration run (~30 min); read the ten cells' relative errors, `uk_target_fit`, and the cross-grain receipt (bridge in `groups`, factor ≈ 1.0, `unbound_bridges == []`); rowwise dry run for the local receipt. +8. Changelog fragments, receipts file, README/docs touch-ups; draft PR whose description carries the register re-adjudication (the three retired entries, the delta receipt, the calibration receipt, the bridge receipt); CI; report to María in-session (no PR comment or issue comment without her go; #791 closes on merge). Afterwards: #901 and #749 rebase; memory entry for the #791 state. + +## Verification + +- `uv run --no-sync pytest packages/microcosm-build/tests/test_uk_frs_relationships.py -q`, then the `spine-uk` and `uk` CI groups (`uv run --no-sync python tools/ci_test_groups.py --list spine-uk`), `tools/ci_test_groups.py --verify`, `uv run ruff check .`; `packages/microcosm-graph/tests/test_acceptance_h_parity.py` after the fixture regeneration. +- `uv run --no-sync python tools/build_uk_frs_spine.py --frs-raw-dir /Users/mariajuaristi/Desktop/PolicyEngine/data/ukds/frs_2024_25 --spine-h5 /791/spine-q.h5 [--sample-fraction 0.01 --sample-seed 42] --spi-tab … --hmrc-ods … --cgt-ods … --was-tab … --lcfs-hh-tab … --lcfs-person-tab … --etb-tab … --logbook-prev-row-digest …` with the pinned input files of the spine-p recipe (`experiments/355-uk-dataset-size-receipts.md:75-86`); check `.spine_gates.json` and the stage evidence sidecar. +- `tools/compare_uk_h5_payload.py spine-p.h5 spine-q.h5 --structure-only` + `tools/classify_uk_payload_diff.py` with the four columns declared candidate-only and everything else byte-equal; `tools/verify_uk_spine_parity.py --strict` (`only_in_candidate` = exactly the four columns). +- `tools/calibrate_uk_national_dataset.py --input-h5 spine-q.h5 --input-sha256 … --ledger-facts … --epochs 1500 --target-weight-rule family_equal …` (`docs/uk-national-calibration-runbook-623.md:30-42`); acceptance = all ten cells inside the 25 % fence, bridge bound, 48 exclusions applied; `tools/build_uk_rowwise_candidate.py --dry-run --sample-fraction 0.01 …` for the cross-grain receipt. +- Doctrine checks before commit: grep the live tree for `policyengine-uk-data` (cite `uk-data#NNN`), `requires_uk` marker on the new test module if it needs the engine (it should not), no hand-copied publisher rows (the ten values stay vendored from the pinned feed). + +## Defaults taken unless María objects + +- Structured `derive_ons_household_composition` op kind with schema + runtime lockstep (design 4, per her 2026-09-11 lean); the household column uses Chronicle's value ids verbatim (design 2). +- `househol` included as a third artifact for the `hrpnum` check (design 3). +- Reciprocity tolerance 0, revisited only if the step-0 probe finds tape defects (then a reviewed gate parameter, reported first). +- "Two or more unrelated adults" read as "no family present", per the ONS glossary quoted above. +- The old-vs-new delta and any cell outside the fence are reported in-session before anything is posted outward. diff --git a/experiments/791-household-composition-receipts.md b/experiments/791-household-composition-receipts.md index 662195950..7faf88d37 100644 --- a/experiments/791-household-composition-receipts.md +++ b/experiments/791-household-composition-receipts.md @@ -1,12 +1,12 @@ # microcosm#791 receipts: relationship-to-head frame column and the ONS household-composition rebind -Plan of record: `repos/uk-791-relationship-to-head-plan.md` (approved 2026-09-11). Branch `uk-household-composition-791` off main `6f7571e1`. +Plan of record: `docs/uk-relationship-to-head-plan-791.md` (approved 2026-09-11; María's working copy `repos/uk-791-relationship-to-head-plan.md`). Branch `uk-household-composition-791` off main `6f7571e1`. ## R1 — vintage documentation check (step 0) The relationship code list the stage declares (`derive_ons_household_composition.frs_household_grid_relationship_codes`) was read from the FRS 2024-25 question instructions for the pinned release, UK Data Service SN 9563 (`9563_frs_2024-25_question_instructions_final.pdf`, P18492, 408 pages, sha256 `8fec3d4e8f66a2a65ccf0b8455d410c39c41181d0c2148949a14840f1f0eb76d`), Household Grid, question "Relationship" (page 17 of the PDF): 1 spouse, 2 cohabitee, 3 son/daughter (incl adopted/legal dependent), 4 step-son/daughter, 5 foster child, 6 son-in-law/daughter-in-law, 7 father/mother/or guardian, 8 step father/mother, 9 foster parent, 10 father/mother-in-law, 11 brother/sister (incl adopted), 12 step-brother/sister, 13 foster brother/sister, 14 brother/sister-in-law, 15 grand-son/daughter, 16 grand-father/mother, 17 other relative, 18 other non-relative, 20 Civil Partner, 97 not used. Identical to the 2023-24 instructions (SN 9367). The instructions add: relatives of cohabitees are coded as if married; half-siblings are coded with step-siblings; a 16-19 in full-time education living with grandparents has the grandparents coded as legal guardian (7/3). The household reference person is the highest-income householder, the elder on ties (FRS background information and methodology). -The ONS definitions come from Families and households in the UK: 2025 (Measuring the data / Glossary) and "Families and households statistics explained" (ONS, 2021): family, dependent child (under 16, or 16-18 in full-time education, excluding 16-18s with a partner or own child in the household), non-dependent child, one-family household ("households where there is one family and one individual are also classified as one-family households"), two or more unrelated adults ("none of whom are living as part of a family"), multi-family household, and foster children / children living with someone other than their parents as separate one-person family units. +The ONS definitions come from Families and households in the UK: 2025 (Measuring the data / Glossary) and "Families and households statistics explained" (ONS, 2021): family, dependent child (under 16, or 16-18 in full-time education, excluding 16-18s with a partner or own child in the household), non-dependent child, one-family household ("households where there is one family and one individual are also classified as one-family households"), two or more unrelated adults ("a household with two or more people, none of whom are living as part of a family (that is, they do not contain either a couple or a parent with their child)", https://www.ons.gov.uk/peoplepopulationandcommunity/birthsdeathsandmarriages/families/articles/familiesandhouseholdsstatisticsexplained/2021-03-02), multi-family household, and foster children / children living with someone other than their parents as separate one-person family units. The ten category identifiers are Chronicle's `ons-families-households-2025` package, Table 7, `ons.household_type` value ids (`lone_households_under_65` ... `multi_family_households`); the package carries no Table 7 note text, so the definitions above are recorded on the contract rows and here. @@ -101,3 +101,7 @@ For comparison: the #757 rebind packet (proxies, 403 targets, loss 0.1362) read `spine-uk` CI group (127 files, 2,403 tests, 35 min): 2,372 passed, 21 skipped, 10 failed on the first pass; all ten were pins or fixtures that had to follow the change, and every one is green on rerun: the data-contract mirrors (the two gate ids in the entry table, the spine part scope, the full-manifest digests `policy 38a8a014…`, `gates_manifest 49e86be9…`, `spec_fingerprint 25049e61…`, the spine part digests `7f9f07e6…`/`7058df03…` and the release-cut part digests `1aaf29c5…`/`4a93792f…`, computed by the producer the sync test `test_gate_battery_contract_pins.py` holds in lockstep), the uk-data parity register regenerated from its source (`data_target_parity.py`), the local-target census regenerated from its source (`local_target_census.py`, the bound-bridge wording), the spine-driver tests' synthetic tabs and synthetic spec (grid columns, `hrpnum`, the declared operation parameters), and the release-assembler tests (which read the contract mirrors). Also green: `packages/microcosm-data/tests` (398), `packages/microcosm-graph/tests` (337, including the H2 parity acceptance on the regenerated fixture and the executor regression), `test_gate_battery_contract_pins.py`, and the targeted pin set (401). `tools/ci_test_groups.py --verify` ok; `tools/build_uk_release_input_coverage_manifest.py` regenerated (only the `source_manifest_sha256` pins moved; 145 required inputs unchanged); `tools/generate_uk_target_references.py`'s pinned-feed regeneration test passes on the ec7169b artifact (no generated surface moved); `ruff check` and `ruff format --check` clean on every changed file. One failure is pre-existing and untouched: `test_uk_parity_reference.py::test_cached_reference_regeneration_matches_committed_surface` regenerates `uk/efrs_parity_reference.json` from the cached licensed eFRS artifact and compares it to the committed file; the committed file was produced with policyengine-uk 2.89.0 (223 input variables) while `uv.lock` on main pins 2.97.0 (228), which now recognises `sic_industry_division`, `employment_sector` and `bus_fare_spending` as inputs. The branch changes neither file; the test skips in CI (no HF cache) and fails identically on main in this environment. The re-pin belongs with #749. + +## R11 — Vahid's review round 1 (comment at 7779747b, 2026-09-11) + +Should-fixes: the `census_disclosure_control_noise` adjudication reason now carries a dated re-wording trailer ("re-worded 2026-09-11 (microcosm#791 …)") beside the #887 one, under the unchanged 2026-08-31 approval; the plan of record is committed as `docs/uk-relationship-to-head-plan-791.md` (the #355 precedent), and the receipts and PR body point there. Questions: the `unrelated_adult_households` and `lone_parent_dependent_children_households` contract notes record the skip-generation age switch (under 16 with no parent present: two unrelated adults, codes 15/16 never form a family; 16-19 in full-time education: the FRS codes the grandparents as legal guardian, 7/3, so a family with a dependent child) and cite the ONS "Families and households statistics explained" definition of two or more unrelated adults by URL, which is the source R1 quotes. Nits: `age` NaN now refuses instead of reading as 0 (`FRSRelationshipsError`, test added); `stage_health.py` is the main text plus the two composition hunks only (the earlier formatter pass had rewritten unrelated gates; CI lints with `ruff check` only); the enum-domain artifact fallback and the head-plus-child-only H2 fixture are left as noted, the couple and multi-family paths being held by the unit tests. The `test_uk_parity_reference.py` cached-reference regeneration test is retired on María's call (R10: it regenerated the reference under the installed engine, was skipped in CI and failed on main since the 2.97.0 lock); the thirteen other integrity tests on the reference, including the cached-artifact sha check, stay. diff --git a/packages/microcosm-build/src/microcosm/build/uk/local_binding_adjudications.json b/packages/microcosm-build/src/microcosm/build/uk/local_binding_adjudications.json index f96d9ae05..e15c32618 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/local_binding_adjudications.json +++ b/packages/microcosm-build/src/microcosm/build/uk/local_binding_adjudications.json @@ -3,7 +3,7 @@ "description": "Reviewed adjudications of the UK local binding fences (uk_local_target_census.json binding_fences). Binding a target family whose fence has no in-force entry here fails in the rowwise doctrine solve before any solve runs. Keys are fence ids; the reason states the ruling (accept the stated basis, or replace it with the named alternative) and cites the evidence.", "exclusions": { "census_disclosure_control_noise": { - "reason": "Accept the stated basis: constituency and local-authority household counts bind to the published disclosure-controlled census values compiled from the pinned Chronicle feed (ons.census.households: ONS TS041 PCON24/LAD, NRS UV404 UKPC24 and council all-occupied totals, NISRA PCON24/LGD14). Per-area dispersion of the retired OA-ladder sums against the published cells at review: England mean 7.4 / max 29, Wales 6.4 / 15, Scotland net −557 (NRS applies disclosure control per output level; same shortfall at both grains), Northern Ireland mean 7 / max 16 after the NI constituency leg moved to NISRA's published DZ2021→PARLCON24 lookup (the earlier postcode inference was a mapping defect of 10 Data Zones, max 694, not perturbation). When a national same-concept control is bound, the standing cross-grain rule declared in uk_runtime.ledger_targets rescales both grains; country wins. The census cells count the occupied-household universe and pair only through the household-composition bridge, never with dwelling stock; that cross-grain rescale applies once the bridge is bound. Bound from microcosm#791 (2026-09-11): the three ONS household-composition cells that held the bridge reviewed-unbound now bind on the frs_relationships household type, so the cross-grain rescale runs on the A15-uprated cells; the ten-cell partition and the A15 control are both ons.households_total, so the declared factor is 1 by closure and the receipt records the bridge as bound. Fence evidence: uk_local_target_census.json#/binding_fences/census_disclosure_control_noise; the published cells preserve the source cell-key controls. Re-worded 2026-09-10 (microcosm#887 review round 1).", + "reason": "Accept the stated basis: constituency and local-authority household counts bind to the published disclosure-controlled census values compiled from the pinned Chronicle feed (ons.census.households: ONS TS041 PCON24/LAD, NRS UV404 UKPC24 and council all-occupied totals, NISRA PCON24/LGD14). Per-area dispersion of the retired OA-ladder sums against the published cells at review: England mean 7.4 / max 29, Wales 6.4 / 15, Scotland net −557 (NRS applies disclosure control per output level; same shortfall at both grains), Northern Ireland mean 7 / max 16 after the NI constituency leg moved to NISRA's published DZ2021→PARLCON24 lookup (the earlier postcode inference was a mapping defect of 10 Data Zones, max 694, not perturbation). When a national same-concept control is bound, the standing cross-grain rule declared in uk_runtime.ledger_targets rescales both grains; country wins. The census cells count the occupied-household universe and pair only through the household-composition bridge, never with dwelling stock; that cross-grain rescale applies once the bridge is bound. Bound from microcosm#791 (2026-09-11): the three ONS household-composition cells that held the bridge reviewed-unbound now bind on the frs_relationships household type, so the cross-grain rescale runs on the A15-uprated cells; the ten-cell partition and the A15 control are both ons.households_total, so the declared factor is 1 by closure and the receipt records the bridge as bound. Fence evidence: uk_local_target_census.json#/binding_fences/census_disclosure_control_noise; the published cells preserve the source cell-key controls. Re-worded 2026-09-10 (microcosm#887 review round 1); re-worded 2026-09-11 (microcosm#791: the three composition cells re-bound, bridge bound).", "approved_by": "juaristi22", "adjudication": "microcosm#802", "approved_on": "2026-08-31", diff --git a/packages/microcosm-build/src/microcosm/build/uk_runtime/frs_relationships.py b/packages/microcosm-build/src/microcosm/build/uk_runtime/frs_relationships.py index 768286b24..8745abe3e 100644 --- a/packages/microcosm-build/src/microcosm/build/uk_runtime/frs_relationships.py +++ b/packages/microcosm-build/src/microcosm/build/uk_runtime/frs_relationships.py @@ -395,7 +395,14 @@ def derive_frs_relationships( raw = _aligned_raw_person(person, raw_adult, raw_child) person_ids = person["person_id"].to_numpy(dtype="int64") household_ids = person["person_household_id"].to_numpy(dtype="int64") - ages = pd.to_numeric(person["age"], errors="coerce").fillna(0).to_numpy() + age_values = pd.to_numeric(person["age"], errors="coerce") + if age_values.isna().any(): + # A blank age would read as 0 and silently make a dependent child. + raise FRSRelationshipsError( + f"{int(age_values.isna().sum())} frame person(s) carry a non-numeric " + "age; the derivation refuses rather than reading them as 0." + ) + ages = age_values.to_numpy() frame_head = person["is_household_head"].to_numpy(dtype=bool) person_index = person_ids % 1000 grid_columns = list(FRS_RELATIONSHIPS_SOURCE_COLUMNS["grid"]) diff --git a/packages/microcosm-build/src/microcosm/build/uk_runtime/stage_health.py b/packages/microcosm-build/src/microcosm/build/uk_runtime/stage_health.py index b60c9eaf9..1e9549283 100644 --- a/packages/microcosm-build/src/microcosm/build/uk_runtime/stage_health.py +++ b/packages/microcosm-build/src/microcosm/build/uk_runtime/stage_health.py @@ -170,11 +170,7 @@ def _support_clip_gate( "columns_checked": len(expected_columns) - len(exempt_columns), "exempt_columns": sorted(exempt_columns), } - return ( - _fail(stage, check, failures, details) - if failures - else _pass(stage, check, details) - ) + return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) def _realization_target_gate( @@ -208,11 +204,7 @@ def _realization_target_gate( if bool(receipt.get("cap_bound")) and not bool(parameters.get("allow_cap_bound")): failures.append(f"{stage}: cap_bound is true but not allowed.") details = {"target": target, "abs_realization_deviation": deviation} - return ( - _fail(stage, check, failures, details) - if failures - else _pass(stage, check, details) - ) + return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) def _student_loan_plans_gate( @@ -235,9 +227,7 @@ def _student_loan_plans_gate( failures.append(f"{stage}: missing receipt for {plan}.") continue stock = _finite_number(receipt.get("stock"), label=f"{stage}.{plan}.stock") - expected = _finite_number( - declared_stock, label=f"{stage}.{plan}.declared_stock" - ) + expected = _finite_number(declared_stock, label=f"{stage}.{plan}.declared_stock") if stock != expected: failures.append(f"{stage}: {plan} stock {stock} != declared {expected}.") final = _finite_number( @@ -258,11 +248,7 @@ def _student_loan_plans_gate( f"{stage}: {plan} realization_deviation {deviation} exceeds {max_deviation}." ) details = {"plans_checked": len(declared_stocks), "worst_abs_deviation": worst} - return ( - _fail(stage, check, failures, details) - if failures - else _pass(stage, check, details) - ) + return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) def _cgt_incidence_mass_gate( @@ -271,9 +257,7 @@ def _cgt_incidence_mass_gate( parameters: Mapping[str, object], ) -> GateResult: check = "cgt_incidence_mass" - mass = _mapping( - evidence.get("mass_by_clone_flag"), label=f"{stage}.mass_by_clone_flag" - ) + mass = _mapping(evidence.get("mass_by_clone_flag"), label=f"{stage}.mass_by_clone_flag") original = _finite_number(mass.get("false"), label=f"{stage}.mass.false") clone = _finite_number(mass.get("true"), label=f"{stage}.mass.true") tolerance = _finite_number( @@ -286,19 +270,9 @@ def _cgt_incidence_mass_gate( if original <= 0.0 or clone <= 0.0: failures.append(f"{stage}: clone and original mass must both be positive.") if imbalance > tolerance: - failures.append( - f"{stage}: clone/original mass imbalance {imbalance} exceeds {tolerance}." - ) - details = { - "original_mass": original, - "clone_mass": clone, - "relative_imbalance": imbalance, - } - return ( - _fail(stage, check, failures, details) - if failures - else _pass(stage, check, details) - ) + failures.append(f"{stage}: clone/original mass imbalance {imbalance} exceeds {tolerance}.") + details = {"original_mass": original, "clone_mass": clone, "relative_imbalance": imbalance} + return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) def _spi_support_channel_gate( @@ -317,24 +291,13 @@ def _spi_support_channel_gate( if abs(share - expected_share) > _finite_number( parameters.get("absolute_tolerance", 0.0), label=f"{stage}.absolute_tolerance" ): - failures.append( - f"{stage}: spi_prior_mass_share {share} != declared {expected_share}." - ) + failures.append(f"{stage}: spi_prior_mass_share {share} != declared {expected_share}.") if evidence.get("household_weight_kind") != parameters.get("household_weight_kind"): failures.append(f"{stage}: household_weight_kind drifted.") - if int(evidence.get("spi_households", 0)) < int( - parameters["minimum_spi_households"] - ): + if int(evidence.get("spi_households", 0)) < int(parameters["minimum_spi_households"]): failures.append(f"{stage}: spi_households below declared minimum.") - details = { - "spi_prior_mass_share": share, - "spi_households": evidence.get("spi_households"), - } - return ( - _fail(stage, check, failures, details) - if failures - else _pass(stage, check, details) - ) + details = {"spi_prior_mass_share": share, "spi_households": evidence.get("spi_households")} + return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) def _spi_income_spine_gate( @@ -356,26 +319,15 @@ def _spi_income_spine_gate( expected_share = _finite_number( parameters["spi_prior_mass_share"], label=f"{stage}.spi_prior_mass_share" ) - share = _finite_number( - prior.get("mass_share"), label=f"{stage}.spi_prior.mass_share" - ) + share = _finite_number(prior.get("mass_share"), label=f"{stage}.spi_prior.mass_share") if abs(share - expected_share) > _finite_number( parameters.get("absolute_tolerance", 0.0), label=f"{stage}.absolute_tolerance" ): - failures.append( - f"{stage}: spi prior mass share {share} != declared {expected_share}." - ) + failures.append(f"{stage}: spi prior mass share {share} != declared {expected_share}.") if int(targets.get("count", 0)) < int(parameters["minimum_target_count"]): failures.append(f"{stage}: target count below declared minimum.") - details = { - "identity_rows": identity.get("rows_checked"), - "target_count": targets.get("count"), - } - return ( - _fail(stage, check, failures, details) - if failures - else _pass(stage, check, details) - ) + details = {"identity_rows": identity.get("rows_checked"), "target_count": targets.get("count")} + return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) def _source_signal_gate( @@ -384,37 +336,20 @@ def _source_signal_gate( parameters: Mapping[str, object], ) -> GateResult: check = "source_signal" - rows = _mapping( - evidence.get("source_signal_rows"), label=f"{stage}.source_signal_rows" - ) - allowed_zero = { - str(column) for column in parameters.get("structural_zero_columns", ()) - } - reported_zero = { - str(column) for column in evidence.get("structural_zero_columns", ()) - } + rows = _mapping(evidence.get("source_signal_rows"), label=f"{stage}.source_signal_rows") + allowed_zero = {str(column) for column in parameters.get("structural_zero_columns", ())} + reported_zero = {str(column) for column in evidence.get("structural_zero_columns", ())} minimum = int(parameters["minimum_signal_rows"]) failures: list[str] = [] if reported_zero - allowed_zero: - failures.append( - f"{stage}: unreviewed structural zero columns {sorted(reported_zero - allowed_zero)}." - ) + failures.append(f"{stage}: unreviewed structural zero columns {sorted(reported_zero - allowed_zero)}.") for column, value in rows.items(): if str(column) in allowed_zero: continue if int(value) < minimum: - failures.append( - f"{stage}: {column} has {value} source-signal row(s), below {minimum}." - ) - details = { - "columns_checked": len(rows), - "structural_zero_columns": sorted(reported_zero), - } - return ( - _fail(stage, check, failures, details) - if failures - else _pass(stage, check, details) - ) + failures.append(f"{stage}: {column} has {value} source-signal row(s), below {minimum}.") + details = {"columns_checked": len(rows), "structural_zero_columns": sorted(reported_zero)} + return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) def _age_tail_targets_gate( @@ -423,12 +358,8 @@ def _age_tail_targets_gate( parameters: Mapping[str, object], ) -> GateResult: check = "age_tail_targets" - achieved = _mapping( - evidence.get("achieved_weighted"), label=f"{stage}.achieved_weighted" - ) - targets = _mapping( - evidence.get("band_populations"), label=f"{stage}.band_populations" - ) + achieved = _mapping(evidence.get("achieved_weighted"), label=f"{stage}.achieved_weighted") + targets = _mapping(evidence.get("band_populations"), label=f"{stage}.band_populations") max_relative = _finite_number( parameters["maximum_relative_deviation"], label=f"{stage}.maximum_relative_deviation", @@ -448,15 +379,9 @@ def _age_tail_targets_gate( relative = abs(value - target) / max(abs(target), 1.0) worst = max(worst, relative) if relative > max_relative: - failures.append( - f"{stage}: {key} relative deviation {relative} exceeds {max_relative}." - ) + failures.append(f"{stage}: {key} relative deviation {relative} exceeds {max_relative}.") details = {"bands_checked": len(targets), "worst_relative_deviation": worst} - return ( - _fail(stage, check, failures, details) - if failures - else _pass(stage, check, details) - ) + return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) def _cgt_band_donor_support_gate( @@ -478,32 +403,16 @@ def _cgt_band_donor_support_gate( if not isinstance(row, Mapping): failures.append(f"{stage}: band row is not an object.") continue - realized_min = _finite_number( - row.get("realized_min_gain"), label=f"{stage}.realized_min_gain" - ) - realized_max = _finite_number( - row.get("realized_max_gain"), label=f"{stage}.realized_max_gain" - ) - lower_limit = _finite_number( - row.get("lower_limit"), label=f"{stage}.lower_limit" - ) + realized_min = _finite_number(row.get("realized_min_gain"), label=f"{stage}.realized_min_gain") + realized_max = _finite_number(row.get("realized_max_gain"), label=f"{stage}.realized_max_gain") + lower_limit = _finite_number(row.get("lower_limit"), label=f"{stage}.lower_limit") band_floor = max(global_lower, lower_limit) if realized_min < band_floor: - failures.append( - f"{stage}: realized gain {realized_min} falls below {band_floor}." - ) - if upper is not None and realized_max >= _finite_number( - upper, label="capital_gains.upper" - ): - failures.append( - f"{stage}: realized gain {realized_max} exceeds open upper bound." - ) + failures.append(f"{stage}: realized gain {realized_min} falls below {band_floor}.") + if upper is not None and realized_max >= _finite_number(upper, label="capital_gains.upper"): + failures.append(f"{stage}: realized gain {realized_max} exceeds open upper bound.") details = {"bands_checked": len(bands), "minimum_lower_limit": global_lower} - return ( - _fail(stage, check, failures, details) - if failures - else _pass(stage, check, details) - ) + return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) def _cgt_imputation_summary_gate( @@ -524,11 +433,7 @@ def _cgt_imputation_summary_gate( if value < 0.0: failures.append(f"{stage}: {key} is negative.") details = {"band_rows": len(rows), "taxpayer_mass": evidence.get("taxpayer_mass")} - return ( - _fail(stage, check, failures, details) - if failures - else _pass(stage, check, details) - ) + return _fail(stage, check, failures, details) if failures else _pass(stage, check, details) def _latent_attribute_realization_gate( diff --git a/packages/microcosm-build/tests/test_uk_frs_relationships.py b/packages/microcosm-build/tests/test_uk_frs_relationships.py index e9f5c0309..c020d92c8 100644 --- a/packages/microcosm-build/tests/test_uk_frs_relationships.py +++ b/packages/microcosm-build/tests/test_uk_frs_relationships.py @@ -498,6 +498,24 @@ def test_reciprocity_mismatches_are_counted_and_fenced() -> None: assert _types(tolerated) == ["lone_parent_dependent_children_households"] +def test_a_non_numeric_age_refuses_instead_of_reading_as_zero() -> None: + person, household, adult, child, raw_household = _tables( + [ + _person(1, age=45, hrp=True, rel={2: PARENT}), + _person(2, age=10, table="child", rel={1: CHILD}), + ] + ) + person.loc[person["person_id"] == 1002, "age"] = np.nan + with pytest.raises(FRSRelationshipsError, match="non-numeric age"): + derive_frs_relationships( + person, + household, + raw_adult=adult, + raw_child=child, + raw_household=raw_household, + ) + + def test_a_frame_person_missing_from_the_tabs_refuses() -> None: person, household, adult, child, raw_household = _tables( [_person(1, age=30, hrp=True)] diff --git a/packages/microcosm-build/tests/test_uk_parity_reference.py b/packages/microcosm-build/tests/test_uk_parity_reference.py index ac7199a3a..1be3a2f8d 100644 --- a/packages/microcosm-build/tests/test_uk_parity_reference.py +++ b/packages/microcosm-build/tests/test_uk_parity_reference.py @@ -189,31 +189,6 @@ def test_recorded_sha_matches_cached_incumbent_bytes(self) -> None: assert digest == source.sha256 @requires_uk - def test_cached_reference_regeneration_matches_committed_surface(self) -> None: - source = load_efrs_parity_reference().source - cached = _cached_incumbent_path(source) - if cached is None: - # A content-addressed blob can still be supplied explicitly even - # when the HF revision-to-filename cache mapping is unavailable. - candidate = ( - Path.home() - / ".cache" - / "huggingface" - / "hub" - / "models--policyengine--policyengine-uk-data-private" - / "blobs" - / source.sha256 - ) - cached = candidate if candidate.is_file() else None - if cached is None: - pytest.skip("pinned licensed eFRS artifact is not in the local HF cache") - - regenerated = _load_generator().build_reference(cached) - committed = json.loads( - _resource(EFRS_PARITY_REFERENCE_RESOURCE).read_text(encoding="utf-8") - ) - assert regenerated == committed - def test_implicit_resolution_requires_revision_mapping( self, monkeypatch, From 00318a27a6039364d676cdfedcb302e634c343d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Fri, 11 Sep 2026 15:55:49 +0200 Subject: [PATCH 3/4] =?UTF-8?q?Keep=20the=20#791=20plan=20of=20record=20ou?= =?UTF-8?q?tside=20the=20tree=20(Mar=C3=ADa's=20convention);=20receipts=20?= =?UTF-8?q?point=20at=20her=20local=20copy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5.1 (cherry picked from commit b4ab81cf87989eb29cbe2b5f797b1f195bf2626b) --- docs/uk-relationship-to-head-plan-791.md | 111 ------------------ .../791-household-composition-receipts.md | 4 +- 2 files changed, 2 insertions(+), 113 deletions(-) delete mode 100644 docs/uk-relationship-to-head-plan-791.md diff --git a/docs/uk-relationship-to-head-plan-791.md b/docs/uk-relationship-to-head-plan-791.md deleted file mode 100644 index 181a61539..000000000 --- a/docs/uk-relationship-to-head-plan-791.md +++ /dev/null @@ -1,111 +0,0 @@ -# Implementation plan for microcosm#791 (relationship-to-head frame column; ONS household-composition split measurable) - -Plan file of record (approved 2026-09-11 in plan mode; María’s rulings the same day: rebind all ten cells, one PR, #791 lands before her #901, all four new columns exported). Committed here as the plan of record for PR #903; María’s working copy is `repos/uk-791-relationship-to-head-plan.md`. - -## Context - -Issue #791 (successor to the #757 `uk_target_fit` dispositions, comment 5427936411): three ONS household-composition targets are unmeasurable because the UK spine carries no relationship-to-head column, so the household-type derivation cannot tell a second family from unrelated adults or from the head's non-dependent children. The three cells (`ons.household_composition.multi_family_households` +1618 %, `unrelated_adult_households` +48 %, `lone_parent_non_dependent_children_households` −0.03 % but the wrong concept) carry signed measure exclusions (`packages/microcosm-build/src/microcosm/build/uk/calibration_measure_exclusions.json:336-364`, approved 2026-08-26, **expires 2026-11-26**, tracking microcosm#791). Closing the issue = derive the column on the spine, re-derive the categories per the ONS definitions, retire the three exclusions. - -### What exploration established (verified on origin/main 6f7571e1; the `populace-887` worktree is byte-identical to it) - -- **There is no classifier function.** The ten `ons.household_composition.*` rows (`uk/uk_population_targets.json:9544-10068`, family `ons_household_composition`, ONS Families and households Table 7, UK, period 2025, `value_variable: household_count`; dimension values `lone_households_under_65`, `lone_households_over_65`, `unrelated_adult_households`, `couple_no_children_households`, `couple_under_3_children_households`, `couple_3_plus_children_households`, `couple_non_dependent_children_only_households`, `lone_parent_dependent_children_households`, `lone_parent_non_dependent_children_households`, `multi_family_households`) derive their category declaratively through `household_conditions` over the engine variables `family_type`, `is_child` (= age < 18), `age`, `household_num_benunits`. Conditions with `reduce` go to `UKFrameTargetAdapter.household_condition` (`uk_runtime/ledger_targets.py:812-857`); reduce-less household conditions (the `multi_family` row today) go through `_predicate_mask` → `_column` → plain `==` (`build/target_materialization.py:675-694`). The conditions were ported from uk-data `targets/compute/households.py`, including its summed-ages "head age" proxy (admitted in the rows' `notes`). -- **The defect is partition-wide.** The seven "exact" cells were tightened in the #757 audit with person-count restrictions (e.g. couple_no_children = couple benunit AND person count == 2). ONS classifies a household with one family plus other individuals (couple + lodger, couple + elderly parent) by that family; today such households fall into no exact cell and were absorbed by `multi_family` (`household_num_benunits > 1`) and `unrelated_adult`. The ten published 2025 values sum exactly to `ons.households_total` (29,003,000; vendored in `uk/registry_parity_fixture_2025.json:6171-6320`) and form the higher side of cross-grain bridge `national_household_composition_partition_vs_census_households` (`ledger_targets.py:78-96`; lower side `ons.census.households`, 1,011 constituency/LA cells), unbound while any member is excluded (`cross_grain.py:516-548`). Hence María's ruling: all ten rows move to one derivation. -- **No new raw input is needed.** `frs_spine.py:334-357` reads every column of the 14 pinned FRS 2024-25 tabs (SN 9563, `uk/frs_release.json`). The local release at `/Users/mariajuaristi/Desktop/PolicyEngine/data/ukds/frs_2024_25/` (per-tab digests match `uk/source_stages.json`) carries on `adult.tab` and `child.tab`: `R01..R14` (on person i's record, `R0j` = i's relationship to within-household person j; j = `person_id % 1000` since `person_id = sernum*1000 + person`, `frs_spine.py:368-371`), `relhrp` (relationship to the household reference person; blank for the HRP; 16,288 blanks = 16,288 households = exactly one HRP, coinciding with `hrpid == 1` = `is_household_head`), `educft` (adult and child; there is no `fted` on the 2024-25 tape, `frs_education.py:157` already falls back `fted → educft`, "in FTE" = `educft == 1`), and `DEPEND` on child (not to be relied on: FRS dependency runs to 19). `househol.tab` carries `hrpnum` and `hhcomps`; `hhcomps` is fully determined by (`adulth`, `depchldh`, sex/pension age), verified by cross-tab, so it carries no family structure. -- **FRS relationship codes** (FRS 2023-24 question instructions, Household Grid "Relationship"; step 0 re-verifies them against the SN 9563 2024-25 documentation): 1 spouse, 2 cohabitee, 3 son/daughter (incl adopted/legal dependent), 4 step-son/daughter, 5 foster child, 6 son/daughter-in-law, 7 father/mother/guardian, 8 step-parent, 9 foster parent, 10 parent-in-law, 11 brother/sister (incl adopted), 12 step-sibling (half-siblings here), 13 foster sibling, 14 sibling-in-law, 15 grandchild, 16 grandparent, 17 other relative, 18 other non-relative, 20 civil partner; 97 unused. Relatives of cohabitees are coded as if married. A 16–19 in FTE living with grandparents has the grandparent coded as guardian (7/3). HRP = highest-income householder, elder on ties (FRS BIM 2023-24). -- **ONS definitions** (Families and households 2024 bulletin; "Families and households statistics explained"): family = married/civil-partnered/cohabiting couple with or without children, or a lone parent with ≥ 1 child, at the same address; children dependent or non-dependent. Dependent child = under 16, or 16–18 in full-time education, excluding 16–18s with a partner or own child in the household. Non-dependent child = living with parent(s), aged 19+ with no partner/child in the household, or 16–18 not in FTE with no partner/child. One-family household = couple (no children / dependent children / non-dependent children only) or lone parent (dependent / non-dependent only); one family plus other individuals is still one-family, classified by the family. "Two or more unrelated adults" = 2+ people none of whom is in a family (no couple, no parent–child; two siblings count here). Multi-family = 2+ families. Foster children and children living with someone other than their parents are separate one-person family units. Source is the LFS; the FRS grid translates the same relationship concept, and the residual differences are translation notes on the rows, not fences. -- **Frame typing, export and parity are fail-closed.** Stage-owned cells are declared in `_STAGE_CELLS` (`uk_runtime/graph.py:353+`; household string cells already exist: `brma`, `household_support_channel`); the export allowlist `UK_ALLOWED_EXTRA_EXPORT_COLUMNS` (`uk_runtime/terminal_gates.py:163-231`, mirrored in `uk/gates.json` gate `uk_export_surface`) must list each non-engine column; `tools/verify_uk_spine_parity.py:396-434` treats an unsigned `only_in_candidate` column as a defect (`uk/spine_swap_signed_differences.json`). Non-engine string columns already ride the H5 into `Microsimulation` (`person_support_channel`, `source_household_key`). -- **Seam side is ready.** `resolve_target_measures` (`target_materialization.py:132-262`) materialises from the frame tables first; a missing column is routed to `UKMeasureResolver.knows` (`measure_simulation.py:367-395`), which refuses non-engine names, so the household column must be on the spine H5 (no engine fallback, no engine change). `_compare_series`/`_compare` handle string `==`. -- **US precedent**: `us_runtime/relationship_inputs.py` (stage `relationship_inputs`, fail-closed on missing/invalid codes, signal gate `:279-300`, tests `tests/test_us_relationship_inputs.py`). UK stage template: `uk_runtime/frs_education.py` (re-reads pinned adult+child tabs; manifest ops `read_tables` + `derive`, `uk/source_stages.json:537-612`). -- **Generated target surfaces do not carry bindings** (`tools/generate_uk_target_references.py:341-366` copies only observation basis/period fields), so rebinding moves none of `target_references.json`, `target_reference_membership.json`, the parity fixtures; it moves the spec digest (`tests/test_spec_engine_country_bundles.py:54`) and the field-usage ledger (`tests/test_spec_engine_field_usage.py`). -- **Binding the bridge is receipt-level, not numeric**: A15 already uprates each census grain to `ons.households_total` (`experiments/887-census-households-receipts.md:155-165`), the ten cells sum to the same total, so `factor = parent_value / raw_sum` (`cross_grain.py:377`) is 1.0 to float precision; what changes is `receipt["groups"]` gaining the bridge, `unbound_bridges == []`, and the dense assembler dropping the `unbound_bridge:` limitation (`tools/assemble_uk_dense_release_dir.py:164-171,515-523`). Deleting all three register entries is what binds it; a partial deletion raises (`cross_grain.py:530-535`). -- **Pinned to the exclusions**: `tests/test_uk_measure_simulation.py:562-680` (`_PACKAGED_EXCLUSION_CENSUS` has `"ons.household_composition.": 3`; 51 names; 2026-08-26 tranche 39; composition entries must track #791); synthetic bridge fixtures in `tests/test_uk_ledger_targets.py:1326-1385`, `tests/test_uk_rowwise_candidate.py:1155-1170`, `tests/test_cross_grain.py:278-325`, `tests/test_uk_dense_release_assembler.py:198-204`; wording in `uk/local_binding_adjudications.json:6` and `uk/uk_local_target_census.json:101`. The release fence `uk_target_fit` (`uk/gates.json:706-715`, 25 %; `target_fit_reviewed_exclusions.json` empty) covers the three cells with no cover once re-bound. -- **Conflict surface**: María's draft #901 (stacked on Max's #893) edits `sources.yaml`, `source_stages.json`, `graph.py`, `graph_kernels.py`, `calibration_run.py` and the spec digest pin; Max's draft #749 edits `spine_swap_signed_differences.json` and the parity pins. Ruling: #791 lands first on main; #901 and #749 rebase. -- **Publisher side (Chronicle, `origin/main` ca727a2; the local `fork/main` is stale)**: package `ons-families-households-2025` (`packages/ons/families_households_2025/source_package.yaml`), Table 7 sheet `7` of `familiesandhouseholdsuk2025.xlsx` (sha `a89eaa3d…`), record sets `cy2018..cy2025`, ten `detail` rows per year with `groupby_dimension ons.household_type`, no total row, no CI, and **no Table 7 note text** (notes 4/5/6/7/10/11 survive only as markers in the row labels; the ONS definitions above come from the bulletin and the "statistics explained" article and are recorded in the contract notes and receipts; a Chronicle follow-up to carry the note text as `definition` fields is optional, María's call). The 2025 values bound today resolve on feed `ec7169b5` (`ledger_source_record_id ons.families_households_2025.table7.cy2025..households`). Sibling census packages (`ons/census2021_ts003_household_composition_country`, NRS UV113, NISRA; chronicle#237) are the independent census benchmark for the LFS-based Table 7 rows; Chronicle states that the map onto Table 7 categories is a consumer declaration, i.e. Microcosm's job (`docs/chronicle-governance.md:10-45`). -- **Evidence on disk**: the rebind packet the register reasons cite is `~/Desktop/PolicyEngine/data/ukds/acceptance/757-swap/calibration_diagnostics_rebind.json` (build `uk-frs-calibration-attempt-20260826T160611Z-f83004f0`, loss 0.1362; multi_family 4,191,850 vs 244,000 = +1617.97 %, unrelated_adult +48.05 %, lone_parent_non_dep −0.03 %, couple_no_children +34.23 %). The latest 55k candidate run (spine-q Q50f, 2026-09-10) fits the seven bound cells within ±0.6 % **except `lone_parent_dependent_children_households` at +21.94 %** (was +0.08 % on the rebind packet): collateral of the three exclusions, the solver parking misclassified households in the nearest bound sibling. The incumbent eFRS carries the same defect (multi_family +1093 %, `uk-dataset-evaluation/reports/55k-rebuild-2026-09-10/inputs/incumbent_national_loss_2025.json`). `uk-candidate-eval/config/assessment_fences.json:17-18` already diagnoses the benunit-vs-family mis-binding in the same terms as this plan. -- **Doctrine**: `DESIGN.md:274-288` permits raw survey structure as calibration input (the holdout rule is for tax-benefit quantities); `uc_relationships.py:16-30` is the precedent for persisting a raw FRS role as a frame column rather than inferring it from age. The retirement mechanism for a measure exclusion is executable (`measure_simulation.py:527-571`: a stale entry hard-fails), but the evidence bar for removing one is written nowhere; the test comment at `test_uk_measure_simulation.py:566-571` says a drifting count "must be re-adjudicated, never absorbed", so the PR description carries the re-adjudication (delta receipt + calibration receipt) and María's review is the adjudication. - -## Design decisions - -1. **New stage `frs_relationships`, positioned after `age_tail` and before `frs_employment`** (roster 28 → 29 executed, manifest 30 → 31). Not `frs_spine` outputs: that would move the CREATE node's root cells and hash (invalidating every downstream cache and the H2 oracle), read top-coded `age` before `age_tail` rewrites it (the #785 rule that every later age reader binds to the disaggregated cell, `graph.py:96-99`), and leave the derivation without a stage receipt. `age_tail` only moves people piled at 80 (`age_tail.py:70`), so the 65 split and the 16–18 window are unaffected either way; no later stage owns `age`. The stage re-reads the pinned `adult`, `child` and `househol` tabs (same artifact pins as `frs_spine`; `househol` only for the `hrpnum` cross-check of HEAD, the one independent check available), joins on `person_id`, and consumes `("person","age")`, `("person","is_household_head")`, `("person","person_household_id")`. -2. **Three code lists, three sources of truth, named for where they come from** (no invented third spelling anywhere): - - *FRS relationship codes* (integers 1–18, 20 in `relhrp` and `r01..r14`): owned by DWP, published in the UKDS SN 9563 FRS 2024-25 documentation (Household Grid, "Relationship"). In the repo they appear once, as the manifest parameter `frs_household_grid_relationship_codes` (code → Microcosm label, e.g. `1: SPOUSE`, `3: CHILD`, `20: CIVIL_PARTNER`), with the documentation reference recorded beside them. The person column `relationship_to_head` carries those labels (`HEAD` for the HRP, which is not a code but the blank + `hrpid == 1` condition). - - *ONS household-type definitions* (family, dependent/non-dependent child, one-family vs multi-family, unrelated adults): owned by ONS, published in the Families and households bulletin and QMI. In the repo they appear as the manifest's rule parameters (`family_link_codes`, `dependent_child`, `one_person_age_split`) plus the ONS reference, and as the translation notes on the ten contract rows. - - *The ten category identifiers*: owned by Chronicle's `ons-families-households-2025` package (`groupby_dimension ons.household_type`, the `value_id`s `lone_households_under_65` … `multi_family_households`). The household column `ons_household_type` takes these value ids **verbatim**, so the frame value, the manifest's `household_type_values`, the contract row's `dimension_values.household_type`, and the Chronicle fact's dimension value are the same string. No map between frame enum and ledger dimension exists to drift. A test pins the manifest list against the pinned feed's `ons.household_type` values for `ons.families_households_table7` (reading the vendored feed as `test_uk_target_references.py::test_committed_surfaces_regenerate_from_pinned_feed` does) and against the ten contract rows. - Columns (all four exported): person `relationship_to_head` (str), person `ons_family_role` (str; `COUPLE_PARTNER, LONE_PARENT, DEPENDENT_CHILD, NON_DEPENDENT_CHILD, INDIVIDUAL`, Microcosm labels declared in the manifest), person `ons_family_index` (int64; 0 = individual, 1..F within household, numbered by lowest member index), household `ons_household_type` (str; the ten Chronicle value ids). No new column is named `household_*` (`graph.py:305-308`). -3. **Derivation** (per household; `p = person_id % 1000`; `Rel[i][j]` = code in `r0j` on i's record = "i is the of j"): - - Partner links = codes {1, 2, 20}. Child-of links = codes {3, 4} on the child's record toward the parent (reciprocal {7, 8} on the parent's record). Foster (5/9/13), in-law (6/10/14), grandchild (15/16), sibling and other codes never form a family link, so foster children and grandchildren with no parent present stay `INDIVIDUAL` (ONS rule). - - Child-eligible(i) = no partner link and nobody has a child-of link toward i (no own child in the household). - - Families: each couple is a family and takes every child-eligible person with a child-of link to either partner; each remaining child-eligible person with a child-of link to an uncoupled person q joins q's lone-parent family (q has an own child, so q is never a child elsewhere). Ties (child-of links to two uncoupled people): natural (3) before step (4), then lowest person index; counted in evidence. Everyone else `INDIVIDUAL`. - - Dependency (children in families only): `age < 16`, or `16 ≤ age ≤ 18` and in FTE (child-tab member, or adult `educft == 1`, `fted` first if present); `age ≥ 19` is non-dependent regardless of FTE. - - Household type: n == 1 → `ONE_PERSON_*` split at `age >= 65` (matches the current `age < 65` / `age >= 65` rows); n ≥ 2 with zero families → `UNRELATED_ADULTS`; exactly one family → by that family regardless of extra individuals (couple: no children → `COUPLE_NO_CHILDREN`; 1–2 dependent → `COUPLE_1_2_…`; 3+ dependent → `COUPLE_3_PLUS_…`; only non-dependent → `COUPLE_NON_DEPENDENT_…`; lone parent: any dependent → `LONE_PARENT_DEPENDENT_…`, else `LONE_PARENT_NON_DEPENDENT_…`); ≥ 2 families → `MULTI_FAMILY`. - - HEAD: `relhrp` NaN after numeric coercion AND `hrpid == 1`; invariants: HEAD ⇔ `is_household_head`, exactly one per household, `hrpnum` equals the HEAD's person index. - - Fail closed (SourceRuntimeError) on: missing tab or required column; a household without exactly one HEAD or HEAD disagreeing with `is_household_head`; unmapped `relhrp` code; person index > 14 or non-contiguous; two partner links on one person; grid reciprocity mismatches above the declared tolerance (default 0; set from the step-0 probe); a household typed outside the domain; partition not closing (household-type counts ≠ household count). -4. **Manifest operations: `read_tables` + a structured kind `derive_ons_household_composition`** (María's lean, 2026-09-11). A prose `derive.scope` guarantees nothing: it is documentation that no code reads. The guarantee comes from three layers that already exist for `disaggregate_top_coded_ages`: (i) a JSON-schema branch in `spec_engine/schema/sources.schema.json` (`additionalProperties: false`, every parameter `required`, closed `enum`s for the label and value-id lists, integer code keys) so a malformed or unknown code cannot load; (ii) the runtime lockstep assert in the `age_tail.py:258-292` pattern (`_assert_frs_relationships_stage_parameters(stage)`: the runtime's pinned constants must equal the manifest's declared parameters key by key, extra keys refuse, drift either way refuses the build with the offending key named); (iii) the spec digest pin (`test_spec_engine_country_bundles.py:54`), so any change to the codes is a reviewed digest move. Parameters: `source_columns` (`head: relhrp`, `head_flag: hrpid`, `head_index: hrpnum`, `grid: [r01..r14]`, `full_time_education: [fted, educft]` in fallback order), `frs_household_grid_relationship_codes` (the 19 code → label pairs), `family_link_codes` (`partner: [1, 2, 20]`, `child_of: [3, 4]`, `parent_of: [7, 8]`), `dependent_child` (`unconditional_below_age: 16`, `full_time_education_through_age: 18`), `one_person_age_split: 65`, `household_type_values` (the ten Chronicle value ids, in Table 7 order), `family_role_values`, `reciprocity_mismatch_tolerance: 0`, `documentation` (`frs_codes`: "UKDS SN 9563, FRS 2024-25 question instructions, Household Grid: Relationship"; `ons_definitions`: "ONS Families and households in the UK: 2025, Measuring the data / Glossary"; `category_ids`: "chronicle ons-families-households-2025, dimension ons.household_type"). Cost accepted: `source_manifest.py:60-135` allowlist entry, the schema branch, field-usage ledger re-pin. -5. **Gates**: `uk_ons_household_type_enum_domain` (`enum_domain`, phase `assembled`, spine scope; the enum domain is passed as `gate_artifacts["ons_household_type_enum_domain"]` next to `rules_engine` at `tools/build_uk_frs_spine.py:1313` and `:883`, the `_evaluate_enum_domain` artifact-first path at `battery_bindings.py:465-488`) and `uk_stage_frs_relationships_composition` (`stage_health`, phase `assembled`, `evidence_absent_blocks: true`, check `household_composition`: head-invariant and hrpnum mismatches = 0, reciprocity ≤ tolerance, person-enum domains, partition closes). Stage evidence keys: `households`, `persons`, `head_invariant_violations`, `hrpnum_mismatches`, `relhrp_unmapped_codes`, `person_index_gaps`, `grid_reciprocity_mismatches`, `multi_partner_persons`, `parent_tie_breaks`, `family_index_violations`, `domain_violations`, `one_family_plus_individuals`, `dependency_counts` (`under_16`, `16_18_fte`, `16_18_not_fte`, `19_plus`), `household_type_counts`, `household_type_weighted` (design weights), `partition_closes`. The weighted ten-cell shares versus the published 2025 values are a diagnostic receipt, not a gate. -6. **Contract**: every one of the ten rows gets the single condition `{"variable": "ons_household_type", "operator": "==", "value": ""}` (household entity, no `entity`, no `reduce`; binding-level `reduce: "any"` dropped), `value_variable: household_count` kept. `notes` rewritten on all ten: source column and stage, the two translation notes (ONS dependency 16–18 in FTE vs the engine's `is_child` age < 18; "unrelated adults" = no family present, so related non-family households count there), the #757 person-count prose and the "Proxied" prose removed. `tools/generate_uk_target_references.py` in check mode must report no diff. -7. **Registers**: delete the three #791 entries (51 → 48); two `column_missing_in_reference` entries in `spine_swap_signed_differences.json` (template `:474-500`), added only with the build because `--strict` refuses unused entries; `uk/local_binding_adjudications.json:6` and `uk/uk_local_target_census.json:101` re-worded and dated ("bound from microcosm#791: the cross-grain rescale runs on the A15-uprated cells with factor 1 by closure"); `uk/uk_data_target_parity.json:870-877` evidence string updated (the derivation no longer mirrors uk-data's proxies). `target_fit_reviewed_exclusions.json` untouched. -8. **If a re-derived cell misses the 25 % `uk_target_fit` fence after calibration: stop and report to María** with the delta receipt; do not pre-sign a reviewed target-fit exclusion (schema-2 entry keyed by the contract target id, `terminal_gates.py:85-140`; it suppresses the fence only, the cell stays in the solve, and stale entries fail). Two outcomes the calibration receipt must speak to explicitly: `lone_parent_dependent_children_households` should return inside the band once its siblings are correctly bound (it is +21.94 % on Q50f as collateral of the exclusions), and the cross-grain receipt must show the bridge factor ≈ 1.0 by closure; if it does not (the 887 plan §52-56 flagged that the 1,011 census cells escape rescaling only while the bridge is unbound), that is a separate adjudication for María, not something this PR absorbs. -9. **Other consumers pick the new derivation up unchanged**: the incumbent-surface evaluator (`tools/evaluate_uk_incumbent_surface.py:118-152`) measures all ten; the dense assembler and data contract (`contract.py:5576-5600, 5879-5887`) see 48 exclusions and no unbound bridge; the data-contract gate mirrors (`contract.py:400-415, 455-480, 515-527`) gain the two new gate ids. - -## How the columns are stored, read, and turned into calibration rows - -1. **Build.** The stage returns a Frame with the four new columns added to the person and household tables through `uk_national_frame` (`national_frame.py:317`; dtype kinds `str` and `int` are first-class in `microcosm-frame/schema.py:24`) and validated by `validate_uk_national_frame`. The graph declares them as stage-owned cells with dtypes in `graph.py:_STAGE_CELLS` (string household cells already exist: `brma`, `household_support_channel`). `write_uk_national_frame` (`national_frame.py:436`) persists the tables to the staging H5 next to `region` and `tenure_type`, so the H5 that calibration and the release read carries them. -2. **Gates at `assembled`.** `uk_ons_household_type_enum_domain` refuses any household value outside the manifest's `household_type_values` (`_evaluate_enum_domain`, `battery_bindings.py:465-488`, artifact-first); `uk_stage_frs_relationships_composition` refuses head-invariant violations, unmapped codes, reciprocity mismatches above tolerance, and a partition that does not close (every household typed exactly once). A wrong code cannot leave the build. -3. **Calibration read path.** `tools/calibrate_uk_national_dataset.py --input-h5` → `load_uk_national_frame` (`national_frame.py:299`) → `CalibrationFrameAdapter(frame)` (`national_calibration.py:365`, a `UKFrameTargetAdapter` whose `tables` are copies of the entity tables) → `materialize_target_bindings` (`target_materialization.py:472-546`). For each of the ten rows, `_prepared_column_values` (`:640-660`) takes `household_count` (ones per household, `ledger_targets.py:722-731`), ANDs in `_predicate_mask` (`:675-689`), which for the reduce-less condition reads `_column(adapter, "household", "ons_household_type")` and compares `== ""` (`_compare`, `:692`), and returns a 0/1 column over households. That column is the target's row of the loss matrix; the row's value is the weighted household count under the current weights and its target is the Chronicle fact. No engine variable is involved: `resolve_target_measures` only consults `UKMeasureResolver` for columns the frame lacks, so a present frame column is used as-is. -4. **Fail-closed on a wrong code downstream.** Contract compile: a new check in `compile_uk_target_registry`'s roster passes (next to `_assert_local_reference_in_crosswalk`) that every `ons_household_type` condition value is in the manifest's `household_type_values` and that the ten rows cover them exactly once, plus the population-targets test. Calibration initialisation: `microcosm-calibrate/initialization.py:55` raises "nonzero target at row has no support" if a condition matches no household, so a typo cannot silently become a zero row. Partition: the cross-grain bridge closure check (`cross_grain.py:396`) refuses if the ten rows do not sum to the household control. Each of these names the offending target id. -5. **Release.** The four columns ride into the release H5 through the export allowlist and are visible to the incumbent-surface evaluator and the dense/local assemblers unchanged. - -## Files to change - -Runtime (`packages/microcosm-build/src/microcosm/build/`): -- New `uk_runtime/frs_relationships.py`: `FRS_RELATIONSHIPS_STAGE_NAME`, `FRS_RELATIONSHIPS_OUTPUT_COLUMNS`, the runtime's pinned constants named for their source (`FRS_HOUSEHOLD_GRID_RELATIONSHIP_CODES`, `ONS_FAMILY_LINK_CODES`, `ONS_DEPENDENT_CHILD_RULE`, `ONS_ONE_PERSON_AGE_SPLIT`, `CHRONICLE_ONS_HOUSEHOLD_TYPE_VALUE_IDS`), `_assert_frs_relationships_stage_parameters(stage)` (age_tail lockstep pattern), `UKFRSRelationshipsStageTransform` (mirrors `UKFRSEducationStageTransform`, `frs_education.py:112-128`; `checkpoint_metadata` returns `{"evidence": …}` as `uc_deduction_attributes.py:148-151`), `add_frs_relationships(frame, raw_dir, *, stage)` (reads via `frs_spine.read_pinned_tab`/`_normalize_ids` as `frs_education.py:130-140`, writes person + household columns through `uk_national_frame`, validates with `validate_uk_national_frame`, `national_frame.py:488`), pure `derive_frs_relationships(person, household, raw_adult, raw_child, raw_household)` returning person values, household values and evidence, helpers `_relationship_grid`, `_assign_families`, `_household_type`, `frs_relationships_domains()`. -- `uk_runtime/__init__.py` exports; `uk_runtime/graph.py` (`_SPLIT_STAGE_SOURCES:104` add `"frs_relationships": ("frs",)`; `_STAGE_CONSUMES:133-243`; `_STAGE_CELLS:353+` four cells); `uk_runtime/graph_kernels.py` (`_STAGE_MODULES:65-94`, fixture implementations `:335-520`, "28-stage" string `:322`); `uk_runtime/source_runtime.py:50-121` (`frs_relationships_transform` kwarg); `uk_runtime/stage_health.py:17-62` (`household_composition` check); `uk_runtime/calibration_run.py:120-135` (`UK_SPINE_GATE_SCOPE` + the two gate ids); `uk_runtime/terminal_gates.py:163-231` (four allowlist rows). -- `tools/build_uk_frs_spine.py` (import block `:57-59`; wiring next to `frs_education` at `:1109-1114`; `gate_artifacts` at `:883` and `:1313`). - -Spec, manifest, gates, registers (`packages/microcosm-build/src/microcosm/build/uk/`): -- `spec/sources.yaml` and `source_stages.json` in lockstep (new stage block after `age_tail`, before `frs_employment`: `survey`/`source` as `frs_education`, artifacts = the `adult`, `child`, `househol` pins from `frs_spine`, ops `read_tables` + `derive_ons_household_composition` with the parameters of design 4, `outputs` = the four columns, mixed person/household `grain` as `was_wealth`, `notes`). -- `build/spec_engine/schema/sources.schema.json`: the `derive_ons_household_composition` branch (template: the `disaggregate_top_coded_ages` branch at `:2264-2304`; closed enums for labels and the ten value ids, integer-keyed code map, `additionalProperties: false`); `build/source_manifest.py:60-135`: allowlist entry. -- `uk_runtime/ledger_targets.py` / `compile_uk_target_registry`: the compile-time roster check that `ons_household_type` condition values are declared manifest values, covered exactly once. -- `gates.json`: stage-health gate after `uk_stage_age_tail_targets` (`:395-406`), enum gate near `uk_brma_enum_domain` (`:654-665`), four `uk_export_surface.allowed_extra_columns` rows (`:575+`). -- `calibration_measure_exclusions.json:336-364` (delete three); `spine_swap_signed_differences.json` (two entries, with the build); `local_binding_adjudications.json:6`; `uk_local_target_census.json:101`; `uk_data_target_parity.json:870-877`. -- `uk_population_targets.json:9544-10068` (ten rebound rows + notes). -- `packages/microcosm-data/src/microcosm/data/contract.py:400-415, 455-480, 515-527` (gate mirrors). - -Tests (`packages/microcosm-build/tests/` unless noted): -- New `test_uk_frs_relationships.py`: manifest-parameter lockstep (schema validation of the stage block; `_assert_frs_relationships_stage_parameters` passes on the committed manifest and refuses a mutated copy with the key named); `household_type_values` equals the pinned feed's `ons.household_type` value ids and the ten contract rows' dimension values; hand-built raw tabs + frame fixtures (couple + lodger → `COUPLE_NO_CHILDREN` with one individual; couple + 22-year-old child → `COUPLE_NON_DEPENDENT_CHILDREN_ONLY`; couple + adult child + child-in-law + grandchild → `MULTI_FAMILY`; lone parent + 19-year-old in FTE → `LONE_PARENT_NON_DEPENDENT_CHILDREN_ONLY`; lone parent + 17-year-old not in FTE → same; two sharers and two siblings → `UNRELATED_ADULTS`; grandparent + lone-parent daughter + grandchild → `LONE_PARENT_DEPENDENT_CHILDREN` with the grandparent an individual; grandparent + unpartnered childless adult daughter → `LONE_PARENT_NON_DEPENDENT_CHILDREN_ONLY`; adult + foster child → `UNRELATED_ADULTS`; two lone parents not a couple → `MULTI_FAMILY`; one person aged 64 / 65 → the split), domain pins, the ledger map covers exactly the ten contract cells, fail-closed cases, `checkpoint_metadata` shape, the stage-health check pass/fail, manifest lockstep (outputs == constant; artifact pins equal `frs_spine`'s, as `test_uk_source_stages.py:540`). -- Re-pins: `test_uk_source_stages.py:23-81` (roster) and outputs-backing test `:367+`; `test_uk_graph.py:169` 28 → 29 plus a consumes/cells assertion; `test_country_spec.py:970` 30 → 31; `test_spec_engine_country_bundles.py:54` (new uk sha); `test_spec_engine_field_usage.py` counts; `test_uk_spine_acceptance_receipt.py:45-70` pending-roster transformation until the receipt is re-minted; `test_uk_battery_bindings.py:80-86` and `test_country_spec.py:1463` (allowlist mirror); `packages/microcosm-graph/tests/test_acceptance_h_parity.py:46,259` comments. -- `test_uk_measure_simulation.py:562-620`: census entry removed, 51 → 48, tranche 39 → 36, the #791 tracking loop replaced by "no composition entry remains", the three lifted cells added to the not-excluded list. -- `test_uk_population_targets.py` (~`:475-490`): each of the ten rows carries one reduce-less `ons_household_type` condition whose value is in the domain and maps to its own `dimension_values.household_type`. -- `test_uk_ledger_targets.py:1326-1385`: keep as the synthetic partial-bridge case (renamed), add `test_fully_bound_household_composition_bridge_reconciles_census_cells` (ten K02000001 rows summing to a control, two census rows, expect `unbound_bridges == []` and one group with `declared_factor`). The other synthetic fixtures do not read the register and stay. - -Fixture and generated surfaces (regenerate, never hand-edit): `tools/graph_uk_spine_fixture.py` (`_frs_tables:272-400` add `RELHRP`, `R01..R14`, keep `FTED`; `_NORMALIZED_STRING_COLUMNS:134-158`; `UK_FIXTURE_STAGE_COUNT:131` 28 → 29; `_build_implementations`) then regenerate `packages/microcosm-graph/tests/fixtures/parity/uk_spine/` (`uk_spine.json`, `sources/fixture.json`, `sources/frs_raw/adult.tab`, `child.tab`, `PRODUCED_BY.txt`); `tools/spec_envelope_digests.py uk`; `tools/build_uk_release_input_coverage_manifest.py --check` (expected unchanged); `tools/generate_uk_target_references.py` check mode (expected no diff); `tools/ci_test_groups.py --verify`. - -Changelog and receipts: `changelog.d/uk-household-composition-791.added.md` (stage, gates, export columns) and `…791.changed.md` (rebind, exclusions lifted, bridge bound); `experiments/791-household-composition-receipts.md`. - -## Implementation steps (one PR, branch `uk-household-composition-791` off main, worktree `populace-791`) - -0. **Probe and verify vintage docs** (read-only scratchpad script, results into the receipts file): re-verify the relationship code list and HRP definition in the SN 9563 (FRS 2024-25) documentation; on the licensed tape tabulate `relhrp` codes on adult/child, HRP uniqueness and `hrpnum` agreement, PERSON contiguity, grid reciprocity rate, partner-link multiplicity, the share of households with one family plus individuals, and a first pass of the ten-cell weighted shares versus the published 2025 values. Sets the reciprocity tolerance (default 0). -1. Write `frs_relationships.py` + `test_uk_frs_relationships.py`; unit tests green. -2. Wire manifest/spec/graph/kernels/runtime/gates/allowlist/data-contract mirrors; re-pin the moved surfaces (spec sha, field-usage counts, roster and count pins, acceptance-receipt pending transformation); regenerate the H2 fixture; run the build shard. -3. Rebind the ten rows and rewrite their notes; the contract test; generator check mode. -4. Delete the three exclusions; re-pin `test_uk_measure_simulation.py`; adjudication wording; parity-register evidence; bridge test. -5. Sampled spine build (1 %), then the full licensed build (spine-q; spine-p took 424 s, 3.84 GB peak); expect 29 stages, both new gates green; sign the two parity-register entries; twin-build diff and parity verification. -6. Derivation-delta receipt on the new spine: the old ten bindings (copy of the pre-change rows) versus the new column through `UKFrameTargetAdapter`, a 10×10 design-weighted crosstab, and each cell's design-weight total against the published 2025 values, the rebind packet (`data/ukds/acceptance/757-swap/calibration_diagnostics_rebind.json`) and the Q50f run. Optional diagnostic, not a target: the E&W census TS003 "other household types" and "other family composition" leaves from the Chronicle census package as a second-source sanity check on the multi-family and unrelated-adults magnitudes (their map onto Table 7 is a consumer declaration and stays a note). -7. National calibration run (~30 min); read the ten cells' relative errors, `uk_target_fit`, and the cross-grain receipt (bridge in `groups`, factor ≈ 1.0, `unbound_bridges == []`); rowwise dry run for the local receipt. -8. Changelog fragments, receipts file, README/docs touch-ups; draft PR whose description carries the register re-adjudication (the three retired entries, the delta receipt, the calibration receipt, the bridge receipt); CI; report to María in-session (no PR comment or issue comment without her go; #791 closes on merge). Afterwards: #901 and #749 rebase; memory entry for the #791 state. - -## Verification - -- `uv run --no-sync pytest packages/microcosm-build/tests/test_uk_frs_relationships.py -q`, then the `spine-uk` and `uk` CI groups (`uv run --no-sync python tools/ci_test_groups.py --list spine-uk`), `tools/ci_test_groups.py --verify`, `uv run ruff check .`; `packages/microcosm-graph/tests/test_acceptance_h_parity.py` after the fixture regeneration. -- `uv run --no-sync python tools/build_uk_frs_spine.py --frs-raw-dir /Users/mariajuaristi/Desktop/PolicyEngine/data/ukds/frs_2024_25 --spine-h5 /791/spine-q.h5 [--sample-fraction 0.01 --sample-seed 42] --spi-tab … --hmrc-ods … --cgt-ods … --was-tab … --lcfs-hh-tab … --lcfs-person-tab … --etb-tab … --logbook-prev-row-digest …` with the pinned input files of the spine-p recipe (`experiments/355-uk-dataset-size-receipts.md:75-86`); check `.spine_gates.json` and the stage evidence sidecar. -- `tools/compare_uk_h5_payload.py spine-p.h5 spine-q.h5 --structure-only` + `tools/classify_uk_payload_diff.py` with the four columns declared candidate-only and everything else byte-equal; `tools/verify_uk_spine_parity.py --strict` (`only_in_candidate` = exactly the four columns). -- `tools/calibrate_uk_national_dataset.py --input-h5 spine-q.h5 --input-sha256 … --ledger-facts … --epochs 1500 --target-weight-rule family_equal …` (`docs/uk-national-calibration-runbook-623.md:30-42`); acceptance = all ten cells inside the 25 % fence, bridge bound, 48 exclusions applied; `tools/build_uk_rowwise_candidate.py --dry-run --sample-fraction 0.01 …` for the cross-grain receipt. -- Doctrine checks before commit: grep the live tree for `policyengine-uk-data` (cite `uk-data#NNN`), `requires_uk` marker on the new test module if it needs the engine (it should not), no hand-copied publisher rows (the ten values stay vendored from the pinned feed). - -## Defaults taken unless María objects - -- Structured `derive_ons_household_composition` op kind with schema + runtime lockstep (design 4, per her 2026-09-11 lean); the household column uses Chronicle's value ids verbatim (design 2). -- `househol` included as a third artifact for the `hrpnum` check (design 3). -- Reciprocity tolerance 0, revisited only if the step-0 probe finds tape defects (then a reviewed gate parameter, reported first). -- "Two or more unrelated adults" read as "no family present", per the ONS glossary quoted above. -- The old-vs-new delta and any cell outside the fence are reported in-session before anything is posted outward. diff --git a/experiments/791-household-composition-receipts.md b/experiments/791-household-composition-receipts.md index 7faf88d37..228999f83 100644 --- a/experiments/791-household-composition-receipts.md +++ b/experiments/791-household-composition-receipts.md @@ -1,6 +1,6 @@ # microcosm#791 receipts: relationship-to-head frame column and the ONS household-composition rebind -Plan of record: `docs/uk-relationship-to-head-plan-791.md` (approved 2026-09-11; María's working copy `repos/uk-791-relationship-to-head-plan.md`). Branch `uk-household-composition-791` off main `6f7571e1`. +Plan of record: María's local `repos/uk-791-relationship-to-head-plan.md` (approved 2026-09-11 in plan mode; plans are kept outside the tree by her convention, and these receipts carry what the tree needs of it). Branch `uk-household-composition-791` off main `6f7571e1`. ## R1 — vintage documentation check (step 0) @@ -104,4 +104,4 @@ One failure is pre-existing and untouched: `test_uk_parity_reference.py::test_ca ## R11 — Vahid's review round 1 (comment at 7779747b, 2026-09-11) -Should-fixes: the `census_disclosure_control_noise` adjudication reason now carries a dated re-wording trailer ("re-worded 2026-09-11 (microcosm#791 …)") beside the #887 one, under the unchanged 2026-08-31 approval; the plan of record is committed as `docs/uk-relationship-to-head-plan-791.md` (the #355 precedent), and the receipts and PR body point there. Questions: the `unrelated_adult_households` and `lone_parent_dependent_children_households` contract notes record the skip-generation age switch (under 16 with no parent present: two unrelated adults, codes 15/16 never form a family; 16-19 in full-time education: the FRS codes the grandparents as legal guardian, 7/3, so a family with a dependent child) and cite the ONS "Families and households statistics explained" definition of two or more unrelated adults by URL, which is the source R1 quotes. Nits: `age` NaN now refuses instead of reading as 0 (`FRSRelationshipsError`, test added); `stage_health.py` is the main text plus the two composition hunks only (the earlier formatter pass had rewritten unrelated gates; CI lints with `ruff check` only); the enum-domain artifact fallback and the head-plus-child-only H2 fixture are left as noted, the couple and multi-family paths being held by the unit tests. The `test_uk_parity_reference.py` cached-reference regeneration test is retired on María's call (R10: it regenerated the reference under the installed engine, was skipped in CI and failed on main since the 2.97.0 lock); the thirteen other integrity tests on the reference, including the cached-artifact sha check, stay. +Should-fixes: the `census_disclosure_control_noise` adjudication reason now carries a dated re-wording trailer ("re-worded 2026-09-11 (microcosm#791 …)") beside the #887 one, under the unchanged 2026-08-31 approval; the plan of record stays María's local `repos/uk-791-relationship-to-head-plan.md` (her convention: plans live outside the tree; a first attempt to commit it under `docs/` was reverted on her ruling), and the receipts and PR body say so. Questions: the `unrelated_adult_households` and `lone_parent_dependent_children_households` contract notes record the skip-generation age switch (under 16 with no parent present: two unrelated adults, codes 15/16 never form a family; 16-19 in full-time education: the FRS codes the grandparents as legal guardian, 7/3, so a family with a dependent child) and cite the ONS "Families and households statistics explained" definition of two or more unrelated adults by URL, which is the source R1 quotes. Nits: `age` NaN now refuses instead of reading as 0 (`FRSRelationshipsError`, test added); `stage_health.py` is the main text plus the two composition hunks only (the earlier formatter pass had rewritten unrelated gates; CI lints with `ruff check` only); the enum-domain artifact fallback and the head-plus-child-only H2 fixture are left as noted, the couple and multi-family paths being held by the unit tests. The `test_uk_parity_reference.py` cached-reference regeneration test is retired on María's call (R10: it regenerated the reference under the installed engine, was skipped in CI and failed on main since the 2.97.0 lock); the thirteen other integrity tests on the reference, including the cached-artifact sha check, stay. From 48b15664005f68058659f33dae8e5a6417472b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Fri, 11 Sep 2026 18:21:59 +0200 Subject: [PATCH 4/4] Record the rebase onto main 295130c9 in the #791 receipts (R12) Co-Authored-By: Claude Fable 5.1 --- experiments/791-household-composition-receipts.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/experiments/791-household-composition-receipts.md b/experiments/791-household-composition-receipts.md index 228999f83..65d6c4a5c 100644 --- a/experiments/791-household-composition-receipts.md +++ b/experiments/791-household-composition-receipts.md @@ -105,3 +105,7 @@ One failure is pre-existing and untouched: `test_uk_parity_reference.py::test_ca ## R11 — Vahid's review round 1 (comment at 7779747b, 2026-09-11) Should-fixes: the `census_disclosure_control_noise` adjudication reason now carries a dated re-wording trailer ("re-worded 2026-09-11 (microcosm#791 …)") beside the #887 one, under the unchanged 2026-08-31 approval; the plan of record stays María's local `repos/uk-791-relationship-to-head-plan.md` (her convention: plans live outside the tree; a first attempt to commit it under `docs/` was reverted on her ruling), and the receipts and PR body say so. Questions: the `unrelated_adult_households` and `lone_parent_dependent_children_households` contract notes record the skip-generation age switch (under 16 with no parent present: two unrelated adults, codes 15/16 never form a family; 16-19 in full-time education: the FRS codes the grandparents as legal guardian, 7/3, so a family with a dependent child) and cite the ONS "Families and households statistics explained" definition of two or more unrelated adults by URL, which is the source R1 quotes. Nits: `age` NaN now refuses instead of reading as 0 (`FRSRelationshipsError`, test added); `stage_health.py` is the main text plus the two composition hunks only (the earlier formatter pass had rewritten unrelated gates; CI lints with `ruff check` only); the enum-domain artifact fallback and the head-plus-child-only H2 fixture are left as noted, the couple and multi-family paths being held by the unit tests. The `test_uk_parity_reference.py` cached-reference regeneration test is retired on María's call (R10: it regenerated the reference under the installed engine, was skipped in CI and failed on main since the 2.97.0 lock); the thirteen other integrity tests on the reference, including the cached-artifact sha check, stay. + +## R12 — rebase onto main `295130c9` (2026-09-11) + +Main took #894, #855 and #902 after the branch base `6f7571e1`. One conflict, `uk/uk_population_targets.json`, where #855 added `hierarchy` at the top level and `category_id`/`label` on every row (236 rows changed, the ten composition rows among them, their `policyengine` bindings untouched on main). Resolved by taking main's file and re-injecting the branch's ten `policyengine` bindings, written in main's serialisation (`indent=2`, `ensure_ascii=False`); the three commits were re-applied by cherry-pick after a first `git rebase` pass had let a conflict-marked file through. After the rebase: no conflict markers; the UK spec digest is unchanged (`c396ee51…`, main touched no spec, gate or manifest file); the local-target census, uk-data parity register, release-input coverage manifest and CI group partition are all current; the pin, contract, overlap and stage suites rerun green (R10's set plus the #855-touched `test_uk_population_targets.py` and `test_country_spec.py`). One local check no longer runs: the pinned-feed regeneration test (`test_uk_target_references.py`) now stops in #855's hierarchy metadata (`obr.income_tax`: dimension `obr.efo_line` requires exactly one non-empty label, got none) against the local `ec7169b` artifact, which predates the label requirement; the feed pin is unchanged on main and the test is skipped in CI, so this is the local artifact's vintage, not this branch.