You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ACS local release: supply source-backed SPM independence (is_spm_independent_minor_role) so every SPM unit has a classified adult #1263
The certified ACS local-area release populace-us-2024-buildo-acs-local-767312d60-20260923T074941Z (populace_us_2024_acs_local.h5) has no source-backed SPM independence. policyengine.py has used it for US state and congressional-district regions since policyengine 6.2.2. Under canonical SPM (spm-calculator 1.0.0), many SPM units therefore have no classified adult, and every state-region simulation is refused with SPM_COMPOSITION_REQUIRED: "SPM unit has no classified adult: supply source-backed independence or household head/spouse structure".
That refusal blocks every PolicyEngine/policyengine-sim-api deploy past policyengine 6.2.1 (sim-api#747). Its beta verification runs three state/ut US tests. Production stays on 6.2.1 until this is fixed or worked around.
spm_measurement_adults = sum(age >= 18 | (age >= 15 & is_spm_independent_minor_role)). The role defaults to is_household_head | is_household_spouse unless it is supplied as an input. policyengine_amount refuses any unit with spm_measurement_adults < 1.
Evidence
Aggregates only. The columns were read from the release file over HTTP range requests.
ACS local (…acs-local-767312d60-20260923T074941Z)
National (populace-us-2024-spm-20260915)
Persons
3,589,209
166,321
SPM units
1,591,514
59,900
is_spm_independent_minor_role column
absent
present
is_household_spouse column
absent
absent
is_household_head column
present
present
SPM units with no classified adult
5,274 (148 of them in Utah households)
0 (all 28 minors-only units have a role member aged 15+)
The national release passes end to end on the same packages: policyengine 6.2.7, policyengine-us 2.2.1, policyengine-core 3.33.0 and spm-calculator 1.0.0. Its 2026 year file computes SPM thresholds for all 59,900 units.
Ask
Rebuild the ACS local release with source-backed SPM independence, as the national release has (source_spm_person_independence, source_spm_independence_provenance). Every person should carry is_spm_independent_minor_role, plus head/spouse structure where the source supports it.
Acceptance: zero SPM units without a classified adult under the rule above, checked by the release gate. Then certify the new release in policyengine.py.
Interim
The UK Autumn Budget CI coordinator has queued a temporary policyengine.py revert for Max: state and congressional-district regions filter the national file, as in 6.2.1, until this lands. The full diagnosis is held by the W4 session (PolicyEngine/policyengine.py receipt and qualification workstream).
Existing work: branch us-acs-spm-independent-minor-role (pushed 10 Oct, no PR). Its commits are 319dec5 "WIP: derive the ACS SPM independence role and refuse default fills", a merge of main, and a8bc2fb "Test, document and validate the ACS SPM independence role". It is most of the fix. Against this issue's acceptance criterion (zero SPM units without a classified adult, checked by the release gate), I read the diff, not run it:
What it does:
Derives the role for every ACS person.with_acs_spm_independence_role (microcosm/build/us_runtime/acs_inputs.py) treats each ACS household as one SPM unit and reads the role off RELSHIPP (reference person and spouse), following the ASEC rule. Its validation notes say this reproduces Census's SPM adult counts on the pinned ASEC files in every unit but one across three vintages (experiments/acs-spm-role-asec-validation.md).
Refuses a housing-unit SPM unit left with no classified adult, along with off-domain RELSHIPP, a missing age, and a unit with other than exactly one head.
Treats the role as a declared source input.tools/build_us_acs_local_release.py refuses a null or default-filled role (DeclaredSourceInputNullError) and says to rebuild the staging.
What it still lacks for the criterion:
Group-quarters children stay unclassified. A group-quarters person under 15 is a one-person SPM unit with no classified adult. The branch counts these units in its receipt instead of refusing them (docs/us-acs-spm-role.md, "Group-quarters children"), on the grounds that the source places group quarters outside the SPM universe. But spm-calculator 1.0.0's canonical SPM has no group-quarters exclusion, so each such unit would still raise SPM_COMPOSITION_REQUIRED at run time. The criterion needs one of three things:
wire the SPM measurement universe in, so these persons are excluded from SPM measurement in both the data and the runtime;
give them a classified adult;
refuse the release while any exist.
Which of these is right is a design call.
No release-level gate on the final artifact. The zero-adult refusal runs inside the ACS derivation, for housing units only. Nothing in build_us_acs_local_release.py counts SPM units with spm_measurement_adults < 1 (spm-calculator's rule) over the assembled release before publishing. That check is what this issue asks for.
The rest of the path: a PR, then a rebuilt staging (the builder already says pre-existing staging carries the role only on donor rows), a new release, and certification in policyengine.py. That certification would also revert policyengine.py#604, the temporary national-file regions.
Ownership: the session that appears to own the branch ("Register is_spm_independent_minor_role for ACS staging") is no longer among the live sessions. I have not touched the branch. The UK Budget CI coordinator is finding it an owner.
Owner: this session owns #1263 now. The branch is in PR #1264 (draft), with main merged.
Gap 1, group-quarters children, needs Max's call (queued as d1484). The branch's role classifies 3,328 of the certified release's 5,274 unclassified units: 3,300 group-quarters teens aged 15 to 17, plus 28 donor units whose role column the old export held back. The remaining 1,946 units are one-person ACS group-quarters records of a child under 15. No role can give them a classified adult. 49 states plus DC have at least one (Utah has 27), so every state region still fails at run time unless they are handled. They are about 0.005% of the ACS spine's weight. Counts were measured on the cached Build O file, whose composition equals the certified release's on every field.
spm-calculator needs no change. The refusal in spm-calculator's policyengine_amount does not read the universe status, but under policyengine-us#9462 the country owns scope. scoped_spm_amount replaces the calculator's five amount formulas and passes only INCLUDED units to masked_policyengine_amount, which is on pe-us main and applies the composition refusal only to the units it is given.
The blocker is the rest of the chain:
d096 (parked): the export marker for the formula-owned status variable;
#9462 itself: a draft whose owner is archived, and strict, so it also needs a national child that declares scope;
(b) A phased pe-us change that treats an undeclared dataset as INCLUDED. This overturns the 9/22 strict ruling.
(c) Drop the 1,946 records from the ACS local population now. The release discloses it as a reviewed limitation, with a pre-registered flip: re-include them once the engine scopes SPM by universe.
The recommendation is (c) now, with (a) as the destination.
Gap 2 is independent of that call. The release gate I'm adding fails the release on any SPM unit the runtime would measure that has no classified adult. That is every unit under an engine without universe scoping, or only the INCLUDED units once the engine scopes and the file declares. So no option can certify a release that crashes at run time.
Reopened: microcosm#1264 merged the code (d61bce0), but this issue's acceptance is a certified ACS local release with zero measured SPM units without a classified adult, checked by the release gate on the final artifact. The rebuild is running on Modal under Max's ruling d1484; I'll close this when the release passes its gates, publishes tag-only and is certified in policyengine.py.
Beta's three-service verification ran both US state/ut calculations against the deployed stack, and both passed.
Prod serves 6.7.5 and reproduces its sentinel case.
The remaining interim exclusion (d1484 c, the 1,946 one-person group-quarters children under 15) is disclosed in the release. Its flip condition is the first release certified against an engine that scopes SPM by spm_unit_spm_universe_status.
Closing this issue is left to its owner session, which set the close condition.
Activity
MaxGhenis commentedon Oct 13, 2026
Existing work: branch
us-acs-spm-independent-minor-role(pushed 10 Oct, no PR). Its commits are 319dec5 "WIP: derive the ACS SPM independence role and refuse default fills", a merge of main, and a8bc2fb "Test, document and validate the ACS SPM independence role". It is most of the fix. Against this issue's acceptance criterion (zero SPM units without a classified adult, checked by the release gate), I read the diff, not run it:What it does:
with_acs_spm_independence_role(microcosm/build/us_runtime/acs_inputs.py) treats each ACS household as one SPM unit and reads the role offRELSHIPP(reference person and spouse), following the ASEC rule. Its validation notes say this reproduces Census's SPM adult counts on the pinned ASEC files in every unit but one across three vintages (experiments/acs-spm-role-asec-validation.md).RELSHIPP, a missing age, and a unit with other than exactly one head.tools/build_us_acs_local_release.pyrefuses a null or default-filled role (DeclaredSourceInputNullError) and says to rebuild the staging.What it still lacks for the criterion:
Group-quarters children stay unclassified. A group-quarters person under 15 is a one-person SPM unit with no classified adult. The branch counts these units in its receipt instead of refusing them (docs/us-acs-spm-role.md, "Group-quarters children"), on the grounds that the source places group quarters outside the SPM universe. But spm-calculator 1.0.0's canonical SPM has no group-quarters exclusion, so each such unit would still raise
SPM_COMPOSITION_REQUIREDat run time. The criterion needs one of three things:Which of these is right is a design call.
No release-level gate on the final artifact. The zero-adult refusal runs inside the ACS derivation, for housing units only. Nothing in
build_us_acs_local_release.pycounts SPM units withspm_measurement_adults < 1(spm-calculator's rule) over the assembled release before publishing. That check is what this issue asks for.The rest of the path: a PR, then a rebuilt staging (the builder already says pre-existing staging carries the role only on donor rows), a new release, and certification in policyengine.py. That certification would also revert policyengine.py#604, the temporary national-file regions.
Ownership: the session that appears to own the branch ("Register is_spm_independent_minor_role for ACS staging") is no longer among the live sessions. I have not touched the branch. The UK Budget CI coordinator is finding it an owner.
MaxGhenis commentedon Oct 13, 2026
Owner: this session owns #1263 now. The branch is in PR #1264 (draft), with main merged.
Gap 1, group-quarters children, needs Max's call (queued as d1484). The branch's role classifies 3,328 of the certified release's 5,274 unclassified units: 3,300 group-quarters teens aged 15 to 17, plus 28 donor units whose role column the old export held back. The remaining 1,946 units are one-person ACS group-quarters records of a child under 15. No role can give them a classified adult. 49 states plus DC have at least one (Utah has 27), so every state region still fails at run time unless they are handled. They are about 0.005% of the ACS spine's weight. Counts were measured on the cached Build O file, whose composition equals the certified release's on every field.
spm-calculator needs no change. The refusal in spm-calculator's
policyengine_amountdoes not read the universe status, but under policyengine-us#9462 the country owns scope.scoped_spm_amountreplaces the calculator's five amount formulas and passes onlyINCLUDEDunits tomasked_policyengine_amount, which is on pe-us main and applies the composition refusal only to the units it is given.The blocker is the rest of the chain:
Options:
INCLUDED. This overturns the 9/22 strict ruling.The recommendation is (c) now, with (a) as the destination.
Gap 2 is independent of that call. The release gate I'm adding fails the release on any SPM unit the runtime would measure that has no classified adult. That is every unit under an engine without universe scoping, or only the
INCLUDEDunits once the engine scopes and the file declares. So no option can certify a release that crashes at run time.MaxGhenis commentedon Oct 16, 2026
Reopened: microcosm#1264 merged the code (d61bce0), but this issue's acceptance is a certified ACS local release with zero measured SPM units without a classified adult, checked by the release gate on the final artifact. The rebuild is running on Modal under Max's ruling d1484; I'll close this when the release passes its gates, publishes tag-only and is certified in policyengine.py.
MaxGhenis commentedon Oct 18, 2026
The rebuild is now certified in policyengine.py and deployed. This adds evidence for the acceptance condition in this issue.
populace-us-2024-buildo-acs-local-766b7c7-20261017T030317Z, sha2563ce781c4…8d6c.spm_measurement_compositionreports 0 of 1,589,568 SPM units without a classified adult, all units measured.state/utcalculations against the deployed stack, and both passed.The remaining interim exclusion (d1484 c, the 1,946 one-person group-quarters children under 15) is disclosed in the release. Its flip condition is the first release certified against an engine that scopes SPM by
spm_unit_spm_universe_status.Closing this issue is left to its owner session, which set the close condition.
Expect 6.7.5's ACS-local US regional dataset in the catalog test