diff --git a/CLAUDE.md b/CLAUDE.md index ceffd14e0..086343176 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -133,6 +133,15 @@ to the private repository; when you run `tools/build_uk_rowwise_candidate.py` yourself, pass `--staging-local-only` unless the operator asked for a staged upload. +US fiscal builds require the NSECE childcare-attendance stage +(`--childcare-attendance-household-tsv`, `--childcare-attendance-calendar-tsv`, +`--childcare-attendance-inherit-outside-domain-baseline`): attendance is a +required, non-waivable export input bound by a per-person receipt, a build +without it is refused before calibration. The exact-k launcher accepts the same +inputs through an optional `childcare_attendance` configuration object, checks +the packaged survey pins, and forwards them to the fiscal builder. See +[the attendance runbook](docs/us-childcare-attendance.md). + The US fiscal-refresh builder scores its written H5 in household batches. Before a release rerun, run the small-H5 guard sweep described in [the release build rule](docs/us-release-build-rule.md#post-export-scoring). diff --git a/README.md b/README.md index bc7a7c5be..ea638ab33 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,13 @@ This writes `progress.json`, `events.ndjson`, `calibration_progress.json`, and final candidate diagnostics under `runs//` without updating production `latest.json`. +The three childcare-attendance inputs are required export inputs. A US fiscal +build also needs the licensed NSECE files +(`--childcare-attendance-household-tsv`, `--childcare-attendance-calendar-tsv` +and `--childcare-attendance-inherit-outside-domain-baseline`); without them the +build is refused before calibration. See +[docs/us-childcare-attendance.md](docs/us-childcare-attendance.md). + The UK commands (`tools/build_uk_frs_spine.py` and `tools/build_uk_rowwise_candidate.py`, whose `--release-role` builds either the national or the dense line) stage version 2 telemetry to @@ -223,7 +230,9 @@ Check local files from HDF metadata alone with `uv run python -m microcosm.data.stored_inputs path/to/populace_us_2024.h5`. US exact-k ladder candidates use a tag-only lane. Run -`tools/build_us_exact_k_ladder_release.py`, then execute the `publish_command` +`tools/build_us_exact_k_ladder_release.py` with the +[`childcare_attendance` source configuration](docs/us-childcare-attendance.md#build-and-reproduction) +unless the pool already carries bound attendance inputs, then execute the `publish_command` recorded in `package_result.json`. That command includes `--create-tag`, `--no-latest`, and `--tag-only`: it uploads the immutable release and creates its tag without committing candidate artifacts or release copies to the production diff --git a/changelog.d/915-us-childcare-attendance.added.md b/changelog.d/915-us-childcare-attendance.added.md new file mode 100644 index 000000000..655b2a110 --- /dev/null +++ b/changelog.d/915-us-childcare-attendance.added.md @@ -0,0 +1 @@ +Derive the three PolicyEngine-US childcare attendance inputs (`childcare_attending_days_per_month`, `childcare_days_per_week`, `childcare_hours_per_day`) for children ages 0–12 from the licensed 2024 NSECE household and calendar files and transfer them onto the US fiscal refresh population (#915). `tools/build_us_fiscal_refresh_release.py` gains `--childcare-attendance-household-tsv`, `--childcare-attendance-calendar-tsv`, `--childcare-attendance-asec-cache` and `--childcare-attendance-inherit-outside-domain-baseline`; the three inputs become required release inputs bound to a per-person receipt that the native loaders and the builder's `--base-h5` loader check, that the L0 refit export carries forward, and that no coverage override can waive. The builder preserves receipts through value repairs, and the exact-k launcher accepts a `childcare_attendance` source configuration with packaged survey-pin checks. A build with neither the source files nor bound attendance is refused before calibration. PolicyEngine-US defaults are unchanged and no population is published. diff --git a/changelog.d/916-attendance-cache-binding.fixed.md b/changelog.d/916-attendance-cache-binding.fixed.md new file mode 100644 index 000000000..7c4cb7e71 --- /dev/null +++ b/changelog.d/916-attendance-cache-binding.fixed.md @@ -0,0 +1,5 @@ +Bind US fiscal target-frame checkpoints and reform-vector caches to the verified +childcare attendance execution, so a rerun with changed attendance values or +recipe cannot calibrate against stale targets. Revalidate attendance before any +checkpoint lookup and preserve its native receipt before post-export scoring +hashes the finished H5. diff --git a/docs/evidence/spec-engine/us-f0-coverage.json b/docs/evidence/spec-engine/us-f0-coverage.json index c153d5229..d29900faa 100644 --- a/docs/evidence/spec-engine/us-f0-coverage.json +++ b/docs/evidence/spec-engine/us-f0-coverage.json @@ -6,7 +6,7 @@ "country": "us", "documentation_sha256": "0931cbd3aae2abcd8c072b78eba40c1c006b1bf7fa23c6a6681f9a895e47070e", "field_usage": { - "authored_normative_field_count": 32404, + "authored_normative_field_count": 32407, "claim_count": 49, "claims": [ { @@ -16,8 +16,8 @@ "legacy_sinks": [], "mode": "front_end_validation", "pointer_class": "all", - "pointer_count": 104, - "pointer_sha256": "8a186065f5b8ffc59bc3f62fe927975e6f36bc1e913aa61761652c9a8aa67988", + "pointer_count": 107, + "pointer_sha256": "2c2099d3d5ef3d664f74a2e732870391022a852cf49d5cf96810c9a984d2b20b", "rationale": null, "relative_sink_prefix": null, "source_prefix": "/authored/country_package.json", @@ -772,20 +772,20 @@ "verifier": "vintages" } ], - "configuration_field_count": 42184, - "consumed_field_count": 42184, + "configuration_field_count": 42187, + "consumed_field_count": 42187, "generation0_effect_counts": { "legacy_behavior": 38498, - "no_generation0_effect": 3686 + "no_generation0_effect": 3689 }, "mode_counts": { "compiler_semantic": 27717, - "front_end_validation": 354, + "front_end_validation": 357, "identity_only": 103, "legacy_behavior": 14010 }, "multiple_primary_use_field_count": 0, - "pointer_inventory_sha256": "8f655670b9794adae905ede64bdceba6395eeb8d642b6c5896d5c516f1f6a6a7", + "pointer_inventory_sha256": "72c746d5f084f96c2b776c65d69acb82b53c26feaa591bfacf2d8d8c878ef01f", "resolved_binding_field_count": 9780, "unused_field_count": 0 }, @@ -2599,7 +2599,7 @@ "country": "us", "schema_id": "country_spec", "schema_version": 1, - "spec_sha256": "1cf1f44d9a11458f59ea7d75dce68303816cab3e66668a6c6f6ecfe62d56f8dc" + "spec_sha256": "dde0912303e7ee8cfdcad306f0cdc0b92fbab047f99e01cf3ea8bba1aa855269" } }, "report_schema_version": 3, @@ -2609,7 +2609,7 @@ "country": "us", "schema_id": "country_spec", "schema_version": 1, - "spec_sha256": "1cf1f44d9a11458f59ea7d75dce68303816cab3e66668a6c6f6ecfe62d56f8dc" + "spec_sha256": "dde0912303e7ee8cfdcad306f0cdc0b92fbab047f99e01cf3ea8bba1aa855269" }, "status": "pass" } diff --git a/docs/us-annual-static-aging.md b/docs/us-annual-static-aging.md index 554d8eacc..0a4fe250c 100644 --- a/docs/us-annual-static-aging.md +++ b/docs/us-annual-static-aging.md @@ -62,6 +62,14 @@ independent demographic, monetary, identity, and runtime acceptance checks. That process supplies the separate annual projection acceptance report and publication decision; this module supplies no certification override. +If the base contains NSECE childcare attendance, every annual file preserves the +original content-bound attendance receipt. Static aging holds ages and schedules +fixed while changing weights and monetary inputs; the writer verifies that those +bound values remain exact before finalizing a file. It rejects missing receipts +for nonzero attendance and detects altered ages, identities or attendance instead +of rebinding them. Each annual round-trip report includes the validated binding +hash. This preserves provenance, not evidence of attendance changes over time. + ## Qualification and publication order 1. Qualify the base release under its existing contract with the intended diff --git a/docs/us-childcare-attendance.md b/docs/us-childcare-attendance.md new file mode 100644 index 000000000..5308c7d96 --- /dev/null +++ b/docs/us-childcare-attendance.md @@ -0,0 +1,361 @@ +# Child-care attendance: NSECE source and population integration + +Related: [Microcosm #915](https://github.com/PolicyEngine/microcosm/issues/915). + +The US fiscal refresh builder can now produce three **person-level** inputs: +`childcare_attending_days_per_month`, `childcare_days_per_week`, and +`childcare_hours_per_day`. The source model covers children ages 0–12. It does +not change PolicyEngine-US defaults. Attendance, subsidy eligibility, provider +pricing, and benefit receipt are separate concepts. + +The build runs `with_us_childcare_attendance_inputs` after the childcare expense +producer and before release validation. The generated release input contract +requires all three attendance columns. Licensed local source paths are explicit +build inputs; CI does not download or redistribute survey records. This PR +provides build integration and a local population candidate under review; it does +not publish a replacement population or certify national CCDF spending. + +The September 17 candidate was rebuilt from the pinned parent under +PolicyEngine-US 2.2.1 and Core 3.32.5, after the receipt, builder and bridge +changes from the second review. Both native loaders verify the new receipt; +all original values and weights are preserved. The new all-state comparison +reduces all-zero results from 31 jurisdictions to two (MD and NV). The +[aggregate experiment](../experiments/us-childcare-attendance/README.md) records +the current population, sensitivity and model diagnostics. Older 1.819.0 reports +remain historical; their receipts are not reused under the new runtime. + +The latest diagnostic keeps each child's selected donor fixed when varying +modeled schedules. It flags SD, TN and WV for irregular-care sensitivity, WV for +one more day, plus an OK day sensitivity of only about $2. The September 16 +flag for IL disappeared when the bridge change moved a few donor draws, so state +flags are sensitive to single draws. An interval-informed QRF experiment uses the +measured bounds of incomplete training calendars, but still underpredicts weekly +hours for observed children with unresolved siblings by 37.7%. All three tested +completion assumptions fail that subgroup's screens; none is integrated into +the population candidate. + +## Source and mapping + +The [2024 NSECE V1 release](https://www.childandfamilydataarchive.org/cfda/archives/cfda/studies/39466/datadocumentation) +contains household DS5 and calendar DS4 TSVs. Each contains 6,403 households. +The loader verifies the exact source hashes in `us/childcare_attendance_source.json` +before parsing. This separate `SourceStageSpec` compatibility resource preserves +the byte-frozen generation-0 source manifest. It contains declarative operations, +source pins, income bands, and price-year conventions. + +| Field | Meaning | +| --- | --- | +| `HH4_METH_CASEID` | One-to-one household/calendar join | +| `HHC4_AGE_AT_USAGE_X` | Child age in months in the reference week | +| `HHC4_METH_WEIGHT_X` | Child design weight for donor draws | +| `HH4_METH_WEIGHT` | Household design weight for sibling dependence | +| `HH4_MISSING_STATUS_CC_X` | Missing, partial, or complete calendar | +| `HH4_CHCAL_R_X_Z` | 672 successive 15-minute blocks, starting Monday midnight | +| `HH4_TYPEOFCARE_AGG_X_Y` | Child/provider care type | +| `HH4_RPARENT` | Whether respondent care is parental care | +| `HH4_REGION` | Census region | +| `HH4_PARWORK_STATUS` | Work status of parents of any under-13 household child; codes -1, 0, 1, 2 | +| `HH4_METH_QUEXVERSION` | Main, summer/typical-May, or new-school-year instrument | +| `HH4_ECON_INCOME_ANNUAL` | Published household pretax income for 2023 | +| `HHC4_NPC_HRSWEEK_TOC1..5_X` | Regular-care weekly hours for the noncalendar bridge | + +Regular ECE includes provider types 1–5; type 7 is irregular care. K–8 schooling +(type 6) is excluded. Certain unpaid-care gap codes count as ECE. Respondent +care depends on `HH4_RPARENT`; school gap code 68 is classifiable as non-ECE only +at age six or older. Ambiguous codes remain unknown. A complete parental, +self-care, or school-only calendar is a measured zero donor. Missing calendars +never become observed zeros. + +Diagnostic `calendar_ece_hours_lower/upper` and `calendar_ece_days_lower/upper` +retain the definite and possible care in incomplete calendars. For partial +calendars, code 0 is unresolved because unreported time can be encoded as assumed +parental care (User Guide HH-334). Wholly missing calendars have uninformative +bounds. These fields do not populate attendance inputs. Regular-instrument +summary hours derive from the same calendar and are not independent evidence +for completing its missing blocks. + +Attendance uses the union of classified ECE blocks. Days count days with any +ECE; hours per day equal weekly ECE hours divided by days. Monthly days use +`floor(days_per_week * 52 / 12 + 0.5)` (five days becomes 22). This represents a +typical week, not an observed month or a provider-specific schedule. + +## Noncalendar reconstruction and joint transfer + +Summer and new-school-year instruments have no calendars. The summer instrument +refers to a typical May week; this is **not measured summer attendance**. The +bridge preserves their published regular weekly hours and borrows days and +irregular hours jointly from ten nearest complete-calendar donors (including all distance ties), using +log regular hours, matching covariates, and survey weights. Regular-care +participation must agree. Zero regular hours does not establish zero irregular +care. Bridged rows are labeled `summary_bridge`, never `complete`. A cell with +fewer than ten donors widens to the next matching level, so a thin cell cannot +keep donors however distant their regular hours; the receipt counts children by +matching level. + +The loader accepts only regions 1-4, parent-work codes -1, 0, 1 and 2, and +non-negative income; any other value, including a negative reserve code, fails +instead of becoming a matching cell. The pinned files hold no other values. +`HH4_PARWORK_STATUS` (User's Guide HH-483) records whether all, some or no +parents of any under-13 household child attended work in the week before the +interview, and its -1 is "No parents". The ASEC side uses the same last-week +concept and the same -1 ("no resident parent of an under-13 child"), so an +employed parent who was absent that week counts as not working in both sources. +`HH4_ECON_INCOME_ANNUAL` (HH-175) is imputed where unreported, top coded, and +has a minimum of 0, so the lowest income band holds reported or imputed zeros. + +Default matching uses age, Census region, parent work, and household income band. +The declared sparse-cell hierarchy drops region, then income, then parent work; +age is always retained. Chosen levels are recorded. Empty support or incompatible +observations fail; there is no invented full-time schedule. + +The imputer draws a complete schedule jointly with child survey weights. +Observed cells, including observed zeros, constrain matching and are preserved. +Stable source person IDs keep clones identical and assignments independent of +row order. The native adapter losslessly encodes integer IDs temporarily. +A fitted mixture of independent child ranks and a shared household rank models +sibling dependence while preserving each child's conditional donor distribution. +It is fitted on youngest sibling pairs in fully observed households using +household weights and evaluated with household-separated folds. +The same rank also couples days and hours. The expanded validation therefore +integrates the actual weighted donor distributions to test joint day/hour +moments, correlations, and every child's contribution to totals in households +with three or more children. Its provisional screens currently fail; matching +the average participation rate does not qualify this household model. + +The September 16 [household-size experiment](../experiments/us-childcare-attendance/README.md) +tested one additional predictor: all rostered under-13 children, capped at three. +The challenger improves larger-family mean days/hours on a separately reserved +internal partition, but still fails 8 of 15 joint-schedule screens and has much +sparser donor support. It remains diagnostic-only; the build still uses the +four matching fields above. Complete-household evaluation also selects children +with lower observed attendance than children whose siblings have unresolved +calendars. That selection is a separate limitation, not evidence that all +population attendance should simply be scaled downward. The survey had already +informed development, so the reserved comparison is not external validation. + +A subsequent diagnostic model partially pools sparse cells and fits measured +sibling participation, days, and hours jointly. Its exploratory population-moment +fit passes 13 of 15 original household screens. The remaining two hours screens +require incompatible joint moments under its predicted marginal distributions; +changing sibling dependence alone cannot fix both. All 18 observed-child checks +are also reported, including three failures for children with unresolved siblings +(hours underpredicted by 40.7%). This remains experimental, has no production +source/target integration, and does not change population attendance values. +See the [plans and full comparison](../experiments/us-childcare-attendance/README.md) +for source-selection limits and reproducible commands. All inspected survey +partitions now count as development evidence. + +Two further diagnostics add roster composition or use `microcosm.fit`'s canonical +weighted QRF with common household predictors. Composition reduces household +screen failures to one but worsens the unresolved-sibling hours error to −42.8%. +QRF closely matches overall means while still underpredicting that subgroup's +hours by 36.9%, so it was not advanced to joint/production integration. Both +remain experimental; neither relaxes the selection or transport assumptions. + +## ASEC target harmonization + +`harmonize_asec_childcare_predictors` resolves `PEPAR1` and `PEPAR2` against +`A_LINENO` within physical households. It counts measured last-week work among +parents of any under-13 household child, matching the NSECE unit. Unrelated +working adults do not become parents. Dangling parent pointers fail. +Missing household source identities, blank IDs, stringified nulls, and unresolved +person-to-household links fail before shared ranks are assigned. Unrelated +households must never acquire one shared `"nan"` identity. + +Regions derive from the shared Census state mapping. Household income is the +sum of raw `PTOTVAL`, expressed in 2023 dollars using annual CPI-U. The pinned +BuildP parent omits raw income for its 2022/2023 source cohorts. The optional +ASEC cache recovers a temporary income array from the existing pinned Census +archives, joining exact 22-digit `PERIDNUM` plus source year and checking raw +age, line number, and any already observed income. Original population columns, +including raw missingness, remain unchanged. No downloader runs inside the stage. + +## Build and reproduction + +Obtain the two ICPSR TSVs under the archive's terms and the pinned ASEC CSVs in +`education_assistance_source.py` (its existing fetch helper verifies them). +Run the complete local candidate and source diagnostics: + +```bash +uv sync --all-packages --locked --extra us +uv run python tools/prepare_us_childcare_attendance.py \ + --household-tsv /local/39466-0005-Data.tsv \ + --calendar-tsv /local/39466-0004-Data.tsv \ + --asec-population-h5 /local/populace_us_2024.h5 \ + --population-sha256 48b9d479fb4fd1c3537f9383ce4697d130b6f618658409d74f6233c43b994c7e \ + --asec-source-cache /local/asec \ + --production-stage --extended-assessment \ + --inherit-outside-domain-baseline \ + --output-checkpoint /local/attendance-checkpoint.h5 \ + --output-native-h5 /local/attendance-candidate.h5 \ + --report /local/preparation.json +``` + +All output paths must be new. The checkpoint retains per-cell provenance, +matching levels, source and parent receipts, weights, strata, and mass history. +Native export adds only the three inputs and a receipt, reloads the result, and +verifies every original entity column, household weight, and time period. +Code hashes and environment versions accompany the aggregate preparation report. + +The receipt binds the source hashes, contract, recipe code, runtime versions, +seed, matching/bridge settings, fitted dependence, and outside-domain policy to +each person's ID, household link, age, and three attendance values. Both native +US loaders and the fiscal builder's `--base-h5` loader restore and check it. The +builder's Social Security and capital-gains repairs preserve that metadata even +when no rescaling is needed, so a prepared candidate can reach the attendance +reuse check without losing its receipt. A +missing or altered receipt fails at load. Recipe code and runtime versions are +compared when a stage binds and when the fiscal build exports, not at read-only +load, so a released file stays readable as a reference after a dependency bump. +Changing seed or settings requires rebuilding from the original parent. An +identical rerun verifies and reuses the existing values. A production-stage +input with existing under-13 attendance and no production receipt is rejected, +including all-zero columns; use the original unmodified parent. The lower-level +observed-cell imputer remains available for separately sourced observations. + +Immediately before target materialization, the builder revalidates attendance +and adds its `binding_sha256` to the target-frame checkpoint identity. This +binds the execution as well as the values covered by main's staged-frame digest. +The reform-vector cache includes the complete materializer identity digest, so +both caches miss when attendance values or their source execution change, even +with the same parent H5, seed and engine version. An unchanged verified execution +can reuse its checkpoint; tampered attendance is refused before cache lookup. + +Calibration weights and row selection/order may change without invalidating +retained people. Changed IDs, membership, ages or attendance require a new source +execution. The final fiscal export checks every row for completeness, bounds, +integral monthly days, coherent zero schedules, and its source binding before +writing. Generic coverage overrides cannot waive this check. The written native +file receives the receipt and is reloaded and checked before source evidence is +reported. The receipt key holds only the attendance context and binding, never +other frame metadata, and adding it does not rewrite any entity table. The L0 +refit export carries the receipt forward, as do +[annual static-aging exports](us-annual-static-aging.md), which retain and check +the original ages and attendance. Private per-person hashes stay in local checkpoints/H5; public reports +contain only aggregate receipt summaries. The private inventory is a sequence +of ID/hash pairs: population-sized dictionaries cause quadratic traversal in +the Frame metadata container, which is intended for small mappings. These hashes detect accidental stale +or modified artifacts; they are not signatures or publication authorization. + +Supply the same source inputs to the normal fiscal build using +`--childcare-attendance-household-tsv`, `--childcare-attendance-calendar-tsv`, +`--childcare-attendance-asec-cache`, and +`--childcare-attendance-inherit-outside-domain-baseline` alongside its usual flags. +Source receipts enter the fiscal source-coverage report. The frozen pool ABI +continues to describe the earlier pool simulation; attendance is supplied by this +subsequent fiscal-build stage and enforced by the final release input contract. +Existing release input +gates still apply; a build without required attendance inputs cannot substitute +an engine default for a persisted input. A fiscal build given neither the TSV +flags nor bound attendance is refused before calibration, and the +exact-k ladder wrapper forwards these inputs from an optional top-level +`childcare_attendance` object in its existing schema-v1 configuration: + +```json +{ + "childcare_attendance": { + "household_tsv": "/local/39466-0005-Data.tsv", + "calendar_tsv": "/local/39466-0004-Data.tsv", + "asec_source_cache": "/local/asec", + "inherit_outside_domain_baseline": true + } +} +``` + +Add this object alongside `pool`, `ladder`, `targets`, `calibration`, and +`release`; it is not a complete launcher configuration. Relative paths resolve +against the config file. Both TSVs and an explicit boolean outside-domain policy +are required when the object is present; the ASEC cache is optional. The launcher +checks the TSVs against the packaged source hashes before invoking the builder, +and the source stage checks them again when loading. The authenticated multispine +pool ingress does not restore an attendance receipt. Supply this object for +that route even if an earlier local file held attendance. Omitting it is only +supported on a receipt-aware ingress that preserves a production-valid binding; +the fiscal builder otherwise refuses before calibration. +This wiring does not qualify a new survey origin or replace the full fiscal +build and population validation. + +Unknown values outside ages 0–12 stay null in the source model. The explicit +outside-domain export policy fills only these missing cells with the pinned +engine's existing baseline and labels them `inherited_engine_baseline_outside_age_0_12`. +This permits an attendance-only candidate without asserting observed +nonattendance for teens or disability-related older-child care. Observed older +values are preserved; unresolved under-13 values always fail export. + +Compare every state model against the exact parent: + +```bash +uv run python tools/validate_us_childcare_population.py \ + --parent-h5 /local/populace_us_2024.h5 \ + --parent-sha256 48b9d479fb4fd1c3537f9383ce4697d130b6f618658409d74f6233c43b994c7e \ + --candidate-checkpoint /local/attendance-checkpoint.h5 \ + --year 2026 --report /local/population-comparison.json +``` + +Both arms use fixed source ages and incomes without aging or uprating. Direct +state subsidy variables avoid conflating attendance with the separate household +aggregation issue [PolicyEngine-US #9405](https://github.com/PolicyEngine/policyengine-us/issues/9405). +Outputs describe potential modeled benefits, not caseload or spending estimates. + +Run the separate noncalendar assumption stress test with the same parent and +source files: + +```bash +uv run python tools/validate_us_childcare_sensitivity.py \ + --parent-h5 /local/populace_us_2024.h5 \ + --parent-sha256 48b9d479fb4fd1c3537f9383ce4697d130b6f618658409d74f6233c43b994c7e \ + --household-tsv /local/39466-0005-Data.tsv \ + --calendar-tsv /local/39466-0004-Data.tsv \ + --asec-source-cache /local/asec --seed 915 \ + --candidate-checkpoint /local/attendance-checkpoint.h5 \ + --year 2026 --report /local/transport-sensitivity.json +``` + +The alternatives remove modeled irregular hours or shift modeled attended days +by one in either direction, subject to hours/day feasibility. Each preserves +measured regular hours. All arms retain the same donor identities and population +weights. Candidate donor labels must match the original donor values; measured +recipient cells and measured-calendar donors remain unchanged. Inconsistent +lineage or observed constraints cause the comparison to fail. Without an explicit +checkpoint, the tool draws the baseline once before applying paired changes. +The older reports re-sorted and transferred modified donors at fixed random ranks; +those reports include donor reassignment as well as schedule changes. Both are +assumption stress tests, not confidence intervals. The +[declared diagnostic screens](../experiments/us-childcare-attendance/review-validation-criteria.txt) +flag national changes above 10% or state changes above 20% against the candidate, +and separately assess sibling schedule distributions. They were written before +the expanded runs, after seeing earlier development diagnostics, and require +review rather than serving as automatic release acceptance. + +## Validation and limits + +See [the aggregate experiment](../experiments/us-childcare-attendance/README.md). +Diagnostics include five-fold household cross-validation, instrument selection, +income/age/work/region comparisons, masked-calendar reconstruction, sibling joint +attendance, full target support, and all-state benefit comparisons. Development +used these diagnostics; they are not an untouched external acceptance sample. + +`tools/validate_us_childcare_intervals.py` evaluates a separate training-only +experiment. It conditions a QRF/empirical schedule distribution on incomplete +calendars' bounds, divides each child's design weight over eight modeled rows, +and refits once. Whole evaluation households are excluded from initial fitting, +completion and refitting. Unsupported intervals stay unknown. Modeled rows carry +`interval_model` status and require explicit experimental opt-in; they are never +scored as observations. Lower- and higher-hours tilts expose sensitivity to the +unidentified coarsening assumption. All arms retain the original subgroup screens +and fail three of 18; this experiment does not alter the production matcher. + +Calendar selection remains unidentifiable for excluded ambiguous/partial cases. +Conditional matching assumes their schedules resemble supported children with +similar covariates. Bridged schedules are modeled, despite observed regular hours. +Source weights and good predictive means do not establish national validity. +Provider-specific schedules, true summer care, and older-child attendance need +additional evidence. Attendance alone cannot fix other missing CCDF inputs. +The reports retain `production_ready: false` to distinguish this candidate from +a calibrated, independently reviewed and published population release. + +CI uses synthetic records only. Tests cover survey parsing, unknown/zero +separation, weighted joint draws, observed-cell and clone preservation, parent +links, verified income joins, noncalendar reconstruction, sibling ranks, build +orchestration, and native engine export. New runtime modules are classified in +the existing inventory and remain subject to the full source-spine AST guard. diff --git a/experiments/us-childcare-attendance/README.md b/experiments/us-childcare-attendance/README.md new file mode 100644 index 000000000..2a729147b --- /dev/null +++ b/experiments/us-childcare-attendance/README.md @@ -0,0 +1,834 @@ +# NSECE attendance: review hardening and rebuilt candidate — 2026-09-17 + +**September 27 status:** see the [current review audit](merge-readiness.md). +The branch now includes main's test-layout and builder changes and binds target +checkpoints/reform caches to the verified attendance execution (review A4). +The source recipe and population estimates below are unchanged. Maria's C2 +(raw build/certification) and A3 (household-model validation) remain open. + +**PR #916 remains draft.** A second code review found that the fiscal builder +could not finish a build with attendance, and that the native receipt path could +damage or over-share the release file. Those defects are fixed, the noncalendar +bridge now widens thin matching cells, and the candidate was rebuilt from the +pinned parent under **PolicyEngine-US 2.2.1 / Core 3.32.5**. No experimental +model is adopted, no population is published, and every report retains +`production_ready: false`. + +## What changed + +- **Receipt reaches the export.** The builder's ACA source-output step rebuilt + the frame without its metadata, so the final attendance check could never + pass. It now keeps the metadata. +- **Receipt write and content.** The release file gets only a receipt key; the + person table is no longer rewritten. The key holds only the attendance context + and binding, never other frame metadata, and only those keys are restored. +- **Recipe identity.** Code hashes and runtime versions are compared when a + stage binds and when the fiscal build exports. Read-only loads check content + only, so a released file stays readable as a reference after a dependency bump. +- **Other ingress and egress.** The builder's `--base-h5` loader restores and + checks the receipt, and the L0 refit export carries it forward. +- **Fail early.** A build with neither the NSECE files nor bound attendance is + refused before calibration. An unbound-attendance failure stays in the batched + gate report, so such a run keeps its weight evidence. The `require_observed` + outside-domain policy fails before the bridge and names the flag that fixes it. +- **Source codes.** The loader rejects any region outside 1–4, any parent-work + code outside −1, 0, 1, 2, and negative income. The pinned files hold no other + values. The User's Guide (HH-483) defines −1 as "No parents" and the measure as + work attended in the week before the interview, the same concept as the ASEC + side; income (HH-175) has a minimum of 0. +- **Fiscal integration follow-up.** The exact-k wrapper accepts a + `childcare_attendance` configuration object, validates its TSVs against the + packaged source pins, and forwards the source paths and outside-domain policy. + The early Social Security and capital-gains repairs now preserve frame + metadata, allowing a receipted `--base-h5` to reach the reuse check. Synthetic + coverage exercises native ingress, both changed and unchanged repairs, receipt + reuse, engine export and native reload. These changes do not alter the source + recipe or the candidate and report hashes below. + +## Bridge widening + +A matching cell with fewer than ten donors kept every donor, however distant its +regular hours, so the nearest-hours step did nothing in thin cells. Such a cell +now widens to the next matching level. Of the 3,046 bridged source children, +1,382 stay at the finest level, 1,287 drop region, 331 also drop income, and 46 +match on age alone. + +[Five whole-household masked-calendar splits](bridge-widening-masked-splits.json) +compare the two implementations child by child +([script](bridge_widening_masked_splits.py)). Regular weekly hours stay observed, +as in the bridge itself. + +| Mean over five splits | Previous | Widened | +| --- | ---: | ---: | +| Mean days error | +0.077 | +0.076 | +| Mean weekly-hours error | +0.281 | +0.258 | +| Mean absolute days error | 0.922 | 0.831 | +| Mean absolute days error, regular-care children | 1.476 | 1.215 | +| Mean absolute weekly-hours error | 3.082 | 3.064 | +| Mean absolute hours-per-day error, regular-care children | 2.872 | 2.274 | +| Share above 12 hours per day (measured 4.2%) | 7.3% | 5.7% | + +On the single split that the source-stage report uses, the overall mean +weekly-hours error rises from +0.06 to +0.79 hours, and the age-5 group mean +from 17.5 to 25.0 hours against 15.8 measured. One child with a large weight +draws a donor with 158 weekly irregular hours. Per-child days and hours-per-day +errors still fall on that split. These splits were inspected after the change +was made and are development evidence, not untouched validation. They test +reconstruction where calendars exist, not the unobserved days or irregular care +of the summer and fall instruments. + +## Rebuilt candidate + +The candidate again contains **166,321 people, 57,240 households and 31,889 +children ages 0–12**, with every under-13 attendance input resolved. Both native +loaders verify the new receipt; every original value and weight is preserved, +and attendance survives the native reload exactly. + +| Under-13 population, weighted | 2026-09-16 | 2026-09-17 | +| --- | ---: | ---: | +| Attendance share | 48.47% | 48.48% | +| Days per week | 1.959 | 1.957 | +| Hours per week | 14.08 | 14.10 | +| Annual potential modeled benefits | $5.998 billion | $6.206 billion | + +The attendance-only counterfactual still reduces all-zero results from **31 to 2 +jurisdictions (MD and NV)**, and the baseline remains $2.254 billion. Benefits +use 2026 policies on the parent's fixed ages and incomes, without aging or +uprating; they are not calibrated spending or caseload estimates, and positive +benefits do not validate attendance. Target-side matching levels are unchanged +(31,152 / 576 / 161); only the bridged donors' schedules moved. + +| Paired assumption change | Children with changed attendance | Annual potential benefits | Change from candidate | +| --- | ---: | ---: | ---: | +| No modeled irregular hours | 1,429 | $5.985 billion | −3.56% | +| One fewer modeled day | 3,815 | $6.203 billion | −0.04% | +| One more modeled day | 4,404 | $6.235 billion | +0.48% | + +All three national changes stay below the unchanged provisional 10% screen. Five +state comparisons exceed the unchanged 20% screen. Removing irregular care +changes **SD by −49.7% (−$2.9 million)**, **TN by −36.0% (−$43.3 million)** and +**WV by −31.1% (−$4.2 million)**. One more day changes **WV by +38.9% +(+$5.3 million)**, and one fewer day changes OK by −40.0% (−$2.06). IL, flagged +at −29.4% on September 16, is now −1.0%: its flag depended on which bridge donors +a few heavily weighted children drew. TN is unchanged to the dollar. State +results remain sensitive to single donor draws and to the unmeasured +irregular-care assumption. + +- [Source-stage report](review-fixes-source-stage.json) +- [Population and all-state comparison](review-fixes-population.json) +- [Native-loader verification](review-fixes-verification.json) +- [Paired noncalendar sensitivity](review-fixes-sensitivity.json) + +The four reports' code hashes match the checked-in files. The September 16 +reports below are historical: their receipts bind the previous recipe. The +calendar-selection, QRF, interval, pooling and household-size experiments reject +bridged rows and use measured calendars only, so the bridge change cannot move +their results; they were not rerun and their recorded code hashes predate this +update. + +## Code checks for this update + +Repository-wide ruff lint, changed-file formatting and the tracked CI test +inventory pass. The fiscal integration follow-up passes 37 targeted local tests, +including launcher argument forwarding and source-pin refusal, native ingress, +both changed and unchanged value repairs, attendance reuse, and native export +and reload. The earlier four CI failures were fixed in `6863cefa`. + +The population rebuild used the production stage, native export, both native +loaders and the three validation tools end to end on the licensed local inputs. +The fiscal builder itself has still not been run end to end with attendance; +the synthetic integration checks do not establish production readiness. + +## Interval training and paired sensitivity — 2026-09-16 + +This section and those below are historical. + +**PR #916 remains draft.** The population has now been rebuilt from the pinned +parent under **PolicyEngine-US 2.2.1 / Core 3.32.5**. The latest experiment uses +incomplete calendars' measured bounds in training, but still fails the three +unresolved-sibling checks. The new sensitivity comparison holds donor identities +fixed and flags three state comparisons, including one with a $2 effect. No +experimental model replaces the production-stage matcher, no population is +published, and all reports retain `production_ready: false`. + +## Calendar information that can actually be recovered + +The adapter now preserves definite/possible ECE hours and days separately from +completed attendance. The NSECE Household User Guide (HH-334) says unreported +time can be encoded as assumed parental care and derived summaries are not +adjusted for missing-calendar status. Partial-calendar zeros therefore cannot +be treated as observed nonattendance. Summary hours from the regular instrument +derive from the same calendar and cannot independently recover its missing time. +Summer/fall regular hours remain a separate measurement, as before. + +The new fields are diagnostics, not imputed attendance inputs. Unknown schedules +stay unknown. Bounds use known ECE blocks as the lower endpoint and all unresolved +blocks as possible ECE at the upper endpoint. A wholly missing calendar has the +uninformative interval 0–168 hours and 0–7 days. Complete calendars have equal +endpoints. These are identification ranges conditional on the published calendar +classifications, not confidence intervals, plausible point estimates, or benefit +bounds. + +| Regular-questionnaire group | Children | Weighted mean weekly-hours interval | +| --- | ---: | ---: | +| Complete calendars | 7,460 | 14.24–14.24 | +| Ambiguous classifications | 882 | 9.86–32.60 | +| Partial calendars | 174 | 13.19–149.35 | +| All regular-questionnaire children | 8,516 | 13.75–19.28 | + +These broad ranges explain why simply filling the excluded calendars is not a +measured solution. Only 11.4% of the ambiguous-calendar design weight has an +hours interval no wider than one hour. The 149-hour partial-calendar upper bound +means the questionnaire supplies little information; it is not a proposed +attendance schedule. See the [bounds and composition report](calendar-selection-validation.json) +and [plan recorded before that comparison](calendar-selection-plan.txt). + +## Additional model comparisons + +The composition model adds the full roster's under-6 and school-age counts, +youngest age band, and presence of a younger sibling to the pooled matcher. +Missing calendars still count toward these features. The separately declared +QRF experiment uses `microcosm.fit`'s canonical weighted-bootstrap conditional +model, adding measured household income, resident count, and resident-parent +count. An ordinal schedule code is decoded to an observed joint day/hour pair +at the child's exact age. No source response indicator, care outcome, or +incompatible annual/weekly care-expense measure is used as a predictor. + +Every model excludes the evaluation household from training. All 7,460 measured +children are evaluated in the same five folds, including 761 children whose +siblings have unresolved calendars. The QRF uses a fixed 128-point integration +grid; its failed marginal screen did not justify proceeding to dependence fitting +or production integration. All these survey partitions are development data. + +| Model | Failed household screens / 15 | Failed child screens / 18 | Hours error for observed children with unresolved siblings | +| --- | ---: | ---: | ---: | +| Previous pooled population-moment model | 2 | 3 | −40.7% | +| Composition-aware pooled model | 1 | 3 | −42.8% | +| Canonical QRF marginal diagnostic | Not evaluated | 3 | −36.9% | + +The composition model improves the joint-screen count but worsens the important +subgroup. QRF reproduces overall mean weekly hours (14.285 predicted versus +14.240 observed), yet predicts only 15.047 versus 23.830 for the unresolved-sibling +group. Its conditional-mean hours MSE is 495.370 versus 482.798 for the previous +pooled model; subgroup MSE also worsens. Better overall means are insufficient +to adopt either model. These subgroup discrepancies indicate a selection concern; +they do not identify the missing children's outcomes or prove a causal +missingness effect. + +- [QRF plan recorded before its results](qrf-calendar-plan.txt) +- [QRF model, fold counts and marginal diagnostics](qrf-calendar-validation.json) + +## Using partial-calendar information in QRF training + +The next declared experiment conditions the complete-calendar QRF distribution +on each incomplete training child's measured day/hour bounds. Before conditioning, +it mixes 90% QRF and 10% design-weighted exact-age empirical schedules so finite +prediction grids do not remove all observed tail support. Each supported child +contributes eight deterministic midpoint-quantile schedules at one eighth of its +design weight. These rows are labeled `interval_model`, never `complete`. +Unsupported intervals remain unknown; schedules are not clipped into bounds. +The canonical QRF is refitted once, using only training households. + +This assumes a conditional coarsening mechanism that the survey does not +identify. Two declared alternatives tilt the conditional schedule probabilities +by `exp(-weekly_hours / 40)` and `exp(weekly_hours / 40)`. The scale, mixture and +number of draws were fixed before this run. These alternatives expose sensitivity +to assumptions; they are not confidence limits or multiple-imputation uncertainty +estimates. No held-out household's attendance or bounds enter completion or fitting. + +| Model | Overall weekly-hours mean | Overall conditional-mean hours MSE | Unresolved-sibling weekly-hours mean | Subgroup hours error | Failed child screens / 18 | +| --- | ---: | ---: | ---: | ---: | ---: | +| Measured calendars | 14.240 | — | 23.830 | — | — | +| Complete-only QRF | 14.285 | 495.370 | 15.047 | −36.9% | 3 | +| Interval-informed QRF | 14.319 | 491.239 | 14.848 | −37.7% | 3 | +| Lower-hours tilt | 14.048 | 500.343 | 14.464 | −39.3% | 3 | +| Higher-hours tilt | 14.806 | 498.869 | 15.263 | −36.0% | 3 | + +All arms use the same five household folds and 7,460 observed children. The +complete-only arm reproduces every earlier QRF comparison exactly. Across folds, +793–838 incomplete training children have supported schedules; 27–31 do not. +Supported children account for 94.9–96.2% of incomplete-calendar design weight. +Total weight is conserved and all measured rows remain unchanged. + +The central model reduces overall hours MSE by 0.8% and subgroup hours MSE by +3.0%. Subgroup participation error falls from 18.3 to 16.8 percentage points and +days error from 30.0% to 28.2%, but mean-hours bias worsens. Every arm still fails +all three unresolved-sibling checks, so none is adopted. A favorable aggregate +or a selected tilt would not justify production integration. The remaining +discrepancy cannot be removed by treating modeled completions as observations. + +- [Plan recorded before the interval and paired comparisons](interval-and-paired-plan.txt) +- [All model arms, completion support and unchanged screens](interval-training-validation.json) + +## Population rebuilt under PolicyEngine-US 2.2.1 + +The current candidate contains **166,321 people, 57,240 households and 31,889 +children ages 0–12**, with every under-13 attendance input resolved. It uses the +existing default attendance recipe; none of the experimental models above is +used. The current source adapter's bounds do not change the donor attendance. + +The attendance-only counterfactual now reduces all-zero results from **31 to 2 +jurisdictions (MD and NV)**. Annual potential modeled benefits rise from +**$2.254 billion to $5.998 billion**. These use 2026 policies on the parent's +fixed ages/incomes, without aging or uprating; they are not calibrated spending +or caseload estimates. Positive benefits alone do not validate attendance. + +- [Current source-stage report](calendar-review-2.2.1-source-stage.json) +- [Current population and all-state comparison](calendar-review-2.2.1-population.json) +- [Current native-loader verification](calendar-review-2.2.1-verification.json) +- [Current paired noncalendar sensitivity](paired-identity-sensitivity.json) + +Both native loaders verify the saved attendance binding against the current +recipe and runtime. Verification compares every attendance value, every original +population column and all weights with the checkpoint/parent. Only the pandas +string-storage backend is normalized for the comparison; values, missingness and +other dtypes must match exactly. The source-stage exporter also verifies period +preservation. No stale-receipt override is used. + +The paired noncalendar stress test changes only the modeled bridge components of +each child's already selected donor. It verifies those donor labels against the +candidate's attendance values, preserves measured recipient constraints, and +rejects inconsistent or mixed lineage. This isolates schedule assumptions from +changes in donor identity. Measured-calendar assignments do not change in any +arm. All 31,889 under-13 children have donor assignments, including 9,675 assigned +bridge donors. The baseline and candidate results match the population report +exactly in all 51 jurisdictions, with the same checkpoint hash and current recipe. + +| Noncalendar assumption | Children whose attendance changes | Annual potential benefits | Change from candidate | +| --- | ---: | ---: | ---: | +| No modeled irregular hours | 1,289 | $5.754 billion | −4.07% | +| One fewer modeled day | 3,725 | $5.997 billion | −0.02% | +| One more modeled day | 4,271 | $6.019 billion | +0.35% | + +All three national changes remain below the unchanged provisional 10% screen. +Three state comparisons exceed the unchanged 20% screen: removing irregular +care changes IL by **−29.4% (−$57.9 million)** and TN by **−36.0% (−$43.3 million)**; +one fewer day changes OK by **−40.0% (−$2.06)**. The OK denominator is only about +$5, so the relative flag has little monetary significance. IL and TN remain +materially sensitive to the unmeasured irregular-care assumption. + +The [previous quantile-coupled report](calendar-review-2.2.1-sensitivity.json) +remains historical evidence. It re-sorted donors after changing their schedules, +so holding random ranks fixed could select different donors. That experiment +flagged six state comparisons; the paired experiment flags three, adding IL and +removing the IA/KS/MS/AR day flags. These are different conditional comparisons, +not a corrected confidence interval or proof that reassignment uncertainty is +absent. Days and daily-hour rates interact, so benefit changes need not follow +the direction of the day change. Neither experiment identifies missing schedules. + +## Reproduction and remaining decision + +Run the source experiments on the two licensed files with fresh report paths: + +```bash +uv run python tools/validate_us_childcare_calendar_selection.py \ + --household-tsv /local/39466-0005-Data.tsv \ + --calendar-tsv /local/39466-0004-Data.tsv \ + --report /local/calendar-selection.json +uv run python tools/validate_us_childcare_qrf.py \ + --household-tsv /local/39466-0005-Data.tsv \ + --calendar-tsv /local/39466-0004-Data.tsv \ + --report /local/qrf-calendar.json +uv run python tools/validate_us_childcare_intervals.py \ + --household-tsv /local/39466-0005-Data.tsv \ + --calendar-tsv /local/39466-0004-Data.tsv \ + --report /local/interval-training.json +``` + +Rebuild with `tools/prepare_us_childcare_attendance.py --production-stage +--extended-assessment --inherit-outside-domain-baseline`, the original pinned +parent, both source files and the pinned ASEC cache. Then run +`tools/validate_us_childcare_population.py`, +`tools/validate_us_childcare_sensitivity.py`, and +`tools/verify_us_childcare_candidate.py` on those explicit local artifacts. +Each tool's `--help` lists the required file/hash arguments; no report is +overwritten. Supply `--candidate-checkpoint` to the sensitivity tool to reuse the +verified candidate's assignments; otherwise it draws a baseline once and holds +those assignments fixed. Only aggregate reports are committed. + +**Decision:** retain the draft and fail-closed release checks. The current-runtime +rebuild closes the stale-runtime evidence gap. Calendar nonresponse and transport +of unmeasured days/irregular care remain substantive model limitations. A defensible +next model needs independent measured attendance information or a declared +missingness model evaluated across plausible assumptions, followed by fresh +validation. Reusing calendar-derived summaries as truth, conditioning target +predictions on a source-only response flag, or tuning against these already +inspected screens would not resolve those limitations. Provider/activity inputs +and care outside ages 0–12 remain separate gaps. + +## Code validation for this update + +All **613 distinct local regression checks** for this update pass: 612 source, +QRF, pooling and full source-spine architecture tests, followed by the additional +donor-order reversal regression. Tests cover interval bounds, conserved weights, +training-household exclusions, explicit modeled-row opt-in, and preservation of +measured donors and recipient constraints under paired scenarios. The preceding +calendar/runtime update passed 1,048 checks; it is historical validation for that +update. The complete-only real-source arm reproduces the earlier QRF metrics +exactly, and both new reports' code hashes match the checked-in code. + +Repository-wide ruff lint, changed-file formatting, tracked CI inventory and +built-wheel source-byte checks pass. A repository-wide formatting check reports +77 pre-existing files; none is part of this update, and they were not reformatted. +The new flat `test_us_childcare_qrf.py` enters the US CI inventory; CI uses +synthetic records only. Native artifact verification runs separately on the +licensed local inputs. GitHub CI has not been monitored. + +## Earlier pooled-model investigation — 2026-09-16 + +**PR #916 remains draft.** A partially pooled donor model improves conditional +child predictions and larger-family means. An exploratory population-moment +dependence fit passes 13 of the original 15 household screens, but still fails +two hours checks and all three checks for observed children with unresolved +siblings. Neither experimental model has replaced the production-stage recipe. + +**Historical runtime note:** the earlier population artifacts, native-loader +receipts and benefit estimates below used PolicyEngine-US 1.819.0 and Core +3.31.0. The current-runtime rebuild above supersedes their population evidence. +The merge itself did not bypass the requirement to rebuild from the original +parent when the receipt's runtime changed. +The complete three-model survey comparison was rerun with 2.2.1: every model +result and diagnostic code hash matches the pre-upgrade run exactly. The linked +pooled report records the new runtime; this survey replay is separate from +population and benefit validation. + +- [Initial pooling and evaluation plan](pooled-matching-plan.txt) +- [Subsequent exploratory dependence-objective plan](pooled-moments-plan.txt) +- [All three models, full diagnostics and structural check](pooled-matching-validation.json) + +## What was tested + +The new donor model blends each sparse cell with broader empirical distributions +at the same exact age. It adds household size, work, income, and region in that +order. A cell's contribution is `effective_households / (effective_households + 10)`; +the strength ten was fixed before inspecting results. Survey-weight concentration +is measured at the donor-household level. Joint day/hour schedules, including +measured nonattendance, remain intact. + +The sibling fit uses every available observed pair, including families with +unresolved other siblings. Household weight is divided among the household's +observed pairs. Every fitting pair's entire household is excluded from its donor +distributions. The initial fit minimizes individual pair cross-product errors +for participation, days and hours. It improved mean errors but worsened several +correlations. A separately recorded exploratory alternative fits the three +weighted population cross-product moments instead. It retains one shared-rank +coefficient and the same fixed donor distributions; no per-outcome coefficients +or revised thresholds are selected from the evaluation results. + +Every component is refitted inside five household-separated folds. All 7,460 +measured child calendars are scored, alongside 4,450 observed pairs from 2,106 +households and the original complete-household diagnostics. Previously inspected +households, including the earlier reserved partition, are explicitly treated as +development data. This is not independent validation or evidence of release readiness. + +| Quantity | Existing model | Pooled, individual-pair fit | Pooled, population-moment fit | +| --- | ---: | ---: | ---: | +| Failed original household screens / 15 | 9 | 4 | 2 | +| Failed observed-child screens / 18 | 3 | 3 | 3 | +| 3+ household mean-days error | +25.35% | +12.01% | +12.01% | +| 3+ household mean-hours error | +23.36% | +15.91% | +15.91% | +| Conditional mean days prediction MSE | 5.761 | 4.634 | 4.634 | +| Conditional mean weekly-hours prediction MSE | 575.310 | 482.798 | 482.798 | + +Conditional-mean prediction errors improve approximately 20% for days and 16% +for hours. This is not a claim that random donor draws are more accurate: the +expected squared error of a single hours draw rises from 891.140 to 905.994. +The report contains both quantities. Marginals are identical across the pooled +fit objectives because the dependence coefficient changes only joint behavior. + +## What remains unresolved + +For the youngest pair in 3+ complete households, the population-moment model's +weekly-hours correlation is 0.456 versus 0.562 observed (gap 0.106; limit 0.10). +Its hours cross-product is 437.072 versus 337.347 (+29.6%; limit 20%). A change +to sibling dependence alone cannot satisfy both with these predicted marginals: + +| Existing screen | Required hours cross-product interval | +| --- | ---: | +| Correlation within 0.10 of observed | 440.651–553.157 | +| Cross-product within 20% of observed | 269.878–404.816 | + +The intervals do not overlap. Correlation equals `(E[XY] - E[X]E[Y]) / (SD[X]SD[Y])`. +Independent and coupled arms have the same marginal means and variances, so the +report can recover this relationship and test compatibility without choosing +another coefficient. This rules out a dependence-only fix **for these evaluated +marginals**; it does not rule out better marginal models or establish that the +selected complete families represent the whole population. + +The 761 observed children whose siblings have unresolved calendars remain a +material selection concern. Observed versus pooled predictions are 66.0% versus +46.7% participation, 2.819 versus 1.915 days/week, and 23.830 versus 14.135 hours/week. +Hours are underpredicted by 40.7%. Both pooled objectives share these failures; +better complete-family results do not waive them. Missing children are never +scored as zero, and these observed-subgroup differences do not identify their +unobserved schedules or a causal missingness effect. + +**Decision:** keep pooling experimental. The next substantive change must improve +the conditional marginal model and address calendar nonresponse using measured +information or explicit, tested assumptions. Further rho tuning, resplitting this +same survey, or lowering predictions to complete-household means would not close +the evidence gap. A population trial would also require consistent source bridge +and target integration, followed by new benefit/transport sensitivity evidence. + +Reproduce the complete comparison with new local output paths: + +```bash +uv run python tools/validate_us_childcare_pooling.py \ + --household-tsv /local/39466-0005-Data.tsv \ + --calendar-tsv /local/39466-0004-Data.tsv \ + --compare-moment-fit --report /local/pooled-comparison.json +``` + +Synthetic tests cover exact-age support, household-cluster pooling, survey-weight +and row-order invariance, whole-household exclusions at both fit and evaluation +boundaries, inclusion of partially observed families, joint schedule preservation, +structural screen compatibility, and JSON-safe undefined metrics. Tests reside +directly in the build shard's tracked CI inventory; CI does not access survey data. +Attendance recipe code is unchanged by this experiment. Before the main merge, +its full recipe identity matched the last verified population artifact. The +engine upgrade changes that runtime-bound identity; no population rebuild or +new state benefit estimate is claimed here. + +The 616-test attendance/source/architecture regression run passed. After making +undefined relative-error flags JSON-safe, all 96 focused source/pooling tests +passed again. Lint, formatting, tracked CI inventory and build-wheel source-byte +checks passed. The final real-source run reproduces both initial model arms +exactly and records the current diagnostic code hashes; only aggregate evidence +is committed. GitHub CI is separate and has not been monitored. + +After the main merge, 1,142 attendance/source, architecture, fiscal-builder, +coverage, serializer and native-adapter tests passed under the updated lock. +A separate 249-test pool-tool/specification run also passed. The merged coverage +report and spec digest were regenerated; lint, formatting, tracked CI inventory +and current-wheel source/engine-lock byte checks passed. The complete survey +replay above reproduces every model result exactly under PolicyEngine-US 2.2.1. + +## Previous hard household-size investigation — 2026-09-16 + +**PR #916 remains draft.** Adding household size improves larger-family means, +but the proposed matcher still fails joint-schedule validation. It is retained +as an experiment and **has not replaced the production-stage matching recipe**. + +- [Comparison plan recorded before the new results](household-size-plan.txt) +- [Development comparison and calendar-selection diagnostics](household-size-development.json) +- [Reserved-household comparison](household-size-reserved-validation.json) +- [Pre-upgrade artifact verification](household-review-artifact-verification.json) + +The challenger adds the number of rostered children ages 0–12, capped at three, +to the existing age/region/work/income matching. Missing calendars still count +toward household size. Its fallback retains size until the final age-only level. +Both donor selection and the sibling-dependence fit use the revised predictors. +The shared-rank mixture cannot change each child's conditional mean: adjusting +its dependence coefficient alone cannot correct a mean attendance discrepancy. + +Before fitting the challenger, a deterministic 20% household partition was +reserved. Every development donor pool and dependence fit excludes it. Five-fold +development used the remaining households; the fixed challenger was then scored +once on the reserved households. All metrics integrate weighted donor CDFs +exactly. Earlier diagnostics had already used this survey, so this is an +internal comparison, **not untouched external validation**. No model was retuned +after viewing the reserved results. + +| Reserved comparison, 128 complete households with 3+ children | Observed | Existing matcher | Size-conditioned challenger | +| --- | ---: | ---: | ---: | +| Mean total days/week | 4.332 | 5.892 (+36.0%) | 4.964 (+14.6%) | +| Mean total hours/week | 32.575 | 40.793 (+25.2%) | 33.430 (+2.6%) | +| SD of total hours/week | 54.828 | 49.677 | 43.246 (−21.1%) | + +The reserved comparison includes 376 complete sibling households overall. +The existing matcher fails 10 of 15 provisional screens; the challenger fails +8 of 15. Better larger-family means do not establish a realistic joint +distribution. For example, the youngest-pair weekly-hours cross-product error +in 3+ households increases from 18.8% to 36.6%. The challenger's dependence +coefficient reaches its upper bound of one in every development fit and the +reserved fit, yet several joint-participation/intensity checks still fail. +On the development folds, the larger-family hours mean is still 21.2% high. + +Two limitations prevent treating the mean improvement as a resolved model: + +1. **Sparse conditioning:** in the development pool, the median exact cell + falls from 12 donor households to 5. The share of observed children in cells + with fewer than ten donor households rises from 37.2% to 87.9%. These counts + precede fold exclusions, which can further reduce support; ten is a + descriptive cutoff, not a tuned matching rule. +2. **Selected validation households:** totals can be scored only when every + under-13 calendar is complete. In development households with 3+ children, + observed children in fully complete households average 9.86 hours/week; + observed children with unresolved siblings average 26.22. All observed + children in that size group average 12.62. These child-weighted means show + selection differences, not the missing children's outcomes or a causal + missingness effect. Forcing predictions down to the complete-household + average would not establish unbiased population attendance. + +**Decision:** do not adopt hard household-size strata on these results. The +next model design needs to control sparse-cell instability and assess calendar +selection explicitly, scoring all observed child marginals by household size +alongside complete-household joint moments. A partial-pooling or household-level +model requires a new evaluation plan; another split of this same inspected +survey would still not be external acceptance evidence. Noncalendar transport +sensitivity and older-child/provider gaps remain unresolved. + +Reproduce either partition, using a new report path for each run: + +```bash +uv run python tools/validate_us_childcare_household_size.py \ + --household-tsv /local/39466-0005-Data.tsv \ + --calendar-tsv /local/39466-0004-Data.tsv \ + --partition development --report /local/household-development.json +# Repeat with --partition validation and a separate report path only after +# freezing the challenger; do not use those outcomes for further tuning. +``` + +The tool verifies the original source hashes and reports the plan, diagnostic +code, and recipe hashes. It writes aggregates only. Regression tests cover +reserved-household exclusion from every fit and donor pool, poisoning reserved +outcomes without changing development results, actual donor conditioning, +counting unresolved siblings, and rejecting reconstructed calendars as truth. + +The 593-test source/attendance/architecture regression run passed, as did lint, +formatting, the tracked CI test inventory, and exact source-byte checks for both +updated modules in the built wheel. The current recipe was rebuilt from the +original parent because the fitter's code hash changed. Both native loaders +validate its receipt; all 166,321 people's attendance values and IDs and all +57,240 household weights equal the previous candidate exactly. The default +dependence fit and sensitivity evaluator are unchanged, so the historical +benefit and sensitivity estimates still apply. These checks do not certify +the statistical model or authorize population publication. + +## Review revision — 2026-09-15 + +**PR #916 remains draft.** The engineering safeguards have been strengthened, +but the expanded household diagnostics fail provisional statistical screens. +The earlier aggregate means did not establish population validity. Nothing in +these reports authorizes publication or changes PolicyEngine-US defaults. + +- [Criteria declared before the expanded runs](review-validation-criteria.txt) +- [Revised source/stage and household diagnostics](review-source-stage-validation.json) +- [All-state noncalendar sensitivity results](review-transport-sensitivity.json) +- [Final artifact verification](review-artifact-verification.json) +- [Reproduction commands and receipt contract](../../docs/us-childcare-attendance.md) + +The criteria are developmental screens informed by earlier diagnostics, not an +untouched external evaluation or a maintainer-approved release standard. + +## Response to review + +- **C1:** bind attendance to source/recipe/runtime/settings and person-level + content; restore and verify the binding in both native loaders. Reject stale, + missing or changed receipts. An identical rerun validates existing values; + changed source/seed/policy requires rebuilding from the original parent. +- **A1:** recheck every row's completeness and valid schedule at final fiscal + export, independently of optional source flags or generic coverage overrides. + Persist and verify the receipt after native serialization. +- **A2:** reject missing/blank household identities and unresolved household + links before converting IDs to strings or assigning shared ranks. +- **A3:** evaluate the actual shared-rank schedule mixture, including days/hours + cross-moments and correlations and all-child totals for larger households. + The expanded evidence exposes a remaining model limitation; it does not close + this statistical concern. +- **S1:** declare screens and measure benefit sensitivity while preserving every + measured regular-hour value. The state-level sensitivity remains unresolved; + missing days and irregular care are not identified by this experiment. +- **S2:** record the actual calendar, sibling fit, bridge, predictor + harmonization, transfer and outside-domain operations in execution order. + +## Expanded household results + +Five household-separated folds contain 1,941 complete sibling households, +including 661 with three or more children. Predictions integrate the empirical +weighted donor CDFs exactly; no favorable simulation seed is selected. + +| Quantity | Observed | Shared-rank model | +| --- | ---: | ---: | +| Youngest-pair days correlation | 0.580 | 0.442 | +| Youngest-pair weekly-hours correlation | 0.523 | 0.356 | +| Mean total days/week, households with 3+ children | 4.510 | 5.653 | +| Mean total hours/week, households with 3+ children | 33.085 | 40.814 | + +Nine of fifteen provisional screens fail. Larger-household mean total days are +25.35% too high and hours 23.36% too high. A fitted binary-participation mixture +is not enough to establish realistic household schedules. Household-size +conditioning was investigated using the separately reserved internal comparison above. +The tested hard household-size conditioning was not adopted; retuning on these +folds would not create independent validation. + +## Noncalendar assumption sensitivity + +All 51 jurisdictions use the same parent, source, matching fields, survey +weights, seed and policy year. Each alternative modifies only modeled bridge +components and retransfers the resulting joint schedules; measured regular +hours are unchanged. Source-selection, missing partial calendars and true summer +attendance are separate uncertainties this stress test does not resolve. + +| Scenario | National annual potential benefits | Change from candidate | +| --- | ---: | ---: | +| Current candidate | $5.286 billion | — | +| No modeled irregular hours | $5.209 billion | −1.46% | +| One fewer modeled day | $5.222 billion | −1.22% | +| One more modeled day | $5.298 billion | +0.22% | + +State flags above 20% include TN (−36.0%, no irregular hours), IA (+60.0%), +KS (−49.4%) and MS (−69.6%) with one fewer day, and AR (+43.9%) with one +more day. OK also flags at −40.0%, but that is only a $2.06 change from an +approximately $5.15 baseline and must not be read as a material spending result. +Day changes also change daily hours and can cross state policy thresholds; +these are joint-schedule assumption tests, not monotonic attendance effects. +These estimates are potential modeled benefits, not calibrated CCDF expenditure, +caseload estimates or confidence intervals. + +## Revision code checks + +The 750-test regression run passed, covering the complete source-spine +architecture guard, pool-tool regressions, NSECE source/receipt behavior, and +the unconditional fiscal export guard. The preceding focused attendance and +release-coverage run passed 165 tests; native H5, serializer and fiscal-builder +checks also passed before the architecture fixes were verified in the final run. +After replacing the large receipt dictionary with a sequence, all 67 focused +source/receipt and architecture tests passed again. This avoids quadratic +traversal in immutable Frame metadata without changing attendance values. +Repository lint, format checks, the tracked CI inventory and the exact +42,159-field/41-inventory coverage audit passed. The build wheel was rebuilt; +its three new modules match the source bytes and import from the unpacked wheel. +These code checks do not certify restricted data or resolve the statistical gaps. + +## Historical evidence + +The September 12–13 reports below describe the previous execution and remain +available for audit. Their artifact receipts predate the content-binding +contract; rebuild them from the original parent before using the revised release +path. The attendance point estimates are unchanged by the engineering revision. + +## Original population candidate — 2026-09-12 + +Related: [#915](https://github.com/PolicyEngine/microcosm/issues/915) and +[PR #916](https://github.com/PolicyEngine/microcosm/pull/916). + +The real survey adapter, ASEC harmonization, fiscal-builder attendance stage, +and native population export are implemented. The final aggregate reports below +record the source/model diagnostics and the attendance-only state comparison. +This is a local population candidate, not a calibrated or published replacement +population, and the reports retain `production_ready: false`. + +- [Source and production-stage qualification](qualified-preparation.json) +- [All-state population comparison](qualified-population-comparison.json) +- [Reproduction and field mapping](../../docs/us-childcare-attendance.md) + +No individual survey records, identifiers, raw archives, or H5 populations are +committed. Reports contain aggregate diagnostics and exact artifact/code hashes. +The earlier [source-only report](nsece-2024-v1-validation.json) is historical +(f065a3ae), predating the corrected gap-code classification and population model. +It does not describe the final candidate. + +## Source coverage and model + +| Source status | Children | +| --- | ---: | +| Complete classified calendars | 7,460 | +| Reconstructed from observed regular weekly hours | 3,046 | +| Still excluded under age 13 | 1,105 | +| Outside source age domain | 134 | +| Total | 11,745 | + +The 10,506 usable donors include measured nonparticipants and modeled schedules +for May/fall questionnaire respondents. The latter preserve regular weekly hours +but borrow days and irregular care; they are not observed full schedules. The +remaining excluded records comprise 882 ambiguous calendars, 174 partial +calendars, and 49 unusable noncalendar summaries. Conditional matching cannot +identify their missing schedules without additional assumptions. + +Matching uses age, region, parents' last-week work, and household income in 2023 +dollars. The explicit fallback hierarchy always retains age. Tied nearest-hour +donors are all retained. A household shared-rank mixture models sibling +participation; it does not assert common provider identity. + +The source evaluation uses five household-separated folds. Overall observed ECE +participation is 46.51%, compared with 46.55% predicted, and weekly hours are +14.24 observed versus 14.08 predicted. For youngest sibling pairs, joint +attendance is 32.86% observed versus 32.28% predicted; independent draws predict +25.99%. The masked-calendar check holds out 1,581 children by whole household: weekly +hours are 13.10 observed versus 13.16 reconstructed, and days are 1.72 versus +1.79. Subgroup discrepancies remain visible in the final report. These diagnostics informed development and +must not be described as an untouched external acceptance sample. + +## Population boundary + +The exact BuildP parent contains 166,321 people, 57,240 households, and 31,889 +children ages 0–12. The stage restores temporary income predictors for all three +ASEC cohorts from pinned Census sources while preserving the parent's original +columns, raw missingness, entity links, weights, and period. Its native export +adds only the three attendance inputs and a provenance receipt. + +Outside ages 0–12, the explicit export policy inherits existing engine baseline +values where observations are absent. The 134,432 out-of-domain people include +557 disabled teenagers ages 13–17. Their attendance has not been estimated by +this source. Preserving baseline behavior does not establish nonattendance. + +The state experiment applies 2026 policies to fixed source ages and incomes, +without aging or uprating, and calls each direct state child-care subsidy +variable. Only attendance changes. Provider, activity, expense, enrollment, and +take-up inputs remain as in the parent. Benefit amounts are potential modeled +benefits, not national CCDF spending or caseload estimates. Source-selection, +true summer schedules, provider-specific pricing, and older-child coverage +remain limitations for population publication. + + +## Final state results + +All 51 jurisdictions were evaluated. All-zero state results fell from **31 to 3**: +California, Maryland, and Nevada. Positive modeled subsidies became available +in 28 additional jurisdictions. The aggregate annual potential benefit changes +from $2.253 billion to $5.286 billion under this fixed-population experiment; +these amounts are not calibrated spending estimates. + +All 31,889 under-13 children have resolved inputs. Weighted attendance is 48.47%, +with 1.959 days and 14.081 hours per week averaged across all children, including +nonparticipants. Exact four-field support covers 31,152 children; 576 use +age/parent-work/income and 161 use age/parent-work. None needs the age-only level. +The report gives target distributions by age, region, work, and income. + +The [remaining-input diagnostic](qualified-remaining-state-inputs.json) identifies +separate blockers in January 2026: + +| State | Evidence on this candidate | +| --- | --- | +| CA | 341 SPM units meet CAPP eligibility, but state-specific days/month and weeks/month remain zero, making the time coefficient zero. | +| MD | 115 SPM units meet CCS eligibility, but every provider type is `NONE`, giving a zero reimbursement rate. | +| NV | 149 SPM units meet the income test, but every activity test is false. | + +These require additional source/engine mapping work. The PR does not infer +licensed provider status or approved CCDF activity from attendance alone, and +does not claim to close every part of #915. + +### Local checks + +916 distinct targeted tests passed across the attendance/source, architecture, +fiscal-builder, release-coverage, and US bundle suites. Lint, tracked CI test +inventory, generated bundle validation, and diff whitespace checks passed. +The real production stage completed on the pinned parent, and native export +reloaded successfully with original data, weights, and period preserved. +Full GitHub CI runs separately on the submitted commit. + + +## CI integration correction — 2026-09-13 + +The initial commit's full CI exposed three omissions outside the local targeted +selection: the new native writer was absent from the serializer registry, the +new source descriptor's three manifest fields were missing from field-ledger +pins and the generated coverage report, and a pool-tool test retained the old +US spec hash. The same failures repeated across Python versions and test lanes. + +The writer now uses the shared nullable-boolean table boundary and has registry +round-trip coverage for mixed and all-missing Boolean columns. The configuration +ledger retains exact counts and pointer hashes with explicit validation claims +for the new descriptor; its semantic/missing-sink checks remain enforced. + +The [full-population export verification](ci-export-verification.json) reran the +corrected writer on the qualified checkpoint. All 166,321 people's entity-table +values, dtypes, weights, and the time period match the original qualified native +candidate exactly. Attendance estimates and the 31-to-3 state comparison are +unchanged; artifact bytes have their own new hash. + +The correction passed 579 tests across the serializer/source, field-ledger, +coverage-report, pool-spec identity, and architecture regression runs. The +coverage generator reports 42,159/42,159 fields and 41/41 inventory checks. +Repository lint, CI test inventory, and the build wheel also passed locally. diff --git a/experiments/us-childcare-attendance/bridge-widening-masked-splits.json b/experiments/us-childcare-attendance/bridge-widening-masked-splits.json new file mode 100644 index 000000000..f2d0856a2 --- /dev/null +++ b/experiments/us-childcare-attendance/bridge-widening-masked-splits.json @@ -0,0 +1,194 @@ +{ + "design": "whole-household masked-calendar test; regular weekly hours remain observed", + "split_seeds": [ + 161803, + 1, + 2, + 3, + 4 + ], + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "calendar_bounds": { + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568", + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "missing_calendar": "uninformative 0--168 hours and 0--7 days" + }, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "code_sha256": { + "previous_bridge": "70a7edea8b28c6da21ff4fa9bb220766a3e6cd714926684af29bdba1a8421b0a", + "widened_bridge": "517b3c3ae02e2316b028fd15bc60a090e7962d716d46b80e3e73067f08d5ff29", + "diagnostic": "036aa608e71a30cdd6f0d4eec5db699b3ebc0eb15501ba3384d90daa6035af72" + }, + "splits": [ + { + "split_seed": 161803, + "arm": "previous", + "children": 1581, + "mean_days_error": 0.07555584784203043, + "mean_weekly_hours_error": 0.06442258174952367, + "mean_absolute_days_error": 0.8194388977061153, + "mean_absolute_days_error_regular_care": 1.416307757193369, + "mean_absolute_weekly_hours_error": 2.472029687416687, + "mean_absolute_hours_per_day_error_regular_care": 2.6749171113103776, + "share_over_12_hours_per_day": 0.06433796427135285, + "measured_share_over_12_hours_per_day": 0.04767127717601749 + }, + { + "split_seed": 161803, + "arm": "widened", + "children": 1581, + "mean_days_error": 0.08338954399965659, + "mean_weekly_hours_error": 0.7881707582301872, + "mean_absolute_days_error": 0.8178912727204896, + "mean_absolute_days_error_regular_care": 1.262449587041967, + "mean_absolute_weekly_hours_error": 3.1937517487302904, + "mean_absolute_hours_per_day_error_regular_care": 2.325289937528589, + "share_over_12_hours_per_day": 0.06917085310447134, + "measured_share_over_12_hours_per_day": 0.04767127717601749 + }, + { + "split_seed": 1, + "arm": "previous", + "children": 1498, + "mean_days_error": 0.05901730629950177, + "mean_weekly_hours_error": 0.25523504667880387, + "mean_absolute_days_error": 0.9846677194359647, + "mean_absolute_days_error_regular_care": 1.508455957977742, + "mean_absolute_weekly_hours_error": 2.637295564533044, + "mean_absolute_hours_per_day_error_regular_care": 3.2668024843376298, + "share_over_12_hours_per_day": 0.07809780461481491, + "measured_share_over_12_hours_per_day": 0.03668644349178023 + }, + { + "split_seed": 1, + "arm": "widened", + "children": 1498, + "mean_days_error": 0.07007170464299348, + "mean_weekly_hours_error": 0.4971809136961676, + "mean_absolute_days_error": 0.8516253813775049, + "mean_absolute_days_error_regular_care": 1.1339477880687852, + "mean_absolute_weekly_hours_error": 2.8984253467086747, + "mean_absolute_hours_per_day_error_regular_care": 2.161694403089898, + "share_over_12_hours_per_day": 0.06953668955621194, + "measured_share_over_12_hours_per_day": 0.03668644349178023 + }, + { + "split_seed": 2, + "arm": "previous", + "children": 1531, + "mean_days_error": 0.06827414596760045, + "mean_weekly_hours_error": 1.2760359374239916, + "mean_absolute_days_error": 0.9546795851053014, + "mean_absolute_days_error_regular_care": 1.5626003934801598, + "mean_absolute_weekly_hours_error": 3.9925135878772293, + "mean_absolute_hours_per_day_error_regular_care": 3.1923033168138097, + "share_over_12_hours_per_day": 0.09415047341304701, + "measured_share_over_12_hours_per_day": 0.040057325298559814 + }, + { + "split_seed": 2, + "arm": "widened", + "children": 1531, + "mean_days_error": 0.08053525489098147, + "mean_weekly_hours_error": 0.5300039894078206, + "mean_absolute_days_error": 0.7919407627366568, + "mean_absolute_days_error_regular_care": 1.1466730847700461, + "mean_absolute_weekly_hours_error": 3.2895767695540394, + "mean_absolute_hours_per_day_error_regular_care": 2.052681509836228, + "share_over_12_hours_per_day": 0.05670737293048663, + "measured_share_over_12_hours_per_day": 0.040057325298559814 + }, + { + "split_seed": 3, + "arm": "previous", + "children": 1537, + "mean_days_error": 0.0756790816380128, + "mean_weekly_hours_error": -0.39455595017490974, + "mean_absolute_days_error": 1.01617397353552, + "mean_absolute_days_error_regular_care": 1.6219769697494701, + "mean_absolute_weekly_hours_error": 3.740383729412565, + "mean_absolute_hours_per_day_error_regular_care": 3.112855735923538, + "share_over_12_hours_per_day": 0.08215998229723588, + "measured_share_over_12_hours_per_day": 0.05475743603089253 + }, + { + "split_seed": 3, + "arm": "widened", + "children": 1537, + "mean_days_error": 0.07374619811894458, + "mean_weekly_hours_error": -0.7280626961939485, + "mean_absolute_days_error": 0.925768148568642, + "mean_absolute_days_error_regular_care": 1.425660250964262, + "mean_absolute_weekly_hours_error": 3.3817656077824663, + "mean_absolute_hours_per_day_error_regular_care": 2.7577762584587044, + "share_over_12_hours_per_day": 0.0541435371411225, + "measured_share_over_12_hours_per_day": 0.05475743603089253 + }, + { + "split_seed": 4, + "arm": "previous", + "children": 1438, + "mean_days_error": 0.10673552047128448, + "mean_weekly_hours_error": 0.20305407843145099, + "mean_absolute_days_error": 0.8338693326761498, + "mean_absolute_days_error_regular_care": 1.2702457836361305, + "mean_absolute_weekly_hours_error": 2.5668019738013648, + "mean_absolute_hours_per_day_error_regular_care": 2.1150567518211094, + "share_over_12_hours_per_day": 0.04550264288404825, + "measured_share_over_12_hours_per_day": 0.033240843787941086 + }, + { + "split_seed": 4, + "arm": "widened", + "children": 1438, + "mean_days_error": 0.0700161012601131, + "mean_weekly_hours_error": 0.20505374309392338, + "mean_absolute_days_error": 0.7668603978885158, + "mean_absolute_days_error_regular_care": 1.1066075269633475, + "mean_absolute_weekly_hours_error": 2.554031477778747, + "mean_absolute_hours_per_day_error_regular_care": 2.0714607823879065, + "share_over_12_hours_per_day": 0.033934274927228544, + "measured_share_over_12_hours_per_day": 0.033240843787941086 + } + ], + "mean_over_splits": { + "previous": { + "mean_days_error": 0.07705238044368598, + "mean_weekly_hours_error": 0.280838338821772, + "mean_absolute_days_error": 0.9217659016918102, + "mean_absolute_days_error_regular_care": 1.4759173724073742, + "mean_absolute_weekly_hours_error": 3.081804908608178, + "mean_absolute_hours_per_day_error_regular_care": 2.872387080041293, + "share_over_12_hours_per_day": 0.07284977349609978, + "measured_share_over_12_hours_per_day": 0.04248266515703823 + }, + "widened": { + "mean_days_error": 0.07555176058253785, + "mean_weekly_hours_error": 0.2584693416468301, + "mean_absolute_days_error": 0.8308171926583618, + "mean_absolute_days_error_regular_care": 1.2150676475616815, + "mean_absolute_weekly_hours_error": 3.0635101901108435, + "mean_absolute_hours_per_day_error_regular_care": 2.273780578260266, + "share_over_12_hours_per_day": 0.05669854553190419, + "measured_share_over_12_hours_per_day": 0.04248266515703823 + } + }, + "production_ready": false, + "interpretation": "Development evidence on calendars that exist; not a test of the unobserved days or irregular care of the noncalendar instruments." +} diff --git a/experiments/us-childcare-attendance/bridge_widening_masked_splits.py b/experiments/us-childcare-attendance/bridge_widening_masked_splits.py new file mode 100644 index 000000000..24c5efd11 --- /dev/null +++ b/experiments/us-childcare-attendance/bridge_widening_masked_splits.py @@ -0,0 +1,152 @@ +"""Compare the noncalendar bridge before and after thin-cell widening. + +Development diagnostic only. It repeats the whole-household masked-calendar +design of ``assess_noncalendar_bridge`` over several split seeds and reports +per-child errors, which the group means in the source-stage report cannot show. +The previous implementation is loaded from a file, e.g.:: + + git show e1b5d6c7:packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare_bridge.py > /local/previous_bridge.py + uv run python experiments/us-childcare-attendance/bridge_widening_masked_splits.py \ + --household-tsv /local/39466-0005-Data.tsv \ + --calendar-tsv /local/39466-0004-Data.tsv \ + --previous-bridge /local/previous_bridge.py \ + --report /local/bridge-widening-masked-splits.json + +Only aggregates are written; no survey records or donor identities. +""" + +from __future__ import annotations + +import argparse +import hashlib +import importlib.util +import json +from pathlib import Path + +import numpy as np + +from microcosm.build.us_runtime import nsece_childcare_bridge as current_bridge +from microcosm.build.us_runtime.nsece_childcare import ( + NSECEChildcareSource, + load_nsece_childcare, +) + +SPLIT_SEEDS = (161803, 1, 2, 3, 4) +MASKED_COLUMNS = [ + "childcare_attending_days_per_month", + "childcare_days_per_week", + "childcare_hours_per_day", + "ece_hours_per_week", + "irregular_hours_per_week", +] + + +def _sha256(path: Path) -> str: + return hashlib.sha256(path.read_bytes()).hexdigest() + + +def _load(path: Path): + spec = importlib.util.spec_from_file_location("previous_bridge", path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +def _split(source: NSECEChildcareSource, seed: int): + children = source.children.copy() + complete = children.attendance_status.eq("complete") + holdout = complete & children.source_household_id.map( + lambda x: ( + int.from_bytes(hashlib.sha256(f"{seed}:{x}".encode()).digest()[:8], "big") + % 5 + == 0 + ) + ) + truth = children.loc[holdout].copy() + children.loc[~complete, "regular_hours_per_week"] = np.nan + children.loc[holdout, "attendance_status"] = "missing_calendar" + children.loc[holdout, "questionnaire_version"] = 2 + children.loc[holdout, MASKED_COLUMNS] = np.nan + masked = NSECEChildcareSource(children, source.weights, source.source_receipt) + return masked, truth, holdout + + +def _errors(predicted, truth) -> dict: + weight = truth.child_weight + regular = truth.regular_hours_per_week > 0 + + def average(values, mask=None): + mask = slice(None) if mask is None else mask + return float(np.average(values[mask], weights=weight[mask])) + + days = predicted.childcare_days_per_week - truth.childcare_days_per_week + hours = predicted.ece_hours_per_week - truth.ece_hours_per_week + daily = predicted.childcare_hours_per_day - truth.childcare_hours_per_day + return { + "children": len(truth), + "mean_days_error": average(days), + "mean_weekly_hours_error": average(hours), + "mean_absolute_days_error": average(days.abs()), + "mean_absolute_days_error_regular_care": average(days.abs(), regular), + "mean_absolute_weekly_hours_error": average(hours.abs()), + "mean_absolute_hours_per_day_error_regular_care": average(daily.abs(), regular), + "share_over_12_hours_per_day": average( + (predicted.childcare_hours_per_day > 12).astype(float) + ), + "measured_share_over_12_hours_per_day": average( + (truth.childcare_hours_per_day > 12).astype(float) + ), + } + + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--household-tsv", type=Path, required=True) + parser.add_argument("--calendar-tsv", type=Path, required=True) + parser.add_argument("--previous-bridge", type=Path, required=True) + parser.add_argument("--report", type=Path, required=True) + args = parser.parse_args() + if args.report.exists(): + parser.error("The report path must be new") + arms = {"previous": _load(args.previous_bridge), "widened": current_bridge} + source = load_nsece_childcare(args.household_tsv, args.calendar_tsv) + splits = [] + for seed in SPLIT_SEEDS: + masked, truth, holdout = _split(source, seed) + for arm, module in arms.items(): + bridged = module.bridge_nsece_noncalendar_attendance(masked, seed=seed) + predicted = bridged.children.loc[holdout] + if not predicted.attendance_status.eq("summary_bridge").all(): + raise ValueError("Masked-calendar bridge has unsupported records") + splits.append({"split_seed": seed, "arm": arm, **_errors(predicted, truth)}) + metrics = [k for k in splits[0] if k not in ("split_seed", "arm", "children")] + report = { + "design": "whole-household masked-calendar test; regular weekly hours remain observed", + "split_seeds": list(SPLIT_SEEDS), + "source": source.source_receipt, + "code_sha256": { + "previous_bridge": _sha256(args.previous_bridge), + "widened_bridge": _sha256(Path(current_bridge.__file__)), + "diagnostic": _sha256(Path(__file__)), + }, + "splits": splits, + "mean_over_splits": { + arm: { + metric: float(np.mean([s[metric] for s in splits if s["arm"] == arm])) + for metric in metrics + } + for arm in arms + }, + "production_ready": False, + "interpretation": ( + "Development evidence on calendars that exist; not a test of the " + "unobserved days or irregular care of the noncalendar instruments." + ), + } + args.report.parent.mkdir(parents=True, exist_ok=True) + args.report.write_text(json.dumps(report, indent=2, allow_nan=False) + "\n") + print(json.dumps(report["mean_over_splits"], indent=2)) + + +if __name__ == "__main__": + main() diff --git a/experiments/us-childcare-attendance/calendar-review-2.2.1-population.json b/experiments/us-childcare-attendance/calendar-review-2.2.1-population.json new file mode 100644 index 000000000..7a9c95fa3 --- /dev/null +++ b/experiments/us-childcare-attendance/calendar-review-2.2.1-population.json @@ -0,0 +1,1578 @@ +{ + "parent_sha256": "48b9d479fb4fd1c3537f9383ce4697d130b6f618658409d74f6233c43b994c7e", + "candidate_checkpoint_sha256": "31e4a80cc896aeb769ea034a60e8be68c81bed35a52ff52e27ca62d8cb46f40d", + "validation_code_sha256": "ee3ca65dcd2ef4492924edce54b6bdd03b8b4ed882c65684fc57a1622c341dfe", + "engine_version": "2.2.1", + "policy_year": 2026, + "population": "fixed BuildP source ages/incomes; no aging or uprating", + "people": 166321, + "households": 57240, + "under13_children": 31889, + "outside_source_domain_people": 134432, + "outside_source_domain_age13_17_with_disability": 557, + "outside_domain_baseline_receipt": { + "engine_version": "2.2.1", + "inherited_counts": { + "childcare_attending_days_per_month": 134432, + "childcare_days_per_week": 134432, + "childcare_hours_per_day": 134432 + }, + "interpretation": "baseline retained; not evidence of nonattendance outside ages 0-12", + "values": { + "childcare_attending_days_per_month": 0.0, + "childcare_days_per_week": 0.0, + "childcare_hours_per_day": 0.0 + } + }, + "unresolved_people_retaining_baseline": 0, + "unresolved_age13_17_with_disability": 0, + "weighted_under13_attendance_share": 0.48474940604537897, + "weighted_under13_days_per_week": 1.9587696980712788, + "weighted_under13_hours_per_week": 14.080797907203973, + "candidate_receipt": { + "nsece_childcare_attendance": { + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ], + "calendar_bounds": { + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "missing_calendar": "uninformative 0--168 hours and 0--7 days", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568" + }, + "candidate_only": true, + "fallback_match_columns": [ + [ + "age", + "parent_work_status", + "income_band" + ], + [ + "age", + "parent_work_status" + ], + [ + "age" + ] + ], + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "noncalendar_bridge": { + "assumption": "conditional calendar pattern and irregular care transfer across questionnaire instruments", + "completed_children": 3046, + "imputed": "attended days and irregular care jointly from nearest regular-hour calendar donors", + "observed": "regular weekly hours from May/fall questionnaire", + "seed": 915, + "unsupported_children": 0 + }, + "seed": 915, + "sibling_dependence": 0.7413149380294699, + "source_year": 2024, + "study": "ICPSR39466.v1" + }, + "childcare_predictor_harmonization": { + "geography": "Census region from target state_fips", + "income": "Household sum of measured ASEC PTOTVAL, CPI-U adjusted from source year to 2023 dollars", + "income_source_receipts": [ + { + "income_year": 2022, + "matched_people": 54464, + "sha256": "19b56537e50e7663f954361ef2bb5ce9cef8d9d45f156fe1a69a99b654198ffe", + "source_rows": 146133 + }, + { + "income_year": 2023, + "matched_people": 54654, + "sha256": "21a2b9e0e4b08534563578a45acad77868af4ae9a7d46f23776b707d4a559aa7", + "source_rows": 144265 + }, + { + "income_year": 2024, + "matched_people": 57203, + "sha256": "06921fe83fc66c907e6c7b86b82255dc70458ee7d76258fc48297cb34f0c06b5", + "source_rows": 142125 + } + ], + "parent_universe": "parents of any child age 0 through 12 in household", + "source": "ASEC resident parent line pointers", + "work_measure": "hours_worked_last_week > 0" + }, + "childcare_outside_domain_baseline": { + "engine_version": "2.2.1", + "inherited_counts": { + "childcare_attending_days_per_month": 134432, + "childcare_days_per_week": 134432, + "childcare_hours_per_day": 134432 + }, + "interpretation": "baseline retained; not evidence of nonattendance outside ages 0-12", + "values": { + "childcare_attending_days_per_month": 0.0, + "childcare_days_per_week": 0.0, + "childcare_hours_per_day": 0.0 + } + }, + "childcare_attendance_stage": { + "modeled_age_domain": [ + 0, + 12 + ], + "operations": [ + { + "age_max": 12, + "age_min": 0, + "kind": "derive_childcare_inputs", + "operation": "calendar_attendance" + }, + { + "kind": "fit", + "operation": "fit_sibling_dependence", + "rho": 0.7413149380294699 + }, + { + "kind": "derive_childcare_inputs", + "nearest_donors": 10, + "operation": "regular_hours_schedule_bridge" + }, + { + "kind": "derive", + "operation": "harmonize_asec_childcare_predictors" + }, + { + "kind": "derive_childcare_inputs", + "operation": "joint_weighted_schedule_transfer", + "preserve_observed": true + }, + { + "kind": "export_policy", + "operation": "inherit_engine_baseline" + } + ], + "outputs": [ + "childcare_attending_days_per_month", + "childcare_days_per_week", + "childcare_hours_per_day" + ], + "outside_domain_policy": "inherit_engine_baseline", + "seed": 915, + "sibling_dependence": { + "estimation": "youngest pair in fully observed households; household design weights", + "households": 1941, + "independent_both_in_care": 0.2585427028841666, + "observed_both_in_care": 0.32858869865910467, + "rho": 0.7413149380294699, + "shared_both_in_care": 0.3530315526045447, + "unconstrained_rho": 0.7413149380294699 + }, + "stage": "nsece_childcare_attendance" + }, + "childcare_attendance_binding": { + "schema_version": 1, + "binding_sha256": "12d583e1e77f9c53ba57b80c5dc16680e073dcd4ca5ba05e4df1c276b0872e99", + "execution_sha256": "c63f973a39fbe658f31b4408d97363fb5e9a684ad4b897c01b0f8b22e85746a7", + "source_people": 166321, + "retained_people": 166321, + "execution": { + "context": { + "childcare_attendance_stage": { + "modeled_age_domain": [ + 0, + 12 + ], + "operations": [ + { + "age_max": 12, + "age_min": 0, + "kind": "derive_childcare_inputs", + "operation": "calendar_attendance" + }, + { + "kind": "fit", + "operation": "fit_sibling_dependence", + "rho": 0.7413149380294699 + }, + { + "kind": "derive_childcare_inputs", + "nearest_donors": 10, + "operation": "regular_hours_schedule_bridge" + }, + { + "kind": "derive", + "operation": "harmonize_asec_childcare_predictors" + }, + { + "kind": "derive_childcare_inputs", + "operation": "joint_weighted_schedule_transfer", + "preserve_observed": true + }, + { + "kind": "export_policy", + "operation": "inherit_engine_baseline" + } + ], + "outputs": [ + "childcare_attending_days_per_month", + "childcare_days_per_week", + "childcare_hours_per_day" + ], + "outside_domain_policy": "inherit_engine_baseline", + "seed": 915, + "sibling_dependence": { + "estimation": "youngest pair in fully observed households; household design weights", + "households": 1941, + "independent_both_in_care": 0.2585427028841666, + "observed_both_in_care": 0.32858869865910467, + "rho": 0.7413149380294699, + "shared_both_in_care": 0.3530315526045447, + "unconstrained_rho": 0.7413149380294699 + }, + "stage": "nsece_childcare_attendance" + }, + "childcare_outside_domain_baseline": { + "engine_version": "2.2.1", + "inherited_counts": { + "childcare_attending_days_per_month": 134432, + "childcare_days_per_week": 134432, + "childcare_hours_per_day": 134432 + }, + "interpretation": "baseline retained; not evidence of nonattendance outside ages 0-12", + "values": { + "childcare_attending_days_per_month": 0.0, + "childcare_days_per_week": 0.0, + "childcare_hours_per_day": 0.0 + } + }, + "childcare_predictor_harmonization": { + "geography": "Census region from target state_fips", + "income": "Household sum of measured ASEC PTOTVAL, CPI-U adjusted from source year to 2023 dollars", + "income_source_receipts": [ + { + "income_year": 2022, + "matched_people": 54464, + "sha256": "19b56537e50e7663f954361ef2bb5ce9cef8d9d45f156fe1a69a99b654198ffe", + "source_rows": 146133 + }, + { + "income_year": 2023, + "matched_people": 54654, + "sha256": "21a2b9e0e4b08534563578a45acad77868af4ae9a7d46f23776b707d4a559aa7", + "source_rows": 144265 + }, + { + "income_year": 2024, + "matched_people": 57203, + "sha256": "06921fe83fc66c907e6c7b86b82255dc70458ee7d76258fc48297cb34f0c06b5", + "source_rows": 142125 + } + ], + "parent_universe": "parents of any child age 0 through 12 in household", + "source": "ASEC resident parent line pointers", + "work_measure": "hours_worked_last_week > 0" + }, + "nsece_childcare_attendance": { + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ], + "calendar_bounds": { + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "missing_calendar": "uninformative 0--168 hours and 0--7 days", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568" + }, + "candidate_only": true, + "fallback_match_columns": [ + [ + "age", + "parent_work_status", + "income_band" + ], + [ + "age", + "parent_work_status" + ], + [ + "age" + ] + ], + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "noncalendar_bridge": { + "assumption": "conditional calendar pattern and irregular care transfer across questionnaire instruments", + "completed_children": 3046, + "imputed": "attended days and irregular care jointly from nearest regular-hour calendar donors", + "observed": "regular weekly hours from May/fall questionnaire", + "seed": 915, + "unsupported_children": 0 + }, + "seed": 915, + "sibling_dependence": 0.7413149380294699, + "source_year": 2024, + "study": "ICPSR39466.v1" + } + }, + "recipe": { + "code_sha256": { + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "childcare_attendance_receipt.py": "0950fce7f372ca4b240cd055c931f5f8fe070223fd68504a3ea9cfbc4e16c645", + "childcare_attendance_stage.py": "42e777b0edfc813d79204bc2932fe429d6a48cd2866397560a7386cbee54dadb", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "nsece_childcare.py": "0e72ff9388f8f59147305f07effec2b99dada0f91599727cc9e58ad4feb6edbb", + "nsece_childcare_bridge.py": "70a7edea8b28c6da21ff4fa9bb220766a3e6cd714926684af29bdba1a8421b0a", + "nsece_childcare_dependence.py": "1c5123a77f84460ba517d2b4c6c3e04ae658bf36e9cf54ed69ddbcacc85efc09" + }, + "contract_sha256": "ae648c6cb0e2838fdf142975e9c536eb0683d9630fd1738096d524222ffb01dc", + "runtime_versions": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "policyengine-us": "2.2.1" + } + } + } + } + }, + "states": [ + { + "state": "AL", + "sample_households": 1061, + "baseline": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13061.764184842585, + "annual_modeled_benefits": 32688921.398814265 + } + }, + { + "state": "AK", + "sample_households": 826, + "baseline": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + }, + "candidate": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + } + }, + { + "state": "AZ", + "sample_households": 1164, + "baseline": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 18733.37486637244, + "annual_modeled_benefits": 23159527.697095435 + } + }, + { + "state": "AR", + "sample_households": 952, + "baseline": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 17289.894029146235, + "annual_modeled_benefits": 50793417.58586023 + } + }, + { + "state": "CA", + "sample_households": 2659, + "baseline": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 29, + "weighted_positive_units": 175244.38451184036, + "annual_modeled_benefits": 726014134.44521 + } + }, + { + "state": "CO", + "sample_households": 1164, + "baseline": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 19, + "weighted_positive_units": 30914.695305580855, + "annual_modeled_benefits": 252602567.65021172 + }, + "candidate": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18502.53110225743, + "annual_modeled_benefits": 236445530.32343873 + } + }, + { + "state": "CT", + "sample_households": 908, + "baseline": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 405879416.70427954 + }, + "candidate": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 636244010.8081238 + } + }, + { + "state": "DE", + "sample_households": 1068, + "baseline": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + }, + "candidate": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + } + }, + { + "state": "DC", + "sample_households": 551, + "baseline": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 3288.0395223266023, + "annual_modeled_benefits": 23916792.31200898 + } + }, + { + "state": "FL", + "sample_households": 1642, + "baseline": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 87314.34071851184, + "annual_modeled_benefits": 336693781.677099 + } + }, + { + "state": "GA", + "sample_households": 1215, + "baseline": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + }, + "candidate": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + } + }, + { + "state": "HI", + "sample_households": 838, + "baseline": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0001588361046742648, + "annual_modeled_benefits": 0.6336225438054939 + } + }, + { + "state": "ID", + "sample_households": 746, + "baseline": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 2, + "weighted_positive_units": 2335.738774359226, + "annual_modeled_benefits": 10651259.924815893 + } + }, + { + "state": "IL", + "sample_households": 1668, + "baseline": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 62767.78443156066, + "annual_modeled_benefits": 196786246.13666055 + } + }, + { + "state": "IN", + "sample_households": 1141, + "baseline": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + }, + "candidate": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + } + }, + { + "state": "IA", + "sample_households": 973, + "baseline": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 13277.072875641927, + "annual_modeled_benefits": 55836595.8273853 + } + }, + { + "state": "KS", + "sample_households": 921, + "baseline": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 21785.09440057905, + "annual_modeled_benefits": 57457564.33302226 + } + }, + { + "state": "KY", + "sample_households": 776, + "baseline": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.02885724022053182, + "annual_modeled_benefits": 147.92350896229354 + } + }, + { + "state": "LA", + "sample_households": 1000, + "baseline": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 37176.93537535961, + "annual_modeled_benefits": 72842360.51107226 + } + }, + { + "state": "ME", + "sample_households": 785, + "baseline": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683663.687080294 + }, + "candidate": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683670.942570195 + } + }, + { + "state": "MD", + "sample_households": 1091, + "baseline": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + } + }, + { + "state": "MA", + "sample_households": 1522, + "baseline": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 0.0716373446630314, + "annual_modeled_benefits": 214.55442391989982 + } + }, + { + "state": "MI", + "sample_households": 1478, + "baseline": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + }, + "candidate": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + } + }, + { + "state": "MN", + "sample_households": 1166, + "baseline": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 21289.402694451623, + "annual_modeled_benefits": 274850426.86324066 + } + }, + { + "state": "MS", + "sample_households": 882, + "baseline": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 7256.952556610806, + "annual_modeled_benefits": 30449890.664512668 + } + }, + { + "state": "MO", + "sample_households": 1013, + "baseline": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 9981.891486888984, + "annual_modeled_benefits": 44110014.74611533 + } + }, + { + "state": "MT", + "sample_households": 744, + "baseline": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + }, + "candidate": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + } + }, + { + "state": "NE", + "sample_households": 884, + "baseline": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 754.4826039844379 + }, + "candidate": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 752.3048707440652 + } + }, + { + "state": "NV", + "sample_households": 952, + "baseline": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + } + }, + { + "state": "NH", + "sample_households": 840, + "baseline": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + }, + "candidate": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + } + }, + { + "state": "NJ", + "sample_households": 1651, + "baseline": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 54783391.64412939 + }, + "candidate": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 39399036.82068616 + } + }, + { + "state": "NM", + "sample_households": 902, + "baseline": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 40276267.46262546 + }, + "candidate": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 59646231.852653645 + } + }, + { + "state": "NY", + "sample_households": 2166, + "baseline": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 84809.87077922659, + "annual_modeled_benefits": 386150016.03633535 + } + }, + { + "state": "NC", + "sample_households": 1337, + "baseline": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + }, + "candidate": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + } + }, + { + "state": "ND", + "sample_households": 682, + "baseline": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 409.12895149587507 + }, + "candidate": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 471.04686684011335 + } + }, + { + "state": "OH", + "sample_households": 1531, + "baseline": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 57197.27386227145, + "annual_modeled_benefits": 109086186.25780228 + } + }, + { + "state": "OK", + "sample_households": 918, + "baseline": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0031096774619072676, + "annual_modeled_benefits": 5.149625876918435 + } + }, + { + "state": "OR", + "sample_households": 1152, + "baseline": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + }, + "candidate": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + } + }, + { + "state": "PA", + "sample_households": 1999, + "baseline": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.2005278345895931, + "annual_modeled_benefits": 561.099948525683 + } + }, + { + "state": "RI", + "sample_households": 804, + "baseline": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429808.7526231185 + }, + "candidate": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429813.4984327066 + } + }, + { + "state": "SC", + "sample_households": 955, + "baseline": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 27915.89938246878, + "annual_modeled_benefits": 77088809.79821464 + } + }, + { + "state": "SD", + "sample_households": 866, + "baseline": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 2978.0845139123267, + "annual_modeled_benefits": 5809177.944389787 + } + }, + { + "state": "TN", + "sample_households": 1082, + "baseline": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 54836.32565583871, + "annual_modeled_benefits": 120178664.890383 + } + }, + { + "state": "TX", + "sample_households": 1875, + "baseline": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 72034.10924506374, + "annual_modeled_benefits": 172158000.8966679 + } + }, + { + "state": "UT", + "sample_households": 861, + "baseline": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66497469.149597794 + }, + "candidate": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66497469.149597794 + } + }, + { + "state": "VT", + "sample_households": 496, + "baseline": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 78, + "weighted_positive_units": 32213.61921006818, + "annual_modeled_benefits": 526819840.50677323 + }, + "candidate": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 80, + "weighted_positive_units": 32213.669151621914, + "annual_modeled_benefits": 720606373.2116799 + } + }, + { + "state": "VA", + "sample_households": 1394, + "baseline": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 45187.34717369359, + "annual_modeled_benefits": 249203866.21813098 + } + }, + { + "state": "WA", + "sample_households": 1305, + "baseline": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + }, + "candidate": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + } + }, + { + "state": "WV", + "sample_households": 845, + "baseline": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 4, + "weighted_positive_units": 2978.909898934886, + "annual_modeled_benefits": 9329928.243193686 + } + }, + { + "state": "WI", + "sample_households": 1232, + "baseline": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 33918.60478726821, + "annual_modeled_benefits": 249284653.88471013 + } + }, + { + "state": "WY", + "sample_households": 557, + "baseline": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 2962.834392214354, + "annual_modeled_benefits": 18103301.12153925 + } + } + ], + "production_ready": false, + "interpretation": "attendance-only counterfactual; provider, activity, expenses and take-up inputs remain as in parent", + "matching_levels": { + "age,region,parent_work_status,income_band": 31152, + "age,parent_work_status,income_band": 576, + "age,parent_work_status": 161 + }, + "population_attendance_by_group": [ + { + "grouping": "age", + "group": "0.0", + "children": 1689, + "weighted_children": 2750700.861434371, + "attendance_share": 0.3982910388950054, + "days_per_week": 1.4637084569333976, + "hours_per_week": 12.47778129720075 + }, + { + "grouping": "age", + "group": "1.0", + "children": 2157, + "weighted_children": 3858818.186826853, + "attendance_share": 0.5828056228035874, + "days_per_week": 2.420690450933124, + "hours_per_week": 20.799764139530804 + }, + { + "grouping": "age", + "group": "2.0", + "children": 2364, + "weighted_children": 3754041.8444214575, + "attendance_share": 0.6245468848119025, + "days_per_week": 2.622672601643104, + "hours_per_week": 21.59076854224297 + }, + { + "grouping": "age", + "group": "3.0", + "children": 2385, + "weighted_children": 3880377.4871301977, + "attendance_share": 0.6440103162467938, + "days_per_week": 2.9239564940965894, + "hours_per_week": 21.837287866122146 + }, + { + "grouping": "age", + "group": "4.0", + "children": 2482, + "weighted_children": 4358831.600945832, + "attendance_share": 0.7298361168227924, + "days_per_week": 3.346378469862117, + "hours_per_week": 26.819455757918746 + }, + { + "grouping": "age", + "group": "5.0", + "children": 2391, + "weighted_children": 4095170.7360430276, + "attendance_share": 0.5643585836076381, + "days_per_week": 2.549062633648557, + "hours_per_week": 18.492995302361113 + }, + { + "grouping": "age", + "group": "6.0", + "children": 2562, + "weighted_children": 4029009.778184548, + "attendance_share": 0.4495509704841995, + "days_per_week": 1.6790815724045138, + "hours_per_week": 10.176170030770823 + }, + { + "grouping": "age", + "group": "7.0", + "children": 2612, + "weighted_children": 3768786.8623211696, + "attendance_share": 0.348461328136747, + "days_per_week": 1.4555085622939352, + "hours_per_week": 9.205290314751595 + }, + { + "grouping": "age", + "group": "8.0", + "children": 2689, + "weighted_children": 4419397.563846819, + "attendance_share": 0.41984770408640326, + "days_per_week": 1.582158698623752, + "hours_per_week": 9.889788909271815 + }, + { + "grouping": "age", + "group": "9.0", + "children": 2552, + "weighted_children": 3888389.065045069, + "attendance_share": 0.37587948153623024, + "days_per_week": 1.3231923573550826, + "hours_per_week": 8.472614481687524 + }, + { + "grouping": "age", + "group": "10.0", + "children": 2662, + "weighted_children": 4369978.335878741, + "attendance_share": 0.43521505778260355, + "days_per_week": 1.5068808517461778, + "hours_per_week": 8.205007778013812 + }, + { + "grouping": "age", + "group": "11.0", + "children": 2795, + "weighted_children": 4689133.259098214, + "attendance_share": 0.4034636828760653, + "days_per_week": 1.4253271874750526, + "hours_per_week": 8.173318571609755 + }, + { + "grouping": "age", + "group": "12.0", + "children": 2549, + "weighted_children": 4093051.641607744, + "attendance_share": 0.31020269689115165, + "days_per_week": 1.1064542406772742, + "hours_per_week": 7.828746644810994 + }, + { + "grouping": "region", + "group": "1", + "children": 5553, + "weighted_children": 7976838.3562431075, + "attendance_share": 0.5123696490920082, + "days_per_week": 2.208084285948932, + "hours_per_week": 15.123524314240859 + }, + { + "grouping": "region", + "group": "2", + "children": 7790, + "weighted_children": 10772583.599183697, + "attendance_share": 0.5153609964315923, + "days_per_week": 1.9523623395589054, + "hours_per_week": 14.70850903160164 + }, + { + "grouping": "region", + "group": "3", + "children": 10750, + "weighted_children": 21007309.669184513, + "attendance_share": 0.44174742437852166, + "days_per_week": 1.7895644362796808, + "hours_per_week": 13.033216088883725 + }, + { + "grouping": "region", + "group": "4", + "children": 7796, + "weighted_children": 12198955.598172724, + "attendance_share": 0.5137082633621989, + "days_per_week": 2.0927835451441785, + "hours_per_week": 14.648645297341831 + }, + { + "grouping": "parent_work_status", + "group": "-1", + "children": 684, + "weighted_children": 1044954.9507498589, + "attendance_share": 0.5422109593087965, + "days_per_week": 2.2811995403367784, + "hours_per_week": 25.482061788407137 + }, + { + "grouping": "parent_work_status", + "group": "0", + "children": 2876, + "weighted_children": 5039737.2909418885, + "attendance_share": 0.3083075074659248, + "days_per_week": 1.283739352802779, + "hours_per_week": 11.283501114920222 + }, + { + "grouping": "parent_work_status", + "group": "1", + "children": 9966, + "weighted_children": 15397404.080512933, + "attendance_share": 0.3115897123620967, + "days_per_week": 0.9599810926770269, + "hours_per_week": 6.6244519255662295 + }, + { + "grouping": "parent_work_status", + "group": "2", + "children": 18363, + "weighted_children": 30473590.900579363, + "attendance_share": 0.5994515383571952, + "days_per_week": 2.5640085999146067, + "hours_per_week": 17.919932134788446 + }, + { + "grouping": "income_band", + "group": "0", + "children": 94, + "weighted_children": 81378.29635578688, + "attendance_share": 0.29040892685678327, + "days_per_week": 1.0780433457763277, + "hours_per_week": 6.3255131795754185 + }, + { + "grouping": "income_band", + "group": "1", + "children": 3165, + "weighted_children": 6927519.022630059, + "attendance_share": 0.4025097371077471, + "days_per_week": 1.6934463444760064, + "hours_per_week": 12.252209201740305 + }, + { + "grouping": "income_band", + "group": "2", + "children": 6097, + "weighted_children": 10396829.673697237, + "attendance_share": 0.4585389868464392, + "days_per_week": 1.9481109164610568, + "hours_per_week": 14.847718600455874 + }, + { + "grouping": "income_band", + "group": "3", + "children": 9010, + "weighted_children": 14071962.152827512, + "attendance_share": 0.45002653661522485, + "days_per_week": 1.7736004293258292, + "hours_per_week": 13.239778272162871 + }, + { + "grouping": "income_band", + "group": "4", + "children": 7428, + "weighted_children": 13192218.644710096, + "attendance_share": 0.5136530195198358, + "days_per_week": 1.9683914038135206, + "hours_per_week": 14.280673940380375 + }, + { + "grouping": "income_band", + "group": "5", + "children": 6095, + "weighted_children": 7285779.432563353, + "attendance_share": 0.6172477004274525, + "days_per_week": 2.576313155655513, + "hours_per_week": 16.074152133280744 + } + ], + "summary": { + "states_evaluated": 51, + "all_zero_states": { + "baseline": [ + "AL", + "AZ", + "AR", + "CA", + "DC", + "FL", + "HI", + "ID", + "IL", + "IA", + "KS", + "KY", + "LA", + "MD", + "MA", + "MN", + "MS", + "MO", + "NV", + "NY", + "OH", + "OK", + "PA", + "SC", + "SD", + "TN", + "TX", + "VA", + "WV", + "WI", + "WY" + ], + "candidate": [ + "MD", + "NV" + ] + }, + "annual_potential_modeled_benefits": { + "baseline": 2253603947.6976757, + "candidate": 5998228187.26313 + } + } +} diff --git a/experiments/us-childcare-attendance/calendar-review-2.2.1-sensitivity.json b/experiments/us-childcare-attendance/calendar-review-2.2.1-sensitivity.json new file mode 100644 index 000000000..8f2fef044 --- /dev/null +++ b/experiments/us-childcare-attendance/calendar-review-2.2.1-sensitivity.json @@ -0,0 +1,3220 @@ +{ + "parent_sha256": "48b9d479fb4fd1c3537f9383ce4697d130b6f618658409d74f6233c43b994c7e", + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "calendar_bounds": { + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568", + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "missing_calendar": "uninformative 0--168 hours and 0--7 days" + }, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "recipe": { + "contract_sha256": "ae648c6cb0e2838fdf142975e9c536eb0683d9630fd1738096d524222ffb01dc", + "runtime_versions": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "policyengine-us": "2.2.1" + }, + "code_sha256": { + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "nsece_childcare.py": "0e72ff9388f8f59147305f07effec2b99dada0f91599727cc9e58ad4feb6edbb", + "nsece_childcare_bridge.py": "70a7edea8b28c6da21ff4fa9bb220766a3e6cd714926684af29bdba1a8421b0a", + "nsece_childcare_dependence.py": "1c5123a77f84460ba517d2b4c6c3e04ae658bf36e9cf54ed69ddbcacc85efc09", + "childcare_attendance_stage.py": "42e777b0edfc813d79204bc2932fe429d6a48cd2866397560a7386cbee54dadb", + "childcare_attendance_receipt.py": "0950fce7f372ca4b240cd055c931f5f8fe070223fd68504a3ea9cfbc4e16c645" + } + }, + "seed": 915, + "engine_version": "2.2.1", + "policy_year": 2026, + "code_sha256": { + "validate_us_childcare_sensitivity.py": "59d41bf8b6192f9d4d01976e9a3b464446ade56d67f7493cb611ef3d8c01d07c", + "childcare_sensitivity.py": "a3d370bcaf78b609d81c542dc774b7dab0202ea02f53f80135417320840e06ac" + }, + "population": "fixed BuildP source ages/incomes; no aging or uprating", + "assumptions": { + "candidate": {}, + "no_modeled_irregular_hours": { + "include_modeled_irregular_hours": false, + "modeled_day_shift": 0, + "measured_regular_hours_preserved": true + }, + "one_fewer_day": { + "include_modeled_irregular_hours": true, + "modeled_day_shift": -1, + "measured_regular_hours_preserved": true + }, + "one_more_day": { + "include_modeled_irregular_hours": true, + "modeled_day_shift": 1, + "measured_regular_hours_preserved": true + } + }, + "changed_children": { + "candidate": 0, + "no_modeled_irregular_hours": 1809, + "one_fewer_day": 5705, + "one_more_day": 6683 + }, + "screens": { + "national_relative_change": 0.1, + "state_relative_change": 0.2 + }, + "states": [ + { + "state": "AL", + "sample_households": 1061, + "baseline": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13061.764184842585, + "annual_modeled_benefits": 32688921.398814265 + }, + "no_modeled_irregular_hours": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13061.764184842585, + "annual_modeled_benefits": 32688921.398814265 + }, + "one_fewer_day": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13061.764184842585, + "annual_modeled_benefits": 32688921.398814265 + }, + "one_more_day": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13061.764184842585, + "annual_modeled_benefits": 32688921.398814265 + } + }, + { + "state": "AK", + "sample_households": 826, + "baseline": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + }, + "candidate": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + }, + "no_modeled_irregular_hours": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + }, + "one_fewer_day": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + }, + "one_more_day": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + } + }, + { + "state": "AZ", + "sample_households": 1164, + "baseline": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 18733.37486637244, + "annual_modeled_benefits": 23159527.697095435 + }, + "no_modeled_irregular_hours": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18733.29978438327, + "annual_modeled_benefits": 23159479.981134396 + }, + "one_fewer_day": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 18733.37486637244, + "annual_modeled_benefits": 23159508.09361713 + }, + "one_more_day": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 18733.37486637244, + "annual_modeled_benefits": 22260467.45209273 + } + }, + { + "state": "AR", + "sample_households": 952, + "baseline": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 17289.894029146235, + "annual_modeled_benefits": 50793417.58586023 + }, + "no_modeled_irregular_hours": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 17289.87330874073, + "annual_modeled_benefits": 50793412.084522665 + }, + "one_fewer_day": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 17289.894029146235, + "annual_modeled_benefits": 47298738.19780214 + }, + "one_more_day": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 17289.894029146235, + "annual_modeled_benefits": 73116589.09583077 + } + }, + { + "state": "CA", + "sample_households": 2659, + "baseline": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 29, + "weighted_positive_units": 175244.38451184036, + "annual_modeled_benefits": 726014134.44521 + }, + "no_modeled_irregular_hours": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 165687.58177746536, + "annual_modeled_benefits": 597156813.0898787 + }, + "one_fewer_day": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 29, + "weighted_positive_units": 175244.38451184036, + "annual_modeled_benefits": 726014134.44521 + }, + "one_more_day": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 29, + "weighted_positive_units": 175244.38451184036, + "annual_modeled_benefits": 726014134.44521 + } + }, + { + "state": "CO", + "sample_households": 1164, + "baseline": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 19, + "weighted_positive_units": 30914.695305580855, + "annual_modeled_benefits": 252602567.65021172 + }, + "candidate": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18502.53110225743, + "annual_modeled_benefits": 236445530.32343873 + }, + "no_modeled_irregular_hours": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 18502.54616478004, + "annual_modeled_benefits": 236445566.4573961 + }, + "one_fewer_day": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18502.53110225743, + "annual_modeled_benefits": 236445530.32343873 + }, + "one_more_day": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18502.53110225743, + "annual_modeled_benefits": 236445530.32343873 + } + }, + { + "state": "CT", + "sample_households": 908, + "baseline": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 405879416.70427954 + }, + "candidate": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 636244010.8081238 + }, + "no_modeled_irregular_hours": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 636244010.8081238 + }, + "one_fewer_day": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 636244010.8081238 + }, + "one_more_day": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 636244010.8081238 + } + }, + { + "state": "DE", + "sample_households": 1068, + "baseline": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + }, + "candidate": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + }, + "no_modeled_irregular_hours": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + }, + "one_fewer_day": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + }, + "one_more_day": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + } + }, + { + "state": "DC", + "sample_households": 551, + "baseline": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 3288.0395223266023, + "annual_modeled_benefits": 23916792.31200898 + }, + "no_modeled_irregular_hours": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 3288.0395223266023, + "annual_modeled_benefits": 23916792.31200898 + }, + "one_fewer_day": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 3288.0395223266023, + "annual_modeled_benefits": 23916792.31200898 + }, + "one_more_day": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 3288.0395223266023, + "annual_modeled_benefits": 23916792.31200898 + } + }, + { + "state": "FL", + "sample_households": 1642, + "baseline": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 87314.34071851184, + "annual_modeled_benefits": 336693781.677099 + }, + "no_modeled_irregular_hours": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 76833.30946851184, + "annual_modeled_benefits": 320195353.52476215 + }, + "one_fewer_day": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 60231.18556508084, + "annual_modeled_benefits": 320401507.8530382 + }, + "one_more_day": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 60231.18556508084, + "annual_modeled_benefits": 324178392.2600601 + } + }, + { + "state": "GA", + "sample_households": 1215, + "baseline": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + }, + "candidate": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + }, + "no_modeled_irregular_hours": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + }, + "one_fewer_day": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + }, + "one_more_day": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + } + }, + { + "state": "HI", + "sample_households": 838, + "baseline": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0001588361046742648, + "annual_modeled_benefits": 0.6336225438054939 + }, + "no_modeled_irregular_hours": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0001588361046742648, + "annual_modeled_benefits": 0.6336225438054939 + }, + "one_fewer_day": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0001588361046742648, + "annual_modeled_benefits": 0.6336225438054939 + }, + "one_more_day": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0001588361046742648, + "annual_modeled_benefits": 0.6336225438054939 + } + }, + { + "state": "ID", + "sample_households": 746, + "baseline": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 2, + "weighted_positive_units": 2335.738774359226, + "annual_modeled_benefits": 10651259.924815893 + }, + "no_modeled_irregular_hours": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 2, + "weighted_positive_units": 2335.738774359226, + "annual_modeled_benefits": 10651259.924815893 + }, + "one_fewer_day": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 2, + "weighted_positive_units": 2335.738774359226, + "annual_modeled_benefits": 10651259.924815893 + }, + "one_more_day": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 2, + "weighted_positive_units": 2335.738774359226, + "annual_modeled_benefits": 10651167.105942965 + } + }, + { + "state": "IL", + "sample_households": 1668, + "baseline": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 62767.78443156066, + "annual_modeled_benefits": 196786246.13666055 + }, + "no_modeled_irregular_hours": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 62767.78443156066, + "annual_modeled_benefits": 196786246.13666055 + }, + "one_fewer_day": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 62767.78443156066, + "annual_modeled_benefits": 196786122.30308777 + }, + "one_more_day": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 62767.78443156066, + "annual_modeled_benefits": 196786118.53858995 + } + }, + { + "state": "IN", + "sample_households": 1141, + "baseline": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + }, + "candidate": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + }, + "no_modeled_irregular_hours": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + }, + "one_fewer_day": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + }, + "one_more_day": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + } + }, + { + "state": "IA", + "sample_households": 973, + "baseline": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 13277.072875641927, + "annual_modeled_benefits": 55836595.8273853 + }, + "no_modeled_irregular_hours": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 13277.072875641927, + "annual_modeled_benefits": 55836595.8273853 + }, + "one_fewer_day": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 13277.072875641927, + "annual_modeled_benefits": 89338499.34608828 + }, + "one_more_day": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 13277.072875641927, + "annual_modeled_benefits": 55836595.8273853 + } + }, + { + "state": "KS", + "sample_households": 921, + "baseline": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 21785.09440057905, + "annual_modeled_benefits": 57457564.33302226 + }, + "no_modeled_irregular_hours": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 21785.09440057905, + "annual_modeled_benefits": 57457564.33302226 + }, + "one_fewer_day": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 21785.09440057905, + "annual_modeled_benefits": 29101934.00209515 + }, + "one_more_day": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 21785.09440057905, + "annual_modeled_benefits": 58709158.015559085 + } + }, + { + "state": "KY", + "sample_households": 776, + "baseline": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.02885724022053182, + "annual_modeled_benefits": 147.92350896229354 + }, + "no_modeled_irregular_hours": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.02885724022053182, + "annual_modeled_benefits": 147.92350896229354 + }, + "one_fewer_day": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.02885724022053182, + "annual_modeled_benefits": 157.98810727270265 + }, + "one_more_day": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.02885724022053182, + "annual_modeled_benefits": 146.34993561158112 + } + }, + { + "state": "LA", + "sample_households": 1000, + "baseline": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 37176.93537535961, + "annual_modeled_benefits": 72842360.51107226 + }, + "no_modeled_irregular_hours": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 37176.93537535961, + "annual_modeled_benefits": 69024044.59310351 + }, + "one_fewer_day": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 37176.93812166341, + "annual_modeled_benefits": 72842353.11263487 + }, + "one_more_day": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 37176.93537535961, + "annual_modeled_benefits": 72842360.51107226 + } + }, + { + "state": "ME", + "sample_households": 785, + "baseline": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683663.687080294 + }, + "candidate": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683670.942570195 + }, + "no_modeled_irregular_hours": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683670.942570195 + }, + "one_fewer_day": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683670.942570195 + }, + "one_more_day": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683670.942570195 + } + }, + { + "state": "MD", + "sample_households": 1091, + "baseline": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "no_modeled_irregular_hours": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "one_fewer_day": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "one_more_day": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + } + }, + { + "state": "MA", + "sample_households": 1522, + "baseline": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 0.0716373446630314, + "annual_modeled_benefits": 214.55442391989982 + }, + "no_modeled_irregular_hours": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 0.0716373446630314, + "annual_modeled_benefits": 214.55442391989982 + }, + "one_fewer_day": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 0.0716373446630314, + "annual_modeled_benefits": 214.55442391989982 + }, + "one_more_day": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 0.0716373446630314, + "annual_modeled_benefits": 214.55442391989982 + } + }, + { + "state": "MI", + "sample_households": 1478, + "baseline": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + }, + "candidate": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + }, + "no_modeled_irregular_hours": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + }, + "one_fewer_day": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + }, + "one_more_day": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + } + }, + { + "state": "MN", + "sample_households": 1166, + "baseline": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 21289.402694451623, + "annual_modeled_benefits": 274850426.86324066 + }, + "no_modeled_irregular_hours": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 21289.401307827327, + "annual_modeled_benefits": 274850426.2413397 + }, + "one_fewer_day": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 21289.402694451623, + "annual_modeled_benefits": 274850426.86324066 + }, + "one_more_day": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 21289.402694451623, + "annual_modeled_benefits": 274850426.86324066 + } + }, + { + "state": "MS", + "sample_households": 882, + "baseline": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 7256.952556610806, + "annual_modeled_benefits": 30449890.664512668 + }, + "no_modeled_irregular_hours": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 7256.951193145127, + "annual_modeled_benefits": 30449886.57411563 + }, + "one_fewer_day": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 7256.952556610806, + "annual_modeled_benefits": 9247129.336387664 + }, + "one_more_day": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 7256.952556610806, + "annual_modeled_benefits": 30449890.664512668 + } + }, + { + "state": "MO", + "sample_households": 1013, + "baseline": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 9981.891486888984, + "annual_modeled_benefits": 44110014.74611533 + }, + "no_modeled_irregular_hours": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 9981.891486888984, + "annual_modeled_benefits": 44110014.74611533 + }, + "one_fewer_day": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 9981.891486888984, + "annual_modeled_benefits": 44110017.00214956 + }, + "one_more_day": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 9981.891486888984, + "annual_modeled_benefits": 44110014.31673183 + } + }, + { + "state": "MT", + "sample_households": 744, + "baseline": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + }, + "candidate": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + }, + "no_modeled_irregular_hours": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + }, + "one_fewer_day": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + }, + "one_more_day": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + } + }, + { + "state": "NE", + "sample_households": 884, + "baseline": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 754.4826039844379 + }, + "candidate": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 752.3048707440652 + }, + "no_modeled_irregular_hours": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 750.2732835703686 + }, + "one_fewer_day": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 752.3048707440652 + }, + "one_more_day": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 752.3048707440652 + } + }, + { + "state": "NV", + "sample_households": 952, + "baseline": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "no_modeled_irregular_hours": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "one_fewer_day": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "one_more_day": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + } + }, + { + "state": "NH", + "sample_households": 840, + "baseline": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + }, + "candidate": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + }, + "no_modeled_irregular_hours": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + }, + "one_fewer_day": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + }, + "one_more_day": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + } + }, + { + "state": "NJ", + "sample_households": 1651, + "baseline": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 54783391.64412939 + }, + "candidate": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 39399036.82068616 + }, + "no_modeled_irregular_hours": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 39399036.82068616 + }, + "one_fewer_day": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 39399036.82068616 + }, + "one_more_day": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 39399036.82068616 + } + }, + { + "state": "NM", + "sample_households": 902, + "baseline": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 40276267.46262546 + }, + "candidate": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 59646231.852653645 + }, + "no_modeled_irregular_hours": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 59644459.68607285 + }, + "one_fewer_day": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 59646236.386424586 + }, + "one_more_day": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 59647120.40554538 + } + }, + { + "state": "NY", + "sample_households": 2166, + "baseline": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 84809.87077922659, + "annual_modeled_benefits": 386150016.03633535 + }, + "no_modeled_irregular_hours": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 84809.87077922659, + "annual_modeled_benefits": 386150016.03633535 + }, + "one_fewer_day": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 84809.87077922659, + "annual_modeled_benefits": 386147637.05533403 + }, + "one_more_day": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 84809.87077922659, + "annual_modeled_benefits": 386150016.03633535 + } + }, + { + "state": "NC", + "sample_households": 1337, + "baseline": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + }, + "candidate": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + }, + "no_modeled_irregular_hours": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + }, + "one_fewer_day": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + }, + "one_more_day": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + } + }, + { + "state": "ND", + "sample_households": 682, + "baseline": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 409.12895149587507 + }, + "candidate": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 471.04686684011335 + }, + "no_modeled_irregular_hours": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 465.6641840398204 + }, + "one_fewer_day": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 474.0045400403885 + }, + "one_more_day": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 515.8170557760147 + } + }, + { + "state": "OH", + "sample_households": 1531, + "baseline": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 57197.27386227145, + "annual_modeled_benefits": 109086186.25780228 + }, + "no_modeled_irregular_hours": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 57197.27386227145, + "annual_modeled_benefits": 109086186.25780228 + }, + "one_fewer_day": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 57197.27386227145, + "annual_modeled_benefits": 109086186.25780228 + }, + "one_more_day": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 57197.27386227145, + "annual_modeled_benefits": 109088290.29528335 + } + }, + { + "state": "OK", + "sample_households": 918, + "baseline": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0031096774619072676, + "annual_modeled_benefits": 5.149625876918435 + }, + "no_modeled_irregular_hours": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0031096774619072676, + "annual_modeled_benefits": 5.149625876918435 + }, + "one_fewer_day": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0031096774619072676, + "annual_modeled_benefits": 3.0897752604315514 + }, + "one_more_day": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0031096774619072676, + "annual_modeled_benefits": 5.149625876918435 + } + }, + { + "state": "OR", + "sample_households": 1152, + "baseline": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + }, + "candidate": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + }, + "no_modeled_irregular_hours": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + }, + "one_fewer_day": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + }, + "one_more_day": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + } + }, + { + "state": "PA", + "sample_households": 1999, + "baseline": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.2005278345895931, + "annual_modeled_benefits": 561.099948525683 + }, + "no_modeled_irregular_hours": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.2005278345895931, + "annual_modeled_benefits": 561.099948525683 + }, + "one_fewer_day": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.2005278345895931, + "annual_modeled_benefits": 561.099948525683 + }, + "one_more_day": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.2005278345895931, + "annual_modeled_benefits": 561.099948525683 + } + }, + { + "state": "RI", + "sample_households": 804, + "baseline": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429808.7526231185 + }, + "candidate": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429813.4984327066 + }, + "no_modeled_irregular_hours": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429813.4984327066 + }, + "one_fewer_day": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429813.4984327066 + }, + "one_more_day": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429813.4984327066 + } + }, + { + "state": "SC", + "sample_households": 955, + "baseline": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 27915.89938246878, + "annual_modeled_benefits": 77088809.79821464 + }, + "no_modeled_irregular_hours": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 27854.604704734404, + "annual_modeled_benefits": 77020404.93038082 + }, + "one_fewer_day": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 27915.89938246878, + "annual_modeled_benefits": 77088803.73884593 + }, + "one_more_day": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 27915.89938246878, + "annual_modeled_benefits": 77088809.79821464 + } + }, + { + "state": "SD", + "sample_households": 866, + "baseline": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 2978.0845139123267, + "annual_modeled_benefits": 5809177.944389787 + }, + "no_modeled_irregular_hours": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 2978.0845139123267, + "annual_modeled_benefits": 5809177.944389787 + }, + "one_fewer_day": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 2978.0845139123267, + "annual_modeled_benefits": 5809177.483422956 + }, + "one_more_day": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 2978.0845139123267, + "annual_modeled_benefits": 5809179.365034073 + } + }, + { + "state": "TN", + "sample_households": 1082, + "baseline": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 54836.32565583871, + "annual_modeled_benefits": 120178664.890383 + }, + "no_modeled_irregular_hours": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 37178.86130036996, + "annual_modeled_benefits": 76918628.29417688 + }, + "one_fewer_day": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 54836.32565583871, + "annual_modeled_benefits": 120178652.73669359 + }, + "one_more_day": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 58319.75094880746, + "annual_modeled_benefits": 139207804.7182324 + } + }, + { + "state": "TX", + "sample_households": 1875, + "baseline": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 72034.10924506374, + "annual_modeled_benefits": 172158000.8966679 + }, + "no_modeled_irregular_hours": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 72034.10924506374, + "annual_modeled_benefits": 172158000.8966679 + }, + "one_fewer_day": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 72034.10924506374, + "annual_modeled_benefits": 172158000.8966679 + }, + "one_more_day": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 72034.10924506374, + "annual_modeled_benefits": 172158000.8966679 + } + }, + { + "state": "UT", + "sample_households": 861, + "baseline": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66497469.149597794 + }, + "candidate": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66497469.149597794 + }, + "no_modeled_irregular_hours": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66497469.149597794 + }, + "one_fewer_day": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66497469.149597794 + }, + "one_more_day": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66497469.149597794 + } + }, + { + "state": "VT", + "sample_households": 496, + "baseline": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 78, + "weighted_positive_units": 32213.61921006818, + "annual_modeled_benefits": 526819840.50677323 + }, + "candidate": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 80, + "weighted_positive_units": 32213.669151621914, + "annual_modeled_benefits": 720606373.2116799 + }, + "no_modeled_irregular_hours": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 80, + "weighted_positive_units": 32213.669151621914, + "annual_modeled_benefits": 707106120.8814734 + }, + "one_fewer_day": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 80, + "weighted_positive_units": 32213.669151621914, + "annual_modeled_benefits": 723295768.2248663 + }, + "one_more_day": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 81, + "weighted_positive_units": 32213.82430987344, + "annual_modeled_benefits": 735348229.2533482 + } + }, + { + "state": "VA", + "sample_households": 1394, + "baseline": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 45187.34717369359, + "annual_modeled_benefits": 249203866.21813098 + }, + "no_modeled_irregular_hours": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 45187.34378196369, + "annual_modeled_benefits": 249203861.9343761 + }, + "one_fewer_day": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 45187.34717369359, + "annual_modeled_benefits": 218587967.72536415 + }, + "one_more_day": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 45187.52193577867, + "annual_modeled_benefits": 254330473.5103389 + } + }, + { + "state": "WA", + "sample_households": 1305, + "baseline": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + }, + "candidate": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + }, + "no_modeled_irregular_hours": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + }, + "one_fewer_day": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + }, + "one_more_day": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + } + }, + { + "state": "WV", + "sample_households": 845, + "baseline": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 4, + "weighted_positive_units": 2978.909898934886, + "annual_modeled_benefits": 9329928.243193686 + }, + "no_modeled_irregular_hours": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 4, + "weighted_positive_units": 2978.909898934886, + "annual_modeled_benefits": 9329923.422902562 + }, + "one_fewer_day": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 4, + "weighted_positive_units": 2978.909898934886, + "annual_modeled_benefits": 9329930.062846346 + }, + "one_more_day": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 4, + "weighted_positive_units": 2978.909898934886, + "annual_modeled_benefits": 10521487.168013036 + } + }, + { + "state": "WI", + "sample_households": 1232, + "baseline": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 33918.60478726821, + "annual_modeled_benefits": 249284653.88471013 + }, + "no_modeled_irregular_hours": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 33918.60478726821, + "annual_modeled_benefits": 249284653.88471013 + }, + "one_fewer_day": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 33918.60478726821, + "annual_modeled_benefits": 249284617.12617347 + }, + "one_more_day": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 33918.61217102362, + "annual_modeled_benefits": 210174118.98339957 + } + }, + { + "state": "WY", + "sample_households": 557, + "baseline": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 2962.834392214354, + "annual_modeled_benefits": 18103301.12153925 + }, + "no_modeled_irregular_hours": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 2962.834582739495, + "annual_modeled_benefits": 18103300.895859934 + }, + "one_fewer_day": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 2962.834392214354, + "annual_modeled_benefits": 18103301.12153925 + }, + "one_more_day": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 2962.834392214354, + "annual_modeled_benefits": 18834318.50135846 + } + } + ], + "production_ready": false, + "interpretation": "assumption stress tests, not confidence intervals; potential modeled benefits, not calibrated spending", + "summary": { + "states_evaluated": 51, + "annual_potential_modeled_benefits": { + "baseline": 2253603947.6976757, + "candidate": 5998228187.26313, + "no_modeled_irregular_hours": 5792223617.337031, + "one_fewer_day": 5934455676.753909, + "one_more_day": 6010100963.719955 + }, + "sensitivity_flags": [ + { + "scenario": "no_modeled_irregular_hours", + "state": "TN", + "relative_change": -0.3599643633557116, + "absolute_change": -43260036.59620613, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "IA", + "relative_change": 0.5999990332912062, + "absolute_change": 33501903.518702976, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "KS", + "relative_change": -0.49350560992419995, + "absolute_change": -28355630.330927107, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "MS", + "relative_change": -0.6963165011569457, + "absolute_change": -21202761.328125004, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "OK", + "relative_change": -0.40000005159976976, + "absolute_change": -2.0598506164868837, + "flagged": true + }, + { + "scenario": "one_more_day", + "state": "AR", + "relative_change": 0.43948945692098534, + "absolute_change": 22323171.50997054, + "flagged": true + } + ], + "comparisons": [ + { + "scenario": "no_modeled_irregular_hours", + "state": "US", + "relative_change": -0.03434423691375011, + "absolute_change": -206004569.92609882, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "AL", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "AK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "AZ", + "relative_change": -2.0603166723927034e-06, + "absolute_change": -47.715961039066315, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "AR", + "relative_change": -1.0830808059296869e-07, + "absolute_change": -5.501337565481663, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "CA", + "relative_change": -0.1774859678920697, + "absolute_change": -128857321.3553313, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "CO", + "relative_change": 1.5282148622892612e-07, + "absolute_change": 36.13395735621452, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "CT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "DE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "DC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "FL", + "relative_change": -0.04900128559000059, + "absolute_change": -16498428.152336836, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "GA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "HI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "ID", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "IL", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "IN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "IA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "KS", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "KY", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "LA", + "relative_change": -0.0524188932261243, + "absolute_change": -3818315.91796875, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "ME", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MD", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MN", + "relative_change": -2.262688775133818e-09, + "absolute_change": -0.6219009757041931, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MS", + "relative_change": -1.343320763490555e-07, + "absolute_change": -4.090397037565708, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MO", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NE", + "relative_change": -0.002700483876552961, + "absolute_change": -2.0315871736966074, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NV", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NJ", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NM", + "relative_change": -2.9711291489026368e-05, + "absolute_change": -1772.1665807962418, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NY", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "ND", + "relative_change": -0.011427064224842841, + "absolute_change": -5.382682800292969, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "OH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "OK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "OR", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "PA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "RI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "SC", + "relative_change": -0.0008873514588288169, + "absolute_change": -68404.86783382297, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "SD", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "TN", + "relative_change": -0.3599643633557116, + "absolute_change": -43260036.59620613, + "flagged": true + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "TX", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "UT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "VT", + "relative_change": -0.01873457248239016, + "absolute_change": -13500252.330206513, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "VA", + "relative_change": -1.7189760938327763e-08, + "absolute_change": -4.283754885196686, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "WA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "WV", + "relative_change": -5.166482526594711e-07, + "absolute_change": -4.820291124284267, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "WI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "WY", + "relative_change": -1.2466196861638054e-08, + "absolute_change": -0.22567931562662125, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "US", + "relative_change": -0.01063189137162839, + "absolute_change": -63772510.50922108, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "AL", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "AK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "AZ", + "relative_change": -8.464541488685182e-07, + "absolute_change": -19.60347830504179, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "AR", + "relative_change": -0.06880181634068526, + "absolute_change": -3494679.3880580887, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "CA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "CO", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "CT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "DE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "DC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "FL", + "relative_change": -0.04838899531469712, + "absolute_change": -16292273.824060798, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "GA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "HI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "ID", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "IL", + "relative_change": -6.29279612809565e-07, + "absolute_change": -123.8335727751255, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "IN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "IA", + "relative_change": 0.5999990332912062, + "absolute_change": 33501903.518702976, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "KS", + "relative_change": -0.49350560992419995, + "absolute_change": -28355630.330927107, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "KY", + "relative_change": 0.06803920743236715, + "absolute_change": 10.06459831040911, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "LA", + "relative_change": -1.015677875316422e-07, + "absolute_change": -7.398437395691872, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "ME", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MD", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MS", + "relative_change": -0.6963165011569457, + "absolute_change": -21202761.328125004, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "MO", + "relative_change": 5.114562408698159e-08, + "absolute_change": 2.256034232676029, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NV", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NJ", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NM", + "relative_change": 7.601102031722338e-08, + "absolute_change": 4.533770941197872, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NY", + "relative_change": -6.160768878729368e-06, + "absolute_change": -2378.981001317501, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "ND", + "relative_change": 0.006278936149423715, + "absolute_change": 2.957673200275167, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "OH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "OK", + "relative_change": -0.40000005159976976, + "absolute_change": -2.0598506164868837, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "OR", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "PA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "RI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "SC", + "relative_change": -7.860244217741888e-08, + "absolute_change": -6.059368714690208, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "SD", + "relative_change": -7.935147357416053e-08, + "absolute_change": -0.46096683014184237, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "TN", + "relative_change": -1.0113017502190059e-07, + "absolute_change": -12.153689414262772, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "TX", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "UT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "VT", + "relative_change": 0.0037321277096120254, + "absolute_change": 2689395.0131863356, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "VA", + "relative_change": -0.122854829491162, + "absolute_change": -30615898.492766827, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "WA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "WV", + "relative_change": 1.9503393942456014e-07, + "absolute_change": 1.81965265981853, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "WI", + "relative_change": -1.474560751887755e-07, + "absolute_change": -36.7585366666317, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "WY", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "US", + "relative_change": 0.0019793805914280435, + "absolute_change": 11872776.456825256, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "AL", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "AK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "AZ", + "relative_change": -0.038820318650775495, + "absolute_change": -899060.2450027056, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "AR", + "relative_change": 0.43948945692098534, + "absolute_change": 22323171.50997054, + "flagged": true + }, + { + "scenario": "one_more_day", + "state": "CA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "CO", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "CT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "DE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "DC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "FL", + "relative_change": -0.037171430237584874, + "absolute_change": -12515389.417038918, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "GA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "HI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "ID", + "relative_change": -8.714356196712921e-06, + "absolute_change": -92.81887292861938, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "IL", + "relative_change": -6.484094955654378e-07, + "absolute_change": -127.59807059168816, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "IN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "IA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "KS", + "relative_change": 0.02178292270244223, + "absolute_change": 1251593.6825368255, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "KY", + "relative_change": -0.010637750292372622, + "absolute_change": -1.5735733507124223, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "LA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "ME", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MD", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MS", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MO", + "relative_change": -9.734376568026846e-09, + "absolute_change": -0.4293834939599037, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NV", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NJ", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NM", + "relative_change": 1.4897049891328236e-05, + "absolute_change": 888.5528917387128, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NY", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "ND", + "relative_change": 0.09504402234161904, + "absolute_change": 44.77018893590139, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "OH", + "relative_change": 1.9287845264817622e-05, + "absolute_change": 2104.037481069565, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "OK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "OR", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "PA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "RI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "SC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "SD", + "relative_change": 2.445516903920343e-07, + "absolute_change": 1.4206442860886455, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "TN", + "relative_change": 0.15834041628941534, + "absolute_change": 19029139.827849388, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "TX", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "UT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "VT", + "relative_change": 0.020457570998109725, + "absolute_change": 14741856.041668296, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "VA", + "relative_change": 0.020571941238345593, + "absolute_change": 5126607.2922079265, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "WA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "WV", + "relative_change": 0.1277136215585162, + "absolute_change": 1191558.9248193502, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "WI", + "relative_change": -0.1568910652614762, + "absolute_change": -39110534.90131056, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "WY", + "relative_change": 0.04038033587970585, + "absolute_change": 731017.3798192106, + "flagged": false + } + ] + } +} diff --git a/experiments/us-childcare-attendance/calendar-review-2.2.1-source-stage.json b/experiments/us-childcare-attendance/calendar-review-2.2.1-source-stage.json new file mode 100644 index 000000000..3df1fcbed --- /dev/null +++ b/experiments/us-childcare-attendance/calendar-review-2.2.1-source-stage.json @@ -0,0 +1,1994 @@ +{ + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "calendar_bounds": { + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568", + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "missing_calendar": "uninformative 0--168 hours and 0--7 days" + }, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "source_child_count": 11745, + "source_attrition": [ + { + "status": "age_out_of_scope", + "n": 134, + "child_weight": 633390.6468148227 + }, + { + "status": "ambiguous_calendar", + "n": 882, + "child_weight": 3918044.035953992 + }, + { + "status": "complete", + "n": 7460, + "child_weight": 32249785.682044942 + }, + { + "status": "missing_calendar", + "n": 3095, + "child_weight": 14061828.648228496 + }, + { + "status": "partial_calendar", + "n": 174, + "child_weight": 847769.9869632281 + } + ], + "under13_complete_weight_share": 0.6313901604255374, + "seed": 915, + "evaluation_design": "fixed household diagnostic split; not final population certification", + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "training_children": 5988, + "heldout_children": 1472, + "unsupported_heldout_children": 30, + "unsupported_heldout_weight": 153817.788204796, + "household_overlap": 0, + "comparisons": [ + { + "grouping": "all", + "group": "all", + "n": 1442, + "observed": { + "participation": 0.47956011362829676, + "days_per_week": 1.94220990502671, + "hours_per_week": 14.670259928481958 + }, + "predicted": { + "participation": 0.4547372440086608, + "days_per_week": 1.7986704844660344, + "hours_per_week": 13.001295500494344 + } + }, + { + "grouping": "age", + "group": "0", + "n": 87, + "observed": { + "participation": 0.4749769477860246, + "days_per_week": 1.8705229048944185, + "hours_per_week": 15.234832555457738 + }, + "predicted": { + "participation": 0.21347668238234924, + "days_per_week": 0.7762397588546358, + "hours_per_week": 6.331944692101247 + } + }, + { + "grouping": "age", + "group": "1", + "n": 113, + "observed": { + "participation": 0.6026124718926947, + "days_per_week": 2.2004884644301415, + "hours_per_week": 16.058889950232714 + }, + "predicted": { + "participation": 0.5817111215090339, + "days_per_week": 2.3867359768549528, + "hours_per_week": 20.29503642359935 + } + }, + { + "grouping": "age", + "group": "2", + "n": 107, + "observed": { + "participation": 0.6827728698846081, + "days_per_week": 3.2446932739752876, + "hours_per_week": 32.643365116161064 + }, + "predicted": { + "participation": 0.721108922787169, + "days_per_week": 2.9279814704204314, + "hours_per_week": 25.4484971084278 + } + }, + { + "grouping": "age", + "group": "3", + "n": 105, + "observed": { + "participation": 0.5478113606887365, + "days_per_week": 2.4737318877881727, + "hours_per_week": 18.774571500322175 + }, + "predicted": { + "participation": 0.7525857598038783, + "days_per_week": 3.556893850206531, + "hours_per_week": 31.34897414405891 + } + }, + { + "grouping": "age", + "group": "4", + "n": 115, + "observed": { + "participation": 0.6853382748904278, + "days_per_week": 3.133535876664359, + "hours_per_week": 22.72675588135229 + }, + "predicted": { + "participation": 0.6264622224091229, + "days_per_week": 2.555534029105278, + "hours_per_week": 22.558086951188297 + } + }, + { + "grouping": "age", + "group": "5", + "n": 109, + "observed": { + "participation": 0.45965467004039157, + "days_per_week": 2.204288116474054, + "hours_per_week": 16.671100530443887 + }, + "predicted": { + "participation": 0.5197893305690322, + "days_per_week": 2.0628456061601703, + "hours_per_week": 14.660711473842793 + } + }, + { + "grouping": "age", + "group": "6", + "n": 121, + "observed": { + "participation": 0.37767600901948256, + "days_per_week": 1.4233675361325482, + "hours_per_week": 11.368361596236443 + }, + "predicted": { + "participation": 0.3812603191662228, + "days_per_week": 1.344172188177959, + "hours_per_week": 6.687190574415363 + } + }, + { + "grouping": "age", + "group": "7", + "n": 121, + "observed": { + "participation": 0.2903318905157446, + "days_per_week": 0.9137564001326794, + "hours_per_week": 4.425088819370026 + }, + "predicted": { + "participation": 0.3316072853951072, + "days_per_week": 1.3098426672238894, + "hours_per_week": 7.381236186215511 + } + }, + { + "grouping": "age", + "group": "8", + "n": 136, + "observed": { + "participation": 0.33161676756925296, + "days_per_week": 1.2251387657453359, + "hours_per_week": 6.71788070980216 + }, + "predicted": { + "participation": 0.35465278512495324, + "days_per_week": 1.3642638058954168, + "hours_per_week": 9.725344329820171 + } + }, + { + "grouping": "age", + "group": "9", + "n": 101, + "observed": { + "participation": 0.4569510479920196, + "days_per_week": 1.674346958462562, + "hours_per_week": 7.805739183708693 + }, + "predicted": { + "participation": 0.396876880067868, + "days_per_week": 1.3966673442424729, + "hours_per_week": 8.701466574792914 + } + }, + { + "grouping": "age", + "group": "10", + "n": 105, + "observed": { + "participation": 0.45503949077471245, + "days_per_week": 1.5782906105470733, + "hours_per_week": 12.426848636692846 + }, + "predicted": { + "participation": 0.17752112044794535, + "days_per_week": 0.6469841431239514, + "hours_per_week": 3.596759032644189 + } + }, + { + "grouping": "age", + "group": "11", + "n": 119, + "observed": { + "participation": 0.41662598750149954, + "days_per_week": 1.8643111020323588, + "hours_per_week": 12.941021091087745 + }, + "predicted": { + "participation": 0.4008574857176407, + "days_per_week": 1.339718142783517, + "hours_per_week": 7.024111200026524 + } + }, + { + "grouping": "age", + "group": "12", + "n": 103, + "observed": { + "participation": 0.46408861423609865, + "days_per_week": 1.4945247924023801, + "hours_per_week": 11.114322042194766 + }, + "predicted": { + "participation": 0.43591150819042584, + "days_per_week": 1.7008936429461807, + "hours_per_week": 7.10555160431239 + } + }, + { + "grouping": "region", + "group": "1", + "n": 187, + "observed": { + "participation": 0.5340539220646277, + "days_per_week": 2.4009930157522064, + "hours_per_week": 14.79000641069395 + }, + "predicted": { + "participation": 0.6359603067185889, + "days_per_week": 2.7160385976574153, + "hours_per_week": 21.24487930853725 + } + }, + { + "grouping": "region", + "group": "2", + "n": 335, + "observed": { + "participation": 0.46285701128880247, + "days_per_week": 1.8453473655274784, + "hours_per_week": 15.352184287431765 + }, + "predicted": { + "participation": 0.41283532735257467, + "days_per_week": 1.4868890394545802, + "hours_per_week": 9.329182591248077 + } + }, + { + "grouping": "region", + "group": "3", + "n": 470, + "observed": { + "participation": 0.4328632075166446, + "days_per_week": 1.8236781494293404, + "hours_per_week": 15.35364160426729 + }, + "predicted": { + "participation": 0.4184231306502971, + "days_per_week": 1.5947483523709618, + "hours_per_week": 10.342311458512322 + } + }, + { + "grouping": "region", + "group": "4", + "n": 450, + "observed": { + "participation": 0.5171827642556369, + "days_per_week": 1.8475690827448323, + "hours_per_week": 13.04393396272379 + }, + "predicted": { + "participation": 0.4063739455351018, + "days_per_week": 1.670368549893466, + "hours_per_week": 13.748230642009998 + } + }, + { + "grouping": "parent_work_status", + "group": "-1", + "n": 13, + "observed": { + "participation": 0.253295875991658, + "days_per_week": 0.8671327195533685, + "hours_per_week": 3.515415042668932 + }, + "predicted": { + "participation": 0.12949135028799522, + "days_per_week": 0.5134069370080796, + "hours_per_week": 3.2849650228565768 + } + }, + { + "grouping": "parent_work_status", + "group": "0", + "n": 150, + "observed": { + "participation": 0.2939873489805854, + "days_per_week": 1.1857568669020946, + "hours_per_week": 10.001769026104405 + }, + "predicted": { + "participation": 0.20052896295212805, + "days_per_week": 0.7861821143968067, + "hours_per_week": 6.547539835013359 + } + }, + { + "grouping": "parent_work_status", + "group": "1", + "n": 543, + "observed": { + "participation": 0.2512596429034898, + "days_per_week": 0.8664048151368835, + "hours_per_week": 5.612021341518408 + }, + "predicted": { + "participation": 0.30234830539829555, + "days_per_week": 0.9663278582430083, + "hours_per_week": 5.557806485223704 + } + }, + { + "grouping": "parent_work_status", + "group": "2", + "n": 736, + "observed": { + "participation": 0.6462583482271946, + "days_per_week": 2.714084969528804, + "hours_per_week": 21.02161873348801 + }, + "predicted": { + "participation": 0.5856324643226721, + "days_per_week": 2.4572831629804637, + "hours_per_week": 18.54158986890966 + } + } + ], + "production_ready": false, + "limitations": [ + "Only complete, unambiguous calendars enter this holdout; source selection remains unvalidated.", + "The diagnostic matches age and caller-specified covariates; it is not a nationally validated fitted model.", + "Sibling assignments, mixed providers, older-child care and scalar monthly conversion need validation.", + "No full Microcosm population build or state CCDF distribution is certified by this source-only report." + ], + "sibling_dependence": { + "rho": 0.7413149380294699, + "unconstrained_rho": 0.7413149380294699, + "households": 1941, + "observed_both_in_care": 0.32858869865910467, + "independent_both_in_care": 0.2585427028841666, + "shared_both_in_care": 0.3530315526045447, + "estimation": "youngest pair in fully observed households; household design weights" + }, + "selection_and_cross_validation": { + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "calendar_bounds": { + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568", + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "missing_calendar": "uninformative 0--168 hours and 0--7 days" + }, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "seed": 271828, + "design": "five-fold household-separated conditional-expectation diagnostic", + "coverage": [ + { + "grouping": "questionnaire_version", + "group": "1", + "n": 8516, + "weight": 37015599.704962164, + "usable_weight_share": 0.8712484989868113 + }, + { + "grouping": "questionnaire_version", + "group": "2", + "n": 1716, + "weight": 7945306.22844611, + "usable_weight_share": 0.0 + }, + { + "grouping": "questionnaire_version", + "group": "3", + "n": 1379, + "weight": 6116522.419782387, + "usable_weight_share": 0.0 + }, + { + "grouping": "age", + "group": "0", + "n": 709, + "weight": 3159547.2696341733, + "usable_weight_share": 0.6556513621184303 + }, + { + "grouping": "age", + "group": "1", + "n": 856, + "weight": 3710311.739747545, + "usable_weight_share": 0.6518631977426506 + }, + { + "grouping": "age", + "group": "2", + "n": 906, + "weight": 4112848.861546397, + "usable_weight_share": 0.6567885484115844 + }, + { + "grouping": "age", + "group": "3", + "n": 927, + "weight": 4191268.180093972, + "usable_weight_share": 0.5836151261043054 + }, + { + "grouping": "age", + "group": "4", + "n": 890, + "weight": 3761621.476875998, + "usable_weight_share": 0.6069150244376095 + }, + { + "grouping": "age", + "group": "5", + "n": 884, + "weight": 3759953.5032736305, + "usable_weight_share": 0.6441250249176611 + }, + { + "grouping": "age", + "group": "6", + "n": 954, + "weight": 4259102.717846392, + "usable_weight_share": 0.6213110691400029 + }, + { + "grouping": "age", + "group": "7", + "n": 944, + "weight": 4191490.05150999, + "usable_weight_share": 0.6014263712726516 + }, + { + "grouping": "age", + "group": "8", + "n": 925, + "weight": 3969583.419307067, + "usable_weight_share": 0.6776062606911202 + }, + { + "grouping": "age", + "group": "9", + "n": 921, + "weight": 4036325.188020362, + "usable_weight_share": 0.6661696977311178 + }, + { + "grouping": "age", + "group": "10", + "n": 884, + "weight": 3707790.894951107, + "usable_weight_share": 0.6220814618665044 + }, + { + "grouping": "age", + "group": "11", + "n": 908, + "weight": 4069233.422108399, + "usable_weight_share": 0.6084497314858798 + }, + { + "grouping": "age", + "group": "12", + "n": 903, + "weight": 4148351.6282756263, + "usable_weight_share": 0.6217216150291205 + }, + { + "grouping": "region", + "group": "1", + "n": 1468, + "weight": 8153076.12536276, + "usable_weight_share": 0.6401722331669089 + }, + { + "grouping": "region", + "group": "2", + "n": 2680, + "weight": 10714972.208999828, + "usable_weight_share": 0.6330942004076335 + }, + { + "grouping": "region", + "group": "3", + "n": 4275, + "weight": 20022339.81304313, + "usable_weight_share": 0.6249460927360144 + }, + { + "grouping": "region", + "group": "4", + "n": 3188, + "weight": 12187040.205784943, + "usable_weight_share": 0.634603874645437 + }, + { + "grouping": "parent_work_status", + "group": "-1", + "n": 188, + "weight": 819575.738509818, + "usable_weight_share": 0.646736557730207 + }, + { + "grouping": "parent_work_status", + "group": "0", + "n": 1470, + "weight": 5301911.400981113, + "usable_weight_share": 0.6698890755679009 + }, + { + "grouping": "parent_work_status", + "group": "1", + "n": 3380, + "weight": 14009836.058523985, + "usable_weight_share": 0.7212981495115555 + }, + { + "grouping": "parent_work_status", + "group": "2", + "n": 6573, + "weight": 30946105.155175745, + "usable_weight_share": 0.5836849144158337 + }, + { + "grouping": "income_band", + "group": "0", + "n": 120, + "weight": 497291.815717528, + "usable_weight_share": 0.602001589054288 + }, + { + "grouping": "income_band", + "group": "1", + "n": 2057, + "weight": 7466809.932490364, + "usable_weight_share": 0.6413274998297077 + }, + { + "grouping": "income_band", + "group": "2", + "n": 2904, + "weight": 10880663.16706181, + "usable_weight_share": 0.6487048847817203 + }, + { + "grouping": "income_band", + "group": "3", + "n": 2558, + "weight": 11325516.809686286, + "usable_weight_share": 0.6401496463974632 + }, + { + "grouping": "income_band", + "group": "4", + "n": 3134, + "weight": 15757011.988844048, + "usable_weight_share": 0.6309648019074636 + }, + { + "grouping": "income_band", + "group": "5", + "n": 838, + "weight": 5150134.639390623, + "usable_weight_share": 0.5652783862122169 + } + ], + "cross_validation": [ + { + "grouping": "all", + "group": "all", + "n": 7460, + "observed": { + "participation": 0.46514845107061753, + "days": 1.8750709563867467, + "hours": 14.240422572045741 + }, + "expected": { + "participation": 0.4654844290416027, + "days": 1.878527294011518, + "hours": 14.081114700859393 + } + }, + { + "grouping": "age", + "group": "0", + "n": 458, + "observed": { + "participation": 0.40007662898763713, + "days": 1.5207410031354076, + "hours": 12.391341719561105 + }, + "expected": { + "participation": 0.42043937266485903, + "days": 1.5581186938006875, + "hours": 12.778280226573155 + } + }, + { + "grouping": "age", + "group": "1", + "n": 585, + "observed": { + "participation": 0.5768442364096245, + "days": 2.3247221464109487, + "hours": 18.93194004904792 + }, + "expected": { + "participation": 0.5636534387398192, + "days": 2.2787632897750942, + "hours": 18.46136873433321 + } + }, + { + "grouping": "age", + "group": "2", + "n": 599, + "observed": { + "participation": 0.6119472630516792, + "days": 2.661365110302835, + "hours": 23.568671427585098 + }, + "expected": { + "participation": 0.615171451571855, + "days": 2.6668583554129937, + "hours": 24.008204825875836 + } + }, + { + "grouping": "age", + "group": "3", + "n": 597, + "observed": { + "participation": 0.6106570906701301, + "days": 2.6641302585227766, + "hours": 21.96346327818111 + }, + "expected": { + "participation": 0.6452189769582379, + "days": 2.8385499518769803, + "hours": 23.234965023661523 + } + }, + { + "grouping": "age", + "group": "4", + "n": 550, + "observed": { + "participation": 0.7046928755645677, + "days": 3.1467359328380096, + "hours": 25.30894736806148 + }, + "expected": { + "participation": 0.7168364294128767, + "days": 3.1704359925035326, + "hours": 25.23962440956216 + } + }, + { + "grouping": "age", + "group": "5", + "n": 581, + "observed": { + "participation": 0.5580840489623686, + "days": 2.527957605747102, + "hours": 20.351246817207983 + }, + "expected": { + "participation": 0.5580783794454302, + "days": 2.4817744855985993, + "hours": 19.696005730111843 + } + }, + { + "grouping": "age", + "group": "6", + "n": 611, + "observed": { + "participation": 0.38410943637037254, + "days": 1.5233703763582376, + "hours": 9.272995362839891 + }, + "expected": { + "participation": 0.3704517476571586, + "days": 1.4435320487985335, + "hours": 8.308626409800924 + } + }, + { + "grouping": "age", + "group": "7", + "n": 586, + "observed": { + "participation": 0.34047335603475937, + "days": 1.267585660002729, + "hours": 8.978033563109225 + }, + "expected": { + "participation": 0.32048663598972876, + "days": 1.2092330340598734, + "hours": 7.976819608666644 + } + }, + { + "grouping": "age", + "group": "8", + "n": 611, + "observed": { + "participation": 0.37000227568041516, + "days": 1.4234519706143929, + "hours": 8.822905923973602 + }, + "expected": { + "participation": 0.37441818500322505, + "days": 1.4678570808250095, + "hours": 8.581931573672641 + } + }, + { + "grouping": "age", + "group": "9", + "n": 590, + "observed": { + "participation": 0.3862968300759907, + "days": 1.373131779820256, + "hours": 9.825473717875598 + }, + "expected": { + "participation": 0.3658218612710925, + "days": 1.2745107095149821, + "hours": 9.212380152023707 + } + }, + { + "grouping": "age", + "group": "10", + "n": 541, + "observed": { + "participation": 0.39185689727904155, + "days": 1.3647219850376735, + "hours": 8.468134791861964 + }, + "expected": { + "participation": 0.3879904743599543, + "days": 1.313066433397897, + "hours": 7.6091158562940935 + } + }, + { + "grouping": "age", + "group": "11", + "n": 565, + "observed": { + "participation": 0.3768238596848206, + "days": 1.3633597325953704, + "hours": 8.143708694787577 + }, + "expected": { + "participation": 0.37027421084947587, + "days": 1.3896706621501198, + "hours": 8.180743029734462 + } + }, + { + "grouping": "age", + "group": "12", + "n": 586, + "observed": { + "participation": 0.35838594666001994, + "days": 1.3239431239565607, + "hours": 10.203528792841063 + }, + "expected": { + "participation": 0.37173621674013835, + "days": 1.447846572682685, + "hours": 10.94364602719194 + } + }, + { + "grouping": "region", + "group": "1", + "n": 929, + "observed": { + "participation": 0.4988625902951673, + "days": 2.101321934458425, + "hours": 14.697745432365767 + }, + "expected": { + "participation": 0.5341920187102704, + "days": 2.234373766910041, + "hours": 15.515545077772881 + } + }, + { + "grouping": "region", + "group": "2", + "n": 1654, + "observed": { + "participation": 0.495642471526947, + "days": 1.9378635600824832, + "hours": 14.438707404977198 + }, + "expected": { + "participation": 0.48657470779470846, + "days": 1.9053160452954483, + "hours": 13.830397580793818 + } + }, + { + "grouping": "region", + "group": "3", + "n": 2752, + "observed": { + "participation": 0.4310162776090592, + "days": 1.7482660126296112, + "hours": 14.16760866653331 + }, + "expected": { + "participation": 0.4254047590539008, + "days": 1.728432288982956, + "hours": 13.771990873343658 + } + }, + { + "grouping": "region", + "group": "4", + "n": 2125, + "observed": { + "participation": 0.470872102608504, + "days": 1.872465315119329, + "hours": 13.875678601794997 + }, + "expected": { + "participation": 0.46546295898430057, + "days": 1.857723153971244, + "hours": 13.833112421687238 + } + }, + { + "grouping": "parent_work_status", + "group": "-1", + "n": 122, + "observed": { + "participation": 0.34614706740243706, + "days": 1.1849281571656916, + "hours": 9.788566562075097 + }, + "expected": { + "participation": 0.373389275855184, + "days": 1.462386368172592, + "hours": 12.574282386813668 + } + }, + { + "grouping": "parent_work_status", + "group": "0", + "n": 1016, + "observed": { + "participation": 0.3096578455166947, + "days": 1.244408501915661, + "hours": 10.193456359940383 + }, + "expected": { + "participation": 0.2882996076692788, + "days": 1.1762845771341546, + "hours": 10.282450861819337 + } + }, + { + "grouping": "parent_work_status", + "group": "1", + "n": 2418, + "observed": { + "participation": 0.2864480974767621, + "days": 0.9529380212414282, + "hours": 6.42952602558992 + }, + "expected": { + "participation": 0.29059369126489437, + "days": 0.9858655333196232, + "hours": 6.764091600272923 + } + }, + { + "grouping": "parent_work_status", + "group": "2", + "n": 3904, + "observed": { + "participation": 0.5991891288528669, + "days": 2.535220374688929, + "hours": 19.536646150926547 + }, + "expected": { + "participation": 0.6008699918772364, + "days": 2.528223299633135, + "hours": 18.96579429859326 + } + }, + { + "grouping": "income_band", + "group": "0", + "n": 76, + "observed": { + "participation": 0.19070472825408744, + "days": 0.8431547354115522, + "hours": 5.587881885800679 + }, + "expected": { + "participation": 0.25300464764173586, + "days": 0.9988467887623982, + "hours": 7.43593331362669 + } + }, + { + "grouping": "income_band", + "group": "1", + "n": 1378, + "observed": { + "participation": 0.35684525807866907, + "days": 1.5280931021110342, + "hours": 12.098088591903252 + }, + "expected": { + "participation": 0.3773650597658377, + "days": 1.627338456412184, + "hours": 12.706694579809993 + } + }, + { + "grouping": "income_band", + "group": "2", + "n": 1922, + "observed": { + "participation": 0.4194011939997811, + "days": 1.7068232976926216, + "hours": 13.491053608546364 + }, + "expected": { + "participation": 0.4119472083085292, + "days": 1.7030609232530567, + "hours": 13.262000601507708 + } + }, + { + "grouping": "income_band", + "group": "3", + "n": 1632, + "observed": { + "participation": 0.4246978564102466, + "days": 1.7238735833385048, + "hours": 14.076591113511121 + }, + "expected": { + "participation": 0.4255788471352766, + "days": 1.704797441331804, + "hours": 13.264862389978802 + } + }, + { + "grouping": "income_band", + "group": "4", + "n": 1977, + "observed": { + "participation": 0.5221816116808028, + "days": 1.9968956951019248, + "hours": 14.35832226780555 + }, + "expected": { + "participation": 0.519705526319959, + "days": 1.9988673657729517, + "hours": 14.55106672367201 + } + }, + { + "grouping": "income_band", + "group": "5", + "n": 475, + "observed": { + "participation": 0.6883939484468758, + "days": 2.9203317046618578, + "hours": 20.476264713601847 + }, + "expected": { + "participation": 0.6762909354194406, + "days": 2.8292574855634296, + "hours": 19.43897806431697 + } + } + ], + "matching_levels": { + "age,region,parent_work_status,income_band": 7278, + "age,parent_work_status,income_band": 150, + "age,parent_work_status": 32 + }, + "sibling_validation": [ + { + "fold": 0, + "training_rho": 0.7504775690168417, + "households": 351, + "weight": 1627200.3809817089, + "observed_both": 0.3346110552302055, + "independent_both": 0.26023741618799584, + "coupled_both": 0.3228394147816889 + }, + { + "fold": 1, + "training_rho": 0.8095401305423818, + "households": 367, + "weight": 1640369.17044373, + "observed_both": 0.308478237709926, + "independent_both": 0.2538314963354507, + "coupled_both": 0.31777192913378116 + }, + { + "fold": 2, + "training_rho": 0.7176223341350483, + "households": 443, + "weight": 1849383.6729044288, + "observed_both": 0.3831182075641927, + "independent_both": 0.260592140353083, + "coupled_both": 0.3144997720634755 + }, + { + "fold": 3, + "training_rho": 0.8946850037821993, + "households": 398, + "weight": 1567825.4608580691, + "observed_both": 0.2954259187077949, + "independent_both": 0.2551329149477867, + "coupled_both": 0.3186981148017382 + }, + { + "fold": 4, + "training_rho": 0.8022505236076816, + "households": 382, + "weight": 1644777.832273697, + "observed_both": 0.3129856591731878, + "independent_both": 0.2695651435301845, + "coupled_both": 0.3411406780146054 + } + ], + "questionnaire_transport": [ + { + "questionnaire_version": 2, + "scored_children": 1690, + "unsupported_children": 0, + "observed": { + "regular_participation": 0.4166998042800092, + "regular_hours_per_week": 12.379208437570716 + }, + "expected": { + "regular_participation": 0.429264128691119, + "regular_hours_per_week": 14.800674181069196 + } + }, + { + "questionnaire_version": 3, + "scored_children": 1356, + "unsupported_children": 0, + "observed": { + "regular_participation": 0.38447915314763226, + "regular_hours_per_week": 10.163827277430636 + }, + "expected": { + "regular_participation": 0.40786334693307874, + "regular_hours_per_week": 13.921490221932158 + } + } + ], + "assumptions": [ + "Calendar selection is ignorable conditional on matching fields; not identified from these data.", + "Main reference-week schedules transfer to May/fall typical weeks; summer attendance is not observed.", + "Regular-care comparisons cannot validate days or irregular care in instruments without calendars." + ], + "production_ready": false + }, + "masked_calendar_validation": { + "seed": 161803, + "design": "whole-household masked-calendar test; regular weekly hours remain observed", + "comparisons": [ + { + "grouping": "all", + "group": "all", + "n": 1581, + "observed_days": 1.7176113066572272, + "imputed_days": 1.7931671544992573, + "observed_hours": 13.097316141278531, + "imputed_hours": 13.161738723028055 + }, + { + "grouping": "age", + "group": "0", + "n": 104, + "observed_days": 1.841126169101498, + "imputed_days": 1.757972840808916, + "observed_hours": 17.766331967357488, + "imputed_hours": 18.04127357697798 + }, + { + "grouping": "age", + "group": "1", + "n": 113, + "observed_days": 2.37969546844872, + "imputed_days": 2.466724275790995, + "observed_hours": 19.829328945193588, + "imputed_hours": 19.122886717221327 + }, + { + "grouping": "age", + "group": "2", + "n": 141, + "observed_days": 2.4591773765558673, + "imputed_days": 2.5150278262191854, + "observed_hours": 22.536051090399965, + "imputed_hours": 22.20070627284854 + }, + { + "grouping": "age", + "group": "3", + "n": 123, + "observed_days": 2.3763627081083216, + "imputed_days": 2.276649667113583, + "observed_hours": 20.251977914853146, + "imputed_hours": 19.002839959330025 + }, + { + "grouping": "age", + "group": "4", + "n": 115, + "observed_days": 3.137397964036117, + "imputed_days": 3.2507274717120613, + "observed_hours": 23.68360614421261, + "imputed_hours": 24.493916641155817 + }, + { + "grouping": "age", + "group": "5", + "n": 113, + "observed_days": 2.2242008794879244, + "imputed_days": 2.6293843819994196, + "observed_hours": 15.760856040214335, + "imputed_hours": 17.46780844312604 + }, + { + "grouping": "age", + "group": "6", + "n": 130, + "observed_days": 1.1830651060264654, + "imputed_days": 1.4124105587435267, + "observed_hours": 7.042175416036001, + "imputed_hours": 6.515374725210956 + }, + { + "grouping": "age", + "group": "7", + "n": 131, + "observed_days": 1.4073709771017413, + "imputed_days": 1.2967131682238184, + "observed_hours": 10.083939201157254, + "imputed_hours": 9.618996783594744 + }, + { + "grouping": "age", + "group": "8", + "n": 126, + "observed_days": 1.057579033652681, + "imputed_days": 1.0820232296805903, + "observed_hours": 8.256788366496435, + "imputed_hours": 6.9299612873656375 + }, + { + "grouping": "age", + "group": "9", + "n": 118, + "observed_days": 1.4349301372689758, + "imputed_days": 1.2570443106530333, + "observed_hours": 10.733568940718998, + "imputed_hours": 11.528485757775337 + }, + { + "grouping": "age", + "group": "10", + "n": 124, + "observed_days": 1.2058459898990705, + "imputed_days": 1.2067301677274491, + "observed_hours": 4.1774445652404655, + "imputed_hours": 4.342805855105561 + }, + { + "grouping": "age", + "group": "11", + "n": 120, + "observed_days": 0.9483350107584563, + "imputed_days": 1.2273618861530076, + "observed_hours": 5.566349482238208, + "imputed_hours": 6.3416466466885835 + }, + { + "grouping": "age", + "group": "12", + "n": 123, + "observed_days": 1.1181905452629102, + "imputed_days": 1.3377626847259545, + "observed_hours": 8.079018679724042, + "imputed_hours": 9.278796503817835 + }, + { + "grouping": "parent_work_status", + "group": "-1", + "n": 33, + "observed_days": 1.5430497710033617, + "imputed_days": 1.3274872915746017, + "observed_hours": 12.754941207431992, + "imputed_hours": 12.147679308677683 + }, + { + "grouping": "parent_work_status", + "group": "0", + "n": 233, + "observed_days": 1.3163214930511598, + "imputed_days": 1.4661772450887058, + "observed_hours": 9.57367968242547, + "imputed_hours": 9.490248507911081 + }, + { + "grouping": "parent_work_status", + "group": "1", + "n": 529, + "observed_days": 0.8935323002915262, + "imputed_days": 1.0535312696492358, + "observed_hours": 6.370457810059637, + "imputed_hours": 7.0815725747740155 + }, + { + "grouping": "parent_work_status", + "group": "2", + "n": 786, + "observed_days": 2.3152602893352414, + "imputed_days": 2.332856367184494, + "observed_hours": 17.994069548324816, + "imputed_hours": 17.722049473088507 + } + ], + "regular_hours_preserved": true, + "limitations": "Tests reconstruction where calendars exist; not a direct test of unobserved days in the other questionnaire instruments." + }, + "sibling_schedule_validation": { + "design": "household-separated partitions; exact integration of the implemented shared-rank donor CDFs", + "seed": 271828, + "validation_seed": null, + "partition": "all", + "splits": [ + { + "training_households": 5100, + "evaluation_households": 1269, + "household_overlap": 0 + }, + { + "training_households": 5108, + "evaluation_households": 1261, + "household_overlap": 0 + }, + { + "training_households": 5055, + "evaluation_households": 1314, + "household_overlap": 0 + }, + { + "training_households": 5071, + "evaluation_households": 1298, + "household_overlap": 0 + }, + { + "training_households": 5142, + "evaluation_households": 1227, + "household_overlap": 0 + } + ], + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "fallback_match_columns": [ + [ + "age", + "parent_work_status", + "income_band" + ], + [ + "age", + "parent_work_status" + ], + [ + "age" + ] + ], + "matching_counts": { + "age,region,parent_work_status,income_band": 4682, + "age,parent_work_status,income_band": 87, + "age,parent_work_status": 20 + }, + "training_rho": [ + 0.7504775690168417, + 0.8095401305423818, + 0.7176223341350483, + 0.8946850037821993, + 0.8022505236076816 + ], + "youngest_pairs": { + "households": 1941, + "household_weight": 8329556.517461634, + "observed": { + "participation": { + "joint_product": 0.3285886986591048, + "correlation": 0.577510777815278 + }, + "days": { + "joint_product": 5.9171615700449145, + "correlation": 0.5798886366650429 + }, + "weekly_hours": { + "joint_product": 367.6804958137289, + "correlation": 0.523457187358221 + } + }, + "independent": { + "participation": { + "joint_product": 0.2599357218299179, + "correlation": 0.14356484664250233 + }, + "days": { + "joint_product": 4.562554958882675, + "correlation": 0.1514064619097721 + }, + "weekly_hours": { + "joint_product": 274.5482618143516, + "correlation": 0.1290575794049498 + } + }, + "coupled": { + "participation": { + "joint_product": 0.3228241594928079, + "correlation": 0.39662161163709453 + }, + "days": { + "joint_product": 6.168391228908872, + "correlation": 0.44224735414975214 + }, + "weekly_hours": { + "joint_product": 393.50536137310974, + "correlation": 0.35635277128820114 + } + } + }, + "youngest_pairs_in_3plus_households": { + "households": 661, + "household_weight": 2458669.150522002, + "observed": { + "participation": { + "joint_product": 0.2728957065164463, + "correlation": 0.5341073068866067 + }, + "days": { + "joint_product": 5.084876229689592, + "correlation": 0.5617680576612079 + }, + "weekly_hours": { + "joint_product": 337.34705105325276, + "correlation": 0.5623528715201395 + } + }, + "independent": { + "participation": { + "joint_product": 0.26594831103314626, + "correlation": 0.1768906778018396 + }, + "days": { + "joint_product": 4.755017625871223, + "correlation": 0.1796772530434437 + }, + "weekly_hours": { + "joint_product": 288.78160178706247, + "correlation": 0.15022942733210107 + } + }, + "coupled": { + "participation": { + "joint_product": 0.32461663032314914, + "correlation": 0.41320572283269663 + }, + "days": { + "joint_product": 6.243213912824172, + "correlation": 0.44765187465853035 + }, + "weekly_hours": { + "joint_product": 406.53469377347056, + "correlation": 0.3715598543103152 + } + } + }, + "larger_households": { + "households": 661, + "observed": { + "mean_total_days": 4.509647234214243, + "mean_total_weekly_hours": 33.085374473048084, + "sd_total_days": 5.765302178946849, + "sd_total_weekly_hours": 56.21651776123905, + "all_children_attend": 0.18568592787006075 + }, + "independent": { + "mean_total_days": 5.652805180994538, + "mean_total_weekly_hours": 40.814235235209445, + "sd_total_days": 4.742171858563125, + "sd_total_weekly_hours": 43.69183090611876, + "all_children_attend": 0.10870430564775237 + }, + "coupled": { + "mean_total_days": 5.652805180994538, + "mean_total_weekly_hours": 40.814235235209445, + "sd_total_days": 5.826012333228911, + "sd_total_weekly_hours": 52.0732028760817, + "all_children_attend": 0.19850142013240785 + } + }, + "production_ready": false, + "diagnostic_screen": { + "passed": false, + "checks": [ + { + "metric": "youngest_pairs.participation.joint_product", + "absolute_gap": 0.005764539166296878, + "relative": false, + "limit": 0.05, + "passed": true + }, + { + "metric": "youngest_pairs.days.correlation", + "absolute_gap": 0.13764128251529073, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs.weekly_hours.correlation", + "absolute_gap": 0.16710441607001986, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs.days.joint_product", + "absolute_gap": 0.04245779938404666, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs.weekly_hours.joint_product", + "absolute_gap": 0.07023724634135614, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.participation.joint_product", + "absolute_gap": 0.051720923806702845, + "relative": false, + "limit": 0.05, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.days.correlation", + "absolute_gap": 0.11411618300267751, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.correlation", + "absolute_gap": 0.19079301720982428, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.days.joint_product", + "absolute_gap": 0.22780056599436455, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.joint_product", + "absolute_gap": 0.20509336751041, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.mean_total_days", + "absolute_gap": 0.2534916563112233, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.mean_total_weekly_hours", + "absolute_gap": 0.23360354492760613, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.sd_total_days", + "absolute_gap": 0.010530264051684455, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.sd_total_weekly_hours", + "absolute_gap": 0.07370280213290151, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.all_children_attend", + "absolute_gap": 0.0128154922623471, + "relative": false, + "limit": 0.05, + "passed": true + } + ], + "interpretation": "provisional diagnostic screens; not publication authorization" + } + }, + "noncalendar_bridge": { + "seed": 915, + "completed_children": 3046, + "unsupported_children": 0, + "observed": "regular weekly hours from May/fall questionnaire", + "imputed": "attended days and irregular care jointly from nearest regular-hour calendar donors", + "assumption": "conditional calendar pattern and irregular care transfer across questionnaire instruments" + }, + "candidate_frame_written": true, + "environment": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "microcosm-build": "0.1.0", + "microcosm-frame": "0.1.0", + "policyengine-us": "2.2.1", + "python": "3.13.5" + }, + "code_sha256": { + "prepare_us_childcare_attendance.py": "ca4f504a652a9005f692cbd008f430fff0a25bbe32629b75eca80f0be0c7fa51", + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "nsece_childcare.py": "0e72ff9388f8f59147305f07effec2b99dada0f91599727cc9e58ad4feb6edbb", + "nsece_childcare_bridge.py": "70a7edea8b28c6da21ff4fa9bb220766a3e6cd714926684af29bdba1a8421b0a", + "nsece_childcare_sibling_validation.py": "abd2a4c88d3c4585e055fae93be3ac00c060405fc6e24bb079b67196aa88e422", + "nsece_childcare_dependence.py": "1c5123a77f84460ba517d2b4c6c3e04ae658bf36e9cf54ed69ddbcacc85efc09", + "childcare_attendance_stage.py": "42e777b0edfc813d79204bc2932fe429d6a48cd2866397560a7386cbee54dadb", + "childcare_attendance_receipt.py": "0950fce7f372ca4b240cd055c931f5f8fe070223fd68504a3ea9cfbc4e16c645", + "childcare_sensitivity.py": "a3d370bcaf78b609d81c542dc774b7dab0202ea02f53f80135417320840e06ac", + "nsece_childcare_assessment.py": "537d5d839ce9df4f1772ee887597811990aab5b7f10a863b70fe6630583fa3b7", + "nsece_childcare_pooling.py": "a779a0db7fddbb9e33aa7f8c8f7752b5f4a083309bb7d8f03d6ab72555a439f2", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "childcare.py": "a8502e1fc15457a7f120936a8940fbb51cba3e2299d92ca9cd69b749f6deea2f", + "childcare_attendance_source.json": "c5beeeb09ab330c305e3250bc7db5a5003336d26fa508872211cb18958ab9e97", + "education_assistance_source.py": "e259e3fce64fdcab62953f79a1aa41719f81c64c7c5dc1a63f8b1e493ff5f83a", + "geography_constants.py": "96938b5dd6bba8f10d0f52d10a9cdcbc16ae9506c4424f58e10347998ff02a8a", + "uv.lock": "635accf67e2b33ed9a1af306928079d42c0b105d65e030ea597fdb26cd5902a1" + }, + "candidate_checkpoint_sha256": "31e4a80cc896aeb769ea034a60e8be68c81bed35a52ff52e27ca62d8cb46f40d", + "parent_population_sha256": "48b9d479fb4fd1c3537f9383ce4697d130b6f618658409d74f6233c43b994c7e", + "production_stage_executed": true, + "candidate_receipts": { + "nsece_childcare_attendance": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "calendar_bounds": { + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568", + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "missing_calendar": "uninformative 0--168 hours and 0--7 days" + }, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ], + "noncalendar_bridge": { + "seed": 915, + "completed_children": 3046, + "unsupported_children": 0, + "observed": "regular weekly hours from May/fall questionnaire", + "imputed": "attended days and irregular care jointly from nearest regular-hour calendar donors", + "assumption": "conditional calendar pattern and irregular care transfer across questionnaire instruments" + }, + "seed": 915, + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "fallback_match_columns": [ + [ + "age", + "parent_work_status", + "income_band" + ], + [ + "age", + "parent_work_status" + ], + [ + "age" + ] + ], + "sibling_dependence": 0.7413149380294699, + "candidate_only": true + }, + "childcare_predictor_harmonization": { + "source": "ASEC resident parent line pointers", + "parent_universe": "parents of any child age 0 through 12 in household", + "work_measure": "hours_worked_last_week > 0", + "geography": "Census region from target state_fips", + "income_source_receipts": [ + { + "income_year": 2022, + "sha256": "19b56537e50e7663f954361ef2bb5ce9cef8d9d45f156fe1a69a99b654198ffe", + "matched_people": 54464, + "source_rows": 146133 + }, + { + "income_year": 2023, + "sha256": "21a2b9e0e4b08534563578a45acad77868af4ae9a7d46f23776b707d4a559aa7", + "matched_people": 54654, + "source_rows": 144265 + }, + { + "income_year": 2024, + "sha256": "06921fe83fc66c907e6c7b86b82255dc70458ee7d76258fc48297cb34f0c06b5", + "matched_people": 57203, + "source_rows": 142125 + } + ], + "income": "Household sum of measured ASEC PTOTVAL, CPI-U adjusted from source year to 2023 dollars" + }, + "childcare_outside_domain_baseline": { + "engine_version": "2.2.1", + "values": { + "childcare_attending_days_per_month": 0.0, + "childcare_days_per_week": 0.0, + "childcare_hours_per_day": 0.0 + }, + "inherited_counts": { + "childcare_attending_days_per_month": 134432, + "childcare_days_per_week": 134432, + "childcare_hours_per_day": 134432 + }, + "interpretation": "baseline retained; not evidence of nonattendance outside ages 0-12" + }, + "childcare_attendance_stage": { + "stage": "nsece_childcare_attendance", + "outputs": [ + "childcare_attending_days_per_month", + "childcare_days_per_week", + "childcare_hours_per_day" + ], + "seed": 915, + "operations": [ + { + "kind": "derive_childcare_inputs", + "operation": "calendar_attendance", + "age_min": 0, + "age_max": 12 + }, + { + "kind": "fit", + "operation": "fit_sibling_dependence", + "rho": 0.7413149380294699 + }, + { + "kind": "derive_childcare_inputs", + "operation": "regular_hours_schedule_bridge", + "nearest_donors": 10 + }, + { + "kind": "derive", + "operation": "harmonize_asec_childcare_predictors" + }, + { + "kind": "derive_childcare_inputs", + "operation": "joint_weighted_schedule_transfer", + "preserve_observed": true + }, + { + "kind": "export_policy", + "operation": "inherit_engine_baseline" + } + ], + "sibling_dependence": { + "rho": 0.7413149380294699, + "unconstrained_rho": 0.7413149380294699, + "households": 1941, + "observed_both_in_care": 0.32858869865910467, + "independent_both_in_care": 0.2585427028841666, + "shared_both_in_care": 0.3530315526045447, + "estimation": "youngest pair in fully observed households; household design weights" + }, + "modeled_age_domain": [ + 0, + 12 + ], + "outside_domain_policy": "inherit_engine_baseline" + }, + "childcare_attendance_binding": { + "schema_version": 1, + "binding_sha256": "12d583e1e77f9c53ba57b80c5dc16680e073dcd4ca5ba05e4df1c276b0872e99", + "execution_sha256": "c63f973a39fbe658f31b4408d97363fb5e9a684ad4b897c01b0f8b22e85746a7", + "source_people": 166321, + "retained_people": 166321, + "execution": { + "recipe": { + "contract_sha256": "ae648c6cb0e2838fdf142975e9c536eb0683d9630fd1738096d524222ffb01dc", + "runtime_versions": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "policyengine-us": "2.2.1" + }, + "code_sha256": { + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "nsece_childcare.py": "0e72ff9388f8f59147305f07effec2b99dada0f91599727cc9e58ad4feb6edbb", + "nsece_childcare_bridge.py": "70a7edea8b28c6da21ff4fa9bb220766a3e6cd714926684af29bdba1a8421b0a", + "nsece_childcare_dependence.py": "1c5123a77f84460ba517d2b4c6c3e04ae658bf36e9cf54ed69ddbcacc85efc09", + "childcare_attendance_stage.py": "42e777b0edfc813d79204bc2932fe429d6a48cd2866397560a7386cbee54dadb", + "childcare_attendance_receipt.py": "0950fce7f372ca4b240cd055c931f5f8fe070223fd68504a3ea9cfbc4e16c645" + } + }, + "context": { + "nsece_childcare_attendance": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "calendar_bounds": { + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568", + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "missing_calendar": "uninformative 0--168 hours and 0--7 days" + }, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ], + "noncalendar_bridge": { + "seed": 915, + "completed_children": 3046, + "unsupported_children": 0, + "observed": "regular weekly hours from May/fall questionnaire", + "imputed": "attended days and irregular care jointly from nearest regular-hour calendar donors", + "assumption": "conditional calendar pattern and irregular care transfer across questionnaire instruments" + }, + "seed": 915, + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "fallback_match_columns": [ + [ + "age", + "parent_work_status", + "income_band" + ], + [ + "age", + "parent_work_status" + ], + [ + "age" + ] + ], + "sibling_dependence": 0.7413149380294699, + "candidate_only": true + }, + "childcare_predictor_harmonization": { + "source": "ASEC resident parent line pointers", + "parent_universe": "parents of any child age 0 through 12 in household", + "work_measure": "hours_worked_last_week > 0", + "geography": "Census region from target state_fips", + "income_source_receipts": [ + { + "income_year": 2022, + "sha256": "19b56537e50e7663f954361ef2bb5ce9cef8d9d45f156fe1a69a99b654198ffe", + "matched_people": 54464, + "source_rows": 146133 + }, + { + "income_year": 2023, + "sha256": "21a2b9e0e4b08534563578a45acad77868af4ae9a7d46f23776b707d4a559aa7", + "matched_people": 54654, + "source_rows": 144265 + }, + { + "income_year": 2024, + "sha256": "06921fe83fc66c907e6c7b86b82255dc70458ee7d76258fc48297cb34f0c06b5", + "matched_people": 57203, + "source_rows": 142125 + } + ], + "income": "Household sum of measured ASEC PTOTVAL, CPI-U adjusted from source year to 2023 dollars" + }, + "childcare_outside_domain_baseline": { + "engine_version": "2.2.1", + "values": { + "childcare_attending_days_per_month": 0.0, + "childcare_days_per_week": 0.0, + "childcare_hours_per_day": 0.0 + }, + "inherited_counts": { + "childcare_attending_days_per_month": 134432, + "childcare_days_per_week": 134432, + "childcare_hours_per_day": 134432 + }, + "interpretation": "baseline retained; not evidence of nonattendance outside ages 0-12" + }, + "childcare_attendance_stage": { + "stage": "nsece_childcare_attendance", + "outputs": [ + "childcare_attending_days_per_month", + "childcare_days_per_week", + "childcare_hours_per_day" + ], + "seed": 915, + "operations": [ + { + "kind": "derive_childcare_inputs", + "operation": "calendar_attendance", + "age_min": 0, + "age_max": 12 + }, + { + "kind": "fit", + "operation": "fit_sibling_dependence", + "rho": 0.7413149380294699 + }, + { + "kind": "derive_childcare_inputs", + "operation": "regular_hours_schedule_bridge", + "nearest_donors": 10 + }, + { + "kind": "derive", + "operation": "harmonize_asec_childcare_predictors" + }, + { + "kind": "derive_childcare_inputs", + "operation": "joint_weighted_schedule_transfer", + "preserve_observed": true + }, + { + "kind": "export_policy", + "operation": "inherit_engine_baseline" + } + ], + "sibling_dependence": { + "rho": 0.7413149380294699, + "unconstrained_rho": 0.7413149380294699, + "households": 1941, + "observed_both_in_care": 0.32858869865910467, + "independent_both_in_care": 0.2585427028841666, + "shared_both_in_care": 0.3530315526045447, + "estimation": "youngest pair in fully observed households; household design weights" + }, + "modeled_age_domain": [ + 0, + 12 + ], + "outside_domain_policy": "inherit_engine_baseline" + } + } + } + } + }, + "native_candidate_written": true, + "native_candidate_sha256": "e7b9f98c592ae34e58e27a1e6affc68e6b4ab82b5f0427eb7c12026fab80c510" +} diff --git a/experiments/us-childcare-attendance/calendar-review-2.2.1-verification.json b/experiments/us-childcare-attendance/calendar-review-2.2.1-verification.json new file mode 100644 index 000000000..3d03500f5 --- /dev/null +++ b/experiments/us-childcare-attendance/calendar-review-2.2.1-verification.json @@ -0,0 +1,39 @@ +{ + "parent_sha256": "48b9d479fb4fd1c3537f9383ce4697d130b6f618658409d74f6233c43b994c7e", + "checkpoint_sha256": "31e4a80cc896aeb769ea034a60e8be68c81bed35a52ff52e27ca62d8cb46f40d", + "native_sha256": "e7b9f98c592ae34e58e27a1e6affc68e6b4ab82b5f0427eb7c12026fab80c510", + "source_stage_report_sha256": "7406a90591e610e75c679e05bdaf0ca8f4291c31444647553b21f7215ea0b3e1", + "verification_code_sha256": "3b4cd482f6465325f66d1d8e1b3d680b281073d7dcb6b4bbedc7899e16d27ed4", + "attendance_recipe": { + "code_sha256": { + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "childcare_attendance_receipt.py": "0950fce7f372ca4b240cd055c931f5f8fe070223fd68504a3ea9cfbc4e16c645", + "childcare_attendance_stage.py": "42e777b0edfc813d79204bc2932fe429d6a48cd2866397560a7386cbee54dadb", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "nsece_childcare.py": "0e72ff9388f8f59147305f07effec2b99dada0f91599727cc9e58ad4feb6edbb", + "nsece_childcare_bridge.py": "70a7edea8b28c6da21ff4fa9bb220766a3e6cd714926684af29bdba1a8421b0a", + "nsece_childcare_dependence.py": "1c5123a77f84460ba517d2b4c6c3e04ae658bf36e9cf54ed69ddbcacc85efc09" + }, + "contract_sha256": "ae648c6cb0e2838fdf142975e9c536eb0683d9630fd1738096d524222ffb01dc", + "runtime_versions": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "policyengine-us": "2.2.1" + } + }, + "content_binding_sha256": "12d583e1e77f9c53ba57b80c5dc16680e073dcd4ca5ba05e4df1c276b0872e99", + "engine_version": "2.2.1", + "core_version": "3.32.5", + "people": 166321, + "households": 57240, + "under13_children": 31889, + "verified_native_loaders": [ + "microcosm.build.us_runtime.h5_io.load_legacy_calibrated_us_h5", + "microcosm.build.us_runtime.l0_refit_export.load_us_frame" + ], + "all_original_columns_and_weights_preserved": true, + "all_attendance_values_preserved_on_native_reload": true, + "comparison": "exact values and dtypes, normalizing only pandas string storage backend", + "interpretation": "artifact integrity and preservation only; no statistical certification or publication", + "production_ready": false +} diff --git a/experiments/us-childcare-attendance/calendar-selection-plan.txt b/experiments/us-childcare-attendance/calendar-selection-plan.txt new file mode 100644 index 000000000..7fe68737d --- /dev/null +++ b/experiments/us-childcare-attendance/calendar-selection-plan.txt @@ -0,0 +1,46 @@ +Calendar selection and household composition investigation, 2026-09-16. + +All previously inspected NSECE records are development evidence. This plan +does not create an untouched validation sample or alter the existing screens. + +1. Audit information loss before fitting another model. The source guide + (HH-334) says unreported calendar time can be encoded as parental care, and + calendar-derived summaries do not account for the missing-calendar flag. + Therefore the regular-instrument summaries are not independent observed + outcomes for partial/missing calendars. For complete-but-ambiguous calendars, + retain definite ECE hours/days as lower bounds and allow every unresolved + block to be ECE in upper bounds. For partial calendars, code 0 also remains + unresolved; fully missing calendars have no informative attendance bounds. + Bounds are not imputations, observed zeros, or confidence intervals. + +2. Compare the existing pooled population-moment model with one predetermined + composition-aware empirical model. Keep exact age and whole joint day/hour + schedules. Add under-6 count, school-age (6-12) count, youngest-child age band + (0-2, 3-5, 6-12), and whether a child has a younger sibling. Counts are capped + at three and use the full roster before calendar selection. Pool in order: + age; age + under-13 count; + under-6 count; + school-age count; + + youngest-child age band; + younger-sibling indicator; + parent work; + + income band; + region. Retain strength 10 and the shared population-moment + dependence objective. No new source-only response indicator enters target + predictors, and no smoothing or dependence coefficient is selected by the + evaluation outcomes. + +3. Use the same five whole-household folds and all 15 household plus 18 observed- + child checks. Exclude fitting households from their own donor distributions. + Keep the unresolved-sibling subgroup visible. Report conditional-mean and + random-draw errors, correlation/joint-moment compatibility and donor support. + +4. Use the calendar bounds to test the consequences of the source exclusions, + including whether uncertainty is concentrated among high-attendance families. + Do not promote a completion rule merely because it makes validation pass. + Any additional model must have a separately recorded rationale and evaluation + plan before its results, and must preserve the measured parts of calendars. + +5. Rebuild the current approved-in-code attendance recipe from the original + SHA-pinned parent under PolicyEngine-US 2.2.1. Verify both native loaders, + content/runtime receipts, every original column/weight and all attendance + rows. Rerun all-state attendance comparisons and noncalendar stress scenarios. + A model adoption requires equivalent source/target/bridge integration and a + fresh candidate; diagnostic models never silently replace the build recipe. + Statistical source selection, population qualification, and publication are + separate. No population publication or relaxed release gate is authorized. diff --git a/experiments/us-childcare-attendance/calendar-selection-validation.json b/experiments/us-childcare-attendance/calendar-selection-validation.json new file mode 100644 index 000000000..b53bff8ad --- /dev/null +++ b/experiments/us-childcare-attendance/calendar-selection-validation.json @@ -0,0 +1,1896 @@ +{ + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "calendar_bounds": { + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568", + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "missing_calendar": "uninformative 0--168 hours and 0--7 days" + }, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "plan_sha256": "09064740a3e074c83188ff3c0323703639b29aae80cbc627c7e6716ada56cceb", + "recipe": { + "contract_sha256": "ae648c6cb0e2838fdf142975e9c536eb0683d9630fd1738096d524222ffb01dc", + "runtime_versions": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "policyengine-us": "2.2.1" + }, + "code_sha256": { + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "nsece_childcare.py": "0e72ff9388f8f59147305f07effec2b99dada0f91599727cc9e58ad4feb6edbb", + "nsece_childcare_bridge.py": "70a7edea8b28c6da21ff4fa9bb220766a3e6cd714926684af29bdba1a8421b0a", + "nsece_childcare_dependence.py": "1c5123a77f84460ba517d2b4c6c3e04ae658bf36e9cf54ed69ddbcacc85efc09", + "childcare_attendance_stage.py": "42e777b0edfc813d79204bc2932fe429d6a48cd2866397560a7386cbee54dadb", + "childcare_attendance_receipt.py": "0950fce7f372ca4b240cd055c931f5f8fe070223fd68504a3ea9cfbc4e16c645" + } + }, + "diagnostic_code_sha256": { + "validate_us_childcare_calendar_selection.py": "83905fb60bd6b97bd4338177afce1a329b0bc6463a12c6fb9c27616f982ca60a", + "nsece_childcare_pooling.py": "a779a0db7fddbb9e33aa7f8c8f7752b5f4a083309bb7d8f03d6ab72555a439f2", + "nsece_childcare_sibling_validation.py": "abd2a4c88d3c4585e055fae93be3ac00c060405fc6e24bb079b67196aa88e422" + }, + "production_ready": false, + "interpretation": "fixed model comparison on previously inspected development data; no independent validation claim", + "calendar_bounds": { + "interpretation": "regular questionnaire only; measured calendar classifications conditional on published completeness status; identification bounds, not confidence intervals or completed schedules", + "comparisons": [ + { + "group": "all_regular_instrument", + "children": 8516, + "child_weight": 37015599.704962164, + "mean_hours_lower": 13.752732174958528, + "mean_hours_upper": 19.277785432593692, + "mean_days_lower": 1.8681623591758092, + "mean_days_upper": 2.2700564555072797, + "definitely_in_care_share": 0.4678654605697152, + "possibly_in_care_share": 0.5340113908145044, + "hours_interval_width_le_1_share": 0.8833384698718048 + }, + { + "group": "ambiguous_calendar", + "children": 882, + "child_weight": 3918044.035953992, + "mean_hours_lower": 9.860427216978815, + "mean_hours_upper": 32.59604037159691, + "mean_days_lower": 1.664693482330874, + "mean_days_upper": 4.497773509477583, + "definitely_in_care_share": 0.4411424517865376, + "possibly_in_care_share": 1.0, + "hours_interval_width_le_1_share": 0.11421962556237487 + }, + { + "group": "complete", + "children": 7460, + "child_weight": 32249785.682044942, + "mean_hours_lower": 14.240422572045741, + "mean_hours_upper": 14.240422572045741, + "mean_days_lower": 1.8750709563867467, + "mean_days_upper": 1.8750709563867467, + "definitely_in_care_share": 0.46514845107061753, + "possibly_in_care_share": 0.46514845107061753, + "hours_interval_width_le_1_share": 1.0 + }, + { + "group": "partial_calendar", + "children": 174, + "child_weight": 847769.9869632281, + "mean_hours_lower": 13.189267360358828, + "mean_hours_upper": 149.35123108179786, + "mean_days_lower": 2.5457037310587567, + "mean_days_upper": 7.000000000000001, + "definitely_in_care_share": 0.6947252246391856, + "possibly_in_care_share": 1.0, + "hours_interval_width_le_1_share": 0.0 + } + ] + }, + "pooled_moments": { + "design": "household-separated partitions; exact integration of the implemented shared-rank donor CDFs", + "seed": 271828, + "validation_seed": null, + "partition": "all", + "splits": [ + { + "training_households": 5100, + "evaluation_households": 1269, + "household_overlap": 0 + }, + { + "training_households": 5108, + "evaluation_households": 1261, + "household_overlap": 0 + }, + { + "training_households": 5055, + "evaluation_households": 1314, + "household_overlap": 0 + }, + { + "training_households": 5071, + "evaluation_households": 1298, + "household_overlap": 0 + }, + { + "training_households": 5142, + "evaluation_households": 1227, + "household_overlap": 0 + } + ], + "match_columns": [ + "age", + "childcare_household_size", + "parent_work_status", + "income_band", + "region" + ], + "fallback_match_columns": [], + "matching_counts": { + "partially_pooled": 7460 + }, + "training_rho": [ + 0.7652583390107988, + 0.7261225249617242, + 0.7209478813856636, + 0.7820313193382383, + 0.81974924157628 + ], + "youngest_pairs": { + "households": 1941, + "household_weight": 8329556.517461634, + "observed": { + "participation": { + "joint_product": 0.3285886986591048, + "correlation": 0.577510777815278 + }, + "days": { + "joint_product": 5.9171615700449145, + "correlation": 0.5798886366650429 + }, + "weekly_hours": { + "joint_product": 367.6804958137289, + "correlation": 0.523457187358221 + } + }, + "independent": { + "participation": { + "joint_product": 0.24236105200931968, + "correlation": 0.09396101556276153 + }, + "days": { + "joint_product": 4.135970938921813, + "correlation": 0.11086235305220805 + }, + "weekly_hours": { + "joint_product": 234.25280025856392, + "correlation": 0.09296236405577511 + } + }, + "coupled": { + "participation": { + "joint_product": 0.3478032040042286, + "correlation": 0.5194576064772242 + }, + "days": { + "joint_product": 6.714922913449467, + "correlation": 0.5919617343470333 + }, + "weekly_hours": { + "joint_product": 426.7255628007384, + "correlation": 0.4820957188644195 + } + } + }, + "youngest_pairs_in_3plus_households": { + "households": 661, + "household_weight": 2458669.150522002, + "observed": { + "participation": { + "joint_product": 0.2728957065164463, + "correlation": 0.5341073068866067 + }, + "days": { + "joint_product": 5.084876229689592, + "correlation": 0.5617680576612079 + }, + "weekly_hours": { + "joint_product": 337.34705105325276, + "correlation": 0.5623528715201395 + } + }, + "independent": { + "participation": { + "joint_product": 0.20749391246494672, + "correlation": 0.07367636621560582 + }, + "days": { + "joint_product": 3.5642905999293837, + "correlation": 0.09515516766062374 + }, + "weekly_hours": { + "joint_product": 216.49341419707955, + "correlation": 0.063874755675981 + } + }, + "coupled": { + "participation": { + "joint_product": 0.31038475496885254, + "correlation": 0.49338255183709395 + }, + "days": { + "joint_product": 6.0717725199533, + "correlation": 0.5677801532872357 + }, + "weekly_hours": { + "joint_product": 437.0722821479231, + "correlation": 0.45599184970931156 + } + } + }, + "larger_households": { + "households": 661, + "observed": { + "mean_total_days": 4.509647234214243, + "mean_total_weekly_hours": 33.085374473048084, + "sd_total_days": 5.765302178946849, + "sd_total_weekly_hours": 56.21651776123905, + "all_children_attend": 0.18568592787006075 + }, + "independent": { + "mean_total_days": 5.051031204266368, + "mean_total_weekly_hours": 38.34794143790316, + "sd_total_days": 4.395160013019163, + "sd_total_weekly_hours": 44.20739654038455, + "all_children_attend": 0.06527654820049239 + }, + "coupled": { + "mean_total_days": 5.051031204266368, + "mean_total_weekly_hours": 38.34794143790316, + "sd_total_days": 6.177046168973302, + "sd_total_weekly_hours": 59.820431157004805, + "all_children_attend": 0.20892405597176808 + } + }, + "production_ready": false, + "diagnostic_screen": { + "passed": false, + "checks": [ + { + "metric": "youngest_pairs.participation.joint_product", + "absolute_gap": 0.01921450534512381, + "relative": false, + "limit": 0.05, + "passed": true + }, + { + "metric": "youngest_pairs.days.correlation", + "absolute_gap": 0.012073097681990386, + "relative": false, + "limit": 0.1, + "passed": true + }, + { + "metric": "youngest_pairs.weekly_hours.correlation", + "absolute_gap": 0.04136146849380151, + "relative": false, + "limit": 0.1, + "passed": true + }, + { + "metric": "youngest_pairs.days.joint_product", + "absolute_gap": 0.13482162586925894, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs.weekly_hours.joint_product", + "absolute_gap": 0.1605879769508426, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.participation.joint_product", + "absolute_gap": 0.03748904845240625, + "relative": false, + "limit": 0.05, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.days.correlation", + "absolute_gap": 0.006012095626027891, + "relative": false, + "limit": 0.1, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.correlation", + "absolute_gap": 0.1063610218108279, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.days.joint_product", + "absolute_gap": 0.1940846238304513, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.joint_product", + "absolute_gap": 0.2956161341363792, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.mean_total_days", + "absolute_gap": 0.12005018174031427, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.mean_total_weekly_hours", + "absolute_gap": 0.15906022067672387, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.sd_total_days", + "absolute_gap": 0.07141759048294442, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.sd_total_weekly_hours", + "absolute_gap": 0.0641077309532437, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.all_children_attend", + "absolute_gap": 0.023238128101707334, + "relative": false, + "limit": 0.05, + "passed": true + } + ], + "interpretation": "provisional diagnostic screens; not publication authorization" + }, + "model": { + "name": "partially_pooled_empirical_schedules", + "levels": [ + [ + "age" + ], + [ + "age", + "childcare_household_size" + ], + [ + "age", + "childcare_household_size", + "parent_work_status" + ], + [ + "age", + "childcare_household_size", + "parent_work_status", + "income_band" + ], + [ + "age", + "childcare_household_size", + "parent_work_status", + "income_band", + "region" + ] + ], + "composition": false, + "strength": 10.0, + "dependence_objective": "population_moments", + "dependence_fits": [ + { + "rho": 0.7652583390107988, + "unconstrained_rho": 0.7652583390107988, + "households": 1730, + "households_with_unresolved_siblings": 140, + "observed_pairs": 3670, + "outcome_second_moments": [ + 0.4359359926938946, + 8.277205060093346, + 593.7870077076072 + ], + "objective": "population_moments", + "normalized_mean_residual": [ + 0.2502298693914833, + 0.27527547268127456, + 0.2850732476726967 + ], + "normalized_mean_shared_increment": [ + 0.30253311517140813, + 0.38487878025611877, + 0.36627648825439335 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + }, + { + "rho": 0.7261225249617242, + "unconstrained_rho": 0.7261225249617242, + "households": 1697, + "households_with_unresolved_siblings": 123, + "observed_pairs": 3594, + "outcome_second_moments": [ + 0.44126287158160343, + 8.359355045936002, + 694.2809842648821 + ], + "objective": "population_moments", + "normalized_mean_residual": [ + 0.22454696976548358, + 0.25665784026502875, + 0.3085026964880856 + ], + "normalized_mean_shared_increment": [ + 0.3121975302394453, + 0.3956058631862616, + 0.37836062350370525 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + }, + { + "rho": 0.7209478813856636, + "unconstrained_rho": 0.7209478813856636, + "households": 1633, + "households_with_unresolved_siblings": 135, + "observed_pairs": 3453, + "outcome_second_moments": [ + 0.4338366370776943, + 8.256340131249516, + 694.144636825422 + ], + "objective": "population_moments", + "normalized_mean_residual": [ + 0.22762977893389097, + 0.2491739115147974, + 0.31614054777338935 + ], + "normalized_mean_shared_increment": [ + 0.3218355084453624, + 0.40226719431104246, + 0.37196853323063156 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + }, + { + "rho": 0.7820313193382383, + "unconstrained_rho": 0.7820313193382383, + "households": 1668, + "households_with_unresolved_siblings": 125, + "observed_pairs": 3499, + "outcome_second_moments": [ + 0.4428268423383291, + 8.341086892139936, + 679.4142064233605 + ], + "objective": "population_moments", + "normalized_mean_residual": [ + 0.24679819920578627, + 0.27437897292653474, + 0.337362053609579 + ], + "normalized_mean_shared_increment": [ + 0.3146404967452197, + 0.40232577509104867, + 0.3772940863523165 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + }, + { + "rho": 0.81974924157628, + "unconstrained_rho": 0.81974924157628, + "households": 1696, + "households_with_unresolved_siblings": 137, + "observed_pairs": 3584, + "outcome_second_moments": [ + 0.4413586153564347, + 8.485578051981562, + 676.0109573424492 + ], + "objective": "population_moments", + "normalized_mean_residual": [ + 0.2543497335812991, + 0.28684691450840843, + 0.35816569978000246 + ], + "normalized_mean_shared_increment": [ + 0.3106084542826501, + 0.4028661500770573, + 0.38060896199156885 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + } + ] + }, + "matching_count_universe": "every held-out child with an observed complete calendar", + "observed_child_validation": { + "comparisons": [ + { + "group": "all", + "children": 7460, + "child_weight": 32249785.682044946, + "observed": { + "participation": 0.4651484510706186, + "days": 1.8750709563867471, + "weekly_hours": 14.240422572045734 + }, + "expected": { + "participation": 0.46964890773471457, + "days": 1.8870313262922465, + "weekly_hours": 14.121321880052811 + }, + "conditional_mean_squared_error": { + "participation": 0.21786002566014795, + "days": 4.634484500691751, + "weekly_hours": 482.79806934933634 + }, + "expected_draw_squared_error": { + "participation": 0.4189867368126556, + "days": 8.871248441333941, + "weekly_hours": 905.9935560782225 + } + }, + { + "group": "household_size_1", + "children": 1910, + "child_weight": 9010809.078107145, + "observed": { + "participation": 0.5242108914088932, + "days": 2.119495964700082, + "weekly_hours": 16.911581677434366 + }, + "expected": { + "participation": 0.5309528476583814, + "days": 2.1450855821675643, + "weekly_hours": 16.7286558904403 + }, + "conditional_mean_squared_error": { + "participation": 0.21998157968908702, + "days": 4.8634925946342795, + "weekly_hours": 551.1632871152738 + }, + "expected_draw_squared_error": { + "participation": 0.4281854166170082, + "days": 9.372662082607494, + "weekly_hours": 1034.4761146276157 + } + }, + { + "group": "household_size_2", + "children": 2845, + "child_weight": 13265562.299413564, + "observed": { + "participation": 0.47658623296590163, + "days": 1.921092628643475, + "weekly_hours": 13.941634457809398 + }, + "expected": { + "participation": 0.48651284376374204, + "days": 1.9627422616863737, + "weekly_hours": 14.1440528078623 + }, + "conditional_mean_squared_error": { + "participation": 0.21802706174990996, + "days": 4.583635321783541, + "weekly_hours": 414.2968731100742 + }, + "expected_draw_squared_error": { + "participation": 0.4176700262900522, + "days": 8.771188666124276, + "weekly_hours": 779.6025285290256 + } + }, + { + "group": "household_size_3", + "children": 2705, + "child_weight": 9973414.304524235, + "observed": { + "participation": 0.39657324091775625, + "days": 1.5930240706983663, + "weekly_hours": 12.224491842781102 + }, + "expected": { + "participation": 0.3918312548530712, + "days": 1.5531811863063212, + "weekly_hours": 11.73540600582258 + }, + "conditional_mean_squared_error": { + "participation": 0.2157210644872454, + "days": 4.495213713500396, + "weekly_hours": 512.1441841789803 + }, + "expected_draw_squared_error": { + "participation": 0.41242723371549633, + "days": 8.551318544556374, + "weekly_hours": 958.0235058267347 + } + }, + { + "group": "complete_household", + "children": 6699, + "child_weight": 29099899.91535441, + "observed": { + "participation": 0.44408939246351814, + "days": 1.7729192348218488, + "weekly_hours": 13.20243633175764 + }, + "expected": { + "participation": 0.46990822362498935, + "days": 1.8840103414261442, + "weekly_hours": 14.119885124808388 + }, + "conditional_mean_squared_error": { + "participation": 0.21582355854647822, + "days": 4.473903862652206, + "weekly_hours": 447.4809381900267 + }, + "expected_draw_squared_error": { + "participation": 0.4175485380163647, + "days": 8.708831987458572, + "weekly_hours": 872.7199874173884 + } + }, + { + "group": "unresolved_siblings", + "children": 761, + "child_weight": 3149885.766690531, + "observed": { + "participation": 0.659700426338619, + "days": 2.8187892667948593, + "weekly_hours": 23.829753088509108 + }, + "expected": { + "participation": 0.46725324420518616, + "days": 1.914940388322065, + "weekly_hours": 14.13459519753524 + }, + "conditional_mean_squared_error": { + "participation": 0.23667372037103993, + "days": 6.117992424918431, + "weekly_hours": 809.0718005751868 + }, + "expected_draw_squared_error": { + "participation": 0.4322733904027592, + "days": 10.371716363808677, + "weekly_hours": 1213.3880426008857 + } + } + ], + "screen": { + "passed": false, + "checks": [ + { + "group": "all", + "metric": "participation", + "relative": false, + "gap": 0.0045004566640959864, + "limit": 0.05, + "passed": true + }, + { + "group": "all", + "metric": "days", + "relative": true, + "gap": 0.006378622560794653, + "limit": 0.2, + "passed": true + }, + { + "group": "all", + "metric": "weekly_hours", + "relative": true, + "gap": 0.008363564451150505, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "participation", + "relative": false, + "gap": 0.006741956249488146, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_1", + "metric": "days", + "relative": true, + "gap": 0.01207344476879113, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "weekly_hours", + "relative": true, + "gap": 0.010816598381105233, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "participation", + "relative": false, + "gap": 0.009926610797840407, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_2", + "metric": "days", + "relative": true, + "gap": 0.02168017950925578, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "weekly_hours", + "relative": true, + "gap": 0.014518982739467643, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "participation", + "relative": false, + "gap": 0.0047419860646850664, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_3", + "metric": "days", + "relative": true, + "gap": 0.02501084894127077, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "weekly_hours", + "relative": true, + "gap": 0.0400086844711946, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "participation", + "relative": false, + "gap": 0.025818831161471212, + "limit": 0.05, + "passed": true + }, + { + "group": "complete_household", + "metric": "days", + "relative": true, + "gap": 0.06265999286507735, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "weekly_hours", + "relative": true, + "gap": 0.06949087047243553, + "limit": 0.2, + "passed": true + }, + { + "group": "unresolved_siblings", + "metric": "participation", + "relative": false, + "gap": 0.19244718213343287, + "limit": 0.05, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "days", + "relative": true, + "gap": 0.3206514545518074, + "limit": 0.2, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "weekly_hours", + "relative": true, + "gap": 0.4068509587557979, + "limit": 0.2, + "passed": false + } + ] + }, + "interpretation": "child-weighted predictions of observed calendars; missing children are not scored as zeros; previously used survey, not external validation" + }, + "all_observed_sibling_pairs": { + "household_weight": 8945945.325594446, + "observed": { + "participation": { + "joint_product": 0.3302177486685269, + "correlation": 0.569690244749424 + }, + "days": { + "joint_product": 6.027208927705104, + "correlation": 0.5724522456066773 + }, + "weekly_hours": { + "joint_product": 426.22614842124585, + "correlation": 0.5408408373849536 + } + }, + "independent": { + "participation": { + "joint_product": 0.2260919090368316, + "correlation": 0.09520635050450324 + }, + "days": { + "joint_product": 3.8285744975466867, + "correlation": 0.10968106727006208 + }, + "weekly_hours": { + "joint_product": 212.90904376258283, + "correlation": 0.08730651835284241 + } + }, + "coupled": { + "participation": { + "joint_product": 0.33074016165677533, + "correlation": 0.5208339015307502 + }, + "days": { + "joint_product": 6.372410806864982, + "correlation": 0.5918345128361356 + }, + "weekly_hours": { + "joint_product": 401.34477075365476, + "correlation": 0.4737561541826404 + } + }, + "observed_pairs": 4450, + "households": 2106, + "interpretation": "all observed pairs including households with unresolved other siblings; household weight divided among observed pairs" + }, + "dependence_only_screen_compatibility": { + "comparisons": [ + { + "population": "youngest_pairs", + "metric": "days", + "identified": true, + "predicted_product_of_marginal_means": 3.5416889767723654, + "predicted_product_of_marginal_standard_deviations": 5.360538954730504, + "joint_product_required_by_correlation_screen": [ + 6.114150707547841, + 7.186258498493942 + ], + "joint_product_allowed_by_product_screen": [ + 4.733729256035931, + 7.100593884053898 + ], + "screen_intervals_overlap": true, + "overlap_interval": [ + 6.114150707547841, + 7.100593884053898 + ] + }, + { + "population": "youngest_pairs", + "metric": "weekly_hours", + "identified": true, + "predicted_product_of_marginal_means": 188.27184591178198, + "predicted_product_of_marginal_standard_deviations": 494.6190301184091, + "joint_product_required_by_correlation_screen": [ + 397.7218292195747, + 496.6456352432565 + ], + "joint_product_allowed_by_product_screen": [ + 294.14439665098314, + 441.21659497647465 + ], + "screen_intervals_overlap": true, + "overlap_interval": [ + 397.7218292195747, + 441.21659497647465 + ] + }, + { + "population": "youngest_pairs_in_3plus_households", + "metric": "days", + "identified": true, + "predicted_product_of_marginal_means": 3.0594508860714296, + "predicted_product_of_marginal_standard_deviations": 5.305436649100272, + "joint_product_required_by_correlation_screen": [ + 5.509332062571049, + 6.570419392391104 + ], + "joint_product_allowed_by_product_screen": [ + 4.067900983751674, + 6.101851475627511 + ], + "screen_intervals_overlap": true, + "overlap_interval": [ + 5.509332062571049, + 6.101851475627511 + ] + }, + { + "population": "youngest_pairs_in_3plus_households", + "metric": "weekly_hours", + "identified": true, + "predicted_product_of_marginal_means": 180.56174604989343, + "predicted_product_of_marginal_standard_deviations": 562.5331598833434, + "joint_product_required_by_correlation_screen": [ + 440.650567847255, + 553.1571998239236 + ], + "joint_product_allowed_by_product_screen": [ + 269.8776408426022, + 404.8164612639033 + ], + "screen_intervals_overlap": false, + "overlap_interval": null + } + ], + "interpretation": "disjoint screen intervals rule out a dependence-only fix for these conditional marginals; overlapping intervals do not establish that a feasible joint distribution exists" + } + }, + "composition": { + "design": "household-separated partitions; exact integration of the implemented shared-rank donor CDFs", + "seed": 271828, + "validation_seed": null, + "partition": "all", + "splits": [ + { + "training_households": 5100, + "evaluation_households": 1269, + "household_overlap": 0 + }, + { + "training_households": 5108, + "evaluation_households": 1261, + "household_overlap": 0 + }, + { + "training_households": 5055, + "evaluation_households": 1314, + "household_overlap": 0 + }, + { + "training_households": 5071, + "evaluation_households": 1298, + "household_overlap": 0 + }, + { + "training_households": 5142, + "evaluation_households": 1227, + "household_overlap": 0 + } + ], + "match_columns": [ + "age", + "childcare_household_size", + "childcare_under6_count", + "childcare_schoolage_count", + "childcare_youngest_age_band", + "childcare_has_younger_sibling", + "parent_work_status", + "income_band", + "region" + ], + "fallback_match_columns": [], + "matching_counts": { + "partially_pooled": 7460 + }, + "training_rho": [ + 0.8399640846621534, + 0.8570423272969275, + 0.8230102157132589, + 0.864578324659506, + 0.9166961809991262 + ], + "youngest_pairs": { + "households": 1941, + "household_weight": 8329556.517461634, + "observed": { + "participation": { + "joint_product": 0.3285886986591048, + "correlation": 0.577510777815278 + }, + "days": { + "joint_product": 5.9171615700449145, + "correlation": 0.5798886366650429 + }, + "weekly_hours": { + "joint_product": 367.6804958137289, + "correlation": 0.523457187358221 + } + }, + "independent": { + "participation": { + "joint_product": 0.23403263223181478, + "correlation": 0.05505364256311636 + }, + "days": { + "joint_product": 3.793349125556499, + "correlation": 0.05205827852433274 + }, + "weekly_hours": { + "joint_product": 204.3674792287307, + "correlation": 0.052403482951996 + } + }, + "coupled": { + "participation": { + "joint_product": 0.35484511473052854, + "correlation": 0.5445752375628808 + }, + "days": { + "joint_product": 6.718882876240173, + "correlation": 0.6060563801476498 + }, + "weekly_hours": { + "joint_product": 407.28869084882973, + "correlation": 0.48750091812507396 + } + } + }, + "youngest_pairs_in_3plus_households": { + "households": 661, + "household_weight": 2458669.150522002, + "observed": { + "participation": { + "joint_product": 0.2728957065164463, + "correlation": 0.5341073068866067 + }, + "days": { + "joint_product": 5.084876229689592, + "correlation": 0.5617680576612079 + }, + "weekly_hours": { + "joint_product": 337.34705105325276, + "correlation": 0.5623528715201395 + } + }, + "independent": { + "participation": { + "joint_product": 0.18622994721190744, + "correlation": 0.004424326621928326 + }, + "days": { + "joint_product": 2.9357117242328004, + "correlation": 0.003213461024514607 + }, + "weekly_hours": { + "joint_product": 160.51024640001995, + "correlation": 0.0011368384394220272 + } + }, + "coupled": { + "participation": { + "joint_product": 0.29900866121222525, + "correlation": 0.46870525036610444 + }, + "days": { + "joint_product": 5.682552831905449, + "correlation": 0.540022542299082 + }, + "weekly_hours": { + "joint_product": 371.00824393473454, + "correlation": 0.455014242859092 + } + } + }, + "larger_households": { + "households": 661, + "observed": { + "mean_total_days": 4.509647234214243, + "mean_total_weekly_hours": 33.085374473048084, + "sd_total_days": 5.765302178946849, + "sd_total_weekly_hours": 56.21651776123905, + "all_children_attend": 0.18568592787006075 + }, + "independent": { + "mean_total_days": 5.092979651989213, + "mean_total_weekly_hours": 37.72006977012014, + "sd_total_days": 4.138811595986753, + "sd_total_weekly_hours": 41.22796200054727, + "all_children_attend": 0.052578178673632084 + }, + "coupled": { + "mean_total_days": 5.092979651989213, + "mean_total_weekly_hours": 37.72006977012014, + "sd_total_days": 6.181228072584479, + "sd_total_weekly_hours": 58.28009064320519, + "all_children_attend": 0.20401682495167728 + } + }, + "production_ready": false, + "diagnostic_screen": { + "passed": false, + "checks": [ + { + "metric": "youngest_pairs.participation.joint_product", + "absolute_gap": 0.02625641607142376, + "relative": false, + "limit": 0.05, + "passed": true + }, + { + "metric": "youngest_pairs.days.correlation", + "absolute_gap": 0.026167743482606975, + "relative": false, + "limit": 0.1, + "passed": true + }, + { + "metric": "youngest_pairs.weekly_hours.correlation", + "absolute_gap": 0.03595626923314704, + "relative": false, + "limit": 0.1, + "passed": true + }, + { + "metric": "youngest_pairs.days.joint_product", + "absolute_gap": 0.1354908593765461, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs.weekly_hours.joint_product", + "absolute_gap": 0.10772449310220358, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.participation.joint_product", + "absolute_gap": 0.026112954695778956, + "relative": false, + "limit": 0.05, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.days.correlation", + "absolute_gap": 0.021745515362125878, + "relative": false, + "limit": 0.1, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.correlation", + "absolute_gap": 0.10733862866104749, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.days.joint_product", + "absolute_gap": 0.11754004920043884, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.joint_product", + "absolute_gap": 0.09978208724927644, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.mean_total_days", + "absolute_gap": 0.12935211724528825, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.mean_total_weekly_hours", + "absolute_gap": 0.14008290282002275, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.sd_total_days", + "absolute_gap": 0.07214294771165103, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.sd_total_weekly_hours", + "absolute_gap": 0.03670758994234549, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.all_children_attend", + "absolute_gap": 0.018330897081616532, + "relative": false, + "limit": 0.05, + "passed": true + } + ], + "interpretation": "provisional diagnostic screens; not publication authorization" + }, + "model": { + "name": "partially_pooled_empirical_schedules", + "levels": [ + [ + "age" + ], + [ + "age", + "childcare_household_size" + ], + [ + "age", + "childcare_household_size", + "childcare_under6_count" + ], + [ + "age", + "childcare_household_size", + "childcare_under6_count", + "childcare_schoolage_count" + ], + [ + "age", + "childcare_household_size", + "childcare_under6_count", + "childcare_schoolage_count", + "childcare_youngest_age_band" + ], + [ + "age", + "childcare_household_size", + "childcare_under6_count", + "childcare_schoolage_count", + "childcare_youngest_age_band", + "childcare_has_younger_sibling" + ], + [ + "age", + "childcare_household_size", + "childcare_under6_count", + "childcare_schoolage_count", + "childcare_youngest_age_band", + "childcare_has_younger_sibling", + "parent_work_status" + ], + [ + "age", + "childcare_household_size", + "childcare_under6_count", + "childcare_schoolage_count", + "childcare_youngest_age_band", + "childcare_has_younger_sibling", + "parent_work_status", + "income_band" + ], + [ + "age", + "childcare_household_size", + "childcare_under6_count", + "childcare_schoolage_count", + "childcare_youngest_age_band", + "childcare_has_younger_sibling", + "parent_work_status", + "income_band", + "region" + ] + ], + "composition": true, + "strength": 10.0, + "dependence_objective": "population_moments", + "dependence_fits": [ + { + "rho": 0.8399640846621534, + "unconstrained_rho": 0.8399640846621534, + "households": 1730, + "households_with_unresolved_siblings": 140, + "observed_pairs": 3670, + "outcome_second_moments": [ + 0.4359359926938946, + 8.277205060093346, + 593.7870077076072 + ], + "objective": "population_moments", + "normalized_mean_residual": [ + 0.2628889402077603, + 0.30752410801290964, + 0.3162598566632183 + ], + "normalized_mean_shared_increment": [ + 0.30573202616046746, + 0.3859771076106248, + 0.36143383682784197 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + }, + { + "rho": 0.8570423272969275, + "unconstrained_rho": 0.8570423272969275, + "households": 1697, + "households_with_unresolved_siblings": 123, + "observed_pairs": 3594, + "outcome_second_moments": [ + 0.44126287158160343, + 8.359355045936002, + 694.2809842648821 + ], + "objective": "population_moments", + "normalized_mean_residual": [ + 0.2443600196619892, + 0.2990893124631417, + 0.3469623228273086 + ], + "normalized_mean_shared_increment": [ + 0.3093672228441525, + 0.39089237144982414, + 0.3331400290247654 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + }, + { + "rho": 0.8230102157132589, + "unconstrained_rho": 0.8230102157132589, + "households": 1633, + "households_with_unresolved_siblings": 135, + "observed_pairs": 3453, + "outcome_second_moments": [ + 0.4338366370776943, + 8.256340131249516, + 694.144636825422 + ], + "objective": "population_moments", + "normalized_mean_residual": [ + 0.24816322664921883, + 0.2859806861379085, + 0.3421789090009365 + ], + "normalized_mean_shared_increment": [ + 0.32207809778668695, + 0.3942246598593399, + 0.3426789060896911 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + }, + { + "rho": 0.864578324659506, + "unconstrained_rho": 0.864578324659506, + "households": 1668, + "households_with_unresolved_siblings": 125, + "observed_pairs": 3499, + "outcome_second_moments": [ + 0.4428268423383291, + 8.341086892139936, + 679.4142064233605 + ], + "objective": "population_moments", + "normalized_mean_residual": [ + 0.25329497627486214, + 0.3037274504890692, + 0.36190503905052646 + ], + "normalized_mean_shared_increment": [ + 0.3108759554369621, + 0.39736383237268086, + 0.35048479033181906 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + }, + { + "rho": 0.9166961809991262, + "unconstrained_rho": 0.9166961809991262, + "households": 1696, + "households_with_unresolved_siblings": 137, + "observed_pairs": 3584, + "outcome_second_moments": [ + 0.4413586153564347, + 8.485578051981562, + 676.0109573424492 + ], + "objective": "population_moments", + "normalized_mean_residual": [ + 0.2716286888941078, + 0.32001227998102094, + 0.3876781485857021 + ], + "normalized_mean_shared_increment": [ + 0.3135365037544654, + 0.4022432617843371, + 0.3453688379556845 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + } + ] + }, + "matching_count_universe": "every held-out child with an observed complete calendar", + "observed_child_validation": { + "comparisons": [ + { + "group": "all", + "children": 7460, + "child_weight": 32249785.682044946, + "observed": { + "participation": 0.4651484510706186, + "days": 1.8750709563867471, + "weekly_hours": 14.240422572045734 + }, + "expected": { + "participation": 0.47072573788331684, + "days": 1.891415566726541, + "weekly_hours": 14.051047147885557 + }, + "conditional_mean_squared_error": { + "participation": 0.22658158908250814, + "days": 4.838377344868154, + "weekly_hours": 502.89523404077755 + }, + "expected_draw_squared_error": { + "participation": 0.4301190485183399, + "days": 9.155938510049051, + "weekly_hours": 919.6053921259771 + } + }, + { + "group": "household_size_1", + "children": 1910, + "child_weight": 9010809.078107145, + "observed": { + "participation": 0.5242108914088932, + "days": 2.119495964700082, + "weekly_hours": 16.911581677434366 + }, + "expected": { + "participation": 0.5334523349716616, + "days": 2.157243247532589, + "weekly_hours": 16.87219330898405 + }, + "conditional_mean_squared_error": { + "participation": 0.2203944172588559, + "days": 4.875138146962889, + "weekly_hours": 552.334405111881 + }, + "expected_draw_squared_error": { + "participation": 0.42868789798870033, + "days": 9.398241596110811, + "weekly_hours": 1039.203894337865 + } + }, + { + "group": "household_size_2", + "children": 2845, + "child_weight": 13265562.299413564, + "observed": { + "participation": 0.47658623296590163, + "days": 1.921092628643475, + "weekly_hours": 13.941634457809398 + }, + "expected": { + "participation": 0.48969985296599344, + "days": 1.9755769244726475, + "weekly_hours": 14.151729788046943 + }, + "conditional_mean_squared_error": { + "participation": 0.2264818868005256, + "days": 4.746127518844021, + "weekly_hours": 423.93181581930173 + }, + "expected_draw_squared_error": { + "participation": 0.4310797875791831, + "days": 9.081249304141137, + "weekly_hours": 802.3902348660534 + } + }, + { + "group": "household_size_3", + "children": 2705, + "child_weight": 9973414.304524235, + "observed": { + "participation": 0.39657324091775625, + "days": 1.5930240706983663, + "weekly_hours": 12.224491842781102 + }, + "expected": { + "participation": 0.3888160055444834, + "days": 1.5393024280784862, + "weekly_hours": 11.368272677914653 + }, + "conditional_mean_squared_error": { + "participation": 0.23230420614490324, + "days": 4.927865379531953, + "weekly_hours": 563.2564297064381 + }, + "expected_draw_squared_error": { + "participation": 0.4301341968231166, + "days": 9.036365363174667, + "weekly_hours": 967.4571795917512 + } + }, + { + "group": "complete_household", + "children": 6699, + "child_weight": 29099899.91535441, + "observed": { + "participation": 0.44408939246351814, + "days": 1.7729192348218488, + "weekly_hours": 13.20243633175764 + }, + "expected": { + "participation": 0.4730372440960363, + "days": 1.8975754143009322, + "weekly_hours": 14.097344593444705 + }, + "conditional_mean_squared_error": { + "participation": 0.2229085673024625, + "days": 4.649026562188718, + "weekly_hours": 463.3225631391084 + }, + "expected_draw_squared_error": { + "participation": 0.42716654608125787, + "days": 8.974736797922452, + "weekly_hours": 882.6176744431627 + } + }, + { + "group": "unresolved_siblings", + "children": 761, + "child_weight": 3149885.766690531, + "observed": { + "participation": 0.659700426338619, + "days": 2.8187892667948593, + "weekly_hours": 23.829753088509108 + }, + "expected": { + "participation": 0.44937112237467763, + "days": 1.8345084401875262, + "weekly_hours": 13.623332896672485 + }, + "conditional_mean_squared_error": { + "participation": 0.26051442795448626, + "days": 6.5876753299361495, + "weekly_hours": 868.4833372029435 + }, + "expected_draw_squared_error": { + "participation": 0.4573954425791977, + "days": 10.829952134014457, + "weekly_hours": 1261.3126673704833 + } + } + ], + "screen": { + "passed": false, + "checks": [ + { + "group": "all", + "metric": "participation", + "relative": false, + "gap": 0.005577286812698257, + "limit": 0.05, + "passed": true + }, + { + "group": "all", + "metric": "days", + "relative": true, + "gap": 0.00871679564131799, + "limit": 0.2, + "passed": true + }, + { + "group": "all", + "metric": "weekly_hours", + "relative": true, + "gap": 0.013298441335015258, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "participation", + "relative": false, + "gap": 0.009241443562768348, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_1", + "metric": "days", + "relative": true, + "gap": 0.017809556357352218, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "weekly_hours", + "relative": true, + "gap": 0.002329076558396374, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "participation", + "relative": false, + "gap": 0.013113620000091808, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_2", + "metric": "days", + "relative": true, + "gap": 0.028361097750734178, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "weekly_hours", + "relative": true, + "gap": 0.015069634114518045, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "participation", + "relative": false, + "gap": 0.0077572353732728305, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_3", + "metric": "days", + "relative": true, + "gap": 0.03372305767880146, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "weekly_hours", + "relative": true, + "gap": 0.07004128890413303, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "participation", + "relative": false, + "gap": 0.028947851632518173, + "limit": 0.05, + "passed": true + }, + { + "group": "complete_household", + "metric": "days", + "relative": true, + "gap": 0.0703112567288546, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "weekly_hours", + "relative": true, + "gap": 0.06778356957756485, + "limit": 0.2, + "passed": true + }, + { + "group": "unresolved_siblings", + "metric": "participation", + "relative": false, + "gap": 0.2103293039639414, + "limit": 0.05, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "days", + "relative": true, + "gap": 0.3491856728000537, + "limit": 0.2, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "weekly_hours", + "relative": true, + "gap": 0.4283057467665596, + "limit": 0.2, + "passed": false + } + ] + }, + "interpretation": "child-weighted predictions of observed calendars; missing children are not scored as zeros; previously used survey, not external validation" + }, + "all_observed_sibling_pairs": { + "household_weight": 8945945.325594446, + "observed": { + "participation": { + "joint_product": 0.3302177486685269, + "correlation": 0.569690244749424 + }, + "days": { + "joint_product": 6.027208927705104, + "correlation": 0.5724522456066773 + }, + "weekly_hours": { + "joint_product": 426.22614842124585, + "correlation": 0.5408408373849536 + } + }, + "independent": { + "participation": { + "joint_product": 0.21912452735602767, + "correlation": 0.06104800089898952 + }, + "days": { + "joint_product": 3.547131863081251, + "correlation": 0.05993325215301244 + }, + "weekly_hours": { + "joint_product": 191.1715812535131, + "correlation": 0.058509149210166214 + } + }, + "coupled": { + "participation": { + "joint_product": 0.33817967669080706, + "correlation": 0.5465533102310314 + }, + "days": { + "joint_product": 6.401711376096358, + "correlation": 0.6089880012372204 + }, + "weekly_hours": { + "joint_product": 389.86012743614157, + "correlation": 0.48451497075234107 + } + }, + "observed_pairs": 4450, + "households": 2106, + "interpretation": "all observed pairs including households with unresolved other siblings; household weight divided among observed pairs" + }, + "dependence_only_screen_compatibility": { + "comparisons": [ + { + "population": "youngest_pairs", + "metric": "days", + "identified": true, + "predicted_product_of_marginal_means": 3.518441593600768, + "predicted_product_of_marginal_standard_deviations": 5.280764937842418, + "joint_product_required_by_correlation_screen": [ + 6.052620680170525, + 7.108773667739009 + ], + "joint_product_allowed_by_product_screen": [ + 4.733729256035931, + 7.100593884053898 + ], + "screen_intervals_overlap": true, + "overlap_interval": [ + 6.052620680170525, + 7.100593884053898 + ] + }, + { + "population": "youngest_pairs", + "metric": "weekly_hours", + "identified": true, + "predicted_product_of_marginal_means": 179.92748626599993, + "predicted_product_of_marginal_standard_deviations": 466.3810797675209, + "joint_product_required_by_correlation_screen": [ + 377.41990654144445, + 470.69612249494855 + ], + "joint_product_allowed_by_product_screen": [ + 294.14439665098314, + 441.21659497647465 + ], + "screen_intervals_overlap": true, + "overlap_interval": [ + 377.41990654144445, + 441.21659497647465 + ] + }, + { + "population": "youngest_pairs_in_3plus_households", + "metric": "days", + "identified": true, + "predicted_product_of_marginal_means": 2.9192685097866464, + "predicted_product_of_marginal_standard_deviations": 5.116979580804991, + "joint_product_required_by_correlation_screen": [ + 5.282126231907029, + 6.305522148068027 + ], + "joint_product_allowed_by_product_screen": [ + 4.067900983751674, + 6.101851475627511 + ], + "screen_intervals_overlap": true, + "overlap_interval": [ + 5.282126231907029, + 6.101851475627511 + ] + }, + { + "population": "youngest_pairs_in_3plus_households", + "metric": "weekly_hours", + "identified": true, + "predicted_product_of_marginal_means": 159.98300663728094, + "predicted_product_of_marginal_standard_deviations": 463.7772127120063, + "joint_product_required_by_correlation_screen": [ + 374.4117326802836, + 467.1671752226848 + ], + "joint_product_allowed_by_product_screen": [ + 269.8776408426022, + 404.8164612639033 + ], + "screen_intervals_overlap": true, + "overlap_interval": [ + 374.4117326802836, + 404.8164612639033 + ] + } + ], + "interpretation": "disjoint screen intervals rule out a dependence-only fix for these conditional marginals; overlapping intervals do not establish that a feasible joint distribution exists" + } + } +} diff --git a/experiments/us-childcare-attendance/ci-export-verification.json b/experiments/us-childcare-attendance/ci-export-verification.json new file mode 100644 index 000000000..319bd2f5f --- /dev/null +++ b/experiments/us-childcare-attendance/ci-export-verification.json @@ -0,0 +1,9 @@ +{ + "previous_candidate_sha256": "a2d0ed98081b3707727eddb3d90e007117aa1da50e75c83a1a33fe381f41bcd2", + "updated_candidate_sha256": "7e4231f15d48ec060a07616068b5cfd03d8e4e45c0ef089dfacaa01d73dcc44f", + "checkpoint_sha256": "882c2ae6b683e2a04ce6c94f5f694f70750a8c2876e8108e3715a7f7095d1f66", + "export_code_sha256": "b8dc8009aa87e31e569261d1f1f5efdfb5c59b3345c62360ef9303d496f3963c", + "all_entity_values_dtypes_weights_period_equal": true, + "people": 166321, + "interpretation": "Serializer registry/dtype fix only; qualified attendance values unchanged." +} diff --git a/experiments/us-childcare-attendance/household-review-artifact-verification.json b/experiments/us-childcare-attendance/household-review-artifact-verification.json new file mode 100644 index 000000000..5e34d4ac7 --- /dev/null +++ b/experiments/us-childcare-attendance/household-review-artifact-verification.json @@ -0,0 +1,44 @@ +{ + "date": "2026-09-16", + "people": 166321, + "under13_children": 31889, + "households": 57240, + "native_sha256": "fc84fa083061bb28732b03ae6b06168505fe28be58f72954f52bf99b95eed1e8", + "checkpoint_sha256": "d69901b04c049142bc4ceabcd4ac547c324b43c18799a86cd39a9eac2e66f256", + "previous_native_sha256": "937c0c0c9798f0cf9e015fc4d5bed204342480bf93a415d94d3080d66f20cb6f", + "source_stage_report_sha256": "cb26f9ddc19d2924ac303c15b66a94f5d393c435ab55922309d2f24fa16fc3d2", + "attendance_recipe": { + "contract_sha256": "ae648c6cb0e2838fdf142975e9c536eb0683d9630fd1738096d524222ffb01dc", + "runtime_versions": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "policyengine-us": "1.819.0" + }, + "code_sha256": { + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "nsece_childcare.py": "affc8ac5a3ce853e2ef8b062c51a1801a15573cbcbf6eacc2c093334a1d12c11", + "nsece_childcare_bridge.py": "70a7edea8b28c6da21ff4fa9bb220766a3e6cd714926684af29bdba1a8421b0a", + "nsece_childcare_dependence.py": "1c5123a77f84460ba517d2b4c6c3e04ae658bf36e9cf54ed69ddbcacc85efc09", + "childcare_attendance_stage.py": "42e777b0edfc813d79204bc2932fe429d6a48cd2866397560a7386cbee54dadb", + "childcare_attendance_receipt.py": "0950fce7f372ca4b240cd055c931f5f8fe070223fd68504a3ea9cfbc4e16c645" + } + }, + "content_binding_sha256": "80282b5b68b744768d49a455adc2ffc5b931f70507069eea4b45223c7fce2f46", + "verified_native_loaders": [ + "microcosm.build.us_runtime.h5_io.load_legacy_calibrated_us_h5", + "microcosm.build.us_runtime.l0_refit_export.load_us_frame" + ], + "all_attendance_values_and_person_ids_equal_previous_candidate": true, + "household_weights_equal_previous_candidate": true, + "original_columns_and_period_verified_by_source_stage_export": true, + "build_wheel_sha256": "7c10e316c709be5a5ed0db5a82faf2646f189ee337c7ed0d23d60b1a1e777c24", + "verification_code_sha256": "6dda5a07a99d4693719d344cb33729d3431d08909f6ee9930c665fc0ac236f12", + "interpretation": "The household-size challenger is diagnostic-only. The default dependence fitter accepts explicit matching columns for assessment but retains its original production defaults. Rebuilt from the unchanged original parent because recipe code hashes changed; every attendance value equals the previous candidate, so its benefit comparison and transport-sensitivity estimates remain applicable. Neither the old nor current candidate is certified.", + "default_sibling_fit_matches_previous_execution": true, + "changed_recipe_files": [ + "nsece_childcare_dependence.py" + ], + "sensitivity_model_and_evaluator_code_unchanged": true, + "production_ready": false +} diff --git a/experiments/us-childcare-attendance/household-size-development.json b/experiments/us-childcare-attendance/household-size-development.json new file mode 100644 index 000000000..e0a5c2eae --- /dev/null +++ b/experiments/us-childcare-attendance/household-size-development.json @@ -0,0 +1,734 @@ +{ + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "partition": "development", + "validation_seed": 20260916, + "legacy": { + "design": "household-separated partitions; exact integration of the implemented shared-rank donor CDFs", + "seed": 271828, + "validation_seed": 20260916, + "partition": "development", + "splits": [ + { + "training_households": 4097, + "evaluation_households": 1039, + "household_overlap": 0 + }, + { + "training_households": 4112, + "evaluation_households": 1024, + "household_overlap": 0 + }, + { + "training_households": 4073, + "evaluation_households": 1063, + "household_overlap": 0 + }, + { + "training_households": 4113, + "evaluation_households": 1023, + "household_overlap": 0 + }, + { + "training_households": 4149, + "evaluation_households": 987, + "household_overlap": 0 + } + ], + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "fallback_match_columns": [ + [ + "age", + "parent_work_status", + "income_band" + ], + [ + "age", + "parent_work_status" + ], + [ + "age" + ] + ], + "matching_counts": { + "age,region,parent_work_status,income_band": 3745, + "age,parent_work_status,income_band": 97, + "age,parent_work_status": 15 + }, + "training_rho": [ + 0.6848203293890904, + 0.8388331395514941, + 0.7672584653221455, + 0.913950703165035, + 0.801448169860078 + ], + "youngest_pairs": { + "households": 1565, + "household_weight": 6748306.0591101395, + "observed": { + "participation": { + "joint_product": 0.3199254439129754, + "correlation": 0.5813359742882304 + }, + "days": { + "joint_product": 5.606681648963777, + "correlation": 0.5820637734098711 + }, + "weekly_hours": { + "joint_product": 338.57812172627393, + "correlation": 0.548207236935218 + } + }, + "independent": { + "participation": { + "joint_product": 0.2575450863451372, + "correlation": 0.13528005655281253 + }, + "days": { + "joint_product": 4.48267591905156, + "correlation": 0.14390476225719756 + }, + "weekly_hours": { + "joint_product": 257.2445077783002, + "correlation": 0.1160908773407519 + } + }, + "coupled": { + "participation": { + "joint_product": 0.31482088549744375, + "correlation": 0.36593111538647133 + }, + "days": { + "joint_product": 5.938130785995765, + "correlation": 0.41016522348600426 + }, + "weekly_hours": { + "joint_product": 359.51959348847805, + "correlation": 0.32031500176565186 + } + } + }, + "youngest_pairs_in_3plus_households": { + "households": 533, + "household_weight": 2007819.6139549948, + "observed": { + "participation": { + "joint_product": 0.2807799138598989, + "correlation": 0.5474984886830093 + }, + "days": { + "joint_product": 5.043798878017195, + "correlation": 0.5641177009261245 + }, + "weekly_hours": { + "joint_product": 302.8480101771769, + "correlation": 0.5286710123883716 + } + }, + "independent": { + "participation": { + "joint_product": 0.2722007521680011, + "correlation": 0.18155884264108704 + }, + "days": { + "joint_product": 4.833198372869685, + "correlation": 0.16973032613323838 + }, + "weekly_hours": { + "joint_product": 273.58655003554566, + "correlation": 0.1281191585638751 + } + }, + "coupled": { + "participation": { + "joint_product": 0.32553953994339074, + "correlation": 0.3960658173279713 + }, + "days": { + "joint_product": 6.159314398463845, + "correlation": 0.40625610412960306 + }, + "weekly_hours": { + "joint_product": 374.7187606337127, + "correlation": 0.31981724026910857 + } + } + }, + "larger_households": { + "households": 533, + "observed": { + "mean_total_days": 4.549551457601687, + "mean_total_weekly_hours": 33.199873558867296, + "sd_total_days": 5.77030590861846, + "sd_total_weekly_hours": 56.523051645186115, + "all_children_attend": 0.19377899515538355 + }, + "independent": { + "mean_total_days": 5.64924422646984, + "mean_total_weekly_hours": 40.48300647511985, + "sd_total_days": 4.608639098038089, + "sd_total_weekly_hours": 43.22268543690276, + "all_children_attend": 0.10705608714104596 + }, + "coupled": { + "mean_total_days": 5.64924422646984, + "mean_total_weekly_hours": 40.48300647511985, + "sd_total_days": 5.565444503780002, + "sd_total_weekly_hours": 50.662241267526234, + "all_children_attend": 0.1842946017253324 + } + }, + "production_ready": false, + "diagnostic_screen": { + "passed": false, + "checks": [ + { + "metric": "youngest_pairs.participation.joint_product", + "absolute_gap": 0.005104558415531646, + "relative": false, + "limit": 0.05, + "passed": true + }, + { + "metric": "youngest_pairs.days.correlation", + "absolute_gap": 0.17189854992386688, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs.weekly_hours.correlation", + "absolute_gap": 0.22789223516956614, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs.days.joint_product", + "absolute_gap": 0.059116810581397256, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs.weekly_hours.joint_product", + "absolute_gap": 0.06185122551756138, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.participation.joint_product", + "absolute_gap": 0.04475962608349182, + "relative": false, + "limit": 0.05, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.days.correlation", + "absolute_gap": 0.1578615967965214, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.correlation", + "absolute_gap": 0.20885377211926298, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.days.joint_product", + "absolute_gap": 0.22116574181982035, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.joint_product", + "absolute_gap": 0.23731623798514923, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.mean_total_days", + "absolute_gap": 0.24171454683312, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.mean_total_weekly_hours", + "absolute_gap": 0.21937230885348705, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.sd_total_days", + "absolute_gap": 0.03550269397892398, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.sd_total_weekly_hours", + "absolute_gap": 0.10368885272596613, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.all_children_attend", + "absolute_gap": 0.009484393430051141, + "relative": false, + "limit": 0.05, + "passed": true + } + ], + "interpretation": "provisional diagnostic screens; not publication authorization" + } + }, + "household_size": { + "design": "household-separated partitions; exact integration of the implemented shared-rank donor CDFs", + "seed": 271828, + "validation_seed": 20260916, + "partition": "development", + "splits": [ + { + "training_households": 4097, + "evaluation_households": 1039, + "household_overlap": 0 + }, + { + "training_households": 4112, + "evaluation_households": 1024, + "household_overlap": 0 + }, + { + "training_households": 4073, + "evaluation_households": 1063, + "household_overlap": 0 + }, + { + "training_households": 4113, + "evaluation_households": 1023, + "household_overlap": 0 + }, + { + "training_households": 4149, + "evaluation_households": 987, + "household_overlap": 0 + } + ], + "match_columns": [ + "age", + "childcare_household_size", + "region", + "parent_work_status", + "income_band" + ], + "fallback_match_columns": [ + [ + "age", + "childcare_household_size", + "parent_work_status", + "income_band" + ], + [ + "age", + "childcare_household_size", + "parent_work_status" + ], + [ + "age", + "childcare_household_size" + ], + [ + "age" + ] + ], + "matching_counts": { + "age,childcare_household_size,region,parent_work_status,income_band": 3428, + "age,childcare_household_size,parent_work_status,income_band": 342, + "age,childcare_household_size,parent_work_status": 79, + "age,childcare_household_size": 8 + }, + "training_rho": [ + 1.0, + 1.0, + 1.0, + 1.0, + 1.0 + ], + "youngest_pairs": { + "households": 1565, + "household_weight": 6748306.0591101395, + "observed": { + "participation": { + "joint_product": 0.3199254439129754, + "correlation": 0.5813359742882304 + }, + "days": { + "joint_product": 5.606681648963777, + "correlation": 0.5820637734098711 + }, + "weekly_hours": { + "joint_product": 338.57812172627393, + "correlation": 0.548207236935218 + } + }, + "independent": { + "participation": { + "joint_product": 0.2424157631812536, + "correlation": 0.15684839780606782 + }, + "days": { + "joint_product": 4.188249209802441, + "correlation": 0.17515292850190187 + }, + "weekly_hours": { + "joint_product": 235.4304608642769, + "correlation": 0.12984658658248008 + } + }, + "coupled": { + "participation": { + "joint_product": 0.2802071612829887, + "correlation": 0.3103237669397316 + }, + "days": { + "joint_product": 5.040019514661833, + "correlation": 0.33551387728285753 + }, + "weekly_hours": { + "joint_product": 304.05864836293415, + "correlation": 0.27086267382784396 + } + } + }, + "youngest_pairs_in_3plus_households": { + "households": 533, + "household_weight": 2007819.6139549948, + "observed": { + "participation": { + "joint_product": 0.2807799138598989, + "correlation": 0.5474984886830093 + }, + "days": { + "joint_product": 5.043798878017195, + "correlation": 0.5641177009261245 + }, + "weekly_hours": { + "joint_product": 302.8480101771769, + "correlation": 0.5286710123883716 + } + }, + "independent": { + "participation": { + "joint_product": 0.2306517201772058, + "correlation": 0.16098841763316635 + }, + "days": { + "joint_product": 4.50046704664406, + "correlation": 0.22181638064040868 + }, + "weekly_hours": { + "joint_product": 298.87830451258816, + "correlation": 0.15259248561190691 + } + }, + "coupled": { + "participation": { + "joint_product": 0.2649318815369116, + "correlation": 0.30106180716897935 + }, + "days": { + "joint_product": 5.25974745290275, + "correlation": 0.3586483188719107 + }, + "weekly_hours": { + "joint_product": 372.6836980853711, + "correlation": 0.2685558001776592 + } + } + }, + "larger_households": { + "households": 533, + "observed": { + "mean_total_days": 4.549551457601687, + "mean_total_weekly_hours": 33.199873558867296, + "sd_total_days": 5.77030590861846, + "sd_total_weekly_hours": 56.523051645186115, + "all_children_attend": 0.19377899515538355 + }, + "independent": { + "mean_total_days": 5.257588507232319, + "mean_total_weekly_hours": 40.23091201749012, + "sd_total_days": 4.882049352378196, + "sd_total_weekly_hours": 49.29942433861291, + "all_children_attend": 0.08720607874073927 + }, + "coupled": { + "mean_total_days": 5.257588507232319, + "mean_total_weekly_hours": 40.23091201749012, + "sd_total_days": 5.405854455301145, + "sd_total_weekly_hours": 53.74796429671431, + "all_children_attend": 0.12330025112746766 + } + }, + "production_ready": false, + "diagnostic_screen": { + "passed": false, + "checks": [ + { + "metric": "youngest_pairs.participation.joint_product", + "absolute_gap": 0.03971828262998667, + "relative": false, + "limit": 0.05, + "passed": true + }, + { + "metric": "youngest_pairs.days.correlation", + "absolute_gap": 0.2465498961270136, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs.weekly_hours.correlation", + "absolute_gap": 0.27734456310737404, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs.days.joint_product", + "absolute_gap": 0.10106907610969385, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs.weekly_hours.joint_product", + "absolute_gap": 0.1019542349261637, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.participation.joint_product", + "absolute_gap": 0.015848032322987315, + "relative": false, + "limit": 0.05, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.days.correlation", + "absolute_gap": 0.20546938205421378, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.correlation", + "absolute_gap": 0.2601152122107124, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.days.joint_product", + "absolute_gap": 0.04281466809208862, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.joint_product", + "absolute_gap": 0.23059648920043363, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.mean_total_days", + "absolute_gap": 0.15562788029303362, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.mean_total_weekly_hours", + "absolute_gap": 0.21177907337978147, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.sd_total_days", + "absolute_gap": 0.06315981493684325, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.sd_total_weekly_hours", + "absolute_gap": 0.04909655915062668, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.all_children_attend", + "absolute_gap": 0.07047874402791589, + "relative": false, + "limit": 0.05, + "passed": false + } + ], + "interpretation": "provisional diagnostic screens; not publication authorization" + } + }, + "development_selection": { + "partition": "development only", + "observed_child_comparisons": [ + { + "household_size_capped_at_3": 1, + "sample": "all_observed_children", + "children": 1534, + "households": 1534, + "child_weight": 7081698.15383859, + "mean_days": 2.12170224791113, + "mean_weekly_hours": 16.593123351196084 + }, + { + "household_size_capped_at_3": 1, + "sample": "children_in_complete_households", + "children": 1534, + "households": 1534, + "child_weight": 7081698.15383859, + "mean_days": 2.12170224791113, + "mean_weekly_hours": 16.593123351196084 + }, + { + "household_size_capped_at_3": 2, + "sample": "all_observed_children", + "children": 2291, + "households": 1259, + "child_weight": 10714272.764753226, + "mean_days": 1.8174291558486764, + "mean_weekly_hours": 12.95845201473953 + }, + { + "household_size_capped_at_3": 2, + "sample": "children_in_complete_households", + "children": 2064, + "households": 1032, + "child_weight": 9548734.356105652, + "mean_days": 1.71581007929574, + "mean_weekly_hours": 11.804463953672407 + }, + { + "household_size_capped_at_3": 2, + "sample": "observed_children_with_unresolved_siblings", + "children": 227, + "households": 227, + "child_weight": 1165538.408647576, + "mean_days": 2.6499487539309645, + "mean_weekly_hours": 22.412559544351797 + }, + { + "household_size_capped_at_3": 3, + "sample": "all_observed_children", + "children": 2177, + "households": 723, + "child_weight": 8060168.091557396, + "mean_days": 1.6268475611504107, + "mean_weekly_hours": 12.615632989129697 + }, + { + "household_size_capped_at_3": 3, + "sample": "children_in_complete_households", + "children": 1793, + "households": 533, + "child_weight": 6701383.24976393, + "mean_days": 1.36015412333186, + "mean_weekly_hours": 9.85801688518962 + }, + { + "household_size_capped_at_3": 3, + "sample": "observed_children_with_unresolved_siblings", + "children": 384, + "households": 190, + "child_weight": 1358784.8417934654, + "mean_days": 2.942151413569196, + "mean_weekly_hours": 26.215904201922807 + } + ], + "donor_support": { + "legacy": { + "children": 6002, + "median_donor_households": 12.0, + "children_in_cells_below_10_households": 2233, + "fraction_of_children_in_cells_below_10_households": 0.3720426524491836, + "definition": "Exact matching cells in the whole development pool; fold-training support can be smaller. Ten is a descriptive cutoff, not a tuned fallback rule." + }, + "household_size": { + "children": 6002, + "median_donor_households": 5.0, + "children_in_cells_below_10_households": 5275, + "fraction_of_children_in_cells_below_10_households": 0.8788737087637454, + "definition": "Exact matching cells in the whole development pool; fold-training support can be smaller. Ten is a descriptive cutoff, not a tuned fallback rule." + } + }, + "interpretation": "Descriptive differences under calendar selection; not a causal effect of missingness and not corrected population totals." + }, + "production_recipe_changed": false, + "production_ready": false, + "interpretation": "Prospective internal comparison on previously inspected survey data; not untouched external acceptance evidence. Complete-household totals do not identify totals for families with missing calendars.", + "plan_sha256": "7a75b47e280833a83d97a51a7fd29e210d1144e93aa5d7f2571d3146e619bedc", + "recipe": { + "contract_sha256": "ae648c6cb0e2838fdf142975e9c536eb0683d9630fd1738096d524222ffb01dc", + "runtime_versions": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "policyengine-us": "1.819.0" + }, + "code_sha256": { + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "nsece_childcare.py": "affc8ac5a3ce853e2ef8b062c51a1801a15573cbcbf6eacc2c093334a1d12c11", + "nsece_childcare_bridge.py": "70a7edea8b28c6da21ff4fa9bb220766a3e6cd714926684af29bdba1a8421b0a", + "nsece_childcare_dependence.py": "1c5123a77f84460ba517d2b4c6c3e04ae658bf36e9cf54ed69ddbcacc85efc09", + "childcare_attendance_stage.py": "42e777b0edfc813d79204bc2932fe429d6a48cd2866397560a7386cbee54dadb", + "childcare_attendance_receipt.py": "0950fce7f372ca4b240cd055c931f5f8fe070223fd68504a3ea9cfbc4e16c645" + } + }, + "diagnostic_code_sha256": { + "validate_us_childcare_household_size.py": "066f081a01329f0bbfa7d19b39c62a3ca9c95969a9c200f7f4d544d1390c0f65", + "nsece_childcare_sibling_validation.py": "8f3a6a2ce3813e251ded0b5273f3e3e5ac7504f6b724b881f289263a2f13b86f" + } +} diff --git a/experiments/us-childcare-attendance/household-size-plan.txt b/experiments/us-childcare-attendance/household-size-plan.txt new file mode 100644 index 000000000..c687bf908 --- /dev/null +++ b/experiments/us-childcare-attendance/household-size-plan.txt @@ -0,0 +1,34 @@ +Household-size comparison specified before new results, 2026-09-16. + +Hypothesis: the shared-rank mixture cannot change conditional marginal means. +The 3+ household mean bias is therefore a donor-conditioning problem, not a rho +tuning problem. Compare the current age/region/work/income matcher with exactly +one revision: add the count of all resident children ages 0-12, capped at 3 +(1, 2, 3+). Count children before selecting complete calendars so missing +attendance never changes the predictor. Derive the same count from physical +target household membership, not from repeated source-person clone IDs. + +Candidate fallback: age/count/region/work/income, age/count/work/income, +age/count/work, age/count, age. Report every fallback, including loss of count. +Use the same child/household survey weights and binary sibling-mixture fit; +no tuning of rho to the intensity screens and no favorable simulation seed. + +Reserve households with SHA256('20260916:reserved:') first eight +bytes interpreted big endian modulo 5 equal to zero. Exclude these households +from all development donor pools and dependence fits. Five-fold development +uses existing seed 271828 within the remaining households. Freeze the candidate +before scoring the reserved partition once; train on all remaining households. +Compare both arms on the identical partitions and existing 15 screens. Do not +iterate on reserved outcomes. Require improvement in the larger-family mean +bias without presenting a failed screen as a qualified model. + +The source has already informed earlier development, including aggregate +results covering these households. This is a prospective internal comparison, +not untouched external evidence. Independent source validation and release +certification remain outstanding even if all provisional screens pass. + +If adopted as a draft candidate, derive the predictor in both source/target, +use it consistently in bridge, dependence fit, transfer and diagnostics, then +rebuild from the original parent. Re-run population outcomes and noncalendar +sensitivity on the new candidate; old benefit results must be labeled historical. +Publish only aggregate diagnostics, never raw source records or household IDs. diff --git a/experiments/us-childcare-attendance/household-size-reserved-validation.json b/experiments/us-childcare-attendance/household-size-reserved-validation.json new file mode 100644 index 000000000..9b7a906ad --- /dev/null +++ b/experiments/us-childcare-attendance/household-size-reserved-validation.json @@ -0,0 +1,686 @@ +{ + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "partition": "validation", + "validation_seed": 20260916, + "legacy": { + "design": "household-separated partitions; exact integration of the implemented shared-rank donor CDFs", + "seed": 271828, + "validation_seed": 20260916, + "partition": "validation", + "splits": [ + { + "training_households": 5136, + "evaluation_households": 1233, + "household_overlap": 0 + } + ], + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "fallback_match_columns": [ + [ + "age", + "parent_work_status", + "income_band" + ], + [ + "age", + "parent_work_status" + ], + [ + "age" + ] + ], + "matching_counts": { + "age,region,parent_work_status,income_band": 912, + "age,parent_work_status,income_band": 15, + "age,parent_work_status": 5 + }, + "training_rho": [ + 0.7511342795267243 + ], + "youngest_pairs": { + "households": 376, + "household_weight": 1581250.458351494, + "observed": { + "participation": { + "joint_product": 0.36556088999422404, + "correlation": 0.5610984527348091 + }, + "days": { + "joint_product": 7.242197412151899, + "correlation": 0.5718708775247285 + }, + "weekly_hours": { + "joint_product": 491.8807617182249, + "correlation": 0.4702933377588588 + } + }, + "independent": { + "participation": { + "joint_product": 0.2648063070266509, + "correlation": 0.18506959808631887 + }, + "days": { + "joint_product": 4.679792048576763, + "correlation": 0.16873400086608684 + }, + "weekly_hours": { + "joint_product": 266.85090114375265, + "correlation": 0.11707605097373619 + } + }, + "coupled": { + "participation": { + "joint_product": 0.32269826366104903, + "correlation": 0.41833449873311257 + }, + "days": { + "joint_product": 6.230317317123342, + "correlation": 0.45223091173665864 + }, + "weekly_hours": { + "joint_product": 377.31068164279094, + "correlation": 0.3339999920804771 + } + } + }, + "youngest_pairs_in_3plus_households": { + "households": 128, + "household_weight": 450849.53656700696, + "observed": { + "participation": { + "joint_product": 0.23778406757541562, + "correlation": 0.48592489298077784 + }, + "days": { + "joint_product": 5.267810680515874, + "correlation": 0.5703562333340767 + }, + "weekly_hours": { + "joint_product": 490.9855608342772, + "correlation": 0.6762830071141811 + } + }, + "independent": { + "participation": { + "joint_product": 0.2716208881703992, + "correlation": 0.19301700563340585 + }, + "days": { + "joint_product": 5.057022917507661, + "correlation": 0.19768961582359243 + }, + "weekly_hours": { + "joint_product": 295.49337418852684, + "correlation": 0.1628491947082673 + } + }, + "coupled": { + "participation": { + "joint_product": 0.327632580263415, + "correlation": 0.4185796047514795 + }, + "days": { + "joint_product": 6.552290048872771, + "correlation": 0.4659225374235249 + }, + "weekly_hours": { + "joint_product": 398.86474192922077, + "correlation": 0.36378630854465915 + } + } + }, + "larger_households": { + "households": 128, + "observed": { + "mean_total_days": 4.331937209253313, + "mean_total_weekly_hours": 32.575462647390545, + "sd_total_days": 5.739597650319324, + "sd_total_weekly_hours": 54.82768623012342, + "all_children_attend": 0.14964414915102348 + }, + "independent": { + "mean_total_days": 5.891851945228354, + "mean_total_weekly_hours": 40.79292481988039, + "sd_total_days": 4.731073923959437, + "sd_total_weekly_hours": 41.37835826307807, + "all_children_attend": 0.11201676861081947 + }, + "coupled": { + "mean_total_days": 5.891851945228354, + "mean_total_weekly_hours": 40.79292481988039, + "sd_total_days": 5.925772998641244, + "sd_total_weekly_hours": 49.67736343959238, + "all_children_attend": 0.20405555258916724 + } + }, + "production_ready": false, + "diagnostic_screen": { + "passed": false, + "checks": [ + { + "metric": "youngest_pairs.participation.joint_product", + "absolute_gap": 0.042862626333175, + "relative": false, + "limit": 0.05, + "passed": true + }, + { + "metric": "youngest_pairs.days.correlation", + "absolute_gap": 0.1196399657880699, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs.weekly_hours.correlation", + "absolute_gap": 0.1362933456783817, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs.days.joint_product", + "absolute_gap": 0.1397200376408814, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs.weekly_hours.joint_product", + "absolute_gap": 0.23292246615871046, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.participation.joint_product", + "absolute_gap": 0.0898485126879994, + "relative": false, + "limit": 0.05, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.days.correlation", + "absolute_gap": 0.1044336959105518, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.correlation", + "absolute_gap": 0.31249669856952195, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.days.joint_product", + "absolute_gap": 0.24383552224225127, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.joint_product", + "absolute_gap": 0.1876242933672545, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.mean_total_days", + "absolute_gap": 0.36009634041854455, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.mean_total_weekly_hours", + "absolute_gap": 0.25225926217652983, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.sd_total_days", + "absolute_gap": 0.032437003369314966, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.sd_total_weekly_hours", + "absolute_gap": 0.09393653361394896, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.all_children_attend", + "absolute_gap": 0.05441140343814377, + "relative": false, + "limit": 0.05, + "passed": false + } + ], + "interpretation": "provisional diagnostic screens; not publication authorization" + } + }, + "household_size": { + "design": "household-separated partitions; exact integration of the implemented shared-rank donor CDFs", + "seed": 271828, + "validation_seed": 20260916, + "partition": "validation", + "splits": [ + { + "training_households": 5136, + "evaluation_households": 1233, + "household_overlap": 0 + } + ], + "match_columns": [ + "age", + "childcare_household_size", + "region", + "parent_work_status", + "income_band" + ], + "fallback_match_columns": [ + [ + "age", + "childcare_household_size", + "parent_work_status", + "income_band" + ], + [ + "age", + "childcare_household_size", + "parent_work_status" + ], + [ + "age", + "childcare_household_size" + ], + [ + "age" + ] + ], + "matching_counts": { + "age,childcare_household_size,region,parent_work_status,income_band": 870, + "age,childcare_household_size,parent_work_status,income_band": 46, + "age,childcare_household_size,parent_work_status": 15, + "age,childcare_household_size": 1 + }, + "training_rho": [ + 1.0 + ], + "youngest_pairs": { + "households": 376, + "household_weight": 1581250.458351494, + "observed": { + "participation": { + "joint_product": 0.36556088999422404, + "correlation": 0.5610984527348091 + }, + "days": { + "joint_product": 7.242197412151899, + "correlation": 0.5718708775247285 + }, + "weekly_hours": { + "joint_product": 491.8807617182249, + "correlation": 0.4702933377588588 + } + }, + "independent": { + "participation": { + "joint_product": 0.2619313016547457, + "correlation": 0.18282163006736646 + }, + "days": { + "joint_product": 4.777462329366674, + "correlation": 0.21743973520841575 + }, + "weekly_hours": { + "joint_product": 261.8980750325785, + "correlation": 0.17614513311728405 + } + }, + "coupled": { + "participation": { + "joint_product": 0.31073293503588245, + "correlation": 0.3804640910760853 + }, + "days": { + "joint_product": 6.014701732050489, + "correlation": 0.4510904179360654 + }, + "weekly_hours": { + "joint_product": 350.1657257334819, + "correlation": 0.3797013683288874 + } + } + }, + "youngest_pairs_in_3plus_households": { + "households": 128, + "household_weight": 450849.53656700696, + "observed": { + "participation": { + "joint_product": 0.23778406757541562, + "correlation": 0.48592489298077784 + }, + "days": { + "joint_product": 5.267810680515874, + "correlation": 0.5703562333340767 + }, + "weekly_hours": { + "joint_product": 490.9855608342772, + "correlation": 0.6762830071141811 + } + }, + "independent": { + "participation": { + "joint_product": 0.2614819428939225, + "correlation": 0.1654506920712637 + }, + "days": { + "joint_product": 4.098115261200414, + "correlation": 0.17691033926301059 + }, + "weekly_hours": { + "joint_product": 247.38304587866466, + "correlation": 0.21903583902041535 + } + }, + "coupled": { + "participation": { + "joint_product": 0.2953577249767762, + "correlation": 0.30323468986899804 + }, + "days": { + "joint_product": 5.152178159534045, + "correlation": 0.38887710741586745 + }, + "weekly_hours": { + "joint_product": 311.10123271641834, + "correlation": 0.3737655456308671 + } + } + }, + "larger_households": { + "households": 128, + "observed": { + "mean_total_days": 4.331937209253313, + "mean_total_weekly_hours": 32.575462647390545, + "sd_total_days": 5.739597650319324, + "sd_total_weekly_hours": 54.82768623012342, + "all_children_attend": 0.14964414915102348 + }, + "independent": { + "mean_total_days": 4.964349099595973, + "mean_total_weekly_hours": 33.4300784983736, + "sd_total_days": 4.362529218182336, + "sd_total_weekly_hours": 37.29191742464737, + "all_children_attend": 0.09245331473888625 + }, + "coupled": { + "mean_total_days": 4.964349099595973, + "mean_total_weekly_hours": 33.4300784983736, + "sd_total_days": 5.254529336333213, + "sd_total_weekly_hours": 43.245663726524754, + "all_children_attend": 0.14176731288100003 + } + }, + "production_ready": false, + "diagnostic_screen": { + "passed": false, + "checks": [ + { + "metric": "youngest_pairs.participation.joint_product", + "absolute_gap": 0.054827954958341585, + "relative": false, + "limit": 0.05, + "passed": false + }, + { + "metric": "youngest_pairs.days.correlation", + "absolute_gap": 0.12078045958866312, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs.weekly_hours.correlation", + "absolute_gap": 0.09059196942997139, + "relative": false, + "limit": 0.1, + "passed": true + }, + { + "metric": "youngest_pairs.days.joint_product", + "absolute_gap": 0.1694921596643801, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs.weekly_hours.joint_product", + "absolute_gap": 0.28810851534365317, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.participation.joint_product", + "absolute_gap": 0.057573657401360584, + "relative": false, + "limit": 0.05, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.days.correlation", + "absolute_gap": 0.18147912591820925, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.correlation", + "absolute_gap": 0.302517461483314, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.days.joint_product", + "absolute_gap": 0.021950773859341723, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.joint_product", + "absolute_gap": 0.3663739679272877, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.mean_total_days", + "absolute_gap": 0.1459882403170075, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.mean_total_weekly_hours", + "absolute_gap": 0.02623495666765337, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.sd_total_days", + "absolute_gap": 0.08451259888558985, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.sd_total_weekly_hours", + "absolute_gap": 0.2112440502228466, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.all_children_attend", + "absolute_gap": 0.007876836270023446, + "relative": false, + "limit": 0.05, + "passed": true + } + ], + "interpretation": "provisional diagnostic screens; not publication authorization" + } + }, + "development_selection": { + "partition": "development only", + "observed_child_comparisons": [ + { + "household_size_capped_at_3": 1, + "sample": "all_observed_children", + "children": 1534, + "households": 1534, + "child_weight": 7081698.15383859, + "mean_days": 2.12170224791113, + "mean_weekly_hours": 16.593123351196084 + }, + { + "household_size_capped_at_3": 1, + "sample": "children_in_complete_households", + "children": 1534, + "households": 1534, + "child_weight": 7081698.15383859, + "mean_days": 2.12170224791113, + "mean_weekly_hours": 16.593123351196084 + }, + { + "household_size_capped_at_3": 2, + "sample": "all_observed_children", + "children": 2291, + "households": 1259, + "child_weight": 10714272.764753226, + "mean_days": 1.8174291558486764, + "mean_weekly_hours": 12.95845201473953 + }, + { + "household_size_capped_at_3": 2, + "sample": "children_in_complete_households", + "children": 2064, + "households": 1032, + "child_weight": 9548734.356105652, + "mean_days": 1.71581007929574, + "mean_weekly_hours": 11.804463953672407 + }, + { + "household_size_capped_at_3": 2, + "sample": "observed_children_with_unresolved_siblings", + "children": 227, + "households": 227, + "child_weight": 1165538.408647576, + "mean_days": 2.6499487539309645, + "mean_weekly_hours": 22.412559544351797 + }, + { + "household_size_capped_at_3": 3, + "sample": "all_observed_children", + "children": 2177, + "households": 723, + "child_weight": 8060168.091557396, + "mean_days": 1.6268475611504107, + "mean_weekly_hours": 12.615632989129697 + }, + { + "household_size_capped_at_3": 3, + "sample": "children_in_complete_households", + "children": 1793, + "households": 533, + "child_weight": 6701383.24976393, + "mean_days": 1.36015412333186, + "mean_weekly_hours": 9.85801688518962 + }, + { + "household_size_capped_at_3": 3, + "sample": "observed_children_with_unresolved_siblings", + "children": 384, + "households": 190, + "child_weight": 1358784.8417934654, + "mean_days": 2.942151413569196, + "mean_weekly_hours": 26.215904201922807 + } + ], + "donor_support": { + "legacy": { + "children": 6002, + "median_donor_households": 12.0, + "children_in_cells_below_10_households": 2233, + "fraction_of_children_in_cells_below_10_households": 0.3720426524491836, + "definition": "Exact matching cells in the whole development pool; fold-training support can be smaller. Ten is a descriptive cutoff, not a tuned fallback rule." + }, + "household_size": { + "children": 6002, + "median_donor_households": 5.0, + "children_in_cells_below_10_households": 5275, + "fraction_of_children_in_cells_below_10_households": 0.8788737087637454, + "definition": "Exact matching cells in the whole development pool; fold-training support can be smaller. Ten is a descriptive cutoff, not a tuned fallback rule." + } + }, + "interpretation": "Descriptive differences under calendar selection; not a causal effect of missingness and not corrected population totals." + }, + "production_recipe_changed": false, + "production_ready": false, + "interpretation": "Prospective internal comparison on previously inspected survey data; not untouched external acceptance evidence. Complete-household totals do not identify totals for families with missing calendars.", + "plan_sha256": "7a75b47e280833a83d97a51a7fd29e210d1144e93aa5d7f2571d3146e619bedc", + "recipe": { + "contract_sha256": "ae648c6cb0e2838fdf142975e9c536eb0683d9630fd1738096d524222ffb01dc", + "runtime_versions": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "policyengine-us": "1.819.0" + }, + "code_sha256": { + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "nsece_childcare.py": "affc8ac5a3ce853e2ef8b062c51a1801a15573cbcbf6eacc2c093334a1d12c11", + "nsece_childcare_bridge.py": "70a7edea8b28c6da21ff4fa9bb220766a3e6cd714926684af29bdba1a8421b0a", + "nsece_childcare_dependence.py": "1c5123a77f84460ba517d2b4c6c3e04ae658bf36e9cf54ed69ddbcacc85efc09", + "childcare_attendance_stage.py": "42e777b0edfc813d79204bc2932fe429d6a48cd2866397560a7386cbee54dadb", + "childcare_attendance_receipt.py": "0950fce7f372ca4b240cd055c931f5f8fe070223fd68504a3ea9cfbc4e16c645" + } + }, + "diagnostic_code_sha256": { + "validate_us_childcare_household_size.py": "066f081a01329f0bbfa7d19b39c62a3ca9c95969a9c200f7f4d544d1390c0f65", + "nsece_childcare_sibling_validation.py": "8f3a6a2ce3813e251ded0b5273f3e3e5ac7504f6b724b881f289263a2f13b86f" + } +} diff --git a/experiments/us-childcare-attendance/interval-and-paired-plan.txt b/experiments/us-childcare-attendance/interval-and-paired-plan.txt new file mode 100644 index 000000000..6051f8bae --- /dev/null +++ b/experiments/us-childcare-attendance/interval-and-paired-plan.txt @@ -0,0 +1,49 @@ +Interval-informed attendance and paired schedule sensitivity, 2026-09-16. +Declared after the previous QRF and calendar-bound results, before these runs. +Every previously inspected household remains development evidence. + +1. Isolate schedule sensitivity from reassignment. The prior experiment rebuilds + care-sorted donor CDFs after changing bridge schedules. A fixed random rank + can therefore select another donor. Add a paired contrast which retains the + candidate's selected donor identity and changes only that donor's modeled + bridge components. Validate candidate provenance against the original donor + values, preserve measured recipient cells and measured-calendar donors, and + reject ambiguous/mixed lineage or constraints inconsistent with the scenario. + Keep the previous quantile-coupled experiment as historical evidence; neither + coupling identifies the missing schedules. Do not change the 10% national or + 20% state screens. Report absolute effects and the number of changed children. + +2. Use incomplete calendars' measured information in training, without making + their completed schedules into observations. Fit the existing canonical QRF + on complete training calendars. For each ambiguous/partial regular-instrument + training child, condition its predicted joint schedule distribution on the + child's measured lower/upper days and hours. Mix 90% QRF with 10% design-weighted + exact-age empirical schedules before conditioning, to retain empirical tail + support absent from the finite prediction grid. Exclude unsupported intervals + explicitly; never clip an incompatible schedule into its bounds. + +3. Represent each supported incomplete training child by eight midpoint-quantile + draws of that conditional distribution, each with one eighth of its design + weight. Label these interval_model, never complete. Keep complete children and + their weights unchanged. Refit the same 100-tree canonical QRF once. This is + conditional interval imputation, with a coarsening-at-random assumption given + the predictors and observed bounds; that assumption is not identified by the + survey. It is not an EM convergence claim or a completed population. + +4. Assess that assumption with fixed negative/positive exponential tilts of the + incomplete-child distribution: exp(-weekly_hours/40) and exp(weekly_hours/40), + applied only within supported bounds before the eight draws. Report all three + arms, rather than selecting the arm with the most passing checks. Forty hours + is a declared scale, not an estimated coefficient. No response-pattern flag or + held-out attendance/bounds enter the predictors or training completion. + +5. Use the existing five whole-household folds, same 7,460 observed children and + all 18 original child screens. Report conditional-mean and random-draw errors, + including the unresolved-sibling subgroup, plus completion support and weight + conservation in each fold. The evaluated child's household is absent from + initial fitting, completion and refitting. Any promising marginal result still + needs joint validation, target/bridge integration, grid stability, independent + evidence and a new candidate before adoption. Keep the current build unchanged. + +Parent work hours are not silently equated with the NSECE work/school/training +summary, nor are source-only calendar response indicators given to targets. diff --git a/experiments/us-childcare-attendance/interval-training-validation.json b/experiments/us-childcare-attendance/interval-training-validation.json new file mode 100644 index 000000000..4b90dace5 --- /dev/null +++ b/experiments/us-childcare-attendance/interval-training-validation.json @@ -0,0 +1,1487 @@ +{ + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "calendar_bounds": { + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568", + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "missing_calendar": "uninformative 0--168 hours and 0--7 days" + }, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "recipe": { + "contract_sha256": "ae648c6cb0e2838fdf142975e9c536eb0683d9630fd1738096d524222ffb01dc", + "runtime_versions": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "policyengine-us": "2.2.1" + }, + "code_sha256": { + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "nsece_childcare.py": "0e72ff9388f8f59147305f07effec2b99dada0f91599727cc9e58ad4feb6edbb", + "nsece_childcare_bridge.py": "70a7edea8b28c6da21ff4fa9bb220766a3e6cd714926684af29bdba1a8421b0a", + "nsece_childcare_dependence.py": "1c5123a77f84460ba517d2b4c6c3e04ae658bf36e9cf54ed69ddbcacc85efc09", + "childcare_attendance_stage.py": "42e777b0edfc813d79204bc2932fe429d6a48cd2866397560a7386cbee54dadb", + "childcare_attendance_receipt.py": "0950fce7f372ca4b240cd055c931f5f8fe070223fd68504a3ea9cfbc4e16c645" + } + }, + "plan_sha256": "c563b275a1bd79166f3458dd6858cdc349287877ba1c6e100605b0c1bd294983", + "diagnostic_code_sha256": { + "validate_us_childcare_intervals.py": "71a6f40234397a38618dd7626429b074a8f32d14664814d5b955293de341d55b", + "validate_us_childcare_qrf.py": "29c2fc33c2ea8bf81d2cf9b9ea179d6704930b2da8c1de7f1fd11918206a3e47", + "nsece_childcare_qrf.py": "f8ae9695a648bd163e04ae2ab92a9cd08ce9c29e7e19ed293c118934ff6ef0b1", + "nsece_childcare_pooling.py": "a779a0db7fddbb9e33aa7f8c8f7752b5f4a083309bb7d8f03d6ab72555a439f2", + "nsece_childcare_sibling_validation.py": "abd2a4c88d3c4585e055fae93be3ac00c060405fc6e24bb079b67196aa88e422" + }, + "folds": [ + { + "fold": 0, + "evaluated_children": 1402, + "household_overlap": 0, + "completions": { + "interval": { + "tilt": 0, + "incomplete_training_children": 869, + "completed_training_children": 838, + "unsupported_training_children": 31, + "unsupported_child_weight": 171444.442584318, + "completed_child_weight": 3695550.4472566973, + "draws_per_child": 8, + "empirical_mixture_weight": 0.1, + "design_weight_conserved": true, + "interpretation": "modeled training rows, not observations; conditional coarsening assumption" + }, + "lower_hours": { + "tilt": -1, + "incomplete_training_children": 869, + "completed_training_children": 838, + "unsupported_training_children": 31, + "unsupported_child_weight": 171444.442584318, + "completed_child_weight": 3695550.4472566973, + "draws_per_child": 8, + "empirical_mixture_weight": 0.1, + "design_weight_conserved": true, + "interpretation": "modeled training rows, not observations; conditional coarsening assumption" + }, + "higher_hours": { + "tilt": 1, + "incomplete_training_children": 869, + "completed_training_children": 838, + "unsupported_training_children": 31, + "unsupported_child_weight": 171444.442584318, + "completed_child_weight": 3695550.4472566973, + "draws_per_child": 8, + "empirical_mixture_weight": 0.1, + "design_weight_conserved": true, + "interpretation": "modeled training rows, not observations; conditional coarsening assumption" + } + } + }, + { + "fold": 1, + "evaluated_children": 1461, + "household_overlap": 0, + "completions": { + "interval": { + "tilt": 0, + "incomplete_training_children": 821, + "completed_training_children": 793, + "unsupported_training_children": 28, + "unsupported_child_weight": 193038.165822737, + "completed_child_weight": 3581394.364359614, + "draws_per_child": 8, + "empirical_mixture_weight": 0.1, + "design_weight_conserved": true, + "interpretation": "modeled training rows, not observations; conditional coarsening assumption" + }, + "lower_hours": { + "tilt": -1, + "incomplete_training_children": 821, + "completed_training_children": 793, + "unsupported_training_children": 28, + "unsupported_child_weight": 193038.165822737, + "completed_child_weight": 3581394.364359614, + "draws_per_child": 8, + "empirical_mixture_weight": 0.1, + "design_weight_conserved": true, + "interpretation": "modeled training rows, not observations; conditional coarsening assumption" + }, + "higher_hours": { + "tilt": 1, + "incomplete_training_children": 821, + "completed_training_children": 793, + "unsupported_training_children": 28, + "unsupported_child_weight": 193038.165822737, + "completed_child_weight": 3581394.364359614, + "draws_per_child": 8, + "empirical_mixture_weight": 0.1, + "design_weight_conserved": true, + "interpretation": "modeled training rows, not observations; conditional coarsening assumption" + } + } + }, + { + "fold": 2, + "evaluated_children": 1620, + "household_overlap": 0, + "completions": { + "interval": { + "tilt": 0, + "incomplete_training_children": 844, + "completed_training_children": 817, + "unsupported_training_children": 27, + "unsupported_child_weight": 153841.415545872, + "completed_child_weight": 3632834.4477473935, + "draws_per_child": 8, + "empirical_mixture_weight": 0.1, + "design_weight_conserved": true, + "interpretation": "modeled training rows, not observations; conditional coarsening assumption" + }, + "lower_hours": { + "tilt": -1, + "incomplete_training_children": 844, + "completed_training_children": 817, + "unsupported_training_children": 27, + "unsupported_child_weight": 153841.415545872, + "completed_child_weight": 3632834.4477473935, + "draws_per_child": 8, + "empirical_mixture_weight": 0.1, + "design_weight_conserved": true, + "interpretation": "modeled training rows, not observations; conditional coarsening assumption" + }, + "higher_hours": { + "tilt": 1, + "incomplete_training_children": 844, + "completed_training_children": 817, + "unsupported_training_children": 27, + "unsupported_child_weight": 153841.415545872, + "completed_child_weight": 3632834.4477473935, + "draws_per_child": 8, + "empirical_mixture_weight": 0.1, + "design_weight_conserved": true, + "interpretation": "modeled training rows, not observations; conditional coarsening assumption" + } + } + }, + { + "fold": 3, + "evaluated_children": 1527, + "household_overlap": 0, + "completions": { + "interval": { + "tilt": 0, + "incomplete_training_children": 852, + "completed_training_children": 823, + "unsupported_training_children": 29, + "unsupported_child_weight": 144714.969021018, + "completed_child_weight": 3657561.416389064, + "draws_per_child": 8, + "empirical_mixture_weight": 0.1, + "design_weight_conserved": true, + "interpretation": "modeled training rows, not observations; conditional coarsening assumption" + }, + "lower_hours": { + "tilt": -1, + "incomplete_training_children": 852, + "completed_training_children": 823, + "unsupported_training_children": 29, + "unsupported_child_weight": 144714.969021018, + "completed_child_weight": 3657561.416389064, + "draws_per_child": 8, + "empirical_mixture_weight": 0.1, + "design_weight_conserved": true, + "interpretation": "modeled training rows, not observations; conditional coarsening assumption" + }, + "higher_hours": { + "tilt": 1, + "incomplete_training_children": 852, + "completed_training_children": 823, + "unsupported_training_children": 29, + "unsupported_child_weight": 144714.969021018, + "completed_child_weight": 3657561.416389064, + "draws_per_child": 8, + "empirical_mixture_weight": 0.1, + "design_weight_conserved": true, + "interpretation": "modeled training rows, not observations; conditional coarsening assumption" + } + } + }, + { + "fold": 4, + "evaluated_children": 1450, + "household_overlap": 0, + "completions": { + "interval": { + "tilt": 0, + "incomplete_training_children": 838, + "completed_training_children": 810, + "unsupported_training_children": 28, + "unsupported_child_weight": 191452.505919394, + "completed_child_weight": 3641423.917022772, + "draws_per_child": 8, + "empirical_mixture_weight": 0.1, + "design_weight_conserved": true, + "interpretation": "modeled training rows, not observations; conditional coarsening assumption" + }, + "lower_hours": { + "tilt": -1, + "incomplete_training_children": 838, + "completed_training_children": 810, + "unsupported_training_children": 28, + "unsupported_child_weight": 191452.505919394, + "completed_child_weight": 3641423.917022772, + "draws_per_child": 8, + "empirical_mixture_weight": 0.1, + "design_weight_conserved": true, + "interpretation": "modeled training rows, not observations; conditional coarsening assumption" + }, + "higher_hours": { + "tilt": 1, + "incomplete_training_children": 838, + "completed_training_children": 810, + "unsupported_training_children": 28, + "unsupported_child_weight": 191452.505919394, + "completed_child_weight": 3641423.917022772, + "draws_per_child": 8, + "empirical_mixture_weight": 0.1, + "design_weight_conserved": true, + "interpretation": "modeled training rows, not observations; conditional coarsening assumption" + } + } + } + ], + "models": { + "complete_only": { + "comparisons": [ + { + "group": "all", + "children": 7460, + "child_weight": 32249785.682044946, + "observed": { + "participation": 0.4651484510706186, + "days": 1.8750709563867471, + "weekly_hours": 14.240422572045734 + }, + "expected": { + "participation": 0.4626963402375239, + "days": 1.8782143152899593, + "weekly_hours": 14.28498839270566 + }, + "conditional_mean_squared_error": { + "participation": 0.22193735839098713, + "days": 4.738177957705935, + "weekly_hours": 495.36993857227833 + }, + "expected_draw_squared_error": { + "participation": 0.3980913088338638, + "days": 8.493289037594954, + "weekly_hours": 884.5670742156525 + } + }, + { + "group": "household_size_1", + "children": 1910, + "child_weight": 9010809.078107145, + "observed": { + "participation": 0.5242108914088932, + "days": 2.119495964700082, + "weekly_hours": 16.911581677434366 + }, + "expected": { + "participation": 0.5169591695664993, + "days": 2.1040041234632554, + "weekly_hours": 16.180318254505547 + }, + "conditional_mean_squared_error": { + "participation": 0.21309207916173845, + "days": 4.80186267546308, + "weekly_hours": 547.7558761783448 + }, + "expected_draw_squared_error": { + "participation": 0.3939817087645831, + "days": 8.676322304138447, + "weekly_hours": 939.0868577063078 + } + }, + { + "group": "household_size_2", + "children": 2845, + "child_weight": 13265562.299413564, + "observed": { + "participation": 0.47658623296590163, + "days": 1.921092628643475, + "weekly_hours": 13.941634457809398 + }, + "expected": { + "participation": 0.47437966009242294, + "days": 1.9431615330846461, + "weekly_hours": 14.443491705680222 + }, + "conditional_mean_squared_error": { + "participation": 0.2237912246436724, + "days": 4.589094013107792, + "weekly_hours": 408.2440342383202 + }, + "expected_draw_squared_error": { + "participation": 0.39728485474399067, + "days": 8.251821584734268, + "weekly_hours": 751.137626070225 + } + }, + { + "group": "household_size_3", + "children": 2705, + "child_weight": 9973414.304524235, + "observed": { + "participation": 0.3965732409177563, + "days": 1.5930240706983663, + "weekly_hours": 12.224491842781102 + }, + "expected": { + "participation": 0.39813090829428704, + "days": 1.587831290116023, + "weekly_hours": 12.361766263154577 + }, + "conditional_mean_squared_error": { + "participation": 0.22746310337909134, + "days": 4.878935323151912, + "weekly_hours": 563.9256416456769 + }, + "expected_draw_squared_error": { + "participation": 0.40287692057375285, + "days": 8.64909563220651, + "weekly_hours": 1012.7828745314389 + } + }, + { + "group": "complete_household", + "children": 6699, + "child_weight": 29099899.915354412, + "observed": { + "participation": 0.4440893924635181, + "days": 1.7729192348218485, + "weekly_hours": 13.202436331757639 + }, + "expected": { + "participation": 0.4611924940358734, + "days": 1.8679016105224053, + "weekly_hours": 14.20249149230845 + }, + "conditional_mean_squared_error": { + "participation": 0.21836908152439619, + "days": 4.576891305578152, + "weekly_hours": 458.29836605715 + }, + "expected_draw_squared_error": { + "participation": 0.39552745711675996, + "days": 8.329736490182508, + "weekly_hours": 844.8891652102076 + } + }, + { + "group": "unresolved_siblings", + "children": 761, + "child_weight": 3149885.766690531, + "observed": { + "participation": 0.659700426338619, + "days": 2.8187892667948593, + "weekly_hours": 23.8297530885091 + }, + "expected": { + "participation": 0.4765894707182824, + "days": 1.9734871914576904, + "weekly_hours": 15.047127632887687 + }, + "conditional_mean_squared_error": { + "participation": 0.25490252201250563, + "days": 6.22820832142038, + "weekly_hours": 837.8518981731377 + }, + "expected_draw_squared_error": { + "participation": 0.42177719266956654, + "days": 10.004252644889078, + "weekly_hours": 1251.127408916974 + } + } + ], + "screen": { + "passed": false, + "checks": [ + { + "group": "all", + "metric": "participation", + "relative": false, + "gap": 0.0024521108330947117, + "limit": 0.05, + "passed": true + }, + { + "group": "all", + "metric": "days", + "relative": true, + "gap": 0.0016763946412296814, + "limit": 0.2, + "passed": true + }, + { + "group": "all", + "metric": "weekly_hours", + "relative": true, + "gap": 0.0031295293685603054, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "participation", + "relative": false, + "gap": 0.007251721842393866, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_1", + "metric": "days", + "relative": true, + "gap": 0.007309210064487643, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "weekly_hours", + "relative": true, + "gap": 0.04324039210977919, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "participation", + "relative": false, + "gap": 0.002206572873478696, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_2", + "metric": "days", + "relative": true, + "gap": 0.011487683681736041, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "weekly_hours", + "relative": true, + "gap": 0.035997016661823936, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "participation", + "relative": false, + "gap": 0.0015576673765307358, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_3", + "metric": "days", + "relative": true, + "gap": 0.003259700011982134, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "weekly_hours", + "relative": true, + "gap": 0.011229458217074167, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "participation", + "relative": false, + "gap": 0.01710310157235534, + "limit": 0.05, + "passed": true + }, + { + "group": "complete_household", + "metric": "days", + "relative": true, + "gap": 0.053574000346440526, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "weekly_hours", + "relative": true, + "gap": 0.07574777377605987, + "limit": 0.2, + "passed": true + }, + { + "group": "unresolved_siblings", + "metric": "participation", + "relative": false, + "gap": 0.18311095562033664, + "limit": 0.05, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "days", + "relative": true, + "gap": 0.29988125940976446, + "limit": 0.2, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "weekly_hours", + "relative": true, + "gap": 0.3685571320441615, + "limit": 0.2, + "passed": false + } + ] + }, + "interpretation": "child-weighted predictions of observed calendars; missing children are not scored as zeros; previously used survey, not external validation" + }, + "interval": { + "comparisons": [ + { + "group": "all", + "children": 7460, + "child_weight": 32249785.682044946, + "observed": { + "participation": 0.4651484510706186, + "days": 1.8750709563867471, + "weekly_hours": 14.240422572045734 + }, + "expected": { + "participation": 0.47481553841042756, + "days": 1.9036413478147798, + "weekly_hours": 14.318882355669308 + }, + "conditional_mean_squared_error": { + "participation": 0.21696503199110292, + "days": 4.6544246979093025, + "weekly_hours": 491.23887938195185 + }, + "expected_draw_squared_error": { + "participation": 0.4039248545961482, + "days": 8.520426461063778, + "weekly_hours": 877.6128058327024 + } + }, + { + "group": "household_size_1", + "children": 1910, + "child_weight": 9010809.078107145, + "observed": { + "participation": 0.5242108914088932, + "days": 2.119495964700082, + "weekly_hours": 16.911581677434366 + }, + "expected": { + "participation": 0.5326740409328169, + "days": 2.172525393673113, + "weekly_hours": 16.552752511708448 + }, + "conditional_mean_squared_error": { + "participation": 0.21012332715092863, + "days": 4.6891218802707675, + "weekly_hours": 521.6097072459198 + }, + "expected_draw_squared_error": { + "participation": 0.3972070493680936, + "days": 8.654124801333941, + "weekly_hours": 906.0406910528437 + } + }, + { + "group": "household_size_2", + "children": 2845, + "child_weight": 13265562.299413564, + "observed": { + "participation": 0.47658623296590163, + "days": 1.921092628643475, + "weekly_hours": 13.941634457809398 + }, + "expected": { + "participation": 0.4795097893415978, + "days": 1.9267487111566348, + "weekly_hours": 14.257887223439678 + }, + "conditional_mean_squared_error": { + "participation": 0.21809429079349352, + "days": 4.569188479556899, + "weekly_hours": 412.26761118207486 + }, + "expected_draw_squared_error": { + "participation": 0.40423771240788287, + "days": 8.312462829641136, + "weekly_hours": 758.9488310586797 + } + }, + { + "group": "household_size_3", + "children": 2705, + "child_weight": 9973414.304524235, + "observed": { + "participation": 0.3965732409177563, + "days": 1.5930240706983663, + "weekly_hours": 12.224491842781102 + }, + "expected": { + "participation": 0.41629758456524774, + "days": 1.629974287966794, + "weekly_hours": 12.38174807397901 + }, + "conditional_mean_squared_error": { + "participation": 0.22164437666318373, + "days": 4.73644843160116, + "weekly_hours": 568.8384378793678 + }, + "expected_draw_squared_error": { + "participation": 0.40957814682084925, + "days": 8.676243139581668, + "weekly_hours": 1009.7627460242041 + } + }, + { + "group": "complete_household", + "children": 6699, + "child_weight": 29099899.915354412, + "observed": { + "participation": 0.4440893924635181, + "days": 1.7729192348218485, + "weekly_hours": 13.202436331757639 + }, + "expected": { + "participation": 0.4730180301562414, + "days": 1.8905766191709923, + "weekly_hours": 14.261626546610092 + }, + "conditional_mean_squared_error": { + "participation": 0.21394334213323019, + "days": 4.509246185445723, + "weekly_hours": 456.4800074275843 + }, + "expected_draw_squared_error": { + "participation": 0.40143848378205926, + "days": 8.362060155477566, + "weekly_hours": 842.3490382801908 + } + }, + { + "group": "unresolved_siblings", + "children": 761, + "child_weight": 3149885.766690531, + "observed": { + "participation": 0.659700426338619, + "days": 2.8187892667948593, + "weekly_hours": 23.8297530885091 + }, + "expected": { + "participation": 0.49142163595434285, + "days": 2.02433851720927, + "weekly_hours": 14.847834335711237 + }, + "conditional_mean_squared_error": { + "participation": 0.244880607015825, + "days": 5.995641648449451, + "weekly_hours": 812.3551896110121 + }, + "expected_draw_squared_error": { + "participation": 0.42689493897430747, + "days": 9.983477499693892, + "weekly_hours": 1203.3935427940266 + } + } + ], + "screen": { + "passed": false, + "checks": [ + { + "group": "all", + "metric": "participation", + "relative": false, + "gap": 0.009667087339808977, + "limit": 0.05, + "passed": true + }, + { + "group": "all", + "metric": "days", + "relative": true, + "gap": 0.015236965476275973, + "limit": 0.2, + "passed": true + }, + { + "group": "all", + "metric": "weekly_hours", + "relative": true, + "gap": 0.005509652766736848, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "participation", + "relative": false, + "gap": 0.008463149523923685, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_1", + "metric": "days", + "relative": true, + "gap": 0.025019830118211506, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "weekly_hours", + "relative": true, + "gap": 0.021217954214460908, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "participation", + "relative": false, + "gap": 0.00292355637569619, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_2", + "metric": "days", + "relative": true, + "gap": 0.0029442008307291384, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "weekly_hours", + "relative": true, + "gap": 0.022684052331692774, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "participation", + "relative": false, + "gap": 0.019724343647491427, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_3", + "metric": "days", + "relative": true, + "gap": 0.023195015033406943, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "weekly_hours", + "relative": true, + "gap": 0.012864030114329164, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "participation", + "relative": false, + "gap": 0.028928637692723302, + "limit": 0.05, + "passed": true + }, + { + "group": "complete_household", + "metric": "days", + "relative": true, + "gap": 0.06636364592263365, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "weekly_hours", + "relative": true, + "gap": 0.08022687542182173, + "limit": 0.2, + "passed": true + }, + { + "group": "unresolved_siblings", + "metric": "participation", + "relative": false, + "gap": 0.16827879038427618, + "limit": 0.05, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "days", + "relative": true, + "gap": 0.2818411290777086, + "limit": 0.2, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "weekly_hours", + "relative": true, + "gap": 0.3769203448914046, + "limit": 0.2, + "passed": false + } + ] + }, + "interpretation": "child-weighted predictions of observed calendars; missing children are not scored as zeros; previously used survey, not external validation" + }, + "lower_hours": { + "comparisons": [ + { + "group": "all", + "children": 7460, + "child_weight": 32249785.682044946, + "observed": { + "participation": 0.4651484510706186, + "days": 1.8750709563867471, + "weekly_hours": 14.240422572045734 + }, + "expected": { + "participation": 0.4694631050646648, + "days": 1.8833882492362901, + "weekly_hours": 14.047531587671795 + }, + "conditional_mean_squared_error": { + "participation": 0.21926868145934636, + "days": 4.682031848109813, + "weekly_hours": 500.3427012480258 + }, + "expected_draw_squared_error": { + "participation": 0.4039103799500653, + "days": 8.502006698367383, + "weekly_hours": 881.8243360527052 + } + }, + { + "group": "household_size_1", + "children": 1910, + "child_weight": 9010809.078107145, + "observed": { + "participation": 0.5242108914088932, + "days": 2.119495964700082, + "weekly_hours": 16.911581677434366 + }, + "expected": { + "participation": 0.525047960986181, + "days": 2.1357761191991402, + "weekly_hours": 16.054210770550473 + }, + "conditional_mean_squared_error": { + "participation": 0.20936530757532937, + "days": 4.6155487934088635, + "weekly_hours": 523.6047784780147 + }, + "expected_draw_squared_error": { + "participation": 0.39564566426476305, + "days": 8.55184711704171, + "weekly_hours": 914.9077317360562 + } + }, + { + "group": "household_size_2", + "children": 2845, + "child_weight": 13265562.299413564, + "observed": { + "participation": 0.47658623296590163, + "days": 1.921092628643475, + "weekly_hours": 13.941634457809398 + }, + "expected": { + "participation": 0.4749117033807294, + "days": 1.9068519255675083, + "weekly_hours": 14.003162317182646 + }, + "conditional_mean_squared_error": { + "participation": 0.21815139862014563, + "days": 4.561931500445223, + "weekly_hours": 422.2683367671114 + }, + "expected_draw_squared_error": { + "participation": 0.40165024136872324, + "days": 8.243826381498717, + "weekly_hours": 766.5250069522581 + } + }, + { + "group": "household_size_3", + "children": 2705, + "child_weight": 9973414.304524235, + "observed": { + "participation": 0.3965732409177563, + "days": 1.5930240706983663, + "weekly_hours": 12.224491842781102 + }, + "expected": { + "participation": 0.411996000295025, + "days": 1.6241512727038396, + "weekly_hours": 12.293546528799457 + }, + "conditional_mean_squared_error": { + "participation": 0.22970229959955119, + "days": 4.901842706260032, + "weekly_hours": 583.1719294446634 + }, + "expected_draw_squared_error": { + "participation": 0.41438360216783604, + "days": 8.800380403699931, + "weekly_hours": 1005.2928126952421 + } + }, + { + "group": "complete_household", + "children": 6699, + "child_weight": 29099899.915354412, + "observed": { + "participation": 0.4440893924635181, + "days": 1.7729192348218485, + "weekly_hours": 13.202436331757639 + }, + "expected": { + "participation": 0.468748065741229, + "days": 1.877169949779378, + "weekly_hours": 14.002473817238808 + }, + "conditional_mean_squared_error": { + "participation": 0.21484625757130862, + "days": 4.498558028782448, + "weekly_hours": 463.4897759965144 + }, + "expected_draw_squared_error": { + "participation": 0.40059537458069444, + "days": 8.314169510261438, + "weekly_hours": 843.9903904302846 + } + }, + { + "group": "unresolved_siblings", + "children": 761, + "child_weight": 3149885.766690531, + "observed": { + "participation": 0.659700426338619, + "days": 2.8187892667948593, + "weekly_hours": 23.8297530885091 + }, + "expected": { + "participation": 0.4760689232716501, + "days": 1.9408353775586458, + "weekly_hours": 14.463793226069521 + }, + "conditional_mean_squared_error": { + "participation": 0.2601247956353107, + "days": 6.377036103811426, + "weekly_hours": 840.8047102985204 + }, + "expected_draw_squared_error": { + "participation": 0.4345357205537359, + "days": 10.23732149361069, + "weekly_hours": 1231.349402217937 + } + } + ], + "screen": { + "passed": false, + "checks": [ + { + "group": "all", + "metric": "participation", + "relative": false, + "gap": 0.004314653994046236, + "limit": 0.05, + "passed": true + }, + { + "group": "all", + "metric": "days", + "relative": true, + "gap": 0.004435721656939506, + "limit": 0.2, + "passed": true + }, + { + "group": "all", + "metric": "weekly_hours", + "relative": true, + "gap": 0.013545313237585262, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "participation", + "relative": false, + "gap": 0.0008370695772877967, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_1", + "metric": "days", + "relative": true, + "gap": 0.0076811443712098675, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "weekly_hours", + "relative": true, + "gap": 0.05069726316775619, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "participation", + "relative": false, + "gap": 0.0016745295851722242, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_2", + "metric": "days", + "relative": true, + "gap": 0.007412814386791165, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "weekly_hours", + "relative": true, + "gap": 0.004413245775410731, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "participation", + "relative": false, + "gap": 0.015422759377268669, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_3", + "metric": "days", + "relative": true, + "gap": 0.019539693453487807, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "weekly_hours", + "relative": true, + "gap": 0.005648879880363551, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "participation", + "relative": false, + "gap": 0.02465867327771093, + "limit": 0.05, + "passed": true + }, + { + "group": "complete_household", + "metric": "days", + "relative": true, + "gap": 0.05880172819491406, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "weekly_hours", + "relative": true, + "gap": 0.06059771585921071, + "limit": 0.2, + "passed": true + }, + { + "group": "unresolved_siblings", + "metric": "participation", + "relative": false, + "gap": 0.1836315030669689, + "limit": 0.05, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "days", + "relative": true, + "gap": 0.3114648901137978, + "limit": 0.2, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "weekly_hours", + "relative": true, + "gap": 0.3930363788349918, + "limit": 0.2, + "passed": false + } + ] + }, + "interpretation": "child-weighted predictions of observed calendars; missing children are not scored as zeros; previously used survey, not external validation" + }, + "higher_hours": { + "comparisons": [ + { + "group": "all", + "children": 7460, + "child_weight": 32249785.682044946, + "observed": { + "participation": 0.4651484510706186, + "days": 1.8750709563867471, + "weekly_hours": 14.240422572045734 + }, + "expected": { + "participation": 0.4817605698879911, + "days": 1.935495472459631, + "weekly_hours": 14.8055110801012 + }, + "conditional_mean_squared_error": { + "participation": 0.2183109232064996, + "days": 4.690768651747343, + "weekly_hours": 498.8691681881239 + }, + "expected_draw_squared_error": { + "participation": 0.40741923323645185, + "days": 8.605384759130065, + "weekly_hours": 907.0848865837559 + } + }, + { + "group": "household_size_1", + "children": 1910, + "child_weight": 9010809.078107145, + "observed": { + "participation": 0.5242108914088932, + "days": 2.119495964700082, + "weekly_hours": 16.911581677434366 + }, + "expected": { + "participation": 0.5336709141023375, + "days": 2.188482690987151, + "weekly_hours": 16.9836136757819 + }, + "conditional_mean_squared_error": { + "participation": 0.21203549535609473, + "days": 4.757503626364953, + "weekly_hours": 529.4532061228166 + }, + "expected_draw_squared_error": { + "participation": 0.4019308546381216, + "days": 8.800956479349571, + "weekly_hours": 957.0728947317252 + } + }, + { + "group": "household_size_2", + "children": 2845, + "child_weight": 13265562.299413564, + "observed": { + "participation": 0.47658623296590163, + "days": 1.921092628643475, + "weekly_hours": 13.941634457809398 + }, + "expected": { + "participation": 0.4872962043858133, + "days": 1.961324327491388, + "weekly_hours": 14.581394805547957 + }, + "conditional_mean_squared_error": { + "participation": 0.21757171189632124, + "days": 4.574209050120303, + "weekly_hours": 404.8084050090706 + }, + "expected_draw_squared_error": { + "participation": 0.4060140807749717, + "days": 8.346865239290644, + "weekly_hours": 750.762219107529 + } + }, + { + "group": "household_size_3", + "children": 2705, + "child_weight": 9973414.304524235, + "observed": { + "participation": 0.3965732409177563, + "days": 1.5930240706983663, + "weekly_hours": 12.224491842781102 + }, + "expected": { + "participation": 0.427497557376175, + "days": 1.6725710886094731, + "weekly_hours": 13.135728021730285 + }, + "conditional_mean_squared_error": { + "participation": 0.2249638841589955, + "days": 4.7855097818173356, + "weekly_hours": 596.3465172213456 + }, + "expected_draw_squared_error": { + "participation": 0.41424687191029114, + "days": 8.772543899737947, + "weekly_hours": 1069.845164762894 + } + }, + { + "group": "complete_household", + "children": 6699, + "child_weight": 29099899.915354412, + "observed": { + "participation": 0.4440893924635181, + "days": 1.7729192348218485, + "weekly_hours": 13.202436331757639 + }, + "expected": { + "participation": 0.4805926944205894, + "days": 1.9264832406591257, + "weekly_hours": 14.755995861748625 + }, + "conditional_mean_squared_error": { + "participation": 0.21531436658512484, + "days": 4.537187483655545, + "weekly_hours": 462.1342992299814 + }, + "expected_draw_squared_error": { + "participation": 0.40507603278902476, + "days": 8.436042507760133, + "weekly_hours": 870.7039390572138 + } + }, + { + "group": "unresolved_siblings", + "children": 761, + "child_weight": 3149885.766690531, + "observed": { + "participation": 0.659700426338619, + "days": 2.8187892667948593, + "weekly_hours": 23.8297530885091 + }, + "expected": { + "participation": 0.49254986884428775, + "days": 2.0187540611303847, + "weekly_hours": 15.262952398635264 + }, + "conditional_mean_squared_error": { + "participation": 0.24599430737706623, + "days": 6.109612683367641, + "weekly_hours": 838.2405261560589 + }, + "expected_draw_squared_error": { + "participation": 0.4290666527152173, + "days": 10.169835958731479, + "weekly_hours": 1243.1865773318777 + } + } + ], + "screen": { + "passed": false, + "checks": [ + { + "group": "all", + "metric": "participation", + "relative": false, + "gap": 0.016612118817372512, + "limit": 0.05, + "passed": true + }, + { + "group": "all", + "metric": "days", + "relative": true, + "gap": 0.03222518906128307, + "limit": 0.2, + "passed": true + }, + { + "group": "all", + "metric": "weekly_hours", + "relative": true, + "gap": 0.03968200418186654, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "participation", + "relative": false, + "gap": 0.009460022693444259, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_1", + "metric": "days", + "relative": true, + "gap": 0.032548647148205746, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "weekly_hours", + "relative": true, + "gap": 0.004259329477363312, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "participation", + "relative": false, + "gap": 0.010709971419911646, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_2", + "metric": "days", + "relative": true, + "gap": 0.020942092144886043, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "weekly_hours", + "relative": true, + "gap": 0.04588847524833771, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "participation", + "relative": false, + "gap": 0.0309243164584187, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_3", + "metric": "days", + "relative": true, + "gap": 0.049934598838945486, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "weekly_hours", + "relative": true, + "gap": 0.07454184522911626, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "participation", + "relative": false, + "gap": 0.0365033019570713, + "limit": 0.05, + "passed": true + }, + { + "group": "complete_household", + "metric": "days", + "relative": true, + "gap": 0.08661647006876091, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "weekly_hours", + "relative": true, + "gap": 0.11767218496286139, + "limit": 0.2, + "passed": true + }, + { + "group": "unresolved_siblings", + "metric": "participation", + "relative": false, + "gap": 0.16715055749433128, + "limit": 0.05, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "days", + "relative": true, + "gap": 0.2838222832365773, + "limit": 0.2, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "weekly_hours", + "relative": true, + "gap": 0.35950018693247887, + "limit": 0.2, + "passed": false + } + ] + }, + "interpretation": "child-weighted predictions of observed calendars; missing children are not scored as zeros; previously used survey, not external validation" + } + }, + "production_ready": false, + "interpretation": "development comparison; completed training intervals remain modeled under declared coarsening assumptions; no held-out household contributes to completion or refitting" +} diff --git a/experiments/us-childcare-attendance/merge-readiness.md b/experiments/us-childcare-attendance/merge-readiness.md new file mode 100644 index 000000000..e6c7643e2 --- /dev/null +++ b/experiments/us-childcare-attendance/merge-readiness.md @@ -0,0 +1,237 @@ +# PR #916 merge-readiness audit + +Objective: resolve the PR's engineering, integration and statistical issues to +reach merge-ready quality while retaining draft status. This audit does not +authorize publication or replacing the default population. Completion is not +yet established. + +## Current audit, September 27, 2026 + +This update starts from `25a54a4e` and merges upstream main at `9e5b0cee`. +Maria's [September 22 review](https://github.com/PolicyEngine/microcosm/pull/916#issuecomment-5773509314) +closes C1, A1, A2, S1 and S2. It retains the household-model concern as A3, +names the missing raw-source build/certification as C2, and adds A4 for stale +target-frame and reform-vector caches. S1's requested documentation and paired +sensitivity work are resolved; empirical transport validity remains unproven. + +Main now hashes the staged tables, weights and strata before target +materialization. The PR additionally verifies the attendance binding after the +intervening source stages and includes its digest in the checkpoint identity. +The reform-vector cache already includes that full materializer identity's +digest. Thus changed attendance values or a changed execution invalidate both +caches, including a recipe change that produces numerically identical values. +Regression coverage uses synthetic bound source executions and real on-disk +checkpoints/reform caches. It checks unchanged reuse, changed-value and +changed-recipe misses, and refusal of tampered values before lookup. + +The merge preserves main's stored-input and batched post-export scoring gates. +Attendance is persisted and reloaded before the scorer hashes the final H5. +The attendance tests follow the new environment-specific directory layout, +with shared synthetic fixtures under `test_support/microcosm_build/`. +The exact-k runbook now states that multispine ingress does not restore the +receipt and therefore needs the NSECE source configuration. + +The former upstream blockers have changed: #952 (processed ASEC pins), #955 +(labelled bare feed), #948 (SPM preflight), and #959 (SPM source-role stage) are merged and included +here. #961 and Chronicle #278 remain open as of September 27. The validated +consumer artifact is needed for the exact-k route; the supplied-base route +can use the labelled bare feed. Main also supports `--new-lineage` preflight +without the July frozen selection. The Modal runner currently covers the ACS +local-release tool, not the full national raw-source/fiscal build required here. + +C2 remains open: this update does not carry a from-scratch build/certification +receipt from its own tree, and no suitable build host has been identified for +this task. A3 also remains open: the production household model fails 9/15 +provisional screens, and none of the inspected diagnostic alternatives has +earned adoption. No threshold is relaxed and no development partition is +relabeled as independent validation. The PR remains draft and +`production_ready: false`; engineering cache fixes do not resolve these two +findings or authorize publication. + +September 27 verification: + +- The 1,454-test affected-suite run finished with 1,448 passes, four failures + from stale serializer/export fixtures, and two skips. After the fixture fixes + below, all 23 serializer tests and all 17 selected fiscal-builder/cache tests + pass in follow-up runs, covering every failure. The two skipped tests require + `MICROCOSM_US_CHRONICLE_FACTS` to name the pinned consumer-facts feed; that feed + was not supplied to this run. The entire broad suite was not repeated after + the test-only fixes. GitHub CI was not monitored. +- The focused attendance suite passes 145 tests under the US engine. The four + engine-free attendance modules also pass all 138 tests, and both cache + regressions pass separately, in a locked environment with no country engine + installed. +- Both cache scenarios pass with the fix. A negative control that omits the + receipt's effect on identity reproduces the stale recipe-only checkpoint hit; + main's staged-value digest still protects the changed-value scenario. +- All six workspace wheels build and pass the current wheel-content inspection. + The regenerated compiler report covers 42,187/42,187 fields and 41/41 inventory + checks. CI inventory verifies all 540 test modules in the new directory layout. + Repository lint, changed-file formatting and diff whitespace checks pass. +- Main's SPM role projection and this PR's attendance writer bring the serializer + registry to eleven entries. The first broad run exposed the old count of ten; + the count and uniqueness assertions now cover all eleven registered writers, + and all 23 engine-free serializer checks pass after the correction. +- The new green-export/stored-input harness from main uses household-only + frames and placeholder file bytes. Its attendance boundary doubles now match + that fixture design and append receipt bytes before the scorer opens the file. + The scorer's digest and release-manifest hashes must agree with those final + bytes. Real row, binding and native-reload checks remain in the NSECE tests; + no production gate is weakened to accommodate a fake frame. +- Fresh verification of the existing 166,321-person candidate through both native + loaders reproduces `review-fixes-verification.json` byte for byte (SHA256 + `765ef64f53b7cad45153bc96ffae65b6156f7c23259f004ad722c828edea165e`). Original + columns/weights and attendance bindings remain exact; this is integrity + evidence, not a new population build or statistical certification. + +## Historical audit, September 20, 2026 + +The following records the earlier tree and its checks. Its dependency and +latest-review statements are historical; the September 27 audit above governs +the current status. + +The starting PR head is `d2601c7a0749b134822086f4783e03501c750e32`. +Its 24 GitHub checks passed. The current integration base is +`18c6d39a`, 65 main-branch commits beyond the PR's previous merge base. +Maria's September 15 review is the latest external review; no follow-up approval +is recorded. Passing tests below are engineering evidence, not statistical +acceptance. + +| Requirement | Current evidence and remaining work | +| --- | --- | +| Current main, clean merge and safe PR branch | Merge commit `8d74be68` reconciles README and serializer-test conflicts. At `4f746222`, local HEAD, upstream tracking and push refs match `fork/fix/us-childcare-attendance`; GitHub reports mergeable and draft. | +| C1: exact attendance values and source recipe bound together | The 573-test affected suite passes with no skips. Fresh verification of the real 166,321-person candidate through both native loaders validates the exact source/code/runtime/settings binding and preservation of all original values and weights. | +| A1: row-complete final attendance | The affected suite covers the final rowwise boundary (null days, out-of-range days, incoherent zeros and fractional monthly days), unbound nondegenerate attendance refusal, native tampering, receipt reuse and fiscal-builder checks. The complete national fiscal run remains separate evidence below. | +| A2: valid source household identities | Missing, blank, stringified-null and unresolved household identities are rejected; regression coverage exists. | +| A3: household intensity and larger-sibship validation | Joint days/hours and 3+ child diagnostics exist. Their reported screen failures remain substantive; adding diagnostics alone does not qualify the model. | +| S1: noncalendar transport and sensitivity | Observed regular hours remain fixed; paired sensitivity holds donor identities fixed. State flags and missing-calendar selection remain unresolved statistical evidence. | +| S2: explicit operation provenance | Receipts identify calendar derivation, dependence fitting, noncalendar bridge, target harmonization, joint transfer and outside-domain baseline policy. | +| Fiscal builder and exact-k integration | Repair metadata preservation and exact-k source configuration have targeted tests. The release rule requires a build from raw sources and certification from this PR's tree; a supplied-parent fiscal run is an intermediate integration check only. | +| Annual projection compatibility | The regression reproduced the original receipt loss. All 42 annual/serializer tests now pass: the 2024 base and 2025/2026 projections retain their original receipt, changed attendance is refused before finalizing an output, and the combined serializer inventory has ten writers. | +| Source mapping and population integrity | Licensed DS4/DS5 files, pinned ASEC cache and BuildP parent are available locally. Current candidate evidence preserves original population values/weights. Recheck any affected evidence after implementation or runtime changes. | +| Statistical qualification | Existing experiments fail provisional subgroup/household screens. Do not redefine those failures as acceptance, relax thresholds after seeing results, or call inspected partitions independent validation. A defensible model/assumption treatment and stronger validation remain required. | +| Final tests, packaging, evidence and handoff | The affected engine and wheel suites pass as detailed below; the real candidate report is reproduced. Source microdata and per-person hashes remain local. The PR retains its feature-branch push target, draft status and VS Code PR file-tree view. Full-build and statistical evidence remain separate requirements. | + +## September 20 engineering checks + +- Initial merged attendance, launcher and serializer run: 139 passed, one failed. + The failure was the serializer count: the combined branches contain ten + serializers, while each independently expected nine. The expectation was + corrected; the subsequent 42-test annual/serializer run passes. +- Specification coverage remains current: 42,159/42,159 fields and 41/41 inventory + checks. No checksum regeneration is needed for this merge. +- Repository lint and the tracked CI test inventory passed after conflict + resolution. +- The new annual receipt regression failed on the original annual writer at + native reload, proving the uncovered integration defect. The final annual and + serializer run passes all 42 tests with no skips. Repository-wide lint and + changed-file formatting also pass after the fix. +- VS Code recognizes the worktree as PR #916 and shows the GitHub Pull Request + sidebar with its clickable file tree. Its Sync target is the fork's feature + branch, not main. +- At `4f746222`, all 573 affected source, receipt, coverage, fiscal-builder, + exact-k-launcher and L0-export tests pass, with no skips. +- All workspace wheels build and install into a separate constrained environment. + The five package imports resolve inside that environment, PolicyEngine-US is + absent as required by the base-wheel lane, and the annual exporter matches + the committed source bytes. The affected wheel suite passes 172 tests; its + 40 skips comprise 26 checks requiring PolicyEngine-US and 14 requiring + optional PyTables. The engine-enabled tests above cover those boundaries. +- Fresh native candidate verification reproduces + [the committed report](review-fixes-verification.json) byte for byte + (SHA256 `765ef64f53b7cad45153bc96ffae65b6156f7c23259f004ad722c828edea165e`). + Both native loaders preserve all 166,321 people's original values and weights, + and the exact attendance binding. No recipe change or population rebuild was + necessary for the main merge and annual receipt fix. + +## Full-build preparation and constraints + +The [US release build rule](../../docs/us-release-build-rule.md) requires a +from-scratch build and certification receipt from the PR's own tree for a change +that alters how the dataset is built. Reusing the July BuildP population does +not satisfy that requirement, even if its fiscal refresh passes. Default +promotion additionally requires the exact-k frozen-register improvement gate; +publication remains a separate human decision. + +The pinned DS4/DS5 files, raw ASEC CSV cache and original BuildP parent are +available locally. These are not the complete processed inputs for the raw +base builder. The inspected feed and source-stage remedies are still in open +upstream PRs as of September 20: + +- [#952](https://github.com/PolicyEngine/microcosm/pull/952) pins and fetches the + three processed ASEC H5 inputs from their public mirror. +- [#955](https://github.com/PolicyEngine/microcosm/pull/955) reproduces the + approved Chronicle feed's 586 recordset/period pairs with labelled facts. + [#961](https://github.com/PolicyEngine/microcosm/pull/961), stacked on #955, + pins the validated consumer artifact produced with + [Chronicle #278](https://github.com/PolicyEngine/chronicle/pull/278). +- [#948](https://github.com/PolicyEngine/microcosm/pull/948) diagnoses unresolved + SPM composition, and [#959](https://github.com/PolicyEngine/microcosm/pull/959), + stacked on #948, materializes the Census independence role in raw builds. + +Those implementations have not been incorporated into this PR. The approved +target scope spans multiple years. Both exploratory Chronicle builds were +deliberately stopped: the default run included other countries, and the US-only +2023 run did not reproduce the approved multi-period scope. Their partial +outputs are not accepted consumer artifacts. A generic current-year export +must not silently replace the reviewed feed. + +This host has 16 GiB RAM. The release runbook records a raw base build peaking at +72.47 GB on a 128 GiB machine under the older 1.819.0 engine; it also reports a +July fiscal comparator at about 85 GB. These historical measurements are not a +guarantee for the present larger build, but they rule out treating a generic +32 GiB minimum as adequate preparation here. An appropriately provisioned build +host and the licensed raw inputs are still needed. + +Once the upstream prerequisites are integrated, validation must build a fresh +raw-source base/pool and run the normal preflight and certification gates from +the resulting PR tree, retaining its code, input and artifact identities. The +July frozen household selection cannot be reused for the rebuilt base; the +release runbook explains its donor-loss failure and the permitted new lineage. +No coverage or statistical gate overrides are an acceptance substitute. + +The invocation below is only a prepared **supplied-parent integration check**, +not the required from-scratch build and not a completed run. `/local` denotes +the operator's input/output directory; use a fresh output directory, the +recorded parent hash, and replace the quoted SHA256 placeholders with the actual +qualified consumer-artifact hashes. + +```bash +uv run --no-sync python tools/build_us_fiscal_refresh_release.py \ + --base-h5 /local/populace_us_2024.h5 \ + --ledger-facts /local/chronicle-us-consumer-artifact \ + --ledger-facts-sha256 "CONSUMER_FACTS_SHA256" \ + --ledger-manifest-sha256 "CONSUMER_MANIFEST_SHA256" \ + --asec-2023-weeks-unemployed-source /local/asec/asecpub23csv.zip \ + --childcare-attendance-household-tsv /local/39466-0005-Data.tsv \ + --childcare-attendance-calendar-tsv /local/39466-0004-Data.tsv \ + --childcare-attendance-asec-cache /local/asec \ + --childcare-attendance-inherit-outside-domain-baseline \ + --seed 915 --no-staging --out /local/pr916-fiscal-validation +``` + +That integration check should retain its final H5, source-coverage receipt and +release-gate results, with attendance checked on native reload. Completion of +the merge requirement needs equivalent evidence from the raw-source build and +certification as well. Neither an authenticated target registry nor the +supplied-parent integration result alone meets the requirement. + +## Independent attendance evidence + +Recent SIPP files are not a replacement hours benchmark. The Census Bureau's +[2023 SIPP comparability note](https://www.census.gov/programs-surveys/sipp/tech-documentation/user-notes/2023-usernotes/compr-2023-sipp-chld-care-data-prev-yrs.html) +describes the change from each child's arrangement hours in the 2008 and earlier +panels to the redesigned arrangement questions. The +[2024 SIPP variable catalog](https://api.census.gov/data/2024/sipp/variables.html) +provides arrangement and payment variables, not the joint days/hours calendar +needed here. It could support a separately harmonized participation comparison; +it cannot close the schedule-intensity or noncalendar-transport evidence gap. + +The existing NSECE development folds and incomplete-calendar bounds remain useful +diagnostics. They are not a new independent sample, and missing schedules cannot +be turned into observed validation outcomes. The subgroup and household screen +failures therefore remain open after the engineering checks pass. + +The full fiscal run is not replaced by the standalone attendance-preparation +command or by mocked builder tests. Publication, survey transport validity and +maintainer approval are distinct from serializer and code-contract checks. diff --git a/experiments/us-childcare-attendance/nsece-2024-v1-validation.json b/experiments/us-childcare-attendance/nsece-2024-v1-validation.json new file mode 100644 index 000000000..8a8251642 --- /dev/null +++ b/experiments/us-childcare-attendance/nsece-2024-v1-validation.json @@ -0,0 +1,412 @@ +{ + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "source_child_count": 11745, + "source_attrition": [ + { + "status": "age_out_of_scope", + "n": 134, + "child_weight": 633390.6468148227 + }, + { + "status": "ambiguous_calendar", + "n": 1222, + "child_weight": 5389746.35438953 + }, + { + "status": "complete", + "n": 7120, + "child_weight": 30778083.363609407 + }, + { + "status": "missing_calendar", + "n": 3095, + "child_weight": 14061828.648228496 + }, + { + "status": "partial_calendar", + "n": 174, + "child_weight": 847769.9869632281 + } + ], + "under13_complete_weight_share": 0.6025769964530093, + "seed": 915, + "evaluation_design": "fixed household diagnostic split; not final population certification", + "match_columns": [ + "age", + "region", + "parent_work_status" + ], + "training_children": 5721, + "heldout_children": 1399, + "unsupported_heldout_children": 3, + "unsupported_heldout_weight": 44357.422786916, + "household_overlap": 0, + "comparisons": [ + { + "grouping": "all", + "group": "all", + "n": 1396, + "observed": { + "participation": 0.44824430561905076, + "days_per_week": 1.8230211691271492, + "hours_per_week": 13.652357584014506 + }, + "predicted": { + "participation": 0.4599107708663381, + "days_per_week": 1.792538633803043, + "hours_per_week": 13.094746582956082 + } + }, + { + "grouping": "age", + "group": "0", + "n": 85, + "observed": { + "participation": 0.4250548518820099, + "days_per_week": 1.6272888682251536, + "hours_per_week": 13.475219723863841 + }, + "predicted": { + "participation": 0.4001916699342544, + "days_per_week": 1.1485583331917613, + "hours_per_week": 9.848867658204549 + } + }, + { + "grouping": "age", + "group": "1", + "n": 110, + "observed": { + "participation": 0.5884762506267653, + "days_per_week": 2.113900852594937, + "hours_per_week": 15.642081332218696 + }, + "predicted": { + "participation": 0.546281902566076, + "days_per_week": 2.2283167307047886, + "hours_per_week": 18.453955475585847 + } + }, + { + "grouping": "age", + "group": "2", + "n": 109, + "observed": { + "participation": 0.6638776717499305, + "days_per_week": 3.1543151104205833, + "hours_per_week": 31.753365600922873 + }, + "predicted": { + "participation": 0.6675303263843991, + "days_per_week": 2.153101731321593, + "hours_per_week": 19.06318009755674 + } + }, + { + "grouping": "age", + "group": "3", + "n": 103, + "observed": { + "participation": 0.5305706046713187, + "days_per_week": 2.438879416678265, + "hours_per_week": 18.1763127663353 + }, + "predicted": { + "participation": 0.7244282687897443, + "days_per_week": 3.5317307356291354, + "hours_per_week": 31.010642124434668 + } + }, + { + "grouping": "age", + "group": "4", + "n": 115, + "observed": { + "participation": 0.6728458027114763, + "days_per_week": 3.0618827336322867, + "hours_per_week": 21.645846223858417 + }, + "predicted": { + "participation": 0.7679834812046982, + "days_per_week": 3.0884408007199, + "hours_per_week": 22.77807200190468 + } + }, + { + "grouping": "age", + "group": "5", + "n": 108, + "observed": { + "participation": 0.44276847764953914, + "days_per_week": 2.098241639215739, + "hours_per_week": 15.395426983272767 + }, + "predicted": { + "participation": 0.5098892206159185, + "days_per_week": 2.034518834281255, + "hours_per_week": 12.616686226131161 + } + }, + { + "grouping": "age", + "group": "6", + "n": 114, + "observed": { + "participation": 0.3316947363796176, + "days_per_week": 1.2944962438275214, + "hours_per_week": 9.335974428220535 + }, + "predicted": { + "participation": 0.2502829109705292, + "days_per_week": 0.8489748828146265, + "hours_per_week": 4.095594700920569 + } + }, + { + "grouping": "age", + "group": "7", + "n": 117, + "observed": { + "participation": 0.24608381033211157, + "days_per_week": 0.754974779448484, + "hours_per_week": 4.361409561749528 + }, + "predicted": { + "participation": 0.2816097434308538, + "days_per_week": 1.2011659245211868, + "hours_per_week": 8.378054810826729 + } + }, + { + "grouping": "age", + "group": "8", + "n": 131, + "observed": { + "participation": 0.32031380136011167, + "days_per_week": 1.1016613467219087, + "hours_per_week": 5.702965816381827 + }, + "predicted": { + "participation": 0.3616416815522732, + "days_per_week": 1.3941828221834964, + "hours_per_week": 6.393127232702683 + } + }, + { + "grouping": "age", + "group": "9", + "n": 96, + "observed": { + "participation": 0.34656269944559637, + "days_per_week": 1.3599782610569988, + "hours_per_week": 6.897690557738436 + }, + "predicted": { + "participation": 0.43275434548357045, + "days_per_week": 1.7893869343598068, + "hours_per_week": 12.468455293838895 + } + }, + { + "grouping": "age", + "group": "10", + "n": 101, + "observed": { + "participation": 0.42051506588928955, + "days_per_week": 1.4586593950757574, + "hours_per_week": 9.973639524210338 + }, + "predicted": { + "participation": 0.24474633593038378, + "days_per_week": 0.9756762848157232, + "hours_per_week": 6.008858030670072 + } + }, + { + "grouping": "age", + "group": "11", + "n": 112, + "observed": { + "participation": 0.3912389480210642, + "days_per_week": 1.7037510807546974, + "hours_per_week": 11.42197768791282 + }, + "predicted": { + "participation": 0.27792753401822695, + "days_per_week": 0.8090302361512782, + "hours_per_week": 7.743373773952352 + } + }, + { + "grouping": "age", + "group": "12", + "n": 95, + "observed": { + "participation": 0.42381513275076016, + "days_per_week": 1.3666357724773346, + "hours_per_week": 10.404992746238733 + }, + "predicted": { + "participation": 0.5490190603072337, + "days_per_week": 2.3346754573311457, + "hours_per_week": 13.09355527945929 + } + }, + { + "grouping": "region", + "group": "1", + "n": 176, + "observed": { + "participation": 0.512049571332397, + "days_per_week": 2.3364280889303273, + "hours_per_week": 14.798702419320156 + }, + "predicted": { + "participation": 0.6213815652348272, + "days_per_week": 2.367934702106529, + "hours_per_week": 16.14377173776723 + } + }, + { + "grouping": "region", + "group": "2", + "n": 326, + "observed": { + "participation": 0.4156690296156914, + "days_per_week": 1.6707757670228114, + "hours_per_week": 13.50512496474333 + }, + "predicted": { + "participation": 0.4156827588489637, + "days_per_week": 1.4698531060718576, + "hours_per_week": 11.050552277269526 + } + }, + { + "grouping": "region", + "group": "3", + "n": 460, + "observed": { + "participation": 0.39711564348080924, + "days_per_week": 1.7104278494216743, + "hours_per_week": 14.327410707539498 + }, + "predicted": { + "participation": 0.40609226757761724, + "days_per_week": 1.6125118356079156, + "hours_per_week": 12.357699085016328 + } + }, + { + "grouping": "region", + "group": "4", + "n": 434, + "observed": { + "participation": 0.4998856798556513, + "days_per_week": 1.7358423509265488, + "hours_per_week": 12.03035641734164 + }, + "predicted": { + "participation": 0.4542107213405013, + "days_per_week": 1.9027766791574927, + "hours_per_week": 13.681380128977889 + } + }, + { + "grouping": "parent_work_status", + "group": "-1", + "n": 21, + "observed": { + "participation": 0.2883481772975941, + "days_per_week": 0.9379764610750094, + "hours_per_week": 3.544637613886705 + }, + "predicted": { + "participation": 0.20256052180939443, + "days_per_week": 0.9965262439605058, + "hours_per_week": 4.923861455170338 + } + }, + { + "grouping": "parent_work_status", + "group": "0", + "n": 153, + "observed": { + "participation": 0.28587206721249403, + "days_per_week": 1.1510297379070302, + "hours_per_week": 9.85637208916276 + }, + "predicted": { + "participation": 0.33794446267152484, + "days_per_week": 1.381154311963177, + "hours_per_week": 8.994549754516147 + } + }, + { + "grouping": "parent_work_status", + "group": "1", + "n": 556, + "observed": { + "participation": 0.2544421472652274, + "days_per_week": 0.8655226862627626, + "hours_per_week": 5.479055121121177 + }, + "predicted": { + "participation": 0.3048755294132399, + "days_per_week": 0.9735429342912938, + "hours_per_week": 6.619958653424124 + } + }, + { + "grouping": "parent_work_status", + "group": "2", + "n": 666, + "observed": { + "participation": 0.6079397288949188, + "days_per_week": 2.598506997335398, + "hours_per_week": 20.1129358627005 + }, + "predicted": { + "participation": 0.591426968065257, + "days_per_week": 2.435925494751169, + "hours_per_week": 18.361765426147866 + } + } + ], + "production_ready": false, + "limitations": [ + "Only complete, unambiguous calendars enter this holdout; source selection remains unvalidated.", + "The diagnostic matches age and caller-specified covariates; it is not a nationally validated fitted model.", + "Sibling assignments, mixed providers, older-child care and scalar monthly conversion need validation.", + "No full Microcosm population build or state CCDF distribution is certified by this source-only report." + ], + "candidate_frame_written": true, + "environment": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "microcosm-build": "0.1.0", + "microcosm-frame": "0.1.0", + "python": "3.13.5" + }, + "code_sha256": { + "prepare_us_childcare_attendance.py": "5b83f0e3fb6b2b1e4c4264ffc594a1daefa1de3cd1d05f6bbadeb381d3b7bc88", + "childcare_attendance.py": "f7fede91b10ed5384a7197c1413958c5e526c47300b20e9248b08f12f46168b8", + "nsece_childcare.py": "39100db1e7ede461c37c0e6259a274233074d7838ec61616ed5d62302eb377ed" + } +} diff --git a/experiments/us-childcare-attendance/paired-identity-sensitivity.json b/experiments/us-childcare-attendance/paired-identity-sensitivity.json new file mode 100644 index 000000000..7370cd935 --- /dev/null +++ b/experiments/us-childcare-attendance/paired-identity-sensitivity.json @@ -0,0 +1,3231 @@ +{ + "parent_sha256": "48b9d479fb4fd1c3537f9383ce4697d130b6f618658409d74f6233c43b994c7e", + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "calendar_bounds": { + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568", + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "missing_calendar": "uninformative 0--168 hours and 0--7 days" + }, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "recipe": { + "contract_sha256": "ae648c6cb0e2838fdf142975e9c536eb0683d9630fd1738096d524222ffb01dc", + "runtime_versions": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "policyengine-us": "2.2.1" + }, + "code_sha256": { + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "nsece_childcare.py": "0e72ff9388f8f59147305f07effec2b99dada0f91599727cc9e58ad4feb6edbb", + "nsece_childcare_bridge.py": "70a7edea8b28c6da21ff4fa9bb220766a3e6cd714926684af29bdba1a8421b0a", + "nsece_childcare_dependence.py": "1c5123a77f84460ba517d2b4c6c3e04ae658bf36e9cf54ed69ddbcacc85efc09", + "childcare_attendance_stage.py": "42e777b0edfc813d79204bc2932fe429d6a48cd2866397560a7386cbee54dadb", + "childcare_attendance_receipt.py": "0950fce7f372ca4b240cd055c931f5f8fe070223fd68504a3ea9cfbc4e16c645" + } + }, + "seed": 915, + "candidate_checkpoint_sha256": "31e4a80cc896aeb769ea034a60e8be68c81bed35a52ff52e27ca62d8cb46f40d", + "assignment_checks": { + "candidate": { + "donor_assigned_people": 31889, + "bridge_assigned_people": 9675, + "changed_people": 0, + "measured_calendar_assignments_changed": 0, + "donor_assignment": "held fixed and validated against candidate values" + }, + "no_modeled_irregular_hours": { + "donor_assigned_people": 31889, + "bridge_assigned_people": 9675, + "changed_people": 1289, + "measured_calendar_assignments_changed": 0, + "donor_assignment": "held fixed and validated against candidate values" + }, + "one_fewer_day": { + "donor_assigned_people": 31889, + "bridge_assigned_people": 9675, + "changed_people": 3725, + "measured_calendar_assignments_changed": 0, + "donor_assignment": "held fixed and validated against candidate values" + }, + "one_more_day": { + "donor_assigned_people": 31889, + "bridge_assigned_people": 9675, + "changed_people": 4271, + "measured_calendar_assignments_changed": 0, + "donor_assignment": "held fixed and validated against candidate values" + } + }, + "coupling": "same donor identities across scenarios; no care-rank reassignment", + "engine_version": "2.2.1", + "policy_year": 2026, + "code_sha256": { + "validate_us_childcare_sensitivity.py": "ce58f0179a9b2732d2adf2335ec4444dd8a1f861b248923e9bed561c7282f983", + "childcare_sensitivity.py": "17a684c51ed48f164006d485aa2177d8c1f03609290e96eae377c625bb6d93cf" + }, + "population": "fixed BuildP source ages/incomes; no aging or uprating", + "assumptions": { + "candidate": {}, + "no_modeled_irregular_hours": { + "include_modeled_irregular_hours": false, + "modeled_day_shift": 0, + "measured_regular_hours_preserved": true + }, + "one_fewer_day": { + "include_modeled_irregular_hours": true, + "modeled_day_shift": -1, + "measured_regular_hours_preserved": true + }, + "one_more_day": { + "include_modeled_irregular_hours": true, + "modeled_day_shift": 1, + "measured_regular_hours_preserved": true + } + }, + "changed_children": { + "candidate": 0, + "no_modeled_irregular_hours": 1289, + "one_fewer_day": 3725, + "one_more_day": 4271 + }, + "screens": { + "national_relative_change": 0.1, + "state_relative_change": 0.2 + }, + "states": [ + { + "state": "AL", + "sample_households": 1061, + "baseline": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13061.764184842585, + "annual_modeled_benefits": 32688921.398814265 + }, + "no_modeled_irregular_hours": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13061.764184842585, + "annual_modeled_benefits": 32688921.398814265 + }, + "one_fewer_day": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13061.764184842585, + "annual_modeled_benefits": 32688921.398814265 + }, + "one_more_day": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13061.764184842585, + "annual_modeled_benefits": 32688921.398814265 + } + }, + { + "state": "AK", + "sample_households": 826, + "baseline": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + }, + "candidate": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + }, + "no_modeled_irregular_hours": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + }, + "one_fewer_day": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + }, + "one_more_day": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + } + }, + { + "state": "AZ", + "sample_households": 1164, + "baseline": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 18733.37486637244, + "annual_modeled_benefits": 23159527.697095435 + }, + "no_modeled_irregular_hours": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 18733.37486637244, + "annual_modeled_benefits": 23159608.281765327 + }, + "one_fewer_day": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 18733.37486637244, + "annual_modeled_benefits": 23159539.191150486 + }, + "one_more_day": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 18733.37486637244, + "annual_modeled_benefits": 23159192.944776826 + } + }, + { + "state": "AR", + "sample_households": 952, + "baseline": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 17289.894029146235, + "annual_modeled_benefits": 50793417.58586023 + }, + "no_modeled_irregular_hours": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 17289.894029146235, + "annual_modeled_benefits": 50793417.58586023 + }, + "one_fewer_day": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 17289.894029146235, + "annual_modeled_benefits": 52568414.84511111 + }, + "one_more_day": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 17289.894029146235, + "annual_modeled_benefits": 50793417.58586023 + } + }, + { + "state": "CA", + "sample_households": 2659, + "baseline": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 29, + "weighted_positive_units": 175244.38451184036, + "annual_modeled_benefits": 726014134.44521 + }, + "no_modeled_irregular_hours": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 27, + "weighted_positive_units": 164627.58703250886, + "annual_modeled_benefits": 603001822.2780222 + }, + "one_fewer_day": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 29, + "weighted_positive_units": 175244.38451184036, + "annual_modeled_benefits": 726014134.44521 + }, + "one_more_day": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 29, + "weighted_positive_units": 175244.38451184036, + "annual_modeled_benefits": 726014134.44521 + } + }, + { + "state": "CO", + "sample_households": 1164, + "baseline": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 19, + "weighted_positive_units": 30914.695305580855, + "annual_modeled_benefits": 252602567.65021172 + }, + "candidate": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18502.53110225743, + "annual_modeled_benefits": 236445530.32343873 + }, + "no_modeled_irregular_hours": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18502.53110225743, + "annual_modeled_benefits": 236445530.32343873 + }, + "one_fewer_day": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18502.53110225743, + "annual_modeled_benefits": 236445530.32343873 + }, + "one_more_day": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18502.53110225743, + "annual_modeled_benefits": 236445530.32343873 + } + }, + { + "state": "CT", + "sample_households": 908, + "baseline": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 405879416.70427954 + }, + "candidate": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 636244010.8081238 + }, + "no_modeled_irregular_hours": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 636244010.8081238 + }, + "one_fewer_day": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 636244010.8081238 + }, + "one_more_day": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 636244010.8081238 + } + }, + { + "state": "DE", + "sample_households": 1068, + "baseline": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + }, + "candidate": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + }, + "no_modeled_irregular_hours": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + }, + "one_fewer_day": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + }, + "one_more_day": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + } + }, + { + "state": "DC", + "sample_households": 551, + "baseline": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 3288.0395223266023, + "annual_modeled_benefits": 23916792.31200898 + }, + "no_modeled_irregular_hours": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 3288.039414958679, + "annual_modeled_benefits": 23916791.97702106 + }, + "one_fewer_day": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 3288.0395223266023, + "annual_modeled_benefits": 23916792.300562065 + }, + "one_more_day": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 3288.0395223266023, + "annual_modeled_benefits": 23916792.180974036 + } + }, + { + "state": "FL", + "sample_households": 1642, + "baseline": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 87314.34071851184, + "annual_modeled_benefits": 336693781.677099 + }, + "no_modeled_irregular_hours": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 76833.30946851184, + "annual_modeled_benefits": 320343372.927099 + }, + "one_fewer_day": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 87314.34071851184, + "annual_modeled_benefits": 333643169.7693259 + }, + "one_more_day": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 87314.34071851184, + "annual_modeled_benefits": 352665671.4632517 + } + }, + { + "state": "GA", + "sample_households": 1215, + "baseline": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + }, + "candidate": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + }, + "no_modeled_irregular_hours": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + }, + "one_fewer_day": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + }, + "one_more_day": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + } + }, + { + "state": "HI", + "sample_households": 838, + "baseline": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0001588361046742648, + "annual_modeled_benefits": 0.6336225438054939 + }, + "no_modeled_irregular_hours": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0001588361046742648, + "annual_modeled_benefits": 0.6336225438054939 + }, + "one_fewer_day": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0001588361046742648, + "annual_modeled_benefits": 0.6336225438054939 + }, + "one_more_day": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0001588361046742648, + "annual_modeled_benefits": 0.6336225438054939 + } + }, + { + "state": "ID", + "sample_households": 746, + "baseline": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 2, + "weighted_positive_units": 2335.738774359226, + "annual_modeled_benefits": 10651259.924815893 + }, + "no_modeled_irregular_hours": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 2, + "weighted_positive_units": 2335.738774359226, + "annual_modeled_benefits": 10651259.924815893 + }, + "one_fewer_day": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 2, + "weighted_positive_units": 2335.738774359226, + "annual_modeled_benefits": 10651259.924815893 + }, + "one_more_day": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 2, + "weighted_positive_units": 2335.738774359226, + "annual_modeled_benefits": 10651259.924815893 + } + }, + { + "state": "IL", + "sample_households": 1668, + "baseline": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 62767.78443156066, + "annual_modeled_benefits": 196786246.13666055 + }, + "no_modeled_irregular_hours": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 62767.78443156066, + "annual_modeled_benefits": 138894601.64511302 + }, + "one_fewer_day": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 62767.78443156066, + "annual_modeled_benefits": 196786118.53858995 + }, + "one_more_day": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 62767.78443156066, + "annual_modeled_benefits": 196786246.13666055 + } + }, + { + "state": "IN", + "sample_households": 1141, + "baseline": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + }, + "candidate": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + }, + "no_modeled_irregular_hours": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + }, + "one_fewer_day": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + }, + "one_more_day": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + } + }, + { + "state": "IA", + "sample_households": 973, + "baseline": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 13277.072875641927, + "annual_modeled_benefits": 55836595.8273853 + }, + "no_modeled_irregular_hours": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 13277.072875641927, + "annual_modeled_benefits": 55836595.8273853 + }, + "one_fewer_day": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 13277.072875641927, + "annual_modeled_benefits": 55836595.8273853 + }, + "one_more_day": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 13277.072875641927, + "annual_modeled_benefits": 55836595.8273853 + } + }, + { + "state": "KS", + "sample_households": 921, + "baseline": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 21785.09440057905, + "annual_modeled_benefits": 57457564.33302226 + }, + "no_modeled_irregular_hours": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 21785.09440057905, + "annual_modeled_benefits": 57457564.33302226 + }, + "one_fewer_day": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 21785.09440057905, + "annual_modeled_benefits": 57457564.33302226 + }, + "one_more_day": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 21785.09440057905, + "annual_modeled_benefits": 57457564.33302226 + } + }, + { + "state": "KY", + "sample_households": 776, + "baseline": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.02885724022053182, + "annual_modeled_benefits": 147.92350896229354 + }, + "no_modeled_irregular_hours": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.02885724022053182, + "annual_modeled_benefits": 147.92350896229354 + }, + "one_fewer_day": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.02885724022053182, + "annual_modeled_benefits": 163.49416057119927 + }, + "one_more_day": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.02885724022053182, + "annual_modeled_benefits": 145.79981145011206 + } + }, + { + "state": "LA", + "sample_households": 1000, + "baseline": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 37176.93537535961, + "annual_modeled_benefits": 72842360.51107226 + }, + "no_modeled_irregular_hours": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 37176.93537535961, + "annual_modeled_benefits": 69024044.59310351 + }, + "one_fewer_day": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 37176.93537535961, + "annual_modeled_benefits": 72842360.51107226 + }, + "one_more_day": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 37176.93537535961, + "annual_modeled_benefits": 72842360.51107226 + } + }, + { + "state": "ME", + "sample_households": 785, + "baseline": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683663.687080294 + }, + "candidate": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683670.942570195 + }, + "no_modeled_irregular_hours": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683670.942570195 + }, + "one_fewer_day": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683670.942570195 + }, + "one_more_day": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683670.942570195 + } + }, + { + "state": "MD", + "sample_households": 1091, + "baseline": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "no_modeled_irregular_hours": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "one_fewer_day": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "one_more_day": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + } + }, + { + "state": "MA", + "sample_households": 1522, + "baseline": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 0.0716373446630314, + "annual_modeled_benefits": 214.55442391989982 + }, + "no_modeled_irregular_hours": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 0.0716373446630314, + "annual_modeled_benefits": 214.55442391989982 + }, + "one_fewer_day": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 0.0716373446630314, + "annual_modeled_benefits": 214.55442391989982 + }, + "one_more_day": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 0.0716373446630314, + "annual_modeled_benefits": 214.55442391989982 + } + }, + { + "state": "MI", + "sample_households": 1478, + "baseline": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + }, + "candidate": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + }, + "no_modeled_irregular_hours": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + }, + "one_fewer_day": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + }, + "one_more_day": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + } + }, + { + "state": "MN", + "sample_households": 1166, + "baseline": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 21289.402694451623, + "annual_modeled_benefits": 274850426.86324066 + }, + "no_modeled_irregular_hours": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 21289.401307827327, + "annual_modeled_benefits": 274850426.2413397 + }, + "one_fewer_day": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 21289.402694451623, + "annual_modeled_benefits": 274850426.86324066 + }, + "one_more_day": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 21289.402694451623, + "annual_modeled_benefits": 274850426.86324066 + } + }, + { + "state": "MS", + "sample_households": 882, + "baseline": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 7256.952556610806, + "annual_modeled_benefits": 30449890.664512668 + }, + "no_modeled_irregular_hours": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 7256.951193145127, + "annual_modeled_benefits": 30449886.57411563 + }, + "one_fewer_day": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 7256.952556610806, + "annual_modeled_benefits": 30449890.664512668 + }, + "one_more_day": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 7256.952556610806, + "annual_modeled_benefits": 30449890.664512668 + } + }, + { + "state": "MO", + "sample_households": 1013, + "baseline": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 9981.891486888984, + "annual_modeled_benefits": 44110014.74611533 + }, + "no_modeled_irregular_hours": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 9981.891486888984, + "annual_modeled_benefits": 44110014.74611533 + }, + "one_fewer_day": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 9981.891486888984, + "annual_modeled_benefits": 44110017.43153306 + }, + "one_more_day": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 9981.891486888984, + "annual_modeled_benefits": 44110012.51190349 + } + }, + { + "state": "MT", + "sample_households": 744, + "baseline": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + }, + "candidate": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + }, + "no_modeled_irregular_hours": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + }, + "one_fewer_day": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + }, + "one_more_day": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + } + }, + { + "state": "NE", + "sample_households": 884, + "baseline": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 754.4826039844379 + }, + "candidate": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 752.3048707440652 + }, + "no_modeled_irregular_hours": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 752.3048707440652 + }, + "one_fewer_day": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 752.3048707440652 + }, + "one_more_day": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 752.3048707440652 + } + }, + { + "state": "NV", + "sample_households": 952, + "baseline": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "no_modeled_irregular_hours": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "one_fewer_day": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "one_more_day": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + } + }, + { + "state": "NH", + "sample_households": 840, + "baseline": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + }, + "candidate": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + }, + "no_modeled_irregular_hours": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + }, + "one_fewer_day": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + }, + "one_more_day": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + } + }, + { + "state": "NJ", + "sample_households": 1651, + "baseline": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 54783391.64412939 + }, + "candidate": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 39399036.82068616 + }, + "no_modeled_irregular_hours": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 39399036.82068616 + }, + "one_fewer_day": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 39399036.82068616 + }, + "one_more_day": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 39399036.82068616 + } + }, + { + "state": "NM", + "sample_households": 902, + "baseline": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 40276267.46262546 + }, + "candidate": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 59646231.852653645 + }, + "no_modeled_irregular_hours": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 59644459.68607285 + }, + "one_fewer_day": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 59646231.852653645 + }, + "one_more_day": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 59646231.852653645 + } + }, + { + "state": "NY", + "sample_households": 2166, + "baseline": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 84809.87077922659, + "annual_modeled_benefits": 386150016.03633535 + }, + "no_modeled_irregular_hours": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 84809.87077922659, + "annual_modeled_benefits": 386150016.03633535 + }, + "one_fewer_day": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 84809.87077922659, + "annual_modeled_benefits": 386150016.03633535 + }, + "one_more_day": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 84809.87077922659, + "annual_modeled_benefits": 386150016.03633535 + } + }, + { + "state": "NC", + "sample_households": 1337, + "baseline": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + }, + "candidate": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + }, + "no_modeled_irregular_hours": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + }, + "one_fewer_day": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + }, + "one_more_day": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + } + }, + { + "state": "ND", + "sample_households": 682, + "baseline": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 409.12895149587507 + }, + "candidate": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 471.04686684011335 + }, + "no_modeled_irregular_hours": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 465.6641840398204 + }, + "one_fewer_day": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 471.04686684011335 + }, + "one_more_day": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 471.04686684011335 + } + }, + { + "state": "OH", + "sample_households": 1531, + "baseline": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 57197.27386227145, + "annual_modeled_benefits": 109086186.25780228 + }, + "no_modeled_irregular_hours": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 57197.27386227145, + "annual_modeled_benefits": 109086186.25780228 + }, + "one_fewer_day": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 57197.27386227145, + "annual_modeled_benefits": 109086186.25780228 + }, + "one_more_day": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 57197.27386227145, + "annual_modeled_benefits": 109086186.25780228 + } + }, + { + "state": "OK", + "sample_households": 918, + "baseline": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0031096774619072676, + "annual_modeled_benefits": 5.149625876918435 + }, + "no_modeled_irregular_hours": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0031096774619072676, + "annual_modeled_benefits": 5.149625876918435 + }, + "one_fewer_day": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0031096774619072676, + "annual_modeled_benefits": 3.0897752604315514 + }, + "one_more_day": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0031096774619072676, + "annual_modeled_benefits": 5.149625876918435 + } + }, + { + "state": "OR", + "sample_households": 1152, + "baseline": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + }, + "candidate": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + }, + "no_modeled_irregular_hours": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + }, + "one_fewer_day": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + }, + "one_more_day": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + } + }, + { + "state": "PA", + "sample_households": 1999, + "baseline": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.2005278345895931, + "annual_modeled_benefits": 561.099948525683 + }, + "no_modeled_irregular_hours": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.2005278345895931, + "annual_modeled_benefits": 561.099948525683 + }, + "one_fewer_day": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.2005278345895931, + "annual_modeled_benefits": 560.5847087540619 + }, + "one_more_day": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.2005278345895931, + "annual_modeled_benefits": 561.099948525683 + } + }, + { + "state": "RI", + "sample_households": 804, + "baseline": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429808.7526231185 + }, + "candidate": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429813.4984327066 + }, + "no_modeled_irregular_hours": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429813.4984327066 + }, + "one_fewer_day": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429813.4984327066 + }, + "one_more_day": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429813.4984327066 + } + }, + { + "state": "SC", + "sample_households": 955, + "baseline": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 27915.89938246878, + "annual_modeled_benefits": 77088809.79821464 + }, + "no_modeled_irregular_hours": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 27915.89938246878, + "annual_modeled_benefits": 77088809.79821464 + }, + "one_fewer_day": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 27915.89938246878, + "annual_modeled_benefits": 77088809.79821464 + }, + "one_more_day": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 27915.89938246878, + "annual_modeled_benefits": 77088809.79821464 + } + }, + { + "state": "SD", + "sample_households": 866, + "baseline": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 2978.0845139123267, + "annual_modeled_benefits": 5809177.944389787 + }, + "no_modeled_irregular_hours": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 2978.082701569656, + "annual_modeled_benefits": 5809175.488665467 + }, + "one_fewer_day": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 2978.0845139123267, + "annual_modeled_benefits": 5809177.944389787 + }, + "one_more_day": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 2978.0845139123267, + "annual_modeled_benefits": 5809177.944389787 + } + }, + { + "state": "TN", + "sample_households": 1082, + "baseline": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 54836.32565583871, + "annual_modeled_benefits": 120178664.890383 + }, + "no_modeled_irregular_hours": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 37178.86130036996, + "annual_modeled_benefits": 76918628.79092205 + }, + "one_fewer_day": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 54836.32565583871, + "annual_modeled_benefits": 120178664.890383 + }, + "one_more_day": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 54836.32565583871, + "annual_modeled_benefits": 120178664.890383 + } + }, + { + "state": "TX", + "sample_households": 1875, + "baseline": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 72034.10924506374, + "annual_modeled_benefits": 172158000.8966679 + }, + "no_modeled_irregular_hours": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 72034.10924506374, + "annual_modeled_benefits": 172158000.8966679 + }, + "one_fewer_day": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 72034.10924506374, + "annual_modeled_benefits": 172158000.8966679 + }, + "one_more_day": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 72034.10924506374, + "annual_modeled_benefits": 172158000.8966679 + } + }, + { + "state": "UT", + "sample_households": 861, + "baseline": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66497469.149597794 + }, + "candidate": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66497469.149597794 + }, + "no_modeled_irregular_hours": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66497469.149597794 + }, + "one_fewer_day": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66497469.149597794 + }, + "one_more_day": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66497469.149597794 + } + }, + { + "state": "VT", + "sample_households": 496, + "baseline": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 78, + "weighted_positive_units": 32213.61921006818, + "annual_modeled_benefits": 526819840.50677323 + }, + "candidate": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 80, + "weighted_positive_units": 32213.669151621914, + "annual_modeled_benefits": 720606373.2116799 + }, + "no_modeled_irregular_hours": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 80, + "weighted_positive_units": 32213.669151621914, + "annual_modeled_benefits": 720606370.953774 + }, + "one_fewer_day": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 80, + "weighted_positive_units": 32213.669151621914, + "annual_modeled_benefits": 720606373.2116799 + }, + "one_more_day": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 80, + "weighted_positive_units": 32213.669151621914, + "annual_modeled_benefits": 720606373.2116799 + } + }, + { + "state": "VA", + "sample_households": 1394, + "baseline": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 45187.34717369359, + "annual_modeled_benefits": 249203866.21813098 + }, + "no_modeled_irregular_hours": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 45187.34378196369, + "annual_modeled_benefits": 249203861.9343761 + }, + "one_fewer_day": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 45187.34717369359, + "annual_modeled_benefits": 249203812.3542704 + }, + "one_more_day": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 45187.34717369359, + "annual_modeled_benefits": 254330297.24102315 + } + }, + { + "state": "WA", + "sample_households": 1305, + "baseline": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + }, + "candidate": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + }, + "no_modeled_irregular_hours": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + }, + "one_fewer_day": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + }, + "one_more_day": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + } + }, + { + "state": "WV", + "sample_households": 845, + "baseline": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 4, + "weighted_positive_units": 2978.909898934886, + "annual_modeled_benefits": 9329928.243193686 + }, + "no_modeled_irregular_hours": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 4, + "weighted_positive_units": 2978.909898934886, + "annual_modeled_benefits": 9329928.243193686 + }, + "one_fewer_day": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 4, + "weighted_positive_units": 2978.909898934886, + "annual_modeled_benefits": 9329929.363902913 + }, + "one_more_day": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 4, + "weighted_positive_units": 2978.909898934886, + "annual_modeled_benefits": 9329927.2470084 + } + }, + { + "state": "WI", + "sample_households": 1232, + "baseline": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 33918.60478726821, + "annual_modeled_benefits": 249284653.88471013 + }, + "no_modeled_irregular_hours": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 33918.60478726821, + "annual_modeled_benefits": 249284653.88471013 + }, + "one_fewer_day": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 33918.60478726821, + "annual_modeled_benefits": 249284653.88471013 + }, + "one_more_day": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 33918.60478726821, + "annual_modeled_benefits": 249284653.88471013 + } + }, + { + "state": "WY", + "sample_households": 557, + "baseline": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 2962.834392214354, + "annual_modeled_benefits": 18103301.12153925 + }, + "no_modeled_irregular_hours": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 2962.8060375964124, + "annual_modeled_benefits": 18103216.918334827 + }, + "one_fewer_day": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 2962.834392214354, + "annual_modeled_benefits": 18103301.12153925 + }, + "one_more_day": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 2962.834392214354, + "annual_modeled_benefits": 18103302.078379974 + } + } + ], + "production_ready": false, + "interpretation": "assumption stress tests, not confidence intervals; potential modeled benefits, not calibrated spending", + "summary": { + "states_evaluated": 51, + "annual_potential_modeled_benefits": { + "baseline": 2253603947.6976757, + "candidate": 5998228187.26313, + "no_modeled_irregular_hours": 5753893674.6244955, + "one_fewer_day": 5996952419.436973, + "one_more_day": 6019326168.791568 + }, + "sensitivity_flags": [ + { + "scenario": "no_modeled_irregular_hours", + "state": "IL", + "relative_change": -0.29418542010981796, + "absolute_change": -57891644.491547525, + "flagged": true + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "TN", + "relative_change": -0.3599643592223226, + "absolute_change": -43260036.09946096, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "OK", + "relative_change": -0.40000005159976976, + "absolute_change": -2.0598506164868837, + "flagged": true + } + ], + "comparisons": [ + { + "scenario": "no_modeled_irregular_hours", + "state": "US", + "relative_change": -0.04073444774199555, + "absolute_change": -244334512.63863468, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "AL", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "AK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "AZ", + "relative_change": 3.4795472060447685e-06, + "absolute_change": 80.58466989174485, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "AR", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "CA", + "relative_change": -0.16943514778977237, + "absolute_change": -123012312.16718781, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "CO", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "CT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "DE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "DC", + "relative_change": -1.4006389962646843e-08, + "absolute_change": -0.33498791977763176, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "FL", + "relative_change": -0.048561659406233436, + "absolute_change": -16350408.75, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "GA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "HI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "ID", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "IL", + "relative_change": -0.29418542010981796, + "absolute_change": -57891644.491547525, + "flagged": true + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "IN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "IA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "KS", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "KY", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "LA", + "relative_change": -0.0524188932261243, + "absolute_change": -3818315.91796875, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "ME", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MD", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MN", + "relative_change": -2.262688775133818e-09, + "absolute_change": -0.6219009757041931, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MS", + "relative_change": -1.343320763490555e-07, + "absolute_change": -4.090397037565708, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MO", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NV", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NJ", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NM", + "relative_change": -2.9711291489026368e-05, + "absolute_change": -1772.1665807962418, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NY", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "ND", + "relative_change": -0.011427064224842841, + "absolute_change": -5.382682800292969, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "OH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "OK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "OR", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "PA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "RI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "SC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "SD", + "relative_change": -4.2273181213440405e-07, + "absolute_change": -2.4557243194431067, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "TN", + "relative_change": -0.3599643592223226, + "absolute_change": -43260036.09946096, + "flagged": true + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "TX", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "UT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "VT", + "relative_change": -3.133341646729708e-09, + "absolute_change": -2.257905960083008, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "VA", + "relative_change": -1.7189760938327763e-08, + "absolute_change": -4.283754885196686, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "WA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "WV", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "WI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "WY", + "relative_change": -4.651262433181563e-06, + "absolute_change": -84.20320442318916, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "US", + "relative_change": -0.00021269077906482196, + "absolute_change": -1275767.82615757, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "AL", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "AK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "AZ", + "relative_change": 4.962991992620854e-07, + "absolute_change": 11.494055051356554, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "AR", + "relative_change": 0.03494541898564824, + "absolute_change": 1774997.2592508793, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "CA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "CO", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "CT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "DE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "DC", + "relative_change": -4.786141643741066e-10, + "absolute_change": -0.011446915566921234, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "FL", + "relative_change": -0.009060493759575043, + "absolute_change": -3050611.9077730775, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "GA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "HI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "ID", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "IL", + "relative_change": -6.484094955654378e-07, + "absolute_change": -127.59807059168816, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "IN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "IA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "KS", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "KY", + "relative_change": 0.10526150791132716, + "absolute_change": 15.570651608905735, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "LA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "ME", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MD", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MS", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MO", + "relative_change": 6.088000082391748e-08, + "absolute_change": 2.6854177340865135, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NV", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NJ", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NM", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NY", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "ND", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "OH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "OK", + "relative_change": -0.40000005159976976, + "absolute_change": -2.0598506164868837, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "OR", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "PA", + "relative_change": -0.000918267365689253, + "absolute_change": -0.5152397716210544, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "RI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "SC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "SD", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "TN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "TX", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "UT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "VT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "VA", + "relative_change": -2.161437597047441e-07, + "absolute_change": -53.863860577344894, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "WA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "WV", + "relative_change": 1.2011981209133212e-07, + "absolute_change": 1.120709227398038, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "WI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "WY", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "US", + "relative_change": 0.0035173689412546665, + "absolute_change": 21097981.528437614, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "AL", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "AK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "AZ", + "relative_change": -1.4454194532278352e-05, + "absolute_change": -334.7523186095059, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "AR", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "CA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "CO", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "CT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "DE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "DC", + "relative_change": -5.4787842155856995e-09, + "absolute_change": -0.1310349442064762, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "FL", + "relative_change": 0.047437436196758505, + "absolute_change": 15971889.78615272, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "GA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "HI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "ID", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "IL", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "IN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "IA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "KS", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "KY", + "relative_change": -0.014356727521403111, + "absolute_change": -2.1236975121814794, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "LA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "ME", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MD", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MS", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MO", + "relative_change": -5.06508975930975e-08, + "absolute_change": -2.234211839735508, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NV", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NJ", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NM", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NY", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "ND", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "OH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "OK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "OR", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "PA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "RI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "SC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "SD", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "TN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "TX", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "UT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "VT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "VA", + "relative_change": 0.020571233908566064, + "absolute_change": 5126431.022892177, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "WA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "WV", + "relative_change": -1.0677309192568547e-07, + "absolute_change": -0.9961852859705687, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "WI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "WY", + "relative_change": 5.285448865536073e-08, + "absolute_change": 0.9568407237529755, + "flagged": false + } + ] + } +} diff --git a/experiments/us-childcare-attendance/pooled-matching-plan.txt b/experiments/us-childcare-attendance/pooled-matching-plan.txt new file mode 100644 index 000000000..fc0182d33 --- /dev/null +++ b/experiments/us-childcare-attendance/pooled-matching-plan.txt @@ -0,0 +1,44 @@ +Partially pooled attendance comparison specified before new results, 2026-09-16. + +The previous hard household-size model is rejected. All previously inspected +households, including the September 16 reserved partition, are now development +evidence. Do not call a new split of them independent or untouched validation. + +Compare the existing production matcher with one fixed proposed model. Start +with weighted exact-age empirical donor distributions, then successively add +under-13 household count (capped at 3), parent work, income band, and region. +At each level blend the local distribution with the preceding broader +distribution using lambda = effective_households / (effective_households + 10). +Effective households = squared total weight / sum of squared household weight +contributions to that donor cell. Ten is fixed before results, not optimized. +All days/hours are drawn jointly from real, complete schedules, including zeros; +exact age is never relaxed. Empty local cells inherit their broader distribution. + +Fit the shared-rank mixture to measured participation, days and weekly-hours +cross-products jointly. Use every pair of complete observed children in a +household, including families whose other children have unresolved calendars. +Divide household design weight among its observed pairs. Predict fitting pairs +with their entire household excluded from every donor level. Normalize each +outcome's squared-error contribution by its weighted training second moment; +fit one coefficient by weighted least squares and report its unconstrained value +and clipping. No fitting on held-out household outcomes. + +Evaluation: the same deterministic five whole-household folds, seed 271828, +for both models. Refit every model component solely inside each training fold. +Integrate the donor CDFs exactly. Retain all 15 previous joint-schedule screens. +Additionally score every observed child (not only complete households), with +child weights, overall, by count 1/2/3+, and by complete versus unresolved-sibling +household. Report participation, days, weekly hours, and squared prediction error. +Flag participation mean gaps over 0.05 and days/hour relative mean gaps over 20%. +Report observed-pair results separately from complete-household total results. + +This model does not identify missing calendars, summer patterns or noncalendar +irregular care. Incomplete-family subgroup errors remain visible and cannot be +removed from acceptance merely because complete-family totals look good. Do not +scale the population to complete-household means or claim a missingness correction. + +Do not select a favorable seed or tune smoothing/rho to the evaluation folds. +Any adoption remains draft and requires source/target/bridge consistency, +content-bound receipts, a rebuild from the original parent, population and +noncalendar sensitivity checks. Failed diagnostics and source-selection +uncertainty remain unresolved; publication is not authorized by this experiment. diff --git a/experiments/us-childcare-attendance/pooled-matching-validation.json b/experiments/us-childcare-attendance/pooled-matching-validation.json new file mode 100644 index 000000000..b8acfb953 --- /dev/null +++ b/experiments/us-childcare-attendance/pooled-matching-validation.json @@ -0,0 +1,2517 @@ +{ + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "plan_sha256": "a25a5ea699fb8732ce7f0fb5ded9f6ff191612ec7f850ac7c53d0b66fe3508fe", + "recipe": { + "contract_sha256": "ae648c6cb0e2838fdf142975e9c536eb0683d9630fd1738096d524222ffb01dc", + "runtime_versions": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "policyengine-us": "2.2.1" + }, + "code_sha256": { + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "nsece_childcare.py": "affc8ac5a3ce853e2ef8b062c51a1801a15573cbcbf6eacc2c093334a1d12c11", + "nsece_childcare_bridge.py": "70a7edea8b28c6da21ff4fa9bb220766a3e6cd714926684af29bdba1a8421b0a", + "nsece_childcare_dependence.py": "1c5123a77f84460ba517d2b4c6c3e04ae658bf36e9cf54ed69ddbcacc85efc09", + "childcare_attendance_stage.py": "42e777b0edfc813d79204bc2932fe429d6a48cd2866397560a7386cbee54dadb", + "childcare_attendance_receipt.py": "0950fce7f372ca4b240cd055c931f5f8fe070223fd68504a3ea9cfbc4e16c645" + } + }, + "diagnostic_code_sha256": { + "validate_us_childcare_pooling.py": "717816151c9d167956f3222104012dbc1877d5bd914fa861a5c5cd1d5d59ab0b", + "nsece_childcare_pooling.py": "0e5375a99440e89040cca8051df8178bf714f96938d2d9501453aab65420005a", + "nsece_childcare_sibling_validation.py": "6ed9a3c9c2d881782c8466133da21c952c9542f394b7501afa87e9a3ba3163a1" + }, + "production_ready": false, + "production_recipe_changed": false, + "interpretation": "five household-separated folds on previously inspected development data; no untouched evaluation claim; calendar selection remains unidentified", + "moment_plan_sha256": "1f56373d30787ad399566205718f99d07ae4f6962ab56ac350bba662e7ec9ae0", + "legacy": { + "design": "household-separated partitions; exact integration of the implemented shared-rank donor CDFs", + "seed": 271828, + "validation_seed": null, + "partition": "all", + "splits": [ + { + "training_households": 5100, + "evaluation_households": 1269, + "household_overlap": 0 + }, + { + "training_households": 5108, + "evaluation_households": 1261, + "household_overlap": 0 + }, + { + "training_households": 5055, + "evaluation_households": 1314, + "household_overlap": 0 + }, + { + "training_households": 5071, + "evaluation_households": 1298, + "household_overlap": 0 + }, + { + "training_households": 5142, + "evaluation_households": 1227, + "household_overlap": 0 + } + ], + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "fallback_match_columns": [ + [ + "age", + "parent_work_status", + "income_band" + ], + [ + "age", + "parent_work_status" + ], + [ + "age" + ] + ], + "matching_counts": { + "age,region,parent_work_status,income_band": 7278, + "age,parent_work_status,income_band": 150, + "age,parent_work_status": 32 + }, + "training_rho": [ + 0.7504775690168417, + 0.8095401305423818, + 0.7176223341350483, + 0.8946850037821993, + 0.8022505236076816 + ], + "youngest_pairs": { + "households": 1941, + "household_weight": 8329556.517461634, + "observed": { + "participation": { + "joint_product": 0.3285886986591048, + "correlation": 0.577510777815278 + }, + "days": { + "joint_product": 5.9171615700449145, + "correlation": 0.5798886366650429 + }, + "weekly_hours": { + "joint_product": 367.6804958137289, + "correlation": 0.523457187358221 + } + }, + "independent": { + "participation": { + "joint_product": 0.2599357218299179, + "correlation": 0.14356484664250233 + }, + "days": { + "joint_product": 4.562554958882675, + "correlation": 0.1514064619097721 + }, + "weekly_hours": { + "joint_product": 274.5482618143516, + "correlation": 0.1290575794049498 + } + }, + "coupled": { + "participation": { + "joint_product": 0.3228241594928079, + "correlation": 0.39662161163709453 + }, + "days": { + "joint_product": 6.168391228908872, + "correlation": 0.44224735414975214 + }, + "weekly_hours": { + "joint_product": 393.50536137310974, + "correlation": 0.35635277128820114 + } + } + }, + "youngest_pairs_in_3plus_households": { + "households": 661, + "household_weight": 2458669.150522002, + "observed": { + "participation": { + "joint_product": 0.2728957065164463, + "correlation": 0.5341073068866067 + }, + "days": { + "joint_product": 5.084876229689592, + "correlation": 0.5617680576612079 + }, + "weekly_hours": { + "joint_product": 337.34705105325276, + "correlation": 0.5623528715201395 + } + }, + "independent": { + "participation": { + "joint_product": 0.26594831103314626, + "correlation": 0.1768906778018396 + }, + "days": { + "joint_product": 4.755017625871223, + "correlation": 0.1796772530434437 + }, + "weekly_hours": { + "joint_product": 288.78160178706247, + "correlation": 0.15022942733210107 + } + }, + "coupled": { + "participation": { + "joint_product": 0.32461663032314914, + "correlation": 0.41320572283269663 + }, + "days": { + "joint_product": 6.243213912824172, + "correlation": 0.44765187465853035 + }, + "weekly_hours": { + "joint_product": 406.53469377347056, + "correlation": 0.3715598543103152 + } + } + }, + "larger_households": { + "households": 661, + "observed": { + "mean_total_days": 4.509647234214243, + "mean_total_weekly_hours": 33.085374473048084, + "sd_total_days": 5.765302178946849, + "sd_total_weekly_hours": 56.21651776123905, + "all_children_attend": 0.18568592787006075 + }, + "independent": { + "mean_total_days": 5.652805180994538, + "mean_total_weekly_hours": 40.814235235209445, + "sd_total_days": 4.742171858563125, + "sd_total_weekly_hours": 43.69183090611876, + "all_children_attend": 0.10870430564775237 + }, + "coupled": { + "mean_total_days": 5.652805180994538, + "mean_total_weekly_hours": 40.814235235209445, + "sd_total_days": 5.826012333228911, + "sd_total_weekly_hours": 52.0732028760817, + "all_children_attend": 0.19850142013240785 + } + }, + "production_ready": false, + "diagnostic_screen": { + "passed": false, + "checks": [ + { + "metric": "youngest_pairs.participation.joint_product", + "absolute_gap": 0.005764539166296878, + "relative": false, + "limit": 0.05, + "passed": true + }, + { + "metric": "youngest_pairs.days.correlation", + "absolute_gap": 0.13764128251529073, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs.weekly_hours.correlation", + "absolute_gap": 0.16710441607001986, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs.days.joint_product", + "absolute_gap": 0.04245779938404666, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs.weekly_hours.joint_product", + "absolute_gap": 0.07023724634135614, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.participation.joint_product", + "absolute_gap": 0.051720923806702845, + "relative": false, + "limit": 0.05, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.days.correlation", + "absolute_gap": 0.11411618300267751, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.correlation", + "absolute_gap": 0.19079301720982428, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.days.joint_product", + "absolute_gap": 0.22780056599436455, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.joint_product", + "absolute_gap": 0.20509336751041, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.mean_total_days", + "absolute_gap": 0.2534916563112233, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.mean_total_weekly_hours", + "absolute_gap": 0.23360354492760613, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.sd_total_days", + "absolute_gap": 0.010530264051684455, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.sd_total_weekly_hours", + "absolute_gap": 0.07370280213290151, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.all_children_attend", + "absolute_gap": 0.0128154922623471, + "relative": false, + "limit": 0.05, + "passed": true + } + ], + "interpretation": "provisional diagnostic screens; not publication authorization" + }, + "matching_count_universe": "every held-out child with an observed complete calendar", + "observed_child_validation": { + "comparisons": [ + { + "group": "all", + "children": 7460, + "child_weight": 32249785.682044946, + "observed": { + "participation": 0.4651484510706186, + "days": 1.8750709563867471, + "weekly_hours": 14.240422572045734 + }, + "expected": { + "participation": 0.4654844290416031, + "days": 1.8785272940115059, + "weekly_hours": 14.081114700859386 + }, + "conditional_mean_squared_error": { + "participation": 0.2627611011205091, + "days": 5.761259738909554, + "weekly_hours": 575.3095532746996 + }, + "expected_draw_squared_error": { + "participation": 0.4131049741549481, + "days": 8.904698658118924, + "weekly_hours": 891.1402112413062 + } + }, + { + "group": "household_size_1", + "children": 1910, + "child_weight": 9010809.078107145, + "observed": { + "participation": 0.5242108914088932, + "days": 2.119495964700082, + "weekly_hours": 16.911581677434366 + }, + "expected": { + "participation": 0.4773376030928158, + "days": 1.9290793011901837, + "weekly_hours": 14.82135847302154 + }, + "conditional_mean_squared_error": { + "participation": 0.2595087340797617, + "days": 5.761185130166251, + "weekly_hours": 647.1235859031791 + }, + "expected_draw_squared_error": { + "participation": 0.41350182254230894, + "days": 9.02534933769786, + "weekly_hours": 977.847851925658 + } + }, + { + "group": "household_size_2", + "children": 2845, + "child_weight": 13265562.299413564, + "observed": { + "participation": 0.47658623296590163, + "days": 1.921092628643475, + "weekly_hours": 13.941634457809398 + }, + "expected": { + "participation": 0.4820542836393625, + "days": 1.9588226354748015, + "weekly_hours": 14.72400423392797 + }, + "conditional_mean_squared_error": { + "participation": 0.2603267026889349, + "days": 5.819759954687851, + "weekly_hours": 514.7834898967403 + }, + "expected_draw_squared_error": { + "participation": 0.410695073394001, + "days": 9.00784605459559, + "weekly_hours": 830.9671222797516 + } + }, + { + "group": "household_size_3", + "children": 2705, + "child_weight": 9973414.304524235, + "observed": { + "participation": 0.39657324091775625, + "days": 1.5930240706983663, + "weekly_hours": 12.224491842781102 + }, + "expected": { + "participation": 0.43273585199154396, + "days": 1.7260541997125938, + "weekly_hours": 12.5572146611429 + }, + "conditional_mean_squared_error": { + "participation": 0.26893753384764646, + "days": 5.68351645580513, + "weekly_hours": 590.9320595275229 + }, + "expected_draw_squared_error": { + "participation": 0.4159518190529244, + "days": 8.658497269322753, + "weekly_hours": 892.8371090168542 + } + }, + { + "group": "complete_household", + "children": 6699, + "child_weight": 29099899.91535441, + "observed": { + "participation": 0.44408939246351814, + "days": 1.7729192348218488, + "weekly_hours": 13.20243633175764 + }, + "expected": { + "participation": 0.46248243745239037, + "days": 1.8656545413639731, + "weekly_hours": 13.968992525952057 + }, + "conditional_mean_squared_error": { + "participation": 0.2618570243099771, + "days": 5.617466178489852, + "weekly_hours": 539.6353259350994 + }, + "expected_draw_squared_error": { + "participation": 0.41271493741040616, + "days": 8.768285612163377, + "weekly_hours": 858.5825009186116 + } + }, + { + "group": "unresolved_siblings", + "children": 761, + "child_weight": 3149885.766690531, + "observed": { + "participation": 0.659700426338619, + "days": 2.8187892667948593, + "weekly_hours": 23.829753088509108 + }, + "expected": { + "participation": 0.49321802361085093, + "days": 1.9974509126518023, + "weekly_hours": 15.116944032385828 + }, + "conditional_mean_squared_error": { + "participation": 0.27111332296312274, + "days": 7.0896819505766215, + "weekly_hours": 904.8822813138923 + }, + "expected_draw_squared_error": { + "participation": 0.41670828902735096, + "days": 10.164936736093896, + "weekly_hours": 1191.9213131728277 + } + } + ], + "screen": { + "passed": false, + "checks": [ + { + "group": "all", + "metric": "participation", + "relative": false, + "gap": 0.00033597797098450233, + "limit": 0.05, + "passed": true + }, + { + "group": "all", + "metric": "days", + "relative": true, + "gap": 0.0018433103093970732, + "limit": 0.2, + "passed": true + }, + { + "group": "all", + "metric": "weekly_hours", + "relative": true, + "gap": 0.01118701852984847, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "participation", + "relative": false, + "gap": 0.0468732883160774, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_1", + "metric": "days", + "relative": true, + "gap": 0.08984054071404815, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "weekly_hours", + "relative": true, + "gap": 0.12359714450611524, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "participation", + "relative": false, + "gap": 0.005468050673460845, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_2", + "metric": "days", + "relative": true, + "gap": 0.019639868618916312, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "weekly_hours", + "relative": true, + "gap": 0.056117507490689326, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "participation", + "relative": false, + "gap": 0.03616261107378771, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_3", + "metric": "days", + "relative": true, + "gap": 0.0835079214816311, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "weekly_hours", + "relative": true, + "gap": 0.02721772181951925, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "participation", + "relative": false, + "gap": 0.01839304498887223, + "limit": 0.05, + "passed": true + }, + { + "group": "complete_household", + "metric": "days", + "relative": true, + "gap": 0.05230656011887808, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "weekly_hours", + "relative": true, + "gap": 0.05806172246788369, + "limit": 0.2, + "passed": true + }, + { + "group": "unresolved_siblings", + "metric": "participation", + "relative": false, + "gap": 0.1664824027277681, + "limit": 0.05, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "days", + "relative": true, + "gap": 0.2913798359523947, + "limit": 0.2, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "weekly_hours", + "relative": true, + "gap": 0.36562733250998997, + "limit": 0.2, + "passed": false + } + ] + }, + "interpretation": "child-weighted predictions of observed calendars; missing children are not scored as zeros; previously used survey, not external validation" + }, + "all_observed_sibling_pairs": { + "household_weight": 8945945.325594446, + "observed": { + "participation": { + "joint_product": 0.3302177486685269, + "correlation": 0.569690244749424 + }, + "days": { + "joint_product": 6.027208927705104, + "correlation": 0.5724522456066773 + }, + "weekly_hours": { + "joint_product": 426.22614842124585, + "correlation": 0.5408408373849536 + } + }, + "independent": { + "participation": { + "joint_product": 0.24552027543447916, + "correlation": 0.13532417830267465 + }, + "days": { + "joint_product": 4.226646089372958, + "correlation": 0.14391630402285718 + }, + "weekly_hours": { + "joint_product": 244.5514800119603, + "correlation": 0.1148066000332254 + } + }, + "coupled": { + "participation": { + "joint_product": 0.30897285504551686, + "correlation": 0.3919191231187823 + }, + "days": { + "joint_product": 5.812085743353472, + "correlation": 0.43785061514617757 + }, + "weekly_hours": { + "joint_product": 358.34194451182583, + "correlation": 0.3402179517218739 + } + }, + "observed_pairs": 4450, + "households": 2106, + "interpretation": "all observed pairs including households with unresolved other siblings; household weight divided among observed pairs" + }, + "dependence_only_screen_compatibility": { + "comparisons": [ + { + "population": "youngest_pairs", + "metric": "days", + "identified": true, + "predicted_product_of_marginal_means": 3.7265858962845724, + "predicted_product_of_marginal_standard_deviations": 5.5213565659851636, + "joint_product_required_by_correlation_screen": [ + 6.376222171276775, + 7.480493484473808 + ], + "joint_product_allowed_by_product_screen": [ + 4.733729256035931, + 7.100593884053898 + ], + "screen_intervals_overlap": true, + "overlap_interval": [ + 6.376222171276775, + 7.100593884053898 + ] + }, + { + "population": "youngest_pairs", + "metric": "weekly_hours", + "identified": true, + "predicted_product_of_marginal_means": 207.00475068732095, + "predicted_product_of_marginal_standard_deviations": 523.3595069615889, + "joint_product_required_by_correlation_screen": [ + 428.62509548246067, + 533.2969968747784 + ], + "joint_product_allowed_by_product_screen": [ + 294.14439665098314, + 441.21659497647465 + ], + "screen_intervals_overlap": true, + "overlap_interval": [ + 428.62509548246067, + 441.21659497647465 + ] + }, + { + "population": "youngest_pairs_in_3plus_households", + "metric": "days", + "identified": true, + "predicted_product_of_marginal_means": 3.757180520187241, + "predicted_product_of_marginal_standard_deviations": 5.553497110971067, + "joint_product_required_by_correlation_screen": [ + 6.32160809434748, + 7.432307516541693 + ], + "joint_product_allowed_by_product_screen": [ + 4.067900983751674, + 6.101851475627511 + ], + "screen_intervals_overlap": false, + "overlap_interval": null + }, + { + "population": "youngest_pairs_in_3plus_households", + "metric": "weekly_hours", + "identified": true, + "predicted_product_of_marginal_means": 208.85594575675282, + "predicted_product_of_marginal_standard_deviations": 532.0239679382117, + "joint_product_required_by_correlation_screen": [ + 454.8387550505237, + 561.243548638166 + ], + "joint_product_allowed_by_product_screen": [ + 269.8776408426022, + 404.8164612639033 + ], + "screen_intervals_overlap": false, + "overlap_interval": null + } + ], + "interpretation": "disjoint screen intervals rule out a dependence-only fix for these conditional marginals; overlapping intervals do not establish that a feasible joint distribution exists" + } + }, + "pooled": { + "design": "household-separated partitions; exact integration of the implemented shared-rank donor CDFs", + "seed": 271828, + "validation_seed": null, + "partition": "all", + "splits": [ + { + "training_households": 5100, + "evaluation_households": 1269, + "household_overlap": 0 + }, + { + "training_households": 5108, + "evaluation_households": 1261, + "household_overlap": 0 + }, + { + "training_households": 5055, + "evaluation_households": 1314, + "household_overlap": 0 + }, + { + "training_households": 5071, + "evaluation_households": 1298, + "household_overlap": 0 + }, + { + "training_households": 5142, + "evaluation_households": 1227, + "household_overlap": 0 + } + ], + "match_columns": [ + "age", + "childcare_household_size", + "parent_work_status", + "income_band", + "region" + ], + "fallback_match_columns": [], + "matching_counts": { + "partially_pooled": 7460 + }, + "training_rho": [ + 0.5276809642639594, + 0.4355228994352012, + 0.43533241705543085, + 0.5208424069481076, + 0.5321513856951827 + ], + "youngest_pairs": { + "households": 1941, + "household_weight": 8329556.517461634, + "observed": { + "participation": { + "joint_product": 0.3285886986591048, + "correlation": 0.577510777815278 + }, + "days": { + "joint_product": 5.9171615700449145, + "correlation": 0.5798886366650429 + }, + "weekly_hours": { + "joint_product": 367.6804958137289, + "correlation": 0.523457187358221 + } + }, + "independent": { + "participation": { + "joint_product": 0.24236105200931968, + "correlation": 0.09396101556276153 + }, + "days": { + "joint_product": 4.135970938921813, + "correlation": 0.11086235305220805 + }, + "weekly_hours": { + "joint_product": 234.25280025856392, + "correlation": 0.09296236405577511 + } + }, + "coupled": { + "participation": { + "joint_product": 0.3100628328252084, + "correlation": 0.36716178386071613 + }, + "days": { + "joint_product": 5.7917816408332525, + "correlation": 0.4197512009637115 + }, + "weekly_hours": { + "joint_product": 357.67604657412755, + "correlation": 0.34249430439785367 + } + } + }, + "youngest_pairs_in_3plus_households": { + "households": 661, + "household_weight": 2458669.150522002, + "observed": { + "participation": { + "joint_product": 0.2728957065164463, + "correlation": 0.5341073068866067 + }, + "days": { + "joint_product": 5.084876229689592, + "correlation": 0.5617680576612079 + }, + "weekly_hours": { + "joint_product": 337.34705105325276, + "correlation": 0.5623528715201395 + } + }, + "independent": { + "participation": { + "joint_product": 0.20749391246494672, + "correlation": 0.07367636621560582 + }, + "days": { + "joint_product": 3.5642905999293837, + "correlation": 0.09515516766062374 + }, + "weekly_hours": { + "joint_product": 216.49341419707955, + "correlation": 0.063874755675981 + } + }, + "coupled": { + "participation": { + "joint_product": 0.2737895744968245, + "correlation": 0.34410567515623863 + }, + "days": { + "joint_product": 5.177923531761666, + "correlation": 0.399302222570031 + }, + "weekly_hours": { + "joint_product": 357.8613809895804, + "correlation": 0.3151807708126129 + } + } + }, + "larger_households": { + "households": 661, + "observed": { + "mean_total_days": 4.509647234214243, + "mean_total_weekly_hours": 33.085374473048084, + "sd_total_days": 5.765302178946849, + "sd_total_weekly_hours": 56.21651776123905, + "all_children_attend": 0.18568592787006075 + }, + "independent": { + "mean_total_days": 5.051031204266368, + "mean_total_weekly_hours": 38.34794143790316, + "sd_total_days": 4.395160013019163, + "sd_total_weekly_hours": 44.20739654038455, + "all_children_attend": 0.06527654820049239 + }, + "coupled": { + "mean_total_days": 5.051031204266368, + "mean_total_weekly_hours": 38.34794143790316, + "sd_total_days": 5.603842063134159, + "sd_total_weekly_hours": 54.68976225539357, + "all_children_attend": 0.15764122980318407 + } + }, + "production_ready": false, + "diagnostic_screen": { + "passed": false, + "checks": [ + { + "metric": "youngest_pairs.participation.joint_product", + "absolute_gap": 0.01852586583389637, + "relative": false, + "limit": 0.05, + "passed": true + }, + { + "metric": "youngest_pairs.days.correlation", + "absolute_gap": 0.16013743570133138, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs.weekly_hours.correlation", + "absolute_gap": 0.18096288296036733, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs.days.joint_product", + "absolute_gap": 0.02118920156691112, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs.weekly_hours.joint_product", + "absolute_gap": 0.027209627253847346, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.participation.joint_product", + "absolute_gap": 0.0008938679803782157, + "relative": false, + "limit": 0.05, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.days.correlation", + "absolute_gap": 0.16246583509117685, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.correlation", + "absolute_gap": 0.24717210070752654, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.days.joint_product", + "absolute_gap": 0.0182988332201261, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.joint_product", + "absolute_gap": 0.06081075815626243, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.mean_total_days", + "absolute_gap": 0.12005018174031427, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.mean_total_weekly_hours", + "absolute_gap": 0.15906022067672387, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.sd_total_days", + "absolute_gap": 0.028005490571213053, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.sd_total_weekly_hours", + "absolute_gap": 0.02715848591564965, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.all_children_attend", + "absolute_gap": 0.028044698066876678, + "relative": false, + "limit": 0.05, + "passed": true + } + ], + "interpretation": "provisional diagnostic screens; not publication authorization" + }, + "model": { + "name": "partially_pooled_empirical_schedules", + "levels": [ + [ + "age" + ], + [ + "age", + "childcare_household_size" + ], + [ + "age", + "childcare_household_size", + "parent_work_status" + ], + [ + "age", + "childcare_household_size", + "parent_work_status", + "income_band" + ], + [ + "age", + "childcare_household_size", + "parent_work_status", + "income_band", + "region" + ] + ], + "strength": 10.0, + "dependence_objective": "pair_squared_error", + "dependence_fits": [ + { + "rho": 0.5276809642639594, + "unconstrained_rho": 0.5276809642639594, + "households": 1730, + "households_with_unresolved_siblings": 140, + "observed_pairs": 3670, + "outcome_second_moments": [ + 0.4359359926938946, + 8.277205060093346, + 593.7870077076072 + ], + "objective": "pair_squared_error", + "normalized_mean_residual": [ + 0.2502298693914833, + 0.27527547268127456, + 0.2850732476726967 + ], + "normalized_mean_shared_increment": [ + 0.30253311517140813, + 0.38487878025611877, + 0.36627648825439335 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + }, + { + "rho": 0.4355228994352012, + "unconstrained_rho": 0.4355228994352012, + "households": 1697, + "households_with_unresolved_siblings": 123, + "observed_pairs": 3594, + "outcome_second_moments": [ + 0.44126287158160343, + 8.359355045936002, + 694.2809842648821 + ], + "objective": "pair_squared_error", + "normalized_mean_residual": [ + 0.22454696976548358, + 0.25665784026502875, + 0.3085026964880856 + ], + "normalized_mean_shared_increment": [ + 0.3121975302394453, + 0.3956058631862616, + 0.37836062350370525 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + }, + { + "rho": 0.43533241705543085, + "unconstrained_rho": 0.43533241705543085, + "households": 1633, + "households_with_unresolved_siblings": 135, + "observed_pairs": 3453, + "outcome_second_moments": [ + 0.4338366370776943, + 8.256340131249516, + 694.144636825422 + ], + "objective": "pair_squared_error", + "normalized_mean_residual": [ + 0.22762977893389097, + 0.2491739115147974, + 0.31614054777338935 + ], + "normalized_mean_shared_increment": [ + 0.3218355084453624, + 0.40226719431104246, + 0.37196853323063156 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + }, + { + "rho": 0.5208424069481076, + "unconstrained_rho": 0.5208424069481076, + "households": 1668, + "households_with_unresolved_siblings": 125, + "observed_pairs": 3499, + "outcome_second_moments": [ + 0.4428268423383291, + 8.341086892139936, + 679.4142064233605 + ], + "objective": "pair_squared_error", + "normalized_mean_residual": [ + 0.24679819920578627, + 0.27437897292653474, + 0.337362053609579 + ], + "normalized_mean_shared_increment": [ + 0.3146404967452197, + 0.40232577509104867, + 0.3772940863523165 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + }, + { + "rho": 0.5321513856951827, + "unconstrained_rho": 0.5321513856951827, + "households": 1696, + "households_with_unresolved_siblings": 137, + "observed_pairs": 3584, + "outcome_second_moments": [ + 0.4413586153564347, + 8.485578051981562, + 676.0109573424492 + ], + "objective": "pair_squared_error", + "normalized_mean_residual": [ + 0.2543497335812991, + 0.28684691450840843, + 0.35816569978000246 + ], + "normalized_mean_shared_increment": [ + 0.3106084542826501, + 0.4028661500770573, + 0.38060896199156885 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + } + ] + }, + "matching_count_universe": "every held-out child with an observed complete calendar", + "observed_child_validation": { + "comparisons": [ + { + "group": "all", + "children": 7460, + "child_weight": 32249785.682044946, + "observed": { + "participation": 0.4651484510706186, + "days": 1.8750709563867471, + "weekly_hours": 14.240422572045734 + }, + "expected": { + "participation": 0.46964890773471457, + "days": 1.8870313262922465, + "weekly_hours": 14.121321880052811 + }, + "conditional_mean_squared_error": { + "participation": 0.21786002566014795, + "days": 4.634484500691751, + "weekly_hours": 482.79806934933634 + }, + "expected_draw_squared_error": { + "participation": 0.4189867368126556, + "days": 8.871248441333941, + "weekly_hours": 905.9935560782225 + } + }, + { + "group": "household_size_1", + "children": 1910, + "child_weight": 9010809.078107145, + "observed": { + "participation": 0.5242108914088932, + "days": 2.119495964700082, + "weekly_hours": 16.911581677434366 + }, + "expected": { + "participation": 0.5309528476583814, + "days": 2.1450855821675643, + "weekly_hours": 16.7286558904403 + }, + "conditional_mean_squared_error": { + "participation": 0.21998157968908702, + "days": 4.8634925946342795, + "weekly_hours": 551.1632871152738 + }, + "expected_draw_squared_error": { + "participation": 0.4281854166170082, + "days": 9.372662082607494, + "weekly_hours": 1034.4761146276157 + } + }, + { + "group": "household_size_2", + "children": 2845, + "child_weight": 13265562.299413564, + "observed": { + "participation": 0.47658623296590163, + "days": 1.921092628643475, + "weekly_hours": 13.941634457809398 + }, + "expected": { + "participation": 0.48651284376374204, + "days": 1.9627422616863737, + "weekly_hours": 14.1440528078623 + }, + "conditional_mean_squared_error": { + "participation": 0.21802706174990996, + "days": 4.583635321783541, + "weekly_hours": 414.2968731100742 + }, + "expected_draw_squared_error": { + "participation": 0.4176700262900522, + "days": 8.771188666124276, + "weekly_hours": 779.6025285290256 + } + }, + { + "group": "household_size_3", + "children": 2705, + "child_weight": 9973414.304524235, + "observed": { + "participation": 0.39657324091775625, + "days": 1.5930240706983663, + "weekly_hours": 12.224491842781102 + }, + "expected": { + "participation": 0.3918312548530712, + "days": 1.5531811863063212, + "weekly_hours": 11.73540600582258 + }, + "conditional_mean_squared_error": { + "participation": 0.2157210644872454, + "days": 4.495213713500396, + "weekly_hours": 512.1441841789803 + }, + "expected_draw_squared_error": { + "participation": 0.41242723371549633, + "days": 8.551318544556374, + "weekly_hours": 958.0235058267347 + } + }, + { + "group": "complete_household", + "children": 6699, + "child_weight": 29099899.91535441, + "observed": { + "participation": 0.44408939246351814, + "days": 1.7729192348218488, + "weekly_hours": 13.20243633175764 + }, + "expected": { + "participation": 0.46990822362498935, + "days": 1.8840103414261442, + "weekly_hours": 14.119885124808388 + }, + "conditional_mean_squared_error": { + "participation": 0.21582355854647822, + "days": 4.473903862652206, + "weekly_hours": 447.4809381900267 + }, + "expected_draw_squared_error": { + "participation": 0.4175485380163647, + "days": 8.708831987458572, + "weekly_hours": 872.7199874173884 + } + }, + { + "group": "unresolved_siblings", + "children": 761, + "child_weight": 3149885.766690531, + "observed": { + "participation": 0.659700426338619, + "days": 2.8187892667948593, + "weekly_hours": 23.829753088509108 + }, + "expected": { + "participation": 0.46725324420518616, + "days": 1.914940388322065, + "weekly_hours": 14.13459519753524 + }, + "conditional_mean_squared_error": { + "participation": 0.23667372037103993, + "days": 6.117992424918431, + "weekly_hours": 809.0718005751868 + }, + "expected_draw_squared_error": { + "participation": 0.4322733904027592, + "days": 10.371716363808677, + "weekly_hours": 1213.3880426008857 + } + } + ], + "screen": { + "passed": false, + "checks": [ + { + "group": "all", + "metric": "participation", + "relative": false, + "gap": 0.0045004566640959864, + "limit": 0.05, + "passed": true + }, + { + "group": "all", + "metric": "days", + "relative": true, + "gap": 0.006378622560794653, + "limit": 0.2, + "passed": true + }, + { + "group": "all", + "metric": "weekly_hours", + "relative": true, + "gap": 0.008363564451150505, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "participation", + "relative": false, + "gap": 0.006741956249488146, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_1", + "metric": "days", + "relative": true, + "gap": 0.01207344476879113, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "weekly_hours", + "relative": true, + "gap": 0.010816598381105233, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "participation", + "relative": false, + "gap": 0.009926610797840407, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_2", + "metric": "days", + "relative": true, + "gap": 0.02168017950925578, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "weekly_hours", + "relative": true, + "gap": 0.014518982739467643, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "participation", + "relative": false, + "gap": 0.0047419860646850664, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_3", + "metric": "days", + "relative": true, + "gap": 0.02501084894127077, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "weekly_hours", + "relative": true, + "gap": 0.0400086844711946, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "participation", + "relative": false, + "gap": 0.025818831161471212, + "limit": 0.05, + "passed": true + }, + { + "group": "complete_household", + "metric": "days", + "relative": true, + "gap": 0.06265999286507735, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "weekly_hours", + "relative": true, + "gap": 0.06949087047243553, + "limit": 0.2, + "passed": true + }, + { + "group": "unresolved_siblings", + "metric": "participation", + "relative": false, + "gap": 0.19244718213343287, + "limit": 0.05, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "days", + "relative": true, + "gap": 0.3206514545518074, + "limit": 0.2, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "weekly_hours", + "relative": true, + "gap": 0.4068509587557979, + "limit": 0.2, + "passed": false + } + ] + }, + "interpretation": "child-weighted predictions of observed calendars; missing children are not scored as zeros; previously used survey, not external validation" + }, + "all_observed_sibling_pairs": { + "household_weight": 8945945.325594446, + "observed": { + "participation": { + "joint_product": 0.3302177486685269, + "correlation": 0.569690244749424 + }, + "days": { + "joint_product": 6.027208927705104, + "correlation": 0.5724522456066773 + }, + "weekly_hours": { + "joint_product": 426.22614842124585, + "correlation": 0.5408408373849536 + } + }, + "independent": { + "participation": { + "joint_product": 0.2260919090368316, + "correlation": 0.09520635050450324 + }, + "days": { + "joint_product": 3.8285744975466867, + "correlation": 0.10968106727006208 + }, + "weekly_hours": { + "joint_product": 212.90904376258283, + "correlation": 0.08730651835284241 + } + }, + "coupled": { + "participation": { + "joint_product": 0.29327458485478475, + "correlation": 0.368453127817019 + }, + "days": { + "joint_product": 5.461991300173491, + "correlation": 0.41927549225218075 + }, + "weekly_hours": { + "joint_product": 333.74040670723997, + "correlation": 0.3351110984736457 + } + }, + "observed_pairs": 4450, + "households": 2106, + "interpretation": "all observed pairs including households with unresolved other siblings; household weight divided among observed pairs" + }, + "dependence_only_screen_compatibility": { + "comparisons": [ + { + "population": "youngest_pairs", + "metric": "days", + "identified": true, + "predicted_product_of_marginal_means": 3.5416889767723654, + "predicted_product_of_marginal_standard_deviations": 5.360538954730503, + "joint_product_required_by_correlation_screen": [ + 6.11415070754784, + 7.186258498493941 + ], + "joint_product_allowed_by_product_screen": [ + 4.733729256035931, + 7.100593884053898 + ], + "screen_intervals_overlap": true, + "overlap_interval": [ + 6.11415070754784, + 7.100593884053898 + ] + }, + { + "population": "youngest_pairs", + "metric": "weekly_hours", + "identified": true, + "predicted_product_of_marginal_means": 188.27184591178198, + "predicted_product_of_marginal_standard_deviations": 494.61903011840917, + "joint_product_required_by_correlation_screen": [ + 397.7218292195747, + 496.6456352432566 + ], + "joint_product_allowed_by_product_screen": [ + 294.14439665098314, + 441.21659497647465 + ], + "screen_intervals_overlap": true, + "overlap_interval": [ + 397.7218292195747, + 441.21659497647465 + ] + }, + { + "population": "youngest_pairs_in_3plus_households", + "metric": "days", + "identified": true, + "predicted_product_of_marginal_means": 3.0594508860714296, + "predicted_product_of_marginal_standard_deviations": 5.305436649100271, + "joint_product_required_by_correlation_screen": [ + 5.509332062571049, + 6.570419392391103 + ], + "joint_product_allowed_by_product_screen": [ + 4.067900983751674, + 6.101851475627511 + ], + "screen_intervals_overlap": true, + "overlap_interval": [ + 5.509332062571049, + 6.101851475627511 + ] + }, + { + "population": "youngest_pairs_in_3plus_households", + "metric": "weekly_hours", + "identified": true, + "predicted_product_of_marginal_means": 180.56174604989343, + "predicted_product_of_marginal_standard_deviations": 562.5331598833434, + "joint_product_required_by_correlation_screen": [ + 440.650567847255, + 553.1571998239236 + ], + "joint_product_allowed_by_product_screen": [ + 269.8776408426022, + 404.8164612639033 + ], + "screen_intervals_overlap": false, + "overlap_interval": null + } + ], + "interpretation": "disjoint screen intervals rule out a dependence-only fix for these conditional marginals; overlapping intervals do not establish that a feasible joint distribution exists" + } + }, + "pooled_moments": { + "design": "household-separated partitions; exact integration of the implemented shared-rank donor CDFs", + "seed": 271828, + "validation_seed": null, + "partition": "all", + "splits": [ + { + "training_households": 5100, + "evaluation_households": 1269, + "household_overlap": 0 + }, + { + "training_households": 5108, + "evaluation_households": 1261, + "household_overlap": 0 + }, + { + "training_households": 5055, + "evaluation_households": 1314, + "household_overlap": 0 + }, + { + "training_households": 5071, + "evaluation_households": 1298, + "household_overlap": 0 + }, + { + "training_households": 5142, + "evaluation_households": 1227, + "household_overlap": 0 + } + ], + "match_columns": [ + "age", + "childcare_household_size", + "parent_work_status", + "income_band", + "region" + ], + "fallback_match_columns": [], + "matching_counts": { + "partially_pooled": 7460 + }, + "training_rho": [ + 0.7652583390107988, + 0.7261225249617242, + 0.7209478813856636, + 0.7820313193382383, + 0.81974924157628 + ], + "youngest_pairs": { + "households": 1941, + "household_weight": 8329556.517461634, + "observed": { + "participation": { + "joint_product": 0.3285886986591048, + "correlation": 0.577510777815278 + }, + "days": { + "joint_product": 5.9171615700449145, + "correlation": 0.5798886366650429 + }, + "weekly_hours": { + "joint_product": 367.6804958137289, + "correlation": 0.523457187358221 + } + }, + "independent": { + "participation": { + "joint_product": 0.24236105200931968, + "correlation": 0.09396101556276153 + }, + "days": { + "joint_product": 4.135970938921813, + "correlation": 0.11086235305220805 + }, + "weekly_hours": { + "joint_product": 234.25280025856392, + "correlation": 0.09296236405577511 + } + }, + "coupled": { + "participation": { + "joint_product": 0.3478032040042286, + "correlation": 0.5194576064772242 + }, + "days": { + "joint_product": 6.714922913449467, + "correlation": 0.5919617343470333 + }, + "weekly_hours": { + "joint_product": 426.7255628007384, + "correlation": 0.4820957188644195 + } + } + }, + "youngest_pairs_in_3plus_households": { + "households": 661, + "household_weight": 2458669.150522002, + "observed": { + "participation": { + "joint_product": 0.2728957065164463, + "correlation": 0.5341073068866067 + }, + "days": { + "joint_product": 5.084876229689592, + "correlation": 0.5617680576612079 + }, + "weekly_hours": { + "joint_product": 337.34705105325276, + "correlation": 0.5623528715201395 + } + }, + "independent": { + "participation": { + "joint_product": 0.20749391246494672, + "correlation": 0.07367636621560582 + }, + "days": { + "joint_product": 3.5642905999293837, + "correlation": 0.09515516766062374 + }, + "weekly_hours": { + "joint_product": 216.49341419707955, + "correlation": 0.063874755675981 + } + }, + "coupled": { + "participation": { + "joint_product": 0.31038475496885254, + "correlation": 0.49338255183709395 + }, + "days": { + "joint_product": 6.0717725199533, + "correlation": 0.5677801532872357 + }, + "weekly_hours": { + "joint_product": 437.0722821479231, + "correlation": 0.45599184970931156 + } + } + }, + "larger_households": { + "households": 661, + "observed": { + "mean_total_days": 4.509647234214243, + "mean_total_weekly_hours": 33.085374473048084, + "sd_total_days": 5.765302178946849, + "sd_total_weekly_hours": 56.21651776123905, + "all_children_attend": 0.18568592787006075 + }, + "independent": { + "mean_total_days": 5.051031204266368, + "mean_total_weekly_hours": 38.34794143790316, + "sd_total_days": 4.395160013019163, + "sd_total_weekly_hours": 44.20739654038455, + "all_children_attend": 0.06527654820049239 + }, + "coupled": { + "mean_total_days": 5.051031204266368, + "mean_total_weekly_hours": 38.34794143790316, + "sd_total_days": 6.177046168973302, + "sd_total_weekly_hours": 59.820431157004805, + "all_children_attend": 0.20892405597176808 + } + }, + "production_ready": false, + "diagnostic_screen": { + "passed": false, + "checks": [ + { + "metric": "youngest_pairs.participation.joint_product", + "absolute_gap": 0.01921450534512381, + "relative": false, + "limit": 0.05, + "passed": true + }, + { + "metric": "youngest_pairs.days.correlation", + "absolute_gap": 0.012073097681990386, + "relative": false, + "limit": 0.1, + "passed": true + }, + { + "metric": "youngest_pairs.weekly_hours.correlation", + "absolute_gap": 0.04136146849380151, + "relative": false, + "limit": 0.1, + "passed": true + }, + { + "metric": "youngest_pairs.days.joint_product", + "absolute_gap": 0.13482162586925894, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs.weekly_hours.joint_product", + "absolute_gap": 0.1605879769508426, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.participation.joint_product", + "absolute_gap": 0.03748904845240625, + "relative": false, + "limit": 0.05, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.days.correlation", + "absolute_gap": 0.006012095626027891, + "relative": false, + "limit": 0.1, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.correlation", + "absolute_gap": 0.1063610218108279, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.days.joint_product", + "absolute_gap": 0.1940846238304513, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.joint_product", + "absolute_gap": 0.2956161341363792, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.mean_total_days", + "absolute_gap": 0.12005018174031427, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.mean_total_weekly_hours", + "absolute_gap": 0.15906022067672387, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.sd_total_days", + "absolute_gap": 0.07141759048294442, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.sd_total_weekly_hours", + "absolute_gap": 0.0641077309532437, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.all_children_attend", + "absolute_gap": 0.023238128101707334, + "relative": false, + "limit": 0.05, + "passed": true + } + ], + "interpretation": "provisional diagnostic screens; not publication authorization" + }, + "model": { + "name": "partially_pooled_empirical_schedules", + "levels": [ + [ + "age" + ], + [ + "age", + "childcare_household_size" + ], + [ + "age", + "childcare_household_size", + "parent_work_status" + ], + [ + "age", + "childcare_household_size", + "parent_work_status", + "income_band" + ], + [ + "age", + "childcare_household_size", + "parent_work_status", + "income_band", + "region" + ] + ], + "strength": 10.0, + "dependence_objective": "population_moments", + "dependence_fits": [ + { + "rho": 0.7652583390107988, + "unconstrained_rho": 0.7652583390107988, + "households": 1730, + "households_with_unresolved_siblings": 140, + "observed_pairs": 3670, + "outcome_second_moments": [ + 0.4359359926938946, + 8.277205060093346, + 593.7870077076072 + ], + "objective": "population_moments", + "normalized_mean_residual": [ + 0.2502298693914833, + 0.27527547268127456, + 0.2850732476726967 + ], + "normalized_mean_shared_increment": [ + 0.30253311517140813, + 0.38487878025611877, + 0.36627648825439335 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + }, + { + "rho": 0.7261225249617242, + "unconstrained_rho": 0.7261225249617242, + "households": 1697, + "households_with_unresolved_siblings": 123, + "observed_pairs": 3594, + "outcome_second_moments": [ + 0.44126287158160343, + 8.359355045936002, + 694.2809842648821 + ], + "objective": "population_moments", + "normalized_mean_residual": [ + 0.22454696976548358, + 0.25665784026502875, + 0.3085026964880856 + ], + "normalized_mean_shared_increment": [ + 0.3121975302394453, + 0.3956058631862616, + 0.37836062350370525 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + }, + { + "rho": 0.7209478813856636, + "unconstrained_rho": 0.7209478813856636, + "households": 1633, + "households_with_unresolved_siblings": 135, + "observed_pairs": 3453, + "outcome_second_moments": [ + 0.4338366370776943, + 8.256340131249516, + 694.144636825422 + ], + "objective": "population_moments", + "normalized_mean_residual": [ + 0.22762977893389097, + 0.2491739115147974, + 0.31614054777338935 + ], + "normalized_mean_shared_increment": [ + 0.3218355084453624, + 0.40226719431104246, + 0.37196853323063156 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + }, + { + "rho": 0.7820313193382383, + "unconstrained_rho": 0.7820313193382383, + "households": 1668, + "households_with_unresolved_siblings": 125, + "observed_pairs": 3499, + "outcome_second_moments": [ + 0.4428268423383291, + 8.341086892139936, + 679.4142064233605 + ], + "objective": "population_moments", + "normalized_mean_residual": [ + 0.24679819920578627, + 0.27437897292653474, + 0.337362053609579 + ], + "normalized_mean_shared_increment": [ + 0.3146404967452197, + 0.40232577509104867, + 0.3772940863523165 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + }, + { + "rho": 0.81974924157628, + "unconstrained_rho": 0.81974924157628, + "households": 1696, + "households_with_unresolved_siblings": 137, + "observed_pairs": 3584, + "outcome_second_moments": [ + 0.4413586153564347, + 8.485578051981562, + 676.0109573424492 + ], + "objective": "population_moments", + "normalized_mean_residual": [ + 0.2543497335812991, + 0.28684691450840843, + 0.35816569978000246 + ], + "normalized_mean_shared_increment": [ + 0.3106084542826501, + 0.4028661500770573, + 0.38060896199156885 + ], + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors" + } + ] + }, + "matching_count_universe": "every held-out child with an observed complete calendar", + "observed_child_validation": { + "comparisons": [ + { + "group": "all", + "children": 7460, + "child_weight": 32249785.682044946, + "observed": { + "participation": 0.4651484510706186, + "days": 1.8750709563867471, + "weekly_hours": 14.240422572045734 + }, + "expected": { + "participation": 0.46964890773471457, + "days": 1.8870313262922465, + "weekly_hours": 14.121321880052811 + }, + "conditional_mean_squared_error": { + "participation": 0.21786002566014795, + "days": 4.634484500691751, + "weekly_hours": 482.79806934933634 + }, + "expected_draw_squared_error": { + "participation": 0.4189867368126556, + "days": 8.871248441333941, + "weekly_hours": 905.9935560782225 + } + }, + { + "group": "household_size_1", + "children": 1910, + "child_weight": 9010809.078107145, + "observed": { + "participation": 0.5242108914088932, + "days": 2.119495964700082, + "weekly_hours": 16.911581677434366 + }, + "expected": { + "participation": 0.5309528476583814, + "days": 2.1450855821675643, + "weekly_hours": 16.7286558904403 + }, + "conditional_mean_squared_error": { + "participation": 0.21998157968908702, + "days": 4.8634925946342795, + "weekly_hours": 551.1632871152738 + }, + "expected_draw_squared_error": { + "participation": 0.4281854166170082, + "days": 9.372662082607494, + "weekly_hours": 1034.4761146276157 + } + }, + { + "group": "household_size_2", + "children": 2845, + "child_weight": 13265562.299413564, + "observed": { + "participation": 0.47658623296590163, + "days": 1.921092628643475, + "weekly_hours": 13.941634457809398 + }, + "expected": { + "participation": 0.48651284376374204, + "days": 1.9627422616863737, + "weekly_hours": 14.1440528078623 + }, + "conditional_mean_squared_error": { + "participation": 0.21802706174990996, + "days": 4.583635321783541, + "weekly_hours": 414.2968731100742 + }, + "expected_draw_squared_error": { + "participation": 0.4176700262900522, + "days": 8.771188666124276, + "weekly_hours": 779.6025285290256 + } + }, + { + "group": "household_size_3", + "children": 2705, + "child_weight": 9973414.304524235, + "observed": { + "participation": 0.39657324091775625, + "days": 1.5930240706983663, + "weekly_hours": 12.224491842781102 + }, + "expected": { + "participation": 0.3918312548530712, + "days": 1.5531811863063212, + "weekly_hours": 11.73540600582258 + }, + "conditional_mean_squared_error": { + "participation": 0.2157210644872454, + "days": 4.495213713500396, + "weekly_hours": 512.1441841789803 + }, + "expected_draw_squared_error": { + "participation": 0.41242723371549633, + "days": 8.551318544556374, + "weekly_hours": 958.0235058267347 + } + }, + { + "group": "complete_household", + "children": 6699, + "child_weight": 29099899.91535441, + "observed": { + "participation": 0.44408939246351814, + "days": 1.7729192348218488, + "weekly_hours": 13.20243633175764 + }, + "expected": { + "participation": 0.46990822362498935, + "days": 1.8840103414261442, + "weekly_hours": 14.119885124808388 + }, + "conditional_mean_squared_error": { + "participation": 0.21582355854647822, + "days": 4.473903862652206, + "weekly_hours": 447.4809381900267 + }, + "expected_draw_squared_error": { + "participation": 0.4175485380163647, + "days": 8.708831987458572, + "weekly_hours": 872.7199874173884 + } + }, + { + "group": "unresolved_siblings", + "children": 761, + "child_weight": 3149885.766690531, + "observed": { + "participation": 0.659700426338619, + "days": 2.8187892667948593, + "weekly_hours": 23.829753088509108 + }, + "expected": { + "participation": 0.46725324420518616, + "days": 1.914940388322065, + "weekly_hours": 14.13459519753524 + }, + "conditional_mean_squared_error": { + "participation": 0.23667372037103993, + "days": 6.117992424918431, + "weekly_hours": 809.0718005751868 + }, + "expected_draw_squared_error": { + "participation": 0.4322733904027592, + "days": 10.371716363808677, + "weekly_hours": 1213.3880426008857 + } + } + ], + "screen": { + "passed": false, + "checks": [ + { + "group": "all", + "metric": "participation", + "relative": false, + "gap": 0.0045004566640959864, + "limit": 0.05, + "passed": true + }, + { + "group": "all", + "metric": "days", + "relative": true, + "gap": 0.006378622560794653, + "limit": 0.2, + "passed": true + }, + { + "group": "all", + "metric": "weekly_hours", + "relative": true, + "gap": 0.008363564451150505, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "participation", + "relative": false, + "gap": 0.006741956249488146, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_1", + "metric": "days", + "relative": true, + "gap": 0.01207344476879113, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "weekly_hours", + "relative": true, + "gap": 0.010816598381105233, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "participation", + "relative": false, + "gap": 0.009926610797840407, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_2", + "metric": "days", + "relative": true, + "gap": 0.02168017950925578, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "weekly_hours", + "relative": true, + "gap": 0.014518982739467643, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "participation", + "relative": false, + "gap": 0.0047419860646850664, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_3", + "metric": "days", + "relative": true, + "gap": 0.02501084894127077, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "weekly_hours", + "relative": true, + "gap": 0.0400086844711946, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "participation", + "relative": false, + "gap": 0.025818831161471212, + "limit": 0.05, + "passed": true + }, + { + "group": "complete_household", + "metric": "days", + "relative": true, + "gap": 0.06265999286507735, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "weekly_hours", + "relative": true, + "gap": 0.06949087047243553, + "limit": 0.2, + "passed": true + }, + { + "group": "unresolved_siblings", + "metric": "participation", + "relative": false, + "gap": 0.19244718213343287, + "limit": 0.05, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "days", + "relative": true, + "gap": 0.3206514545518074, + "limit": 0.2, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "weekly_hours", + "relative": true, + "gap": 0.4068509587557979, + "limit": 0.2, + "passed": false + } + ] + }, + "interpretation": "child-weighted predictions of observed calendars; missing children are not scored as zeros; previously used survey, not external validation" + }, + "all_observed_sibling_pairs": { + "household_weight": 8945945.325594446, + "observed": { + "participation": { + "joint_product": 0.3302177486685269, + "correlation": 0.569690244749424 + }, + "days": { + "joint_product": 6.027208927705104, + "correlation": 0.5724522456066773 + }, + "weekly_hours": { + "joint_product": 426.22614842124585, + "correlation": 0.5408408373849536 + } + }, + "independent": { + "participation": { + "joint_product": 0.2260919090368316, + "correlation": 0.09520635050450324 + }, + "days": { + "joint_product": 3.8285744975466867, + "correlation": 0.10968106727006208 + }, + "weekly_hours": { + "joint_product": 212.90904376258283, + "correlation": 0.08730651835284241 + } + }, + "coupled": { + "participation": { + "joint_product": 0.33074016165677533, + "correlation": 0.5208339015307502 + }, + "days": { + "joint_product": 6.372410806864982, + "correlation": 0.5918345128361356 + }, + "weekly_hours": { + "joint_product": 401.34477075365476, + "correlation": 0.4737561541826404 + } + }, + "observed_pairs": 4450, + "households": 2106, + "interpretation": "all observed pairs including households with unresolved other siblings; household weight divided among observed pairs" + }, + "dependence_only_screen_compatibility": { + "comparisons": [ + { + "population": "youngest_pairs", + "metric": "days", + "identified": true, + "predicted_product_of_marginal_means": 3.5416889767723654, + "predicted_product_of_marginal_standard_deviations": 5.360538954730504, + "joint_product_required_by_correlation_screen": [ + 6.114150707547841, + 7.186258498493942 + ], + "joint_product_allowed_by_product_screen": [ + 4.733729256035931, + 7.100593884053898 + ], + "screen_intervals_overlap": true, + "overlap_interval": [ + 6.114150707547841, + 7.100593884053898 + ] + }, + { + "population": "youngest_pairs", + "metric": "weekly_hours", + "identified": true, + "predicted_product_of_marginal_means": 188.27184591178198, + "predicted_product_of_marginal_standard_deviations": 494.6190301184091, + "joint_product_required_by_correlation_screen": [ + 397.7218292195747, + 496.6456352432565 + ], + "joint_product_allowed_by_product_screen": [ + 294.14439665098314, + 441.21659497647465 + ], + "screen_intervals_overlap": true, + "overlap_interval": [ + 397.7218292195747, + 441.21659497647465 + ] + }, + { + "population": "youngest_pairs_in_3plus_households", + "metric": "days", + "identified": true, + "predicted_product_of_marginal_means": 3.0594508860714296, + "predicted_product_of_marginal_standard_deviations": 5.305436649100272, + "joint_product_required_by_correlation_screen": [ + 5.509332062571049, + 6.570419392391104 + ], + "joint_product_allowed_by_product_screen": [ + 4.067900983751674, + 6.101851475627511 + ], + "screen_intervals_overlap": true, + "overlap_interval": [ + 5.509332062571049, + 6.101851475627511 + ] + }, + { + "population": "youngest_pairs_in_3plus_households", + "metric": "weekly_hours", + "identified": true, + "predicted_product_of_marginal_means": 180.56174604989343, + "predicted_product_of_marginal_standard_deviations": 562.5331598833434, + "joint_product_required_by_correlation_screen": [ + 440.650567847255, + 553.1571998239236 + ], + "joint_product_allowed_by_product_screen": [ + 269.8776408426022, + 404.8164612639033 + ], + "screen_intervals_overlap": false, + "overlap_interval": null + } + ], + "interpretation": "disjoint screen intervals rule out a dependence-only fix for these conditional marginals; overlapping intervals do not establish that a feasible joint distribution exists" + } + } +} diff --git a/experiments/us-childcare-attendance/pooled-moments-plan.txt b/experiments/us-childcare-attendance/pooled-moments-plan.txt new file mode 100644 index 000000000..313160165 --- /dev/null +++ b/experiments/us-childcare-attendance/pooled-moments-plan.txt @@ -0,0 +1,26 @@ +Exploratory dependence-objective comparison, specified after the first pooled +results and before the alternative results, 2026-09-16. + +The first pooled model reduces mean errors and original-screen failures (9 to 4) +but worsens all four screened sibling intensity correlations. Its rowwise +cross-product squared-error fit targets individual conditional products, while +the required diagnostics target weighted population joint moments. Retain that +model as a comparator; do not describe its lower screen count as overall success. + +Test one alternative objective with the SAME donor pooling, fixed strength 10, +all observed sibling pairs, household/pair weights, leave-household-out donor +exclusion, training-only normalization scales, and five outer folds. Set rho to +minimize the sum of squared normalized WEIGHTED MEAN cross-product residuals +for participation, days and weekly hours. This has one analytic least-squares +coefficient, clipped to [0, 1]; expose the raw value and moments. Do not choose +separate coefficients for outcomes or alter thresholds after seeing results. + +Compare all three arms (original, pooled rowwise objective, pooled moment +objective) including all original screens and all 18 observed-child checks. +This ablation is motivated by already viewed outcomes. It is exploratory model +development, not a confirmatory test, and the previous held-out sample is not +reused under an independent-evidence label. Reproduce the first pooled arm +numerically to ensure the objective is the only behavioral change. + +Calendar selection remains unidentified. An improvement in correlation cannot +waive incomplete-family mean errors or authorize default population replacement. diff --git a/experiments/us-childcare-attendance/qrf-calendar-plan.txt b/experiments/us-childcare-attendance/qrf-calendar-plan.txt new file mode 100644 index 000000000..3d20de858 --- /dev/null +++ b/experiments/us-childcare-attendance/qrf-calendar-plan.txt @@ -0,0 +1,42 @@ +Canonical conditional-model diagnostic, specified after the composition result +and before this model's results, 2026-09-16. + +The composition-cell model improves the original joint-screen count from two +failures to one but worsens the unresolved-sibling hours prediction. It is not +adopted. Test whether rigid matching cells, rather than insufficient observed +predictors alone, explain that marginal error. + +Use microcosm.fit's canonical regime-gated weighted-bootstrap QRF (100 trees, +seed 915, existing defaults). Predictors: the full-roster composition features +from calendar-selection-plan.txt, region, parent work, income band, measured +household income, number of household members, and number of resident parents +of under-13 children. NSECE HH4_HHCOMP_MEMBERS counts all residents (HH-118); +HH4_HHCOMP_NUMPARENTS is household-wide, not each child's parent count (HH-121). +Corresponding ASEC fields can be derived from household membership and the +existing resident-parent pointers. No calendar-response/status, attendance, +provider usage, or source-only feature enters the predictors. Weekly NSECE +cost after subsidies is not treated as interchangeable with annual ASEC care +expenses. + +Fit one scalar joint schedule code: 25 * attended days + average daily hours. +This orders schedules by days then daily hours, just as the existing donor CDF; +zero means observed nonattendance. Decode positive QRF draws to the nearest +observed positive schedule code among training donors of the recipient's exact +age (ties choose the lower code). This is an ordinal distributional-matching +model, not an observed quantity or a claim that days and hours are fungible. +All output schedules therefore remain observed joint pairs; no fractional or +independently combined day/hour schedule is invented. Record decoder movement. + +Evaluate all 7,460 observed children using the same five whole-household folds. +Fit all QRF parameters and age-specific decoder catalogs solely on training +households. Use a fixed 128-point two-dimensional Sobol grid for gate/quantile +integration, and retain the empirical resulting CDF. The grid is fixed before +results, not a selected simulation seed. Report the same 18 observed-child +screens, conditional-mean MSE and expected random-draw error. These data have +already informed development; no independent validation claim is possible. + +This is a marginal-model diagnostic first. Only a promising result proceeds to +cross-fitted dependence estimation, joint household checks, higher-resolution +integration stability, source/target/bridge integration and a fresh population +candidate. Do not adopt it on child-average performance alone. Calendar +nonresponse and noncalendar duration assumptions remain unidentified. diff --git a/experiments/us-childcare-attendance/qrf-calendar-validation.json b/experiments/us-childcare-attendance/qrf-calendar-validation.json new file mode 100644 index 000000000..ded101e07 --- /dev/null +++ b/experiments/us-childcare-attendance/qrf-calendar-validation.json @@ -0,0 +1,417 @@ +{ + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "calendar_bounds": { + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568", + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "missing_calendar": "uninformative 0--168 hours and 0--7 days" + }, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "recipe": { + "contract_sha256": "ae648c6cb0e2838fdf142975e9c536eb0683d9630fd1738096d524222ffb01dc", + "runtime_versions": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "policyengine-us": "2.2.1" + }, + "code_sha256": { + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "nsece_childcare.py": "0e72ff9388f8f59147305f07effec2b99dada0f91599727cc9e58ad4feb6edbb", + "nsece_childcare_bridge.py": "70a7edea8b28c6da21ff4fa9bb220766a3e6cd714926684af29bdba1a8421b0a", + "nsece_childcare_dependence.py": "1c5123a77f84460ba517d2b4c6c3e04ae658bf36e9cf54ed69ddbcacc85efc09", + "childcare_attendance_stage.py": "42e777b0edfc813d79204bc2932fe429d6a48cd2866397560a7386cbee54dadb", + "childcare_attendance_receipt.py": "0950fce7f372ca4b240cd055c931f5f8fe070223fd68504a3ea9cfbc4e16c645" + } + }, + "plan_sha256": "8f3ea047c8d87a27faf5dbb0f7ce719f5aab9a1a8508fb3b6602d0cbbc4d4577", + "diagnostic_code_sha256": { + "validate_us_childcare_qrf.py": "78fd063407aaa24a1565ddab8b8b527c4cfa8a04f6a72b8b750658e511ede8d7", + "nsece_childcare_qrf.py": "cd18d77cce2199246b22407f4dc7f19f35fff25d94af4ce128c94b86188f838a" + }, + "model": { + "name": "canonical_weighted_QRF_joint_schedule_decoder", + "predictors": [ + "age", + "childcare_household_size", + "childcare_under6_count", + "childcare_schoolage_count", + "childcare_youngest_age_band", + "childcare_has_younger_sibling", + "parent_work_status", + "income_band", + "region", + "household_income", + "household_members", + "resident_parent_count" + ], + "trees": 100, + "seed": 915, + "integration_points": 128, + "mean_positive_decoder_code_movement": 0.2967616315205634, + "max_positive_decoder_code_movement": 12.0 + }, + "splits": [ + { + "fold": 0, + "training_households": 5100, + "evaluation_households": 857, + "household_overlap": 0, + "evaluated_children": 1402, + "profiles": 1361 + }, + { + "fold": 1, + "training_households": 5108, + "evaluation_households": 864, + "household_overlap": 0, + "evaluated_children": 1461, + "profiles": 1422 + }, + { + "fold": 2, + "training_households": 5055, + "evaluation_households": 928, + "household_overlap": 0, + "evaluated_children": 1620, + "profiles": 1578 + }, + { + "fold": 3, + "training_households": 5071, + "evaluation_households": 874, + "household_overlap": 0, + "evaluated_children": 1527, + "profiles": 1482 + }, + { + "fold": 4, + "training_households": 5142, + "evaluation_households": 849, + "household_overlap": 0, + "evaluated_children": 1450, + "profiles": 1410 + } + ], + "observed_child_validation": { + "comparisons": [ + { + "group": "all", + "children": 7460, + "child_weight": 32249785.682044946, + "observed": { + "participation": 0.4651484510706186, + "days": 1.8750709563867471, + "weekly_hours": 14.240422572045734 + }, + "expected": { + "participation": 0.4626963402375239, + "days": 1.8782143152899593, + "weekly_hours": 14.28498839270566 + }, + "conditional_mean_squared_error": { + "participation": 0.22193735839098713, + "days": 4.738177957705935, + "weekly_hours": 495.36993857227833 + }, + "expected_draw_squared_error": { + "participation": 0.3980913088338638, + "days": 8.493289037594954, + "weekly_hours": 884.5670742156525 + } + }, + { + "group": "household_size_1", + "children": 1910, + "child_weight": 9010809.078107145, + "observed": { + "participation": 0.5242108914088932, + "days": 2.119495964700082, + "weekly_hours": 16.911581677434366 + }, + "expected": { + "participation": 0.5169591695664993, + "days": 2.1040041234632554, + "weekly_hours": 16.180318254505547 + }, + "conditional_mean_squared_error": { + "participation": 0.21309207916173845, + "days": 4.80186267546308, + "weekly_hours": 547.7558761783448 + }, + "expected_draw_squared_error": { + "participation": 0.3939817087645831, + "days": 8.676322304138447, + "weekly_hours": 939.0868577063078 + } + }, + { + "group": "household_size_2", + "children": 2845, + "child_weight": 13265562.299413564, + "observed": { + "participation": 0.47658623296590163, + "days": 1.921092628643475, + "weekly_hours": 13.941634457809398 + }, + "expected": { + "participation": 0.47437966009242294, + "days": 1.9431615330846461, + "weekly_hours": 14.443491705680222 + }, + "conditional_mean_squared_error": { + "participation": 0.2237912246436724, + "days": 4.589094013107792, + "weekly_hours": 408.2440342383202 + }, + "expected_draw_squared_error": { + "participation": 0.39728485474399067, + "days": 8.251821584734268, + "weekly_hours": 751.137626070225 + } + }, + { + "group": "household_size_3", + "children": 2705, + "child_weight": 9973414.304524235, + "observed": { + "participation": 0.3965732409177563, + "days": 1.5930240706983663, + "weekly_hours": 12.224491842781102 + }, + "expected": { + "participation": 0.39813090829428704, + "days": 1.587831290116023, + "weekly_hours": 12.361766263154577 + }, + "conditional_mean_squared_error": { + "participation": 0.22746310337909134, + "days": 4.878935323151912, + "weekly_hours": 563.9256416456769 + }, + "expected_draw_squared_error": { + "participation": 0.40287692057375285, + "days": 8.64909563220651, + "weekly_hours": 1012.7828745314389 + } + }, + { + "group": "complete_household", + "children": 6699, + "child_weight": 29099899.915354412, + "observed": { + "participation": 0.4440893924635181, + "days": 1.7729192348218485, + "weekly_hours": 13.202436331757639 + }, + "expected": { + "participation": 0.4611924940358734, + "days": 1.8679016105224053, + "weekly_hours": 14.20249149230845 + }, + "conditional_mean_squared_error": { + "participation": 0.21836908152439619, + "days": 4.576891305578152, + "weekly_hours": 458.29836605715 + }, + "expected_draw_squared_error": { + "participation": 0.39552745711675996, + "days": 8.329736490182508, + "weekly_hours": 844.8891652102076 + } + }, + { + "group": "unresolved_siblings", + "children": 761, + "child_weight": 3149885.766690531, + "observed": { + "participation": 0.659700426338619, + "days": 2.8187892667948593, + "weekly_hours": 23.8297530885091 + }, + "expected": { + "participation": 0.4765894707182824, + "days": 1.9734871914576904, + "weekly_hours": 15.047127632887687 + }, + "conditional_mean_squared_error": { + "participation": 0.25490252201250563, + "days": 6.22820832142038, + "weekly_hours": 837.8518981731377 + }, + "expected_draw_squared_error": { + "participation": 0.42177719266956654, + "days": 10.004252644889078, + "weekly_hours": 1251.127408916974 + } + } + ], + "screen": { + "passed": false, + "checks": [ + { + "group": "all", + "metric": "participation", + "relative": false, + "gap": 0.0024521108330947117, + "limit": 0.05, + "passed": true + }, + { + "group": "all", + "metric": "days", + "relative": true, + "gap": 0.0016763946412296814, + "limit": 0.2, + "passed": true + }, + { + "group": "all", + "metric": "weekly_hours", + "relative": true, + "gap": 0.0031295293685603054, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "participation", + "relative": false, + "gap": 0.007251721842393866, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_1", + "metric": "days", + "relative": true, + "gap": 0.007309210064487643, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_1", + "metric": "weekly_hours", + "relative": true, + "gap": 0.04324039210977919, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "participation", + "relative": false, + "gap": 0.002206572873478696, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_2", + "metric": "days", + "relative": true, + "gap": 0.011487683681736041, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_2", + "metric": "weekly_hours", + "relative": true, + "gap": 0.035997016661823936, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "participation", + "relative": false, + "gap": 0.0015576673765307358, + "limit": 0.05, + "passed": true + }, + { + "group": "household_size_3", + "metric": "days", + "relative": true, + "gap": 0.003259700011982134, + "limit": 0.2, + "passed": true + }, + { + "group": "household_size_3", + "metric": "weekly_hours", + "relative": true, + "gap": 0.011229458217074167, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "participation", + "relative": false, + "gap": 0.01710310157235534, + "limit": 0.05, + "passed": true + }, + { + "group": "complete_household", + "metric": "days", + "relative": true, + "gap": 0.053574000346440526, + "limit": 0.2, + "passed": true + }, + { + "group": "complete_household", + "metric": "weekly_hours", + "relative": true, + "gap": 0.07574777377605987, + "limit": 0.2, + "passed": true + }, + { + "group": "unresolved_siblings", + "metric": "participation", + "relative": false, + "gap": 0.18311095562033664, + "limit": 0.05, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "days", + "relative": true, + "gap": 0.29988125940976446, + "limit": 0.2, + "passed": false + }, + { + "group": "unresolved_siblings", + "metric": "weekly_hours", + "relative": true, + "gap": 0.3685571320441615, + "limit": 0.2, + "passed": false + } + ] + }, + "interpretation": "child-weighted predictions of observed calendars; missing children are not scored as zeros; previously used survey, not external validation" + }, + "production_ready": false, + "interpretation": "marginal development diagnostic only; no dependence fit, no source-selection correction, no population integration or independent validation" +} diff --git a/experiments/us-childcare-attendance/qualified-population-comparison.json b/experiments/us-childcare-attendance/qualified-population-comparison.json new file mode 100644 index 000000000..100da246c --- /dev/null +++ b/experiments/us-childcare-attendance/qualified-population-comparison.json @@ -0,0 +1,1370 @@ +{ + "parent_sha256": "48b9d479fb4fd1c3537f9383ce4697d130b6f618658409d74f6233c43b994c7e", + "candidate_checkpoint_sha256": "882c2ae6b683e2a04ce6c94f5f694f70750a8c2876e8108e3715a7f7095d1f66", + "validation_code_sha256": "91e5d7c5eb7a634a5518ee44bac4ae60a84cef86819bd01752375659339285f8", + "engine_version": "1.819.0", + "policy_year": 2026, + "population": "fixed BuildP source ages/incomes; no aging or uprating", + "people": 166321, + "households": 57240, + "under13_children": 31889, + "outside_source_domain_people": 134432, + "outside_source_domain_age13_17_with_disability": 557, + "outside_domain_baseline_receipt": { + "engine_version": "1.819.0", + "inherited_counts": { + "childcare_attending_days_per_month": 134432, + "childcare_days_per_week": 134432, + "childcare_hours_per_day": 134432 + }, + "interpretation": "baseline retained; not evidence of nonattendance outside ages 0-12", + "values": { + "childcare_attending_days_per_month": 0.0, + "childcare_days_per_week": 0.0, + "childcare_hours_per_day": 0.0 + } + }, + "unresolved_people_retaining_baseline": 0, + "unresolved_age13_17_with_disability": 0, + "weighted_under13_attendance_share": 0.48474940604537897, + "weighted_under13_days_per_week": 1.9587696980712788, + "weighted_under13_hours_per_week": 14.080797907203973, + "candidate_receipt": { + "childcare_attendance_stage": { + "modeled_age_domain": [ + 0, + 12 + ], + "operation_order": [ + "derive_childcare_inputs", + "derive_childcare_inputs", + "derive_childcare_inputs" + ], + "outputs": [ + "childcare_attending_days_per_month", + "childcare_days_per_week", + "childcare_hours_per_day" + ], + "outside_domain_policy": "inherit_engine_baseline", + "seed": 915, + "sibling_dependence": { + "estimation": "youngest pair in fully observed households; household design weights", + "households": 1941, + "independent_both_in_care": 0.2585427028841666, + "observed_both_in_care": 0.32858869865910467, + "rho": 0.7413149380294699, + "shared_both_in_care": 0.3530315526045447, + "unconstrained_rho": 0.7413149380294699 + }, + "stage": "nsece_childcare_attendance" + }, + "childcare_outside_domain_baseline": { + "engine_version": "1.819.0", + "inherited_counts": { + "childcare_attending_days_per_month": 134432, + "childcare_days_per_week": 134432, + "childcare_hours_per_day": 134432 + }, + "interpretation": "baseline retained; not evidence of nonattendance outside ages 0-12", + "values": { + "childcare_attending_days_per_month": 0.0, + "childcare_days_per_week": 0.0, + "childcare_hours_per_day": 0.0 + } + }, + "childcare_predictor_harmonization": { + "geography": "Census region from target state_fips", + "income": "Household sum of measured ASEC PTOTVAL, CPI-U adjusted from source year to 2023 dollars", + "income_source_receipts": [ + { + "income_year": 2022, + "matched_people": 54464, + "sha256": "19b56537e50e7663f954361ef2bb5ce9cef8d9d45f156fe1a69a99b654198ffe", + "source_rows": 146133 + }, + { + "income_year": 2023, + "matched_people": 54654, + "sha256": "21a2b9e0e4b08534563578a45acad77868af4ae9a7d46f23776b707d4a559aa7", + "source_rows": 144265 + }, + { + "income_year": 2024, + "matched_people": 57203, + "sha256": "06921fe83fc66c907e6c7b86b82255dc70458ee7d76258fc48297cb34f0c06b5", + "source_rows": 142125 + } + ], + "parent_universe": "parents of any child age 0 through 12 in household", + "source": "ASEC resident parent line pointers", + "work_measure": "hours_worked_last_week > 0" + }, + "nsece_childcare_attendance": { + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ], + "candidate_only": true, + "fallback_match_columns": [ + [ + "age", + "parent_work_status", + "income_band" + ], + [ + "age", + "parent_work_status" + ], + [ + "age" + ] + ], + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "noncalendar_bridge": { + "assumption": "conditional calendar pattern and irregular care transfer across questionnaire instruments", + "completed_children": 3046, + "imputed": "attended days and irregular care jointly from nearest regular-hour calendar donors", + "observed": "regular weekly hours from May/fall questionnaire", + "seed": 915, + "unsupported_children": 0 + }, + "seed": 915, + "sibling_dependence": 0.7413149380294699, + "source_year": 2024, + "study": "ICPSR39466.v1" + } + }, + "states": [ + { + "state": "AL", + "sample_households": 1061, + "baseline": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13061.764184842585, + "annual_modeled_benefits": 32688921.398814265 + } + }, + { + "state": "AK", + "sample_households": 826, + "baseline": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + }, + "candidate": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + } + }, + { + "state": "AZ", + "sample_households": 1164, + "baseline": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 18733.37486637244, + "annual_modeled_benefits": 23159527.697095435 + } + }, + { + "state": "AR", + "sample_households": 952, + "baseline": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 17289.894029146235, + "annual_modeled_benefits": 50793417.58586023 + } + }, + { + "state": "CA", + "sample_households": 2659, + "baseline": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + } + }, + { + "state": "CO", + "sample_households": 1164, + "baseline": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 19, + "weighted_positive_units": 30914.695305580855, + "annual_modeled_benefits": 252602567.65021172 + }, + "candidate": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18502.53110225743, + "annual_modeled_benefits": 236445530.32343873 + } + }, + { + "state": "CT", + "sample_households": 908, + "baseline": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 405879416.70427954 + }, + "candidate": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 636244010.8081238 + } + }, + { + "state": "DE", + "sample_households": 1068, + "baseline": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + }, + "candidate": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + } + }, + { + "state": "DC", + "sample_households": 551, + "baseline": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 3288.0395223266023, + "annual_modeled_benefits": 23916792.31200898 + } + }, + { + "state": "FL", + "sample_households": 1642, + "baseline": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 87314.34071851184, + "annual_modeled_benefits": 336693781.677099 + } + }, + { + "state": "GA", + "sample_households": 1215, + "baseline": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + }, + "candidate": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + } + }, + { + "state": "HI", + "sample_households": 838, + "baseline": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 2554.6082648136944, + "annual_modeled_benefits": 15688867.198366832 + } + }, + { + "state": "ID", + "sample_households": 746, + "baseline": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 2, + "weighted_positive_units": 2335.738774359226, + "annual_modeled_benefits": 10651259.924815893 + } + }, + { + "state": "IL", + "sample_households": 1668, + "baseline": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 62767.78443156066, + "annual_modeled_benefits": 196786246.13666055 + } + }, + { + "state": "IN", + "sample_households": 1141, + "baseline": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + }, + "candidate": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + } + }, + { + "state": "IA", + "sample_households": 973, + "baseline": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13277.069981029548, + "annual_modeled_benefits": 54542065.75748161 + } + }, + { + "state": "KS", + "sample_households": 921, + "baseline": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 21785.09440057905, + "annual_modeled_benefits": 57457564.33302226 + } + }, + { + "state": "KY", + "sample_households": 776, + "baseline": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.02885724022053182, + "annual_modeled_benefits": 147.92350896229354 + } + }, + { + "state": "LA", + "sample_households": 1000, + "baseline": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 37176.93537535961, + "annual_modeled_benefits": 72842360.51107226 + } + }, + { + "state": "ME", + "sample_households": 785, + "baseline": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683663.687080294 + }, + "candidate": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683670.942570195 + } + }, + { + "state": "MD", + "sample_households": 1091, + "baseline": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + } + }, + { + "state": "MA", + "sample_households": 1522, + "baseline": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 0.0716373446630314, + "annual_modeled_benefits": 212.01572016369738 + } + }, + { + "state": "MI", + "sample_households": 1478, + "baseline": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + }, + "candidate": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + } + }, + { + "state": "MN", + "sample_households": 1166, + "baseline": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 21289.402694451623, + "annual_modeled_benefits": 274850426.86324066 + } + }, + { + "state": "MS", + "sample_households": 882, + "baseline": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 7256.952556610806, + "annual_modeled_benefits": 30449890.664512668 + } + }, + { + "state": "MO", + "sample_households": 1013, + "baseline": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 9981.891486888984, + "annual_modeled_benefits": 44110014.74611533 + } + }, + { + "state": "MT", + "sample_households": 744, + "baseline": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + }, + "candidate": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + } + }, + { + "state": "NE", + "sample_households": 884, + "baseline": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 754.4826039844379 + }, + "candidate": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 752.3048707440652 + } + }, + { + "state": "NV", + "sample_households": 952, + "baseline": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + } + }, + { + "state": "NH", + "sample_households": 840, + "baseline": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + }, + "candidate": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + } + }, + { + "state": "NJ", + "sample_households": 1651, + "baseline": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 54783391.64412939 + }, + "candidate": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 39399036.82068616 + } + }, + { + "state": "NM", + "sample_households": 902, + "baseline": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 40276267.46262546 + }, + "candidate": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 59646231.852653645 + } + }, + { + "state": "NY", + "sample_households": 2166, + "baseline": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 84809.87077922659, + "annual_modeled_benefits": 386150016.03633535 + } + }, + { + "state": "NC", + "sample_households": 1337, + "baseline": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + }, + "candidate": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + } + }, + { + "state": "ND", + "sample_households": 682, + "baseline": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 409.12895149587507 + }, + "candidate": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 471.04686684011335 + } + }, + { + "state": "OH", + "sample_households": 1531, + "baseline": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 57197.27386227145, + "annual_modeled_benefits": 109086186.25780228 + } + }, + { + "state": "OK", + "sample_households": 918, + "baseline": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0031096774619072676, + "annual_modeled_benefits": 5.149625876918435 + } + }, + { + "state": "OR", + "sample_households": 1152, + "baseline": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + }, + "candidate": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + } + }, + { + "state": "PA", + "sample_households": 1999, + "baseline": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.2005278345895931, + "annual_modeled_benefits": 561.099948525683 + } + }, + { + "state": "RI", + "sample_households": 804, + "baseline": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429808.7526231185 + }, + "candidate": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429813.4984327066 + } + }, + { + "state": "SC", + "sample_households": 955, + "baseline": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 27915.89938246878, + "annual_modeled_benefits": 77088809.79821464 + } + }, + { + "state": "SD", + "sample_households": 866, + "baseline": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 2978.0845139123267, + "annual_modeled_benefits": 5809177.944389787 + } + }, + { + "state": "TN", + "sample_households": 1082, + "baseline": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 54836.32565583871, + "annual_modeled_benefits": 120178664.890383 + } + }, + { + "state": "TX", + "sample_households": 1875, + "baseline": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 72034.10924506374, + "annual_modeled_benefits": 172158000.8966679 + } + }, + { + "state": "UT", + "sample_households": 861, + "baseline": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66285594.41326967 + }, + "candidate": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66285594.41326967 + } + }, + { + "state": "VT", + "sample_households": 496, + "baseline": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 78, + "weighted_positive_units": 32213.61921006818, + "annual_modeled_benefits": 526819840.50677323 + }, + "candidate": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 80, + "weighted_positive_units": 32213.669151621914, + "annual_modeled_benefits": 720606373.2116799 + } + }, + { + "state": "VA", + "sample_households": 1394, + "baseline": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 45187.34717369359, + "annual_modeled_benefits": 249203866.21813098 + } + }, + { + "state": "WA", + "sample_households": 1305, + "baseline": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + }, + "candidate": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + } + }, + { + "state": "WV", + "sample_households": 845, + "baseline": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 4, + "weighted_positive_units": 2978.909898934886, + "annual_modeled_benefits": 9329928.243193686 + } + }, + { + "state": "WI", + "sample_households": 1232, + "baseline": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 33918.60478726821, + "annual_modeled_benefits": 249284653.88471013 + } + }, + { + "state": "WY", + "sample_households": 557, + "baseline": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 2962.834392214354, + "annual_modeled_benefits": 18103301.12153925 + } + } + ], + "production_ready": false, + "interpretation": "attendance-only counterfactual; provider, activity, expenses and take-up inputs remain as in parent", + "matching_levels": { + "age,region,parent_work_status,income_band": 31152, + "age,parent_work_status,income_band": 576, + "age,parent_work_status": 161 + }, + "population_attendance_by_group": [ + { + "grouping": "age", + "group": "0.0", + "children": 1689, + "weighted_children": 2750700.861434371, + "attendance_share": 0.3982910388950054, + "days_per_week": 1.4637084569333976, + "hours_per_week": 12.47778129720075 + }, + { + "grouping": "age", + "group": "1.0", + "children": 2157, + "weighted_children": 3858818.186826853, + "attendance_share": 0.5828056228035874, + "days_per_week": 2.420690450933124, + "hours_per_week": 20.799764139530804 + }, + { + "grouping": "age", + "group": "2.0", + "children": 2364, + "weighted_children": 3754041.8444214575, + "attendance_share": 0.6245468848119025, + "days_per_week": 2.622672601643104, + "hours_per_week": 21.59076854224297 + }, + { + "grouping": "age", + "group": "3.0", + "children": 2385, + "weighted_children": 3880377.4871301977, + "attendance_share": 0.6440103162467938, + "days_per_week": 2.9239564940965894, + "hours_per_week": 21.837287866122146 + }, + { + "grouping": "age", + "group": "4.0", + "children": 2482, + "weighted_children": 4358831.600945832, + "attendance_share": 0.7298361168227924, + "days_per_week": 3.346378469862117, + "hours_per_week": 26.819455757918746 + }, + { + "grouping": "age", + "group": "5.0", + "children": 2391, + "weighted_children": 4095170.7360430276, + "attendance_share": 0.5643585836076381, + "days_per_week": 2.549062633648557, + "hours_per_week": 18.492995302361113 + }, + { + "grouping": "age", + "group": "6.0", + "children": 2562, + "weighted_children": 4029009.778184548, + "attendance_share": 0.4495509704841995, + "days_per_week": 1.6790815724045138, + "hours_per_week": 10.176170030770823 + }, + { + "grouping": "age", + "group": "7.0", + "children": 2612, + "weighted_children": 3768786.8623211696, + "attendance_share": 0.348461328136747, + "days_per_week": 1.4555085622939352, + "hours_per_week": 9.205290314751595 + }, + { + "grouping": "age", + "group": "8.0", + "children": 2689, + "weighted_children": 4419397.563846819, + "attendance_share": 0.41984770408640326, + "days_per_week": 1.582158698623752, + "hours_per_week": 9.889788909271815 + }, + { + "grouping": "age", + "group": "9.0", + "children": 2552, + "weighted_children": 3888389.065045069, + "attendance_share": 0.37587948153623024, + "days_per_week": 1.3231923573550826, + "hours_per_week": 8.472614481687524 + }, + { + "grouping": "age", + "group": "10.0", + "children": 2662, + "weighted_children": 4369978.335878741, + "attendance_share": 0.43521505778260355, + "days_per_week": 1.5068808517461778, + "hours_per_week": 8.205007778013812 + }, + { + "grouping": "age", + "group": "11.0", + "children": 2795, + "weighted_children": 4689133.259098214, + "attendance_share": 0.4034636828760653, + "days_per_week": 1.4253271874750526, + "hours_per_week": 8.173318571609755 + }, + { + "grouping": "age", + "group": "12.0", + "children": 2549, + "weighted_children": 4093051.641607744, + "attendance_share": 0.31020269689115165, + "days_per_week": 1.1064542406772742, + "hours_per_week": 7.828746644810994 + }, + { + "grouping": "region", + "group": "1", + "children": 5553, + "weighted_children": 7976838.3562431075, + "attendance_share": 0.5123696490920082, + "days_per_week": 2.208084285948932, + "hours_per_week": 15.123524314240859 + }, + { + "grouping": "region", + "group": "2", + "children": 7790, + "weighted_children": 10772583.599183697, + "attendance_share": 0.5153609964315923, + "days_per_week": 1.9523623395589054, + "hours_per_week": 14.70850903160164 + }, + { + "grouping": "region", + "group": "3", + "children": 10750, + "weighted_children": 21007309.669184513, + "attendance_share": 0.44174742437852166, + "days_per_week": 1.7895644362796808, + "hours_per_week": 13.033216088883725 + }, + { + "grouping": "region", + "group": "4", + "children": 7796, + "weighted_children": 12198955.598172724, + "attendance_share": 0.5137082633621989, + "days_per_week": 2.0927835451441785, + "hours_per_week": 14.648645297341831 + }, + { + "grouping": "parent_work_status", + "group": "-1", + "children": 684, + "weighted_children": 1044954.9507498589, + "attendance_share": 0.5422109593087965, + "days_per_week": 2.2811995403367784, + "hours_per_week": 25.482061788407137 + }, + { + "grouping": "parent_work_status", + "group": "0", + "children": 2876, + "weighted_children": 5039737.2909418885, + "attendance_share": 0.3083075074659248, + "days_per_week": 1.283739352802779, + "hours_per_week": 11.283501114920222 + }, + { + "grouping": "parent_work_status", + "group": "1", + "children": 9966, + "weighted_children": 15397404.080512933, + "attendance_share": 0.3115897123620967, + "days_per_week": 0.9599810926770269, + "hours_per_week": 6.6244519255662295 + }, + { + "grouping": "parent_work_status", + "group": "2", + "children": 18363, + "weighted_children": 30473590.900579363, + "attendance_share": 0.5994515383571952, + "days_per_week": 2.5640085999146067, + "hours_per_week": 17.919932134788446 + }, + { + "grouping": "income_band", + "group": "0", + "children": 94, + "weighted_children": 81378.29635578688, + "attendance_share": 0.29040892685678327, + "days_per_week": 1.0780433457763277, + "hours_per_week": 6.3255131795754185 + }, + { + "grouping": "income_band", + "group": "1", + "children": 3165, + "weighted_children": 6927519.022630059, + "attendance_share": 0.4025097371077471, + "days_per_week": 1.6934463444760064, + "hours_per_week": 12.252209201740305 + }, + { + "grouping": "income_band", + "group": "2", + "children": 6097, + "weighted_children": 10396829.673697237, + "attendance_share": 0.4585389868464392, + "days_per_week": 1.9481109164610568, + "hours_per_week": 14.847718600455874 + }, + { + "grouping": "income_band", + "group": "3", + "children": 9010, + "weighted_children": 14071962.152827512, + "attendance_share": 0.45002653661522485, + "days_per_week": 1.7736004293258292, + "hours_per_week": 13.239778272162871 + }, + { + "grouping": "income_band", + "group": "4", + "children": 7428, + "weighted_children": 13192218.644710096, + "attendance_share": 0.5136530195198358, + "days_per_week": 1.9683914038135206, + "hours_per_week": 14.280673940380375 + }, + { + "grouping": "income_band", + "group": "5", + "children": 6095, + "weighted_children": 7285779.432563353, + "attendance_share": 0.6172477004274525, + "days_per_week": 2.576313155655513, + "hours_per_week": 16.074152133280744 + } + ], + "summary": { + "states_evaluated": 51, + "all_zero_states": { + "baseline": [ + "AL", + "AZ", + "AR", + "CA", + "DC", + "FL", + "HI", + "ID", + "IL", + "IA", + "KS", + "KY", + "LA", + "MD", + "MA", + "MN", + "MS", + "MO", + "NV", + "NY", + "OH", + "OK", + "PA", + "SC", + "SD", + "TN", + "TX", + "VA", + "WV", + "WI", + "WY" + ], + "candidate": [ + "CA", + "MD", + "NV" + ] + }, + "annual_potential_modeled_benefits": { + "baseline": 2253392072.9613476, + "candidate": 5286396512.037729 + } + } +} diff --git a/experiments/us-childcare-attendance/qualified-preparation.json b/experiments/us-childcare-attendance/qualified-preparation.json new file mode 100644 index 000000000..57afb020c --- /dev/null +++ b/experiments/us-childcare-attendance/qualified-preparation.json @@ -0,0 +1,1476 @@ +{ + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "source_child_count": 11745, + "source_attrition": [ + { + "status": "age_out_of_scope", + "n": 134, + "child_weight": 633390.6468148227 + }, + { + "status": "ambiguous_calendar", + "n": 882, + "child_weight": 3918044.035953992 + }, + { + "status": "complete", + "n": 7460, + "child_weight": 32249785.682044942 + }, + { + "status": "missing_calendar", + "n": 3095, + "child_weight": 14061828.648228496 + }, + { + "status": "partial_calendar", + "n": 174, + "child_weight": 847769.9869632281 + } + ], + "under13_complete_weight_share": 0.6313901604255374, + "seed": 915, + "evaluation_design": "fixed household diagnostic split; not final population certification", + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "training_children": 5988, + "heldout_children": 1472, + "unsupported_heldout_children": 30, + "unsupported_heldout_weight": 153817.788204796, + "household_overlap": 0, + "comparisons": [ + { + "grouping": "all", + "group": "all", + "n": 1442, + "observed": { + "participation": 0.47956011362829676, + "days_per_week": 1.94220990502671, + "hours_per_week": 14.670259928481958 + }, + "predicted": { + "participation": 0.4547372440086608, + "days_per_week": 1.7986704844660344, + "hours_per_week": 13.001295500494344 + } + }, + { + "grouping": "age", + "group": "0", + "n": 87, + "observed": { + "participation": 0.4749769477860246, + "days_per_week": 1.8705229048944185, + "hours_per_week": 15.234832555457738 + }, + "predicted": { + "participation": 0.21347668238234924, + "days_per_week": 0.7762397588546358, + "hours_per_week": 6.331944692101247 + } + }, + { + "grouping": "age", + "group": "1", + "n": 113, + "observed": { + "participation": 0.6026124718926947, + "days_per_week": 2.2004884644301415, + "hours_per_week": 16.058889950232714 + }, + "predicted": { + "participation": 0.5817111215090339, + "days_per_week": 2.3867359768549528, + "hours_per_week": 20.29503642359935 + } + }, + { + "grouping": "age", + "group": "2", + "n": 107, + "observed": { + "participation": 0.6827728698846081, + "days_per_week": 3.2446932739752876, + "hours_per_week": 32.643365116161064 + }, + "predicted": { + "participation": 0.721108922787169, + "days_per_week": 2.9279814704204314, + "hours_per_week": 25.4484971084278 + } + }, + { + "grouping": "age", + "group": "3", + "n": 105, + "observed": { + "participation": 0.5478113606887365, + "days_per_week": 2.4737318877881727, + "hours_per_week": 18.774571500322175 + }, + "predicted": { + "participation": 0.7525857598038783, + "days_per_week": 3.556893850206531, + "hours_per_week": 31.34897414405891 + } + }, + { + "grouping": "age", + "group": "4", + "n": 115, + "observed": { + "participation": 0.6853382748904278, + "days_per_week": 3.133535876664359, + "hours_per_week": 22.72675588135229 + }, + "predicted": { + "participation": 0.6264622224091229, + "days_per_week": 2.555534029105278, + "hours_per_week": 22.558086951188297 + } + }, + { + "grouping": "age", + "group": "5", + "n": 109, + "observed": { + "participation": 0.45965467004039157, + "days_per_week": 2.204288116474054, + "hours_per_week": 16.671100530443887 + }, + "predicted": { + "participation": 0.5197893305690322, + "days_per_week": 2.0628456061601703, + "hours_per_week": 14.660711473842793 + } + }, + { + "grouping": "age", + "group": "6", + "n": 121, + "observed": { + "participation": 0.37767600901948256, + "days_per_week": 1.4233675361325482, + "hours_per_week": 11.368361596236443 + }, + "predicted": { + "participation": 0.3812603191662228, + "days_per_week": 1.344172188177959, + "hours_per_week": 6.687190574415363 + } + }, + { + "grouping": "age", + "group": "7", + "n": 121, + "observed": { + "participation": 0.2903318905157446, + "days_per_week": 0.9137564001326794, + "hours_per_week": 4.425088819370026 + }, + "predicted": { + "participation": 0.3316072853951072, + "days_per_week": 1.3098426672238894, + "hours_per_week": 7.381236186215511 + } + }, + { + "grouping": "age", + "group": "8", + "n": 136, + "observed": { + "participation": 0.33161676756925296, + "days_per_week": 1.2251387657453359, + "hours_per_week": 6.71788070980216 + }, + "predicted": { + "participation": 0.35465278512495324, + "days_per_week": 1.3642638058954168, + "hours_per_week": 9.725344329820171 + } + }, + { + "grouping": "age", + "group": "9", + "n": 101, + "observed": { + "participation": 0.4569510479920196, + "days_per_week": 1.674346958462562, + "hours_per_week": 7.805739183708693 + }, + "predicted": { + "participation": 0.396876880067868, + "days_per_week": 1.3966673442424729, + "hours_per_week": 8.701466574792914 + } + }, + { + "grouping": "age", + "group": "10", + "n": 105, + "observed": { + "participation": 0.45503949077471245, + "days_per_week": 1.5782906105470733, + "hours_per_week": 12.426848636692846 + }, + "predicted": { + "participation": 0.17752112044794535, + "days_per_week": 0.6469841431239514, + "hours_per_week": 3.596759032644189 + } + }, + { + "grouping": "age", + "group": "11", + "n": 119, + "observed": { + "participation": 0.41662598750149954, + "days_per_week": 1.8643111020323588, + "hours_per_week": 12.941021091087745 + }, + "predicted": { + "participation": 0.4008574857176407, + "days_per_week": 1.339718142783517, + "hours_per_week": 7.024111200026524 + } + }, + { + "grouping": "age", + "group": "12", + "n": 103, + "observed": { + "participation": 0.46408861423609865, + "days_per_week": 1.4945247924023801, + "hours_per_week": 11.114322042194766 + }, + "predicted": { + "participation": 0.43591150819042584, + "days_per_week": 1.7008936429461807, + "hours_per_week": 7.10555160431239 + } + }, + { + "grouping": "region", + "group": "1", + "n": 187, + "observed": { + "participation": 0.5340539220646277, + "days_per_week": 2.4009930157522064, + "hours_per_week": 14.79000641069395 + }, + "predicted": { + "participation": 0.6359603067185889, + "days_per_week": 2.7160385976574153, + "hours_per_week": 21.24487930853725 + } + }, + { + "grouping": "region", + "group": "2", + "n": 335, + "observed": { + "participation": 0.46285701128880247, + "days_per_week": 1.8453473655274784, + "hours_per_week": 15.352184287431765 + }, + "predicted": { + "participation": 0.41283532735257467, + "days_per_week": 1.4868890394545802, + "hours_per_week": 9.329182591248077 + } + }, + { + "grouping": "region", + "group": "3", + "n": 470, + "observed": { + "participation": 0.4328632075166446, + "days_per_week": 1.8236781494293404, + "hours_per_week": 15.35364160426729 + }, + "predicted": { + "participation": 0.4184231306502971, + "days_per_week": 1.5947483523709618, + "hours_per_week": 10.342311458512322 + } + }, + { + "grouping": "region", + "group": "4", + "n": 450, + "observed": { + "participation": 0.5171827642556369, + "days_per_week": 1.8475690827448323, + "hours_per_week": 13.04393396272379 + }, + "predicted": { + "participation": 0.4063739455351018, + "days_per_week": 1.670368549893466, + "hours_per_week": 13.748230642009998 + } + }, + { + "grouping": "parent_work_status", + "group": "-1", + "n": 13, + "observed": { + "participation": 0.253295875991658, + "days_per_week": 0.8671327195533685, + "hours_per_week": 3.515415042668932 + }, + "predicted": { + "participation": 0.12949135028799522, + "days_per_week": 0.5134069370080796, + "hours_per_week": 3.2849650228565768 + } + }, + { + "grouping": "parent_work_status", + "group": "0", + "n": 150, + "observed": { + "participation": 0.2939873489805854, + "days_per_week": 1.1857568669020946, + "hours_per_week": 10.001769026104405 + }, + "predicted": { + "participation": 0.20052896295212805, + "days_per_week": 0.7861821143968067, + "hours_per_week": 6.547539835013359 + } + }, + { + "grouping": "parent_work_status", + "group": "1", + "n": 543, + "observed": { + "participation": 0.2512596429034898, + "days_per_week": 0.8664048151368835, + "hours_per_week": 5.612021341518408 + }, + "predicted": { + "participation": 0.30234830539829555, + "days_per_week": 0.9663278582430083, + "hours_per_week": 5.557806485223704 + } + }, + { + "grouping": "parent_work_status", + "group": "2", + "n": 736, + "observed": { + "participation": 0.6462583482271946, + "days_per_week": 2.714084969528804, + "hours_per_week": 21.02161873348801 + }, + "predicted": { + "participation": 0.5856324643226721, + "days_per_week": 2.4572831629804637, + "hours_per_week": 18.54158986890966 + } + } + ], + "production_ready": false, + "limitations": [ + "Only complete, unambiguous calendars enter this holdout; source selection remains unvalidated.", + "The diagnostic matches age and caller-specified covariates; it is not a nationally validated fitted model.", + "Sibling assignments, mixed providers, older-child care and scalar monthly conversion need validation.", + "No full Microcosm population build or state CCDF distribution is certified by this source-only report." + ], + "sibling_dependence": { + "rho": 0.7413149380294699, + "unconstrained_rho": 0.7413149380294699, + "households": 1941, + "observed_both_in_care": 0.32858869865910467, + "independent_both_in_care": 0.2585427028841666, + "shared_both_in_care": 0.3530315526045447, + "estimation": "youngest pair in fully observed households; household design weights" + }, + "selection_and_cross_validation": { + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "seed": 271828, + "design": "five-fold household-separated conditional-expectation diagnostic", + "coverage": [ + { + "grouping": "questionnaire_version", + "group": "1", + "n": 8516, + "weight": 37015599.704962164, + "usable_weight_share": 0.8712484989868113 + }, + { + "grouping": "questionnaire_version", + "group": "2", + "n": 1716, + "weight": 7945306.22844611, + "usable_weight_share": 0.0 + }, + { + "grouping": "questionnaire_version", + "group": "3", + "n": 1379, + "weight": 6116522.419782387, + "usable_weight_share": 0.0 + }, + { + "grouping": "age", + "group": "0", + "n": 709, + "weight": 3159547.2696341733, + "usable_weight_share": 0.6556513621184303 + }, + { + "grouping": "age", + "group": "1", + "n": 856, + "weight": 3710311.739747545, + "usable_weight_share": 0.6518631977426506 + }, + { + "grouping": "age", + "group": "2", + "n": 906, + "weight": 4112848.861546397, + "usable_weight_share": 0.6567885484115844 + }, + { + "grouping": "age", + "group": "3", + "n": 927, + "weight": 4191268.180093972, + "usable_weight_share": 0.5836151261043054 + }, + { + "grouping": "age", + "group": "4", + "n": 890, + "weight": 3761621.476875998, + "usable_weight_share": 0.6069150244376095 + }, + { + "grouping": "age", + "group": "5", + "n": 884, + "weight": 3759953.5032736305, + "usable_weight_share": 0.6441250249176611 + }, + { + "grouping": "age", + "group": "6", + "n": 954, + "weight": 4259102.717846392, + "usable_weight_share": 0.6213110691400029 + }, + { + "grouping": "age", + "group": "7", + "n": 944, + "weight": 4191490.05150999, + "usable_weight_share": 0.6014263712726516 + }, + { + "grouping": "age", + "group": "8", + "n": 925, + "weight": 3969583.419307067, + "usable_weight_share": 0.6776062606911202 + }, + { + "grouping": "age", + "group": "9", + "n": 921, + "weight": 4036325.188020362, + "usable_weight_share": 0.6661696977311178 + }, + { + "grouping": "age", + "group": "10", + "n": 884, + "weight": 3707790.894951107, + "usable_weight_share": 0.6220814618665044 + }, + { + "grouping": "age", + "group": "11", + "n": 908, + "weight": 4069233.422108399, + "usable_weight_share": 0.6084497314858798 + }, + { + "grouping": "age", + "group": "12", + "n": 903, + "weight": 4148351.6282756263, + "usable_weight_share": 0.6217216150291205 + }, + { + "grouping": "region", + "group": "1", + "n": 1468, + "weight": 8153076.12536276, + "usable_weight_share": 0.6401722331669089 + }, + { + "grouping": "region", + "group": "2", + "n": 2680, + "weight": 10714972.208999828, + "usable_weight_share": 0.6330942004076335 + }, + { + "grouping": "region", + "group": "3", + "n": 4275, + "weight": 20022339.81304313, + "usable_weight_share": 0.6249460927360144 + }, + { + "grouping": "region", + "group": "4", + "n": 3188, + "weight": 12187040.205784943, + "usable_weight_share": 0.634603874645437 + }, + { + "grouping": "parent_work_status", + "group": "-1", + "n": 188, + "weight": 819575.738509818, + "usable_weight_share": 0.646736557730207 + }, + { + "grouping": "parent_work_status", + "group": "0", + "n": 1470, + "weight": 5301911.400981113, + "usable_weight_share": 0.6698890755679009 + }, + { + "grouping": "parent_work_status", + "group": "1", + "n": 3380, + "weight": 14009836.058523985, + "usable_weight_share": 0.7212981495115555 + }, + { + "grouping": "parent_work_status", + "group": "2", + "n": 6573, + "weight": 30946105.155175745, + "usable_weight_share": 0.5836849144158337 + }, + { + "grouping": "income_band", + "group": "0", + "n": 120, + "weight": 497291.815717528, + "usable_weight_share": 0.602001589054288 + }, + { + "grouping": "income_band", + "group": "1", + "n": 2057, + "weight": 7466809.932490364, + "usable_weight_share": 0.6413274998297077 + }, + { + "grouping": "income_band", + "group": "2", + "n": 2904, + "weight": 10880663.16706181, + "usable_weight_share": 0.6487048847817203 + }, + { + "grouping": "income_band", + "group": "3", + "n": 2558, + "weight": 11325516.809686286, + "usable_weight_share": 0.6401496463974632 + }, + { + "grouping": "income_band", + "group": "4", + "n": 3134, + "weight": 15757011.988844048, + "usable_weight_share": 0.6309648019074636 + }, + { + "grouping": "income_band", + "group": "5", + "n": 838, + "weight": 5150134.639390623, + "usable_weight_share": 0.5652783862122169 + } + ], + "cross_validation": [ + { + "grouping": "all", + "group": "all", + "n": 7460, + "observed": { + "participation": 0.46514845107061753, + "days": 1.8750709563867467, + "hours": 14.240422572045741 + }, + "expected": { + "participation": 0.4654844290416027, + "days": 1.878527294011518, + "hours": 14.081114700859393 + } + }, + { + "grouping": "age", + "group": "0", + "n": 458, + "observed": { + "participation": 0.40007662898763713, + "days": 1.5207410031354076, + "hours": 12.391341719561105 + }, + "expected": { + "participation": 0.42043937266485903, + "days": 1.5581186938006875, + "hours": 12.778280226573155 + } + }, + { + "grouping": "age", + "group": "1", + "n": 585, + "observed": { + "participation": 0.5768442364096245, + "days": 2.3247221464109487, + "hours": 18.93194004904792 + }, + "expected": { + "participation": 0.5636534387398192, + "days": 2.2787632897750942, + "hours": 18.46136873433321 + } + }, + { + "grouping": "age", + "group": "2", + "n": 599, + "observed": { + "participation": 0.6119472630516792, + "days": 2.661365110302835, + "hours": 23.568671427585098 + }, + "expected": { + "participation": 0.615171451571855, + "days": 2.6668583554129937, + "hours": 24.008204825875836 + } + }, + { + "grouping": "age", + "group": "3", + "n": 597, + "observed": { + "participation": 0.6106570906701301, + "days": 2.6641302585227766, + "hours": 21.96346327818111 + }, + "expected": { + "participation": 0.6452189769582379, + "days": 2.8385499518769803, + "hours": 23.234965023661523 + } + }, + { + "grouping": "age", + "group": "4", + "n": 550, + "observed": { + "participation": 0.7046928755645677, + "days": 3.1467359328380096, + "hours": 25.30894736806148 + }, + "expected": { + "participation": 0.7168364294128767, + "days": 3.1704359925035326, + "hours": 25.23962440956216 + } + }, + { + "grouping": "age", + "group": "5", + "n": 581, + "observed": { + "participation": 0.5580840489623686, + "days": 2.527957605747102, + "hours": 20.351246817207983 + }, + "expected": { + "participation": 0.5580783794454302, + "days": 2.4817744855985993, + "hours": 19.696005730111843 + } + }, + { + "grouping": "age", + "group": "6", + "n": 611, + "observed": { + "participation": 0.38410943637037254, + "days": 1.5233703763582376, + "hours": 9.272995362839891 + }, + "expected": { + "participation": 0.3704517476571586, + "days": 1.4435320487985335, + "hours": 8.308626409800924 + } + }, + { + "grouping": "age", + "group": "7", + "n": 586, + "observed": { + "participation": 0.34047335603475937, + "days": 1.267585660002729, + "hours": 8.978033563109225 + }, + "expected": { + "participation": 0.32048663598972876, + "days": 1.2092330340598734, + "hours": 7.976819608666644 + } + }, + { + "grouping": "age", + "group": "8", + "n": 611, + "observed": { + "participation": 0.37000227568041516, + "days": 1.4234519706143929, + "hours": 8.822905923973602 + }, + "expected": { + "participation": 0.37441818500322505, + "days": 1.4678570808250095, + "hours": 8.581931573672641 + } + }, + { + "grouping": "age", + "group": "9", + "n": 590, + "observed": { + "participation": 0.3862968300759907, + "days": 1.373131779820256, + "hours": 9.825473717875598 + }, + "expected": { + "participation": 0.3658218612710925, + "days": 1.2745107095149821, + "hours": 9.212380152023707 + } + }, + { + "grouping": "age", + "group": "10", + "n": 541, + "observed": { + "participation": 0.39185689727904155, + "days": 1.3647219850376735, + "hours": 8.468134791861964 + }, + "expected": { + "participation": 0.3879904743599543, + "days": 1.313066433397897, + "hours": 7.6091158562940935 + } + }, + { + "grouping": "age", + "group": "11", + "n": 565, + "observed": { + "participation": 0.3768238596848206, + "days": 1.3633597325953704, + "hours": 8.143708694787577 + }, + "expected": { + "participation": 0.37027421084947587, + "days": 1.3896706621501198, + "hours": 8.180743029734462 + } + }, + { + "grouping": "age", + "group": "12", + "n": 586, + "observed": { + "participation": 0.35838594666001994, + "days": 1.3239431239565607, + "hours": 10.203528792841063 + }, + "expected": { + "participation": 0.37173621674013835, + "days": 1.447846572682685, + "hours": 10.94364602719194 + } + }, + { + "grouping": "region", + "group": "1", + "n": 929, + "observed": { + "participation": 0.4988625902951673, + "days": 2.101321934458425, + "hours": 14.697745432365767 + }, + "expected": { + "participation": 0.5341920187102704, + "days": 2.234373766910041, + "hours": 15.515545077772881 + } + }, + { + "grouping": "region", + "group": "2", + "n": 1654, + "observed": { + "participation": 0.495642471526947, + "days": 1.9378635600824832, + "hours": 14.438707404977198 + }, + "expected": { + "participation": 0.48657470779470846, + "days": 1.9053160452954483, + "hours": 13.830397580793818 + } + }, + { + "grouping": "region", + "group": "3", + "n": 2752, + "observed": { + "participation": 0.4310162776090592, + "days": 1.7482660126296112, + "hours": 14.16760866653331 + }, + "expected": { + "participation": 0.4254047590539008, + "days": 1.728432288982956, + "hours": 13.771990873343658 + } + }, + { + "grouping": "region", + "group": "4", + "n": 2125, + "observed": { + "participation": 0.470872102608504, + "days": 1.872465315119329, + "hours": 13.875678601794997 + }, + "expected": { + "participation": 0.46546295898430057, + "days": 1.857723153971244, + "hours": 13.833112421687238 + } + }, + { + "grouping": "parent_work_status", + "group": "-1", + "n": 122, + "observed": { + "participation": 0.34614706740243706, + "days": 1.1849281571656916, + "hours": 9.788566562075097 + }, + "expected": { + "participation": 0.373389275855184, + "days": 1.462386368172592, + "hours": 12.574282386813668 + } + }, + { + "grouping": "parent_work_status", + "group": "0", + "n": 1016, + "observed": { + "participation": 0.3096578455166947, + "days": 1.244408501915661, + "hours": 10.193456359940383 + }, + "expected": { + "participation": 0.2882996076692788, + "days": 1.1762845771341546, + "hours": 10.282450861819337 + } + }, + { + "grouping": "parent_work_status", + "group": "1", + "n": 2418, + "observed": { + "participation": 0.2864480974767621, + "days": 0.9529380212414282, + "hours": 6.42952602558992 + }, + "expected": { + "participation": 0.29059369126489437, + "days": 0.9858655333196232, + "hours": 6.764091600272923 + } + }, + { + "grouping": "parent_work_status", + "group": "2", + "n": 3904, + "observed": { + "participation": 0.5991891288528669, + "days": 2.535220374688929, + "hours": 19.536646150926547 + }, + "expected": { + "participation": 0.6008699918772364, + "days": 2.528223299633135, + "hours": 18.96579429859326 + } + }, + { + "grouping": "income_band", + "group": "0", + "n": 76, + "observed": { + "participation": 0.19070472825408744, + "days": 0.8431547354115522, + "hours": 5.587881885800679 + }, + "expected": { + "participation": 0.25300464764173586, + "days": 0.9988467887623982, + "hours": 7.43593331362669 + } + }, + { + "grouping": "income_band", + "group": "1", + "n": 1378, + "observed": { + "participation": 0.35684525807866907, + "days": 1.5280931021110342, + "hours": 12.098088591903252 + }, + "expected": { + "participation": 0.3773650597658377, + "days": 1.627338456412184, + "hours": 12.706694579809993 + } + }, + { + "grouping": "income_band", + "group": "2", + "n": 1922, + "observed": { + "participation": 0.4194011939997811, + "days": 1.7068232976926216, + "hours": 13.491053608546364 + }, + "expected": { + "participation": 0.4119472083085292, + "days": 1.7030609232530567, + "hours": 13.262000601507708 + } + }, + { + "grouping": "income_band", + "group": "3", + "n": 1632, + "observed": { + "participation": 0.4246978564102466, + "days": 1.7238735833385048, + "hours": 14.076591113511121 + }, + "expected": { + "participation": 0.4255788471352766, + "days": 1.704797441331804, + "hours": 13.264862389978802 + } + }, + { + "grouping": "income_band", + "group": "4", + "n": 1977, + "observed": { + "participation": 0.5221816116808028, + "days": 1.9968956951019248, + "hours": 14.35832226780555 + }, + "expected": { + "participation": 0.519705526319959, + "days": 1.9988673657729517, + "hours": 14.55106672367201 + } + }, + { + "grouping": "income_band", + "group": "5", + "n": 475, + "observed": { + "participation": 0.6883939484468758, + "days": 2.9203317046618578, + "hours": 20.476264713601847 + }, + "expected": { + "participation": 0.6762909354194406, + "days": 2.8292574855634296, + "hours": 19.43897806431697 + } + } + ], + "matching_levels": { + "age,region,parent_work_status,income_band": 7278, + "age,parent_work_status,income_band": 150, + "age,parent_work_status": 32 + }, + "sibling_validation": [ + { + "fold": 0, + "training_rho": 0.7504775690168417, + "households": 351, + "weight": 1627200.3809817089, + "observed_both": 0.3346110552302055, + "independent_both": 0.26023741618799584, + "coupled_both": 0.3228394147816889 + }, + { + "fold": 1, + "training_rho": 0.8095401305423818, + "households": 367, + "weight": 1640369.17044373, + "observed_both": 0.308478237709926, + "independent_both": 0.2538314963354507, + "coupled_both": 0.31777192913378116 + }, + { + "fold": 2, + "training_rho": 0.7176223341350483, + "households": 443, + "weight": 1849383.6729044288, + "observed_both": 0.3831182075641927, + "independent_both": 0.260592140353083, + "coupled_both": 0.3144997720634755 + }, + { + "fold": 3, + "training_rho": 0.8946850037821993, + "households": 398, + "weight": 1567825.4608580691, + "observed_both": 0.2954259187077949, + "independent_both": 0.2551329149477867, + "coupled_both": 0.3186981148017382 + }, + { + "fold": 4, + "training_rho": 0.8022505236076816, + "households": 382, + "weight": 1644777.832273697, + "observed_both": 0.3129856591731878, + "independent_both": 0.2695651435301845, + "coupled_both": 0.3411406780146054 + } + ], + "questionnaire_transport": [ + { + "questionnaire_version": 2, + "scored_children": 1690, + "unsupported_children": 0, + "observed": { + "regular_participation": 0.4166998042800092, + "regular_hours_per_week": 12.379208437570716 + }, + "expected": { + "regular_participation": 0.429264128691119, + "regular_hours_per_week": 14.800674181069196 + } + }, + { + "questionnaire_version": 3, + "scored_children": 1356, + "unsupported_children": 0, + "observed": { + "regular_participation": 0.38447915314763226, + "regular_hours_per_week": 10.163827277430636 + }, + "expected": { + "regular_participation": 0.40786334693307874, + "regular_hours_per_week": 13.921490221932158 + } + } + ], + "assumptions": [ + "Calendar selection is ignorable conditional on matching fields; not identified from these data.", + "Main reference-week schedules transfer to May/fall typical weeks; summer attendance is not observed.", + "Regular-care comparisons cannot validate days or irregular care in instruments without calendars." + ], + "production_ready": false + }, + "masked_calendar_validation": { + "seed": 161803, + "design": "whole-household masked-calendar test; regular weekly hours remain observed", + "comparisons": [ + { + "grouping": "all", + "group": "all", + "n": 1581, + "observed_days": 1.7176113066572272, + "imputed_days": 1.7931671544992573, + "observed_hours": 13.097316141278531, + "imputed_hours": 13.161738723028055 + }, + { + "grouping": "age", + "group": "0", + "n": 104, + "observed_days": 1.841126169101498, + "imputed_days": 1.757972840808916, + "observed_hours": 17.766331967357488, + "imputed_hours": 18.04127357697798 + }, + { + "grouping": "age", + "group": "1", + "n": 113, + "observed_days": 2.37969546844872, + "imputed_days": 2.466724275790995, + "observed_hours": 19.829328945193588, + "imputed_hours": 19.122886717221327 + }, + { + "grouping": "age", + "group": "2", + "n": 141, + "observed_days": 2.4591773765558673, + "imputed_days": 2.5150278262191854, + "observed_hours": 22.536051090399965, + "imputed_hours": 22.20070627284854 + }, + { + "grouping": "age", + "group": "3", + "n": 123, + "observed_days": 2.3763627081083216, + "imputed_days": 2.276649667113583, + "observed_hours": 20.251977914853146, + "imputed_hours": 19.002839959330025 + }, + { + "grouping": "age", + "group": "4", + "n": 115, + "observed_days": 3.137397964036117, + "imputed_days": 3.2507274717120613, + "observed_hours": 23.68360614421261, + "imputed_hours": 24.493916641155817 + }, + { + "grouping": "age", + "group": "5", + "n": 113, + "observed_days": 2.2242008794879244, + "imputed_days": 2.6293843819994196, + "observed_hours": 15.760856040214335, + "imputed_hours": 17.46780844312604 + }, + { + "grouping": "age", + "group": "6", + "n": 130, + "observed_days": 1.1830651060264654, + "imputed_days": 1.4124105587435267, + "observed_hours": 7.042175416036001, + "imputed_hours": 6.515374725210956 + }, + { + "grouping": "age", + "group": "7", + "n": 131, + "observed_days": 1.4073709771017413, + "imputed_days": 1.2967131682238184, + "observed_hours": 10.083939201157254, + "imputed_hours": 9.618996783594744 + }, + { + "grouping": "age", + "group": "8", + "n": 126, + "observed_days": 1.057579033652681, + "imputed_days": 1.0820232296805903, + "observed_hours": 8.256788366496435, + "imputed_hours": 6.9299612873656375 + }, + { + "grouping": "age", + "group": "9", + "n": 118, + "observed_days": 1.4349301372689758, + "imputed_days": 1.2570443106530333, + "observed_hours": 10.733568940718998, + "imputed_hours": 11.528485757775337 + }, + { + "grouping": "age", + "group": "10", + "n": 124, + "observed_days": 1.2058459898990705, + "imputed_days": 1.2067301677274491, + "observed_hours": 4.1774445652404655, + "imputed_hours": 4.342805855105561 + }, + { + "grouping": "age", + "group": "11", + "n": 120, + "observed_days": 0.9483350107584563, + "imputed_days": 1.2273618861530076, + "observed_hours": 5.566349482238208, + "imputed_hours": 6.3416466466885835 + }, + { + "grouping": "age", + "group": "12", + "n": 123, + "observed_days": 1.1181905452629102, + "imputed_days": 1.3377626847259545, + "observed_hours": 8.079018679724042, + "imputed_hours": 9.278796503817835 + }, + { + "grouping": "parent_work_status", + "group": "-1", + "n": 33, + "observed_days": 1.5430497710033617, + "imputed_days": 1.3274872915746017, + "observed_hours": 12.754941207431992, + "imputed_hours": 12.147679308677683 + }, + { + "grouping": "parent_work_status", + "group": "0", + "n": 233, + "observed_days": 1.3163214930511598, + "imputed_days": 1.4661772450887058, + "observed_hours": 9.57367968242547, + "imputed_hours": 9.490248507911081 + }, + { + "grouping": "parent_work_status", + "group": "1", + "n": 529, + "observed_days": 0.8935323002915262, + "imputed_days": 1.0535312696492358, + "observed_hours": 6.370457810059637, + "imputed_hours": 7.0815725747740155 + }, + { + "grouping": "parent_work_status", + "group": "2", + "n": 786, + "observed_days": 2.3152602893352414, + "imputed_days": 2.332856367184494, + "observed_hours": 17.994069548324816, + "imputed_hours": 17.722049473088507 + } + ], + "regular_hours_preserved": true, + "limitations": "Tests reconstruction where calendars exist; not a direct test of unobserved days in the other questionnaire instruments." + }, + "noncalendar_bridge": { + "seed": 915, + "completed_children": 3046, + "unsupported_children": 0, + "observed": "regular weekly hours from May/fall questionnaire", + "imputed": "attended days and irregular care jointly from nearest regular-hour calendar donors", + "assumption": "conditional calendar pattern and irregular care transfer across questionnaire instruments" + }, + "candidate_frame_written": true, + "environment": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "microcosm-build": "0.1.0", + "microcosm-frame": "0.1.0", + "policyengine-us": "1.819.0", + "python": "3.13.5" + }, + "code_sha256": { + "prepare_us_childcare_attendance.py": "94cc41dd804508dbd0d1340ee1ac1b0189dfbcd8f089fc403a9933552e50d799", + "childcare_attendance.py": "43d6ed235cc52ec6d9b6fcde15d10f66e8bb870b8e3cf5232b35573917a1e041", + "nsece_childcare.py": "ecd99fdf630f51c5f75df141ff8a054a5124288cda6a2dbdb338ceb5abae280f", + "nsece_childcare_bridge.py": "70a7edea8b28c6da21ff4fa9bb220766a3e6cd714926684af29bdba1a8421b0a", + "nsece_childcare_dependence.py": "bf9ff3a1992d16c75fc74b8c17634791739669f0ecab4382fdf59a6e6c3c424c", + "childcare_attendance_stage.py": "fced2bd83564d5d6332d4a5511051ca041acd0e1b6983acfc3035fe31ea5b6de", + "nsece_childcare_assessment.py": "537d5d839ce9df4f1772ee887597811990aab5b7f10a863b70fe6630583fa3b7", + "childcare_population.py": "f34711db1f692347a13070a4c6faa7612ebf7c97cba156ca488781559516b6be", + "childcare.py": "a8502e1fc15457a7f120936a8940fbb51cba3e2299d92ca9cd69b749f6deea2f", + "childcare_attendance_source.json": "c5beeeb09ab330c305e3250bc7db5a5003336d26fa508872211cb18958ab9e97", + "education_assistance_source.py": "e259e3fce64fdcab62953f79a1aa41719f81c64c7c5dc1a63f8b1e493ff5f83a", + "geography_constants.py": "dc31ec6aa913d638d51ccc8e3fda11edee6c3f508ea5d2e27690bdb43e081fd2", + "uv.lock": "751d5ef5d25406bbae1798667f0e29890d4aad933d323c12912c7d45d8809bb9" + }, + "candidate_checkpoint_sha256": "882c2ae6b683e2a04ce6c94f5f694f70750a8c2876e8108e3715a7f7095d1f66", + "parent_population_sha256": "48b9d479fb4fd1c3537f9383ce4697d130b6f618658409d74f6233c43b994c7e", + "production_stage_executed": true, + "candidate_receipts": { + "childcare_predictor_harmonization": { + "source": "ASEC resident parent line pointers", + "parent_universe": "parents of any child age 0 through 12 in household", + "work_measure": "hours_worked_last_week > 0", + "geography": "Census region from target state_fips", + "income_source_receipts": [ + { + "income_year": 2022, + "sha256": "19b56537e50e7663f954361ef2bb5ce9cef8d9d45f156fe1a69a99b654198ffe", + "matched_people": 54464, + "source_rows": 146133 + }, + { + "income_year": 2023, + "sha256": "21a2b9e0e4b08534563578a45acad77868af4ae9a7d46f23776b707d4a559aa7", + "matched_people": 54654, + "source_rows": 144265 + }, + { + "income_year": 2024, + "sha256": "06921fe83fc66c907e6c7b86b82255dc70458ee7d76258fc48297cb34f0c06b5", + "matched_people": 57203, + "source_rows": 142125 + } + ], + "income": "Household sum of measured ASEC PTOTVAL, CPI-U adjusted from source year to 2023 dollars" + }, + "nsece_childcare_attendance": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ], + "noncalendar_bridge": { + "seed": 915, + "completed_children": 3046, + "unsupported_children": 0, + "observed": "regular weekly hours from May/fall questionnaire", + "imputed": "attended days and irregular care jointly from nearest regular-hour calendar donors", + "assumption": "conditional calendar pattern and irregular care transfer across questionnaire instruments" + }, + "seed": 915, + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "fallback_match_columns": [ + [ + "age", + "parent_work_status", + "income_band" + ], + [ + "age", + "parent_work_status" + ], + [ + "age" + ] + ], + "sibling_dependence": 0.7413149380294699, + "candidate_only": true + }, + "childcare_outside_domain_baseline": { + "engine_version": "1.819.0", + "values": { + "childcare_attending_days_per_month": 0.0, + "childcare_days_per_week": 0.0, + "childcare_hours_per_day": 0.0 + }, + "inherited_counts": { + "childcare_attending_days_per_month": 134432, + "childcare_days_per_week": 134432, + "childcare_hours_per_day": 134432 + }, + "interpretation": "baseline retained; not evidence of nonattendance outside ages 0-12" + }, + "childcare_attendance_stage": { + "stage": "nsece_childcare_attendance", + "outputs": [ + "childcare_attending_days_per_month", + "childcare_days_per_week", + "childcare_hours_per_day" + ], + "seed": 915, + "operation_order": [ + "derive_childcare_inputs", + "derive_childcare_inputs", + "derive_childcare_inputs" + ], + "sibling_dependence": { + "rho": 0.7413149380294699, + "unconstrained_rho": 0.7413149380294699, + "households": 1941, + "observed_both_in_care": 0.32858869865910467, + "independent_both_in_care": 0.2585427028841666, + "shared_both_in_care": 0.3530315526045447, + "estimation": "youngest pair in fully observed households; household design weights" + }, + "modeled_age_domain": [ + 0, + 12 + ], + "outside_domain_policy": "inherit_engine_baseline" + } + }, + "native_candidate_written": true, + "native_candidate_sha256": "a2d0ed98081b3707727eddb3d90e007117aa1da50e75c83a1a33fe381f41bcd2" +} diff --git a/experiments/us-childcare-attendance/qualified-remaining-state-inputs.json b/experiments/us-childcare-attendance/qualified-remaining-state-inputs.json new file mode 100644 index 000000000..f4bbe77ea --- /dev/null +++ b/experiments/us-childcare-attendance/qualified-remaining-state-inputs.json @@ -0,0 +1,156 @@ +{ + "candidate_checkpoint_sha256": "882c2ae6b683e2a04ce6c94f5f694f70750a8c2876e8108e3715a7f7095d1f66", + "engine_version": "1.819.0", + "scope": "January 2026 diagnostic; fixed parent ages and income", + "states": { + "CA": { + "ca_capp_eligible": { + "period": "2026-01", + "units": 2828, + "positive_units": 341, + "unique_counts": { + "False": 2487, + "True": 341 + } + }, + "ca_calworks_child_care_days_per_month": { + "period": "2026-01", + "units": 7866, + "positive_units": 0, + "unique_counts": { + "0": 7866 + } + }, + "ca_calworks_child_care_weeks_per_month": { + "period": "2026-01", + "units": 7866, + "positive_units": 0, + "unique_counts": { + "0": 7866 + } + }, + "ca_calworks_child_care_time_coefficient": { + "period": "2026-01", + "units": 7866, + "positive_units": 0, + "unique_counts": { + "0.0": 7866 + } + }, + "ca_calworks_child_care_payment_standard": { + "period": "2026-01", + "units": 7866, + "positive_units": 1531, + "unique_counts": { + "0.0": 6335, + "139.94": 886, + "227.58": 207, + "277.15": 83, + "277.58": 111, + "309.93": 188, + "406.72": 56 + } + }, + "ca_capp_payment": { + "period": "2026-01", + "units": 7866, + "positive_units": 0, + "unique_counts": { + "0.0": 7866 + } + }, + "pre_subsidy_childcare_expenses": { + "period": "2026", + "units": 7866, + "positive_units": 313, + "max": 90000.0 + } + }, + "MD": { + "md_ccs_eligible": { + "period": "2026-01", + "units": 1193, + "positive_units": 115, + "unique_counts": { + "False": 1078, + "True": 115 + } + }, + "md_ccs_provider_type": { + "period": "2026-01", + "units": 3268, + "positive_units": null, + "unique_counts": { + "NONE": 3268 + } + }, + "md_ccs_payment_rate": { + "period": "2026-01", + "units": 3268, + "positive_units": 0, + "unique_counts": { + "0.0": 3268 + } + }, + "md_ccs": { + "period": "2026-01", + "units": 1193, + "positive_units": 0, + "unique_counts": { + "0.0": 1193 + } + } + }, + "NV": { + "meets_ccdf_activity_test": { + "period": "2026", + "units": 1011, + "positive_units": 0, + "unique_counts": { + "False": 1011 + } + }, + "nv_ccdp_activity_eligible": { + "period": "2026-01", + "units": 1011, + "positive_units": 0, + "unique_counts": { + "False": 1011 + } + }, + "nv_ccdp_income_eligible": { + "period": "2026-01", + "units": 1011, + "positive_units": 149, + "unique_counts": { + "False": 862, + "True": 149 + } + }, + "is_ccdf_asset_eligible": { + "period": "2026", + "units": 1011, + "positive_units": 1011, + "unique_counts": { + "True": 1011 + } + }, + "nv_ccdp_eligible": { + "period": "2026-01", + "units": 1011, + "positive_units": 0, + "unique_counts": { + "False": 1011 + } + }, + "nv_ccdp": { + "period": "2026-01", + "units": 1011, + "positive_units": 0, + "unique_counts": { + "0.0": 1011 + } + } + } + } +} diff --git a/experiments/us-childcare-attendance/review-artifact-verification.json b/experiments/us-childcare-attendance/review-artifact-verification.json new file mode 100644 index 000000000..54878c4be --- /dev/null +++ b/experiments/us-childcare-attendance/review-artifact-verification.json @@ -0,0 +1,47 @@ +{ + "date": "2026-09-15", + "people": 166321, + "households": 57240, + "under13_children": 31889, + "checkpoint_sha256": "e9d363aa5a10a611c751c704017edd47c6ec8c2ba583bb7124b27514ba15d69e", + "native_sha256": "937c0c0c9798f0cf9e015fc4d5bed204342480bf93a415d94d3080d66f20cb6f", + "previous_native_sha256": "be04c3fe14763bb5d40fbb7057763cec6ffb69e0a43a021c2d0b117d881b54d7", + "source_stage_report_sha256": "3d54dd35857a825679eec8a0d97e352541a673e257ce886aaf37d9c1a8b6bf9a", + "sensitivity_report_sha256": "05c0bedf2b59de80e0645005e4e10ec46c083dfe425f5d88342172af2812bff5", + "attendance_recipe": { + "code_sha256": { + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "childcare_attendance_receipt.py": "0950fce7f372ca4b240cd055c931f5f8fe070223fd68504a3ea9cfbc4e16c645", + "childcare_attendance_stage.py": "42e777b0edfc813d79204bc2932fe429d6a48cd2866397560a7386cbee54dadb", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "nsece_childcare.py": "affc8ac5a3ce853e2ef8b062c51a1801a15573cbcbf6eacc2c093334a1d12c11", + "nsece_childcare_bridge.py": "70a7edea8b28c6da21ff4fa9bb220766a3e6cd714926684af29bdba1a8421b0a", + "nsece_childcare_dependence.py": "bf9ff3a1992d16c75fc74b8c17634791739669f0ecab4382fdf59a6e6c3c424c" + }, + "contract_sha256": "ae648c6cb0e2838fdf142975e9c536eb0683d9630fd1738096d524222ffb01dc", + "runtime_versions": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "policyengine-us": "1.819.0" + } + }, + "content_binding_sha256": "db79754d13221f083d9ee56bd2efbc293039790468c8145ceea4755aa3b21d41", + "verified_native_loaders": [ + "microcosm.build.us_runtime.h5_io.load_legacy_calibrated_us_h5", + "microcosm.build.us_runtime.l0_refit_export.load_us_frame" + ], + "exact_attendance_matches_sensitivity_candidate": true, + "exact_sibling_diagnostics_match_previous_execution": true, + "household_weights_unchanged_on_native_reload": true, + "original_columns_and_period_verified_by_source_stage_export": true, + "difference_since_sensitivity_run": "Equivalent explicit column reindexing and type annotations for the repository AST guard, plus a sequence-based private receipt inventory to avoid quadratic metadata serialization; final attendance arrays and diagnostic values compare exactly.", + "build_wheel_sha256": "bf027a1814f8e374496d3ca42d4ed4b432e5a5e45290480f6c1c62861c3a0cde", + "verification_code_sha256": "203ef9ddacc8bb579b3acbe8a754fac5b2781f2f14f9b6125d179f5a94fb545d", + "changed_recipe_files_since_sensitivity": [ + "childcare_attendance_stage.py", + "childcare_attendance_receipt.py" + ], + "sensitivity_model_and_evaluator_code_unchanged": true, + "engine_version": "1.819.0", + "production_ready": false +} diff --git a/experiments/us-childcare-attendance/review-fixes-population.json b/experiments/us-childcare-attendance/review-fixes-population.json new file mode 100644 index 000000000..d700ff6c9 --- /dev/null +++ b/experiments/us-childcare-attendance/review-fixes-population.json @@ -0,0 +1,1590 @@ +{ + "parent_sha256": "48b9d479fb4fd1c3537f9383ce4697d130b6f618658409d74f6233c43b994c7e", + "candidate_checkpoint_sha256": "5cb9aa418768b5a82ee351e8b737f58c8989212f1ffbee36d605c22887e989a5", + "validation_code_sha256": "ee3ca65dcd2ef4492924edce54b6bdd03b8b4ed882c65684fc57a1622c341dfe", + "engine_version": "2.2.1", + "policy_year": 2026, + "population": "fixed BuildP source ages/incomes; no aging or uprating", + "people": 166321, + "households": 57240, + "under13_children": 31889, + "outside_source_domain_people": 134432, + "outside_source_domain_age13_17_with_disability": 557, + "outside_domain_baseline_receipt": { + "engine_version": "2.2.1", + "inherited_counts": { + "childcare_attending_days_per_month": 134432, + "childcare_days_per_week": 134432, + "childcare_hours_per_day": 134432 + }, + "interpretation": "baseline retained; not evidence of nonattendance outside ages 0-12", + "values": { + "childcare_attending_days_per_month": 0.0, + "childcare_days_per_week": 0.0, + "childcare_hours_per_day": 0.0 + } + }, + "unresolved_people_retaining_baseline": 0, + "unresolved_age13_17_with_disability": 0, + "weighted_under13_attendance_share": 0.48476583170284354, + "weighted_under13_days_per_week": 1.9567197164255687, + "weighted_under13_hours_per_week": 14.09681286757626, + "candidate_receipt": { + "nsece_childcare_attendance": { + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ], + "calendar_bounds": { + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "missing_calendar": "uninformative 0--168 hours and 0--7 days", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568" + }, + "candidate_only": true, + "fallback_match_columns": [ + [ + "age", + "parent_work_status", + "income_band" + ], + [ + "age", + "parent_work_status" + ], + [ + "age" + ] + ], + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "noncalendar_bridge": { + "assumption": "conditional calendar pattern and irregular care transfer across questionnaire instruments", + "completed_children": 3046, + "imputed": "attended days and irregular care jointly from nearest regular-hour calendar donors", + "matching_levels": { + "age": 46, + "age,parent_work_status": 331, + "age,parent_work_status,income_band": 1287, + "age,region,parent_work_status,income_band": 1382 + }, + "observed": "regular weekly hours from May/fall questionnaire", + "seed": 915, + "unsupported_children": 0 + }, + "seed": 915, + "sibling_dependence": 0.7413149380294699, + "source_year": 2024, + "study": "ICPSR39466.v1" + }, + "childcare_predictor_harmonization": { + "geography": "Census region from target state_fips", + "income": "Household sum of measured ASEC PTOTVAL, CPI-U adjusted from source year to 2023 dollars", + "income_source_receipts": [ + { + "income_year": 2022, + "matched_people": 54464, + "sha256": "19b56537e50e7663f954361ef2bb5ce9cef8d9d45f156fe1a69a99b654198ffe", + "source_rows": 146133 + }, + { + "income_year": 2023, + "matched_people": 54654, + "sha256": "21a2b9e0e4b08534563578a45acad77868af4ae9a7d46f23776b707d4a559aa7", + "source_rows": 144265 + }, + { + "income_year": 2024, + "matched_people": 57203, + "sha256": "06921fe83fc66c907e6c7b86b82255dc70458ee7d76258fc48297cb34f0c06b5", + "source_rows": 142125 + } + ], + "parent_universe": "parents of any child age 0 through 12 in household", + "source": "ASEC resident parent line pointers", + "work_measure": "hours_worked_last_week > 0" + }, + "childcare_outside_domain_baseline": { + "engine_version": "2.2.1", + "inherited_counts": { + "childcare_attending_days_per_month": 134432, + "childcare_days_per_week": 134432, + "childcare_hours_per_day": 134432 + }, + "interpretation": "baseline retained; not evidence of nonattendance outside ages 0-12", + "values": { + "childcare_attending_days_per_month": 0.0, + "childcare_days_per_week": 0.0, + "childcare_hours_per_day": 0.0 + } + }, + "childcare_attendance_stage": { + "modeled_age_domain": [ + 0, + 12 + ], + "operations": [ + { + "age_max": 12, + "age_min": 0, + "kind": "derive_childcare_inputs", + "operation": "calendar_attendance" + }, + { + "kind": "fit", + "operation": "fit_sibling_dependence", + "rho": 0.7413149380294699 + }, + { + "kind": "derive_childcare_inputs", + "nearest_donors": 10, + "operation": "regular_hours_schedule_bridge" + }, + { + "kind": "derive", + "operation": "harmonize_asec_childcare_predictors" + }, + { + "kind": "derive_childcare_inputs", + "operation": "joint_weighted_schedule_transfer", + "preserve_observed": true + }, + { + "kind": "export_policy", + "operation": "inherit_engine_baseline" + } + ], + "outputs": [ + "childcare_attending_days_per_month", + "childcare_days_per_week", + "childcare_hours_per_day" + ], + "outside_domain_policy": "inherit_engine_baseline", + "seed": 915, + "sibling_dependence": { + "estimation": "youngest pair in fully observed households; household design weights", + "households": 1941, + "independent_both_in_care": 0.2585427028841666, + "observed_both_in_care": 0.32858869865910467, + "rho": 0.7413149380294699, + "shared_both_in_care": 0.3530315526045447, + "unconstrained_rho": 0.7413149380294699 + }, + "stage": "nsece_childcare_attendance" + }, + "childcare_attendance_binding": { + "schema_version": 1, + "binding_sha256": "5a67c4cdbefa261a6ba7be056ef37afbf6a20755c649432c10020026a7f1e9a2", + "execution_sha256": "a9c0c33d4eac2a876e7cee52c65b8e2ad3d2200bed62d91bc0465c05f590cc27", + "source_people": 166321, + "retained_people": 166321, + "execution": { + "context": { + "childcare_attendance_stage": { + "modeled_age_domain": [ + 0, + 12 + ], + "operations": [ + { + "age_max": 12, + "age_min": 0, + "kind": "derive_childcare_inputs", + "operation": "calendar_attendance" + }, + { + "kind": "fit", + "operation": "fit_sibling_dependence", + "rho": 0.7413149380294699 + }, + { + "kind": "derive_childcare_inputs", + "nearest_donors": 10, + "operation": "regular_hours_schedule_bridge" + }, + { + "kind": "derive", + "operation": "harmonize_asec_childcare_predictors" + }, + { + "kind": "derive_childcare_inputs", + "operation": "joint_weighted_schedule_transfer", + "preserve_observed": true + }, + { + "kind": "export_policy", + "operation": "inherit_engine_baseline" + } + ], + "outputs": [ + "childcare_attending_days_per_month", + "childcare_days_per_week", + "childcare_hours_per_day" + ], + "outside_domain_policy": "inherit_engine_baseline", + "seed": 915, + "sibling_dependence": { + "estimation": "youngest pair in fully observed households; household design weights", + "households": 1941, + "independent_both_in_care": 0.2585427028841666, + "observed_both_in_care": 0.32858869865910467, + "rho": 0.7413149380294699, + "shared_both_in_care": 0.3530315526045447, + "unconstrained_rho": 0.7413149380294699 + }, + "stage": "nsece_childcare_attendance" + }, + "childcare_outside_domain_baseline": { + "engine_version": "2.2.1", + "inherited_counts": { + "childcare_attending_days_per_month": 134432, + "childcare_days_per_week": 134432, + "childcare_hours_per_day": 134432 + }, + "interpretation": "baseline retained; not evidence of nonattendance outside ages 0-12", + "values": { + "childcare_attending_days_per_month": 0.0, + "childcare_days_per_week": 0.0, + "childcare_hours_per_day": 0.0 + } + }, + "childcare_predictor_harmonization": { + "geography": "Census region from target state_fips", + "income": "Household sum of measured ASEC PTOTVAL, CPI-U adjusted from source year to 2023 dollars", + "income_source_receipts": [ + { + "income_year": 2022, + "matched_people": 54464, + "sha256": "19b56537e50e7663f954361ef2bb5ce9cef8d9d45f156fe1a69a99b654198ffe", + "source_rows": 146133 + }, + { + "income_year": 2023, + "matched_people": 54654, + "sha256": "21a2b9e0e4b08534563578a45acad77868af4ae9a7d46f23776b707d4a559aa7", + "source_rows": 144265 + }, + { + "income_year": 2024, + "matched_people": 57203, + "sha256": "06921fe83fc66c907e6c7b86b82255dc70458ee7d76258fc48297cb34f0c06b5", + "source_rows": 142125 + } + ], + "parent_universe": "parents of any child age 0 through 12 in household", + "source": "ASEC resident parent line pointers", + "work_measure": "hours_worked_last_week > 0" + }, + "nsece_childcare_attendance": { + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ], + "calendar_bounds": { + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "missing_calendar": "uninformative 0--168 hours and 0--7 days", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568" + }, + "candidate_only": true, + "fallback_match_columns": [ + [ + "age", + "parent_work_status", + "income_band" + ], + [ + "age", + "parent_work_status" + ], + [ + "age" + ] + ], + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "noncalendar_bridge": { + "assumption": "conditional calendar pattern and irregular care transfer across questionnaire instruments", + "completed_children": 3046, + "imputed": "attended days and irregular care jointly from nearest regular-hour calendar donors", + "matching_levels": { + "age": 46, + "age,parent_work_status": 331, + "age,parent_work_status,income_band": 1287, + "age,region,parent_work_status,income_band": 1382 + }, + "observed": "regular weekly hours from May/fall questionnaire", + "seed": 915, + "unsupported_children": 0 + }, + "seed": 915, + "sibling_dependence": 0.7413149380294699, + "source_year": 2024, + "study": "ICPSR39466.v1" + } + }, + "recipe": { + "code_sha256": { + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "childcare_attendance_receipt.py": "d93ecfe1725bef2c0b87a137eaab88856fa9a76e601227089ceb94daa4335865", + "childcare_attendance_stage.py": "c5243b7f23865c352acee8f5946bb8c7b578645c7b5e56c24632fa94dd9dbecb", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "nsece_childcare.py": "e11eef389f47433a2d407aaf7c01214dbefccb702b3fefe8fa6502c7e947ab4d", + "nsece_childcare_bridge.py": "517b3c3ae02e2316b028fd15bc60a090e7962d716d46b80e3e73067f08d5ff29", + "nsece_childcare_dependence.py": "1c5123a77f84460ba517d2b4c6c3e04ae658bf36e9cf54ed69ddbcacc85efc09" + }, + "contract_sha256": "ae648c6cb0e2838fdf142975e9c536eb0683d9630fd1738096d524222ffb01dc", + "runtime_versions": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "policyengine-us": "2.2.1" + } + } + } + } + }, + "states": [ + { + "state": "AL", + "sample_households": 1061, + "baseline": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13061.764184842585, + "annual_modeled_benefits": 32688921.398814265 + } + }, + { + "state": "AK", + "sample_households": 826, + "baseline": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + }, + "candidate": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + } + }, + { + "state": "AZ", + "sample_households": 1164, + "baseline": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 18733.37486637244, + "annual_modeled_benefits": 21138074.239445645 + } + }, + { + "state": "AR", + "sample_households": 952, + "baseline": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 17289.894029146235, + "annual_modeled_benefits": 50793417.58586023 + } + }, + { + "state": "CA", + "sample_households": 2659, + "baseline": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 31, + "weighted_positive_units": 201632.45677746536, + "annual_modeled_benefits": 935799297.9584653 + } + }, + { + "state": "CO", + "sample_households": 1164, + "baseline": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 19, + "weighted_positive_units": 30914.695305580855, + "annual_modeled_benefits": 252602567.65021172 + }, + "candidate": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18502.53110225743, + "annual_modeled_benefits": 236445530.32343873 + } + }, + { + "state": "CT", + "sample_households": 908, + "baseline": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 405879416.70427954 + }, + "candidate": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 653474165.4604676 + } + }, + { + "state": "DE", + "sample_households": 1068, + "baseline": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + }, + "candidate": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + } + }, + { + "state": "DC", + "sample_households": 551, + "baseline": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 3288.0395223266023, + "annual_modeled_benefits": 23916792.31200898 + } + }, + { + "state": "FL", + "sample_households": 1642, + "baseline": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 60231.19228101184, + "annual_modeled_benefits": 320519265.7821029 + } + }, + { + "state": "GA", + "sample_households": 1215, + "baseline": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + }, + "candidate": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + } + }, + { + "state": "HI", + "sample_households": 838, + "baseline": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0001588361046742648, + "annual_modeled_benefits": 0.6336225438054939 + } + }, + { + "state": "ID", + "sample_households": 746, + "baseline": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 2, + "weighted_positive_units": 2335.738774359226, + "annual_modeled_benefits": 10651259.924815893 + } + }, + { + "state": "IL", + "sample_households": 1668, + "baseline": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 62767.78443156066, + "annual_modeled_benefits": 196786246.13666055 + } + }, + { + "state": "IN", + "sample_households": 1141, + "baseline": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + }, + "candidate": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + } + }, + { + "state": "IA", + "sample_households": 973, + "baseline": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 13277.072875641927, + "annual_modeled_benefits": 55836595.948581845 + } + }, + { + "state": "KS", + "sample_households": 921, + "baseline": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 21785.09440057905, + "annual_modeled_benefits": 58709143.174893744 + } + }, + { + "state": "KY", + "sample_households": 776, + "baseline": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.02885724022053182, + "annual_modeled_benefits": 168.32094133054224 + } + }, + { + "state": "LA", + "sample_households": 1000, + "baseline": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 37176.93537535961, + "annual_modeled_benefits": 72842360.51107226 + } + }, + { + "state": "ME", + "sample_households": 785, + "baseline": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683663.687080294 + }, + "candidate": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683670.942570195 + } + }, + { + "state": "MD", + "sample_households": 1091, + "baseline": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + } + }, + { + "state": "MA", + "sample_households": 1522, + "baseline": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 0.07485817919950932, + "annual_modeled_benefits": 214.60111108028417 + } + }, + { + "state": "MI", + "sample_households": 1478, + "baseline": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + }, + "candidate": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + } + }, + { + "state": "MN", + "sample_households": 1166, + "baseline": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 21289.401307827327, + "annual_modeled_benefits": 274850426.2413397 + } + }, + { + "state": "MS", + "sample_households": 882, + "baseline": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 7256.952556610806, + "annual_modeled_benefits": 30449890.664512668 + } + }, + { + "state": "MO", + "sample_households": 1013, + "baseline": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 9981.891486888984, + "annual_modeled_benefits": 44110018.22040879 + } + }, + { + "state": "MT", + "sample_households": 744, + "baseline": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + }, + "candidate": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + } + }, + { + "state": "NE", + "sample_households": 884, + "baseline": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 754.4826039844379 + }, + "candidate": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 752.3048707440652 + } + }, + { + "state": "NV", + "sample_households": 952, + "baseline": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + } + }, + { + "state": "NH", + "sample_households": 840, + "baseline": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + }, + "candidate": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + } + }, + { + "state": "NJ", + "sample_households": 1651, + "baseline": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 54783391.64412939 + }, + "candidate": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 39399036.82068616 + } + }, + { + "state": "NM", + "sample_households": 902, + "baseline": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 40276267.46262546 + }, + "candidate": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 59647115.49393122 + } + }, + { + "state": "NY", + "sample_households": 2166, + "baseline": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 84809.87077922659, + "annual_modeled_benefits": 386147637.05533403 + } + }, + { + "state": "NC", + "sample_households": 1337, + "baseline": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + }, + "candidate": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + } + }, + { + "state": "ND", + "sample_households": 682, + "baseline": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 409.12895149587507 + }, + "candidate": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 476.4295530626239 + } + }, + { + "state": "OH", + "sample_households": 1531, + "baseline": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 57197.27386227145, + "annual_modeled_benefits": 104095590.72541192 + } + }, + { + "state": "OK", + "sample_households": 918, + "baseline": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0031096774619072676, + "annual_modeled_benefits": 5.149625876918435 + } + }, + { + "state": "OR", + "sample_households": 1152, + "baseline": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + }, + "candidate": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + } + }, + { + "state": "PA", + "sample_households": 1999, + "baseline": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.2005278345895931, + "annual_modeled_benefits": 561.099948525683 + } + }, + { + "state": "RI", + "sample_households": 804, + "baseline": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429808.7526231185 + }, + "candidate": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429813.4984327066 + } + }, + { + "state": "SC", + "sample_households": 955, + "baseline": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 27915.89938246878, + "annual_modeled_benefits": 77088809.79821464 + } + }, + { + "state": "SD", + "sample_households": 866, + "baseline": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 2978.0845139123267, + "annual_modeled_benefits": 5809179.365034073 + } + }, + { + "state": "TN", + "sample_households": 1082, + "baseline": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 54836.32565583871, + "annual_modeled_benefits": 120178659.05015105 + } + }, + { + "state": "TX", + "sample_households": 1875, + "baseline": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 93309.70299506374, + "annual_modeled_benefits": 199602579.27443355 + } + }, + { + "state": "UT", + "sample_households": 861, + "baseline": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66497469.149597794 + }, + "candidate": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66497469.149597794 + } + }, + { + "state": "VT", + "sample_households": 496, + "baseline": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 78, + "weighted_positive_units": 32213.61921006818, + "annual_modeled_benefits": 526819840.50677323 + }, + "candidate": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 81, + "weighted_positive_units": 33402.23592408285, + "annual_modeled_benefits": 686206383.39497 + } + }, + { + "state": "VA", + "sample_households": 1394, + "baseline": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 45187.34717369359, + "annual_modeled_benefits": 254330200.2860741 + } + }, + { + "state": "WA", + "sample_households": 1305, + "baseline": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + }, + "candidate": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + } + }, + { + "state": "WV", + "sample_households": 845, + "baseline": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 5322.572984872386, + "annual_modeled_benefits": 13548522.496824618 + } + }, + { + "state": "WI", + "sample_households": 1232, + "baseline": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 33918.60478726821, + "annual_modeled_benefits": 249284653.88471013 + } + }, + { + "state": "WY", + "sample_households": 557, + "baseline": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 2962.834392214354, + "annual_modeled_benefits": 18103301.12153925 + } + } + ], + "production_ready": false, + "interpretation": "attendance-only counterfactual; provider, activity, expenses and take-up inputs remain as in parent", + "matching_levels": { + "age,region,parent_work_status,income_band": 31152, + "age,parent_work_status,income_band": 576, + "age,parent_work_status": 161 + }, + "population_attendance_by_group": [ + { + "grouping": "age", + "group": "0.0", + "children": 1689, + "weighted_children": 2750700.861434371, + "attendance_share": 0.3908649027002664, + "days_per_week": 1.4733482895551573, + "hours_per_week": 12.433364620574558 + }, + { + "grouping": "age", + "group": "1.0", + "children": 2157, + "weighted_children": 3858818.186826853, + "attendance_share": 0.5857212350699339, + "days_per_week": 2.4682816215895658, + "hours_per_week": 20.936959602461613 + }, + { + "grouping": "age", + "group": "2.0", + "children": 2364, + "weighted_children": 3754041.8444214575, + "attendance_share": 0.63217333018214, + "days_per_week": 2.625776145467515, + "hours_per_week": 21.417061319044002 + }, + { + "grouping": "age", + "group": "3.0", + "children": 2385, + "weighted_children": 3880377.4871301977, + "attendance_share": 0.6496350615721032, + "days_per_week": 2.8214495362637413, + "hours_per_week": 22.433119986053377 + }, + { + "grouping": "age", + "group": "4.0", + "children": 2482, + "weighted_children": 4358831.600945832, + "attendance_share": 0.7378382488231238, + "days_per_week": 3.4554539884839417, + "hours_per_week": 26.564435597480422 + }, + { + "grouping": "age", + "group": "5.0", + "children": 2391, + "weighted_children": 4095170.7360430276, + "attendance_share": 0.5629639983082603, + "days_per_week": 2.558431264266053, + "hours_per_week": 18.571862465758638 + }, + { + "grouping": "age", + "group": "6.0", + "children": 2562, + "weighted_children": 4029009.778184548, + "attendance_share": 0.44994930361979923, + "days_per_week": 1.6816438584425009, + "hours_per_week": 10.601418302478313 + }, + { + "grouping": "age", + "group": "7.0", + "children": 2612, + "weighted_children": 3768786.8623211696, + "attendance_share": 0.34301503193166, + "days_per_week": 1.4050708577667275, + "hours_per_week": 9.321322146324611 + }, + { + "grouping": "age", + "group": "8.0", + "children": 2689, + "weighted_children": 4419397.563846819, + "attendance_share": 0.4289583167472629, + "days_per_week": 1.572046628602081, + "hours_per_week": 9.528014323588392 + }, + { + "grouping": "age", + "group": "9.0", + "children": 2552, + "weighted_children": 3888389.065045069, + "attendance_share": 0.38602014666142587, + "days_per_week": 1.2822278907340288, + "hours_per_week": 8.230580792584078 + }, + { + "grouping": "age", + "group": "10.0", + "children": 2662, + "weighted_children": 4369978.335878741, + "attendance_share": 0.4062473204874741, + "days_per_week": 1.5012465135600794, + "hours_per_week": 7.890631718854404 + }, + { + "grouping": "age", + "group": "11.0", + "children": 2795, + "weighted_children": 4689133.259098214, + "attendance_share": 0.40248285339977075, + "days_per_week": 1.4232741547650194, + "hours_per_week": 8.373396107105151 + }, + { + "grouping": "age", + "group": "12.0", + "children": 2549, + "weighted_children": 4093051.641607744, + "attendance_share": 0.31040280481013055, + "days_per_week": 1.1000106686299516, + "hours_per_week": 7.921206635626762 + }, + { + "grouping": "region", + "group": "1", + "children": 5553, + "weighted_children": 7976838.3562431075, + "attendance_share": 0.5122082980828326, + "days_per_week": 2.137540339663031, + "hours_per_week": 14.921393569988492 + }, + { + "grouping": "region", + "group": "2", + "children": 7790, + "weighted_children": 10772583.599183697, + "attendance_share": 0.5121729637562082, + "days_per_week": 1.9819630179827, + "hours_per_week": 14.461387736332831 + }, + { + "grouping": "region", + "group": "3", + "children": 10750, + "weighted_children": 21007309.669184513, + "attendance_share": 0.44090280170545504, + "days_per_week": 1.803568625325827, + "hours_per_week": 13.322474186390497 + }, + { + "grouping": "region", + "group": "4", + "children": 7796, + "weighted_children": 12198955.598172724, + "attendance_share": 0.5181534861817509, + "days_per_week": 2.079925340499398, + "hours_per_week": 14.569132992972806 + }, + { + "grouping": "parent_work_status", + "group": "-1", + "children": 684, + "weighted_children": 1044954.9507498589, + "attendance_share": 0.5521504831293419, + "days_per_week": 2.3270185315729743, + "hours_per_week": 25.40529368071806 + }, + { + "grouping": "parent_work_status", + "group": "0", + "children": 2876, + "weighted_children": 5039737.2909418885, + "attendance_share": 0.3074240397539245, + "days_per_week": 1.2719798150247412, + "hours_per_week": 11.03519233829625 + }, + { + "grouping": "parent_work_status", + "group": "1", + "children": 9966, + "weighted_children": 15397404.080512933, + "attendance_share": 0.30361930919230407, + "days_per_week": 0.9707253415100399, + "hours_per_week": 6.653502499604582 + }, + { + "grouping": "parent_work_status", + "group": "2", + "children": 18363, + "weighted_children": 30473590.900579363, + "attendance_share": 0.6033120290865125, + "days_per_week": 2.5554583917183713, + "hours_per_week": 17.97625615205827 + }, + { + "grouping": "income_band", + "group": "0", + "children": 94, + "weighted_children": 81378.29635578688, + "attendance_share": 0.3855688612887243, + "days_per_week": 1.1732033382726887, + "hours_per_week": 6.896472838209584 + }, + { + "grouping": "income_band", + "group": "1", + "children": 3165, + "weighted_children": 6927519.022630059, + "attendance_share": 0.4099489581643712, + "days_per_week": 1.7141304062628688, + "hours_per_week": 12.474528478758927 + }, + { + "grouping": "income_band", + "group": "2", + "children": 6097, + "weighted_children": 10396829.673697237, + "attendance_share": 0.4650799637140388, + "days_per_week": 1.9345932911088046, + "hours_per_week": 14.621868846831072 + }, + { + "grouping": "income_band", + "group": "3", + "children": 9010, + "weighted_children": 14071962.152827512, + "attendance_share": 0.4488404939306434, + "days_per_week": 1.7742390271484756, + "hours_per_week": 13.367286745016436 + }, + { + "grouping": "income_band", + "group": "4", + "children": 7428, + "weighted_children": 13192218.644710096, + "attendance_share": 0.5109061436767217, + "days_per_week": 1.9814314491639318, + "hours_per_week": 14.248294331748822 + }, + { + "grouping": "income_band", + "group": "5", + "children": 6095, + "weighted_children": 7285779.432563353, + "attendance_share": 0.6071590090255058, + "days_per_week": 2.5354095841254956, + "hours_per_week": 16.105235893357964 + } + ], + "summary": { + "states_evaluated": 51, + "all_zero_states": { + "baseline": [ + "AL", + "AZ", + "AR", + "CA", + "DC", + "FL", + "HI", + "ID", + "IL", + "IA", + "KS", + "KY", + "LA", + "MD", + "MA", + "MN", + "MS", + "MO", + "NV", + "NY", + "OH", + "OK", + "PA", + "SC", + "SD", + "TN", + "TX", + "VA", + "WV", + "WI", + "WY" + ], + "candidate": [ + "MD", + "NV" + ] + }, + "annual_potential_modeled_benefits": { + "baseline": 2253603947.6976757, + "candidate": 6205696565.309278 + } + } +} diff --git a/experiments/us-childcare-attendance/review-fixes-sensitivity.json b/experiments/us-childcare-attendance/review-fixes-sensitivity.json new file mode 100644 index 000000000..a3a268ddd --- /dev/null +++ b/experiments/us-childcare-attendance/review-fixes-sensitivity.json @@ -0,0 +1,3245 @@ +{ + "parent_sha256": "48b9d479fb4fd1c3537f9383ce4697d130b6f618658409d74f6233c43b994c7e", + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "calendar_bounds": { + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568", + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "missing_calendar": "uninformative 0--168 hours and 0--7 days" + }, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "recipe": { + "contract_sha256": "ae648c6cb0e2838fdf142975e9c536eb0683d9630fd1738096d524222ffb01dc", + "runtime_versions": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "policyengine-us": "2.2.1" + }, + "code_sha256": { + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "nsece_childcare.py": "e11eef389f47433a2d407aaf7c01214dbefccb702b3fefe8fa6502c7e947ab4d", + "nsece_childcare_bridge.py": "517b3c3ae02e2316b028fd15bc60a090e7962d716d46b80e3e73067f08d5ff29", + "nsece_childcare_dependence.py": "1c5123a77f84460ba517d2b4c6c3e04ae658bf36e9cf54ed69ddbcacc85efc09", + "childcare_attendance_stage.py": "c5243b7f23865c352acee8f5946bb8c7b578645c7b5e56c24632fa94dd9dbecb", + "childcare_attendance_receipt.py": "d93ecfe1725bef2c0b87a137eaab88856fa9a76e601227089ceb94daa4335865" + } + }, + "seed": 915, + "candidate_checkpoint_sha256": "5cb9aa418768b5a82ee351e8b737f58c8989212f1ffbee36d605c22887e989a5", + "assignment_checks": { + "candidate": { + "donor_assigned_people": 31889, + "bridge_assigned_people": 9642, + "changed_people": 0, + "measured_calendar_assignments_changed": 0, + "donor_assignment": "held fixed and validated against candidate values" + }, + "no_modeled_irregular_hours": { + "donor_assigned_people": 31889, + "bridge_assigned_people": 9642, + "changed_people": 1429, + "measured_calendar_assignments_changed": 0, + "donor_assignment": "held fixed and validated against candidate values" + }, + "one_fewer_day": { + "donor_assigned_people": 31889, + "bridge_assigned_people": 9642, + "changed_people": 3815, + "measured_calendar_assignments_changed": 0, + "donor_assignment": "held fixed and validated against candidate values" + }, + "one_more_day": { + "donor_assigned_people": 31889, + "bridge_assigned_people": 9642, + "changed_people": 4404, + "measured_calendar_assignments_changed": 0, + "donor_assignment": "held fixed and validated against candidate values" + } + }, + "coupling": "same donor identities across scenarios; no care-rank reassignment", + "engine_version": "2.2.1", + "policy_year": 2026, + "code_sha256": { + "validate_us_childcare_sensitivity.py": "ce58f0179a9b2732d2adf2335ec4444dd8a1f861b248923e9bed561c7282f983", + "childcare_sensitivity.py": "17a684c51ed48f164006d485aa2177d8c1f03609290e96eae377c625bb6d93cf" + }, + "population": "fixed BuildP source ages/incomes; no aging or uprating", + "assumptions": { + "candidate": {}, + "no_modeled_irregular_hours": { + "include_modeled_irregular_hours": false, + "modeled_day_shift": 0, + "measured_regular_hours_preserved": true + }, + "one_fewer_day": { + "include_modeled_irregular_hours": true, + "modeled_day_shift": -1, + "measured_regular_hours_preserved": true + }, + "one_more_day": { + "include_modeled_irregular_hours": true, + "modeled_day_shift": 1, + "measured_regular_hours_preserved": true + } + }, + "changed_children": { + "candidate": 0, + "no_modeled_irregular_hours": 1429, + "one_fewer_day": 3815, + "one_more_day": 4404 + }, + "screens": { + "national_relative_change": 0.1, + "state_relative_change": 0.2 + }, + "states": [ + { + "state": "AL", + "sample_households": 1061, + "baseline": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13061.764184842585, + "annual_modeled_benefits": 32688921.398814265 + }, + "no_modeled_irregular_hours": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13061.764184842585, + "annual_modeled_benefits": 32688921.398814265 + }, + "one_fewer_day": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13061.764184842585, + "annual_modeled_benefits": 32688921.398814265 + }, + "one_more_day": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13061.764184842585, + "annual_modeled_benefits": 32688921.398814265 + } + }, + { + "state": "AK", + "sample_households": 826, + "baseline": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + }, + "candidate": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + }, + "no_modeled_irregular_hours": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + }, + "one_fewer_day": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + }, + "one_more_day": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + } + }, + { + "state": "AZ", + "sample_households": 1164, + "baseline": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 18733.37486637244, + "annual_modeled_benefits": 21138074.239445645 + }, + "no_modeled_irregular_hours": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18733.29978438327, + "annual_modeled_benefits": 23160681.10555565 + }, + "one_fewer_day": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 18733.37486637244, + "annual_modeled_benefits": 21137750.54961618 + }, + "one_more_day": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 18733.37486637244, + "annual_modeled_benefits": 20238702.645136394 + } + }, + { + "state": "AR", + "sample_households": 952, + "baseline": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 17289.894029146235, + "annual_modeled_benefits": 50793417.58586023 + }, + "no_modeled_irregular_hours": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 17289.894029146235, + "annual_modeled_benefits": 50793417.58586023 + }, + "one_fewer_day": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 17289.894029146235, + "annual_modeled_benefits": 50793417.58586023 + }, + "one_more_day": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 17289.894029146235, + "annual_modeled_benefits": 50793417.58586023 + } + }, + { + "state": "CA", + "sample_households": 2659, + "baseline": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 31, + "weighted_positive_units": 201632.45677746536, + "annual_modeled_benefits": 935799297.9584653 + }, + "no_modeled_irregular_hours": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 29, + "weighted_positive_units": 191015.65929813386, + "annual_modeled_benefits": 812786996.789741 + }, + "one_fewer_day": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 31, + "weighted_positive_units": 201632.45677746536, + "annual_modeled_benefits": 935799297.9584653 + }, + "one_more_day": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 31, + "weighted_positive_units": 201632.45677746536, + "annual_modeled_benefits": 935799297.9584653 + } + }, + { + "state": "CO", + "sample_households": 1164, + "baseline": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 19, + "weighted_positive_units": 30914.695305580855, + "annual_modeled_benefits": 252602567.65021172 + }, + "candidate": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18502.53110225743, + "annual_modeled_benefits": 236445530.32343873 + }, + "no_modeled_irregular_hours": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18502.53110225743, + "annual_modeled_benefits": 236445530.32343873 + }, + "one_fewer_day": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18502.53110225743, + "annual_modeled_benefits": 236445530.32343873 + }, + "one_more_day": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18502.53110225743, + "annual_modeled_benefits": 236445530.32343873 + } + }, + { + "state": "CT", + "sample_households": 908, + "baseline": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 405879416.70427954 + }, + "candidate": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 653474165.4604676 + }, + "no_modeled_irregular_hours": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 653474133.8050566 + }, + "one_fewer_day": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 653474165.4604676 + }, + "one_more_day": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 653474165.4604676 + } + }, + { + "state": "DE", + "sample_households": 1068, + "baseline": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + }, + "candidate": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + }, + "no_modeled_irregular_hours": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + }, + "one_fewer_day": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + }, + "one_more_day": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + } + }, + { + "state": "DC", + "sample_households": 551, + "baseline": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 3288.0395223266023, + "annual_modeled_benefits": 23916792.31200898 + }, + "no_modeled_irregular_hours": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 3288.0395223266023, + "annual_modeled_benefits": 23916792.31200898 + }, + "one_fewer_day": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 3288.0395223266023, + "annual_modeled_benefits": 23916792.300562065 + }, + "one_more_day": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 3288.0395223266023, + "annual_modeled_benefits": 23916792.180974036 + } + }, + { + "state": "FL", + "sample_households": 1642, + "baseline": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 60231.19228101184, + "annual_modeled_benefits": 320519265.7821029 + }, + "no_modeled_irregular_hours": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 49750.16103101184, + "annual_modeled_benefits": 304168857.0321029 + }, + "one_fewer_day": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 60231.19228101184, + "annual_modeled_benefits": 318098303.34044707 + }, + "one_more_day": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 60231.19228101184, + "annual_modeled_benefits": 337107334.9374325 + } + }, + { + "state": "GA", + "sample_households": 1215, + "baseline": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + }, + "candidate": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + }, + "no_modeled_irregular_hours": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + }, + "one_fewer_day": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + }, + "one_more_day": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + } + }, + { + "state": "HI", + "sample_households": 838, + "baseline": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0001588361046742648, + "annual_modeled_benefits": 0.6336225438054939 + }, + "no_modeled_irregular_hours": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0001588361046742648, + "annual_modeled_benefits": 0.6336225438054939 + }, + "one_fewer_day": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0001588361046742648, + "annual_modeled_benefits": 0.6336225438054939 + }, + "one_more_day": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0001588361046742648, + "annual_modeled_benefits": 0.6336225438054939 + } + }, + { + "state": "ID", + "sample_households": 746, + "baseline": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 2, + "weighted_positive_units": 2335.738774359226, + "annual_modeled_benefits": 10651259.924815893 + }, + "no_modeled_irregular_hours": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 2, + "weighted_positive_units": 2335.738774359226, + "annual_modeled_benefits": 10651259.924815893 + }, + "one_fewer_day": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 2, + "weighted_positive_units": 2335.738774359226, + "annual_modeled_benefits": 10651259.924815893 + }, + "one_more_day": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 2, + "weighted_positive_units": 2335.738774359226, + "annual_modeled_benefits": 10651259.924815893 + } + }, + { + "state": "IL", + "sample_households": 1668, + "baseline": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 62767.78443156066, + "annual_modeled_benefits": 196786246.13666055 + }, + "no_modeled_irregular_hours": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 62767.78443156066, + "annual_modeled_benefits": 194890109.83533916 + }, + "one_fewer_day": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 62767.78443156066, + "annual_modeled_benefits": 196786118.53858995 + }, + "one_more_day": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 62767.78443156066, + "annual_modeled_benefits": 196786246.13666055 + } + }, + { + "state": "IN", + "sample_households": 1141, + "baseline": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + }, + "candidate": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + }, + "no_modeled_irregular_hours": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + }, + "one_fewer_day": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + }, + "one_more_day": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + } + }, + { + "state": "IA", + "sample_households": 973, + "baseline": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 13277.072875641927, + "annual_modeled_benefits": 55836595.948581845 + }, + "no_modeled_irregular_hours": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 13277.072875641927, + "annual_modeled_benefits": 55836595.948581845 + }, + "one_fewer_day": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 13277.072875641927, + "annual_modeled_benefits": 55836595.948581845 + }, + "one_more_day": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 13277.072875641927, + "annual_modeled_benefits": 55836595.948581845 + } + }, + { + "state": "KS", + "sample_households": 921, + "baseline": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 21785.09440057905, + "annual_modeled_benefits": 58709143.174893744 + }, + "no_modeled_irregular_hours": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 21785.09440057905, + "annual_modeled_benefits": 58709143.174893744 + }, + "one_fewer_day": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 21785.09440057905, + "annual_modeled_benefits": 58709143.174893744 + }, + "one_more_day": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 21785.09440057905, + "annual_modeled_benefits": 58709143.174893744 + } + }, + { + "state": "KY", + "sample_households": 776, + "baseline": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.02885724022053182, + "annual_modeled_benefits": 168.32094133054224 + }, + "no_modeled_irregular_hours": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.02885724022053182, + "annual_modeled_benefits": 168.32094133054224 + }, + "one_fewer_day": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.02885724022053182, + "annual_modeled_benefits": 173.82699462903886 + }, + "one_more_day": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.02885724022053182, + "annual_modeled_benefits": 163.91609819387403 + } + }, + { + "state": "LA", + "sample_households": 1000, + "baseline": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 37176.93537535961, + "annual_modeled_benefits": 72842360.51107226 + }, + "no_modeled_irregular_hours": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 37176.93537535961, + "annual_modeled_benefits": 69024044.59310351 + }, + "one_fewer_day": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 37176.93537535961, + "annual_modeled_benefits": 72842360.51107226 + }, + "one_more_day": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 37176.93537535961, + "annual_modeled_benefits": 72842360.51107226 + } + }, + { + "state": "ME", + "sample_households": 785, + "baseline": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683663.687080294 + }, + "candidate": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683670.942570195 + }, + "no_modeled_irregular_hours": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683670.942570195 + }, + "one_fewer_day": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683670.942570195 + }, + "one_more_day": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683670.942570195 + } + }, + { + "state": "MD", + "sample_households": 1091, + "baseline": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "no_modeled_irregular_hours": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "one_fewer_day": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "one_more_day": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + } + }, + { + "state": "MA", + "sample_households": 1522, + "baseline": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 0.07485817919950932, + "annual_modeled_benefits": 214.60111108028417 + }, + "no_modeled_irregular_hours": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 0.07485817919950932, + "annual_modeled_benefits": 214.60111108028417 + }, + "one_fewer_day": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 0.07485817919950932, + "annual_modeled_benefits": 214.60111108028417 + }, + "one_more_day": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 0.07485817919950932, + "annual_modeled_benefits": 214.60111108028417 + } + }, + { + "state": "MI", + "sample_households": 1478, + "baseline": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + }, + "candidate": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + }, + "no_modeled_irregular_hours": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + }, + "one_fewer_day": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + }, + "one_more_day": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + } + }, + { + "state": "MN", + "sample_households": 1166, + "baseline": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 21289.401307827327, + "annual_modeled_benefits": 274850426.2413397 + }, + "no_modeled_irregular_hours": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 21289.401307827327, + "annual_modeled_benefits": 274850426.2413397 + }, + "one_fewer_day": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 21289.401307827327, + "annual_modeled_benefits": 274850426.2413397 + }, + "one_more_day": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 21289.401307827327, + "annual_modeled_benefits": 274850426.2413397 + } + }, + { + "state": "MS", + "sample_households": 882, + "baseline": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 7256.952556610806, + "annual_modeled_benefits": 30449890.664512668 + }, + "no_modeled_irregular_hours": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 7256.951193145127, + "annual_modeled_benefits": 30449886.57411563 + }, + "one_fewer_day": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 7256.952556610806, + "annual_modeled_benefits": 30449890.664512668 + }, + "one_more_day": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 7256.952556610806, + "annual_modeled_benefits": 30449890.664512668 + } + }, + { + "state": "MO", + "sample_households": 1013, + "baseline": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 9981.891486888984, + "annual_modeled_benefits": 44110018.22040879 + }, + "no_modeled_irregular_hours": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 9981.891486888984, + "annual_modeled_benefits": 44110018.22040879 + }, + "one_fewer_day": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 9981.891486888984, + "annual_modeled_benefits": 44110019.68683209 + }, + "one_more_day": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 9981.891486888984, + "annual_modeled_benefits": 44110017.04727027 + } + }, + { + "state": "MT", + "sample_households": 744, + "baseline": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + }, + "candidate": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + }, + "no_modeled_irregular_hours": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + }, + "one_fewer_day": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + }, + "one_more_day": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + } + }, + { + "state": "NE", + "sample_households": 884, + "baseline": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 754.4826039844379 + }, + "candidate": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 752.3048707440652 + }, + "no_modeled_irregular_hours": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 752.3048707440652 + }, + "one_fewer_day": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 752.3048707440652 + }, + "one_more_day": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 752.3048707440652 + } + }, + { + "state": "NV", + "sample_households": 952, + "baseline": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "no_modeled_irregular_hours": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "one_fewer_day": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "one_more_day": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + } + }, + { + "state": "NH", + "sample_households": 840, + "baseline": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + }, + "candidate": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + }, + "no_modeled_irregular_hours": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + }, + "one_fewer_day": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + }, + "one_more_day": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + } + }, + { + "state": "NJ", + "sample_households": 1651, + "baseline": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 54783391.64412939 + }, + "candidate": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 39399036.82068616 + }, + "no_modeled_irregular_hours": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 39399036.82068616 + }, + "one_fewer_day": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 39399036.82068616 + }, + "one_more_day": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 39399036.82068616 + } + }, + { + "state": "NM", + "sample_households": 902, + "baseline": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 40276267.46262546 + }, + "candidate": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 59647115.49393122 + }, + "no_modeled_irregular_hours": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 59647115.49393122 + }, + "one_fewer_day": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 59647115.49393122 + }, + "one_more_day": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 59647115.49393122 + } + }, + { + "state": "NY", + "sample_households": 2166, + "baseline": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 84809.87077922659, + "annual_modeled_benefits": 386147637.05533403 + }, + "no_modeled_irregular_hours": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 84809.87077922659, + "annual_modeled_benefits": 386147637.05533403 + }, + "one_fewer_day": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 84809.87077922659, + "annual_modeled_benefits": 386146572.1787399 + }, + "one_more_day": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 84809.87077922659, + "annual_modeled_benefits": 386148701.9332047 + } + }, + { + "state": "NC", + "sample_households": 1337, + "baseline": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + }, + "candidate": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + }, + "no_modeled_irregular_hours": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + }, + "one_fewer_day": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + }, + "one_more_day": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + } + }, + { + "state": "ND", + "sample_households": 682, + "baseline": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 409.12895149587507 + }, + "candidate": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 476.4295530626239 + }, + "no_modeled_irregular_hours": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 471.04686684011335 + }, + "one_fewer_day": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 476.4295530626239 + }, + "one_more_day": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 476.4295530626239 + } + }, + { + "state": "OH", + "sample_households": 1531, + "baseline": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 57197.27386227145, + "annual_modeled_benefits": 104095590.72541192 + }, + "no_modeled_irregular_hours": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 57197.27386227145, + "annual_modeled_benefits": 104095590.72541192 + }, + "one_fewer_day": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 57197.27386227145, + "annual_modeled_benefits": 104095590.72541192 + }, + "one_more_day": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 57197.27386227145, + "annual_modeled_benefits": 104095590.72541192 + } + }, + { + "state": "OK", + "sample_households": 918, + "baseline": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0031096774619072676, + "annual_modeled_benefits": 5.149625876918435 + }, + "no_modeled_irregular_hours": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0031096774619072676, + "annual_modeled_benefits": 5.149625876918435 + }, + "one_fewer_day": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0031096774619072676, + "annual_modeled_benefits": 3.0897752604315514 + }, + "one_more_day": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0031096774619072676, + "annual_modeled_benefits": 5.149625876918435 + } + }, + { + "state": "OR", + "sample_households": 1152, + "baseline": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + }, + "candidate": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + }, + "no_modeled_irregular_hours": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + }, + "one_fewer_day": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + }, + "one_more_day": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + } + }, + { + "state": "PA", + "sample_households": 1999, + "baseline": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.2005278345895931, + "annual_modeled_benefits": 561.099948525683 + }, + "no_modeled_irregular_hours": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.197240982321091, + "annual_modeled_benefits": 532.083619909163 + }, + "one_fewer_day": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.2005278345895931, + "annual_modeled_benefits": 560.5847087540619 + }, + "one_more_day": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.2005278345895931, + "annual_modeled_benefits": 561.099948525683 + } + }, + { + "state": "RI", + "sample_households": 804, + "baseline": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429808.7526231185 + }, + "candidate": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429813.4984327066 + }, + "no_modeled_irregular_hours": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429813.4984327066 + }, + "one_fewer_day": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429813.4984327066 + }, + "one_more_day": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429813.4984327066 + } + }, + { + "state": "SC", + "sample_households": 955, + "baseline": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 27915.89938246878, + "annual_modeled_benefits": 77088809.79821464 + }, + "no_modeled_irregular_hours": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 27915.89938246878, + "annual_modeled_benefits": 77088809.79821464 + }, + "one_fewer_day": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 27915.89938246878, + "annual_modeled_benefits": 77088809.79821464 + }, + "one_more_day": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 27915.89938246878, + "annual_modeled_benefits": 77088809.79821464 + } + }, + { + "state": "SD", + "sample_households": 866, + "baseline": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 2978.0845139123267, + "annual_modeled_benefits": 5809179.365034073 + }, + "no_modeled_irregular_hours": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 1592.1698410607642, + "annual_modeled_benefits": 2921857.242712675 + }, + "one_fewer_day": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 2978.0845139123267, + "annual_modeled_benefits": 5809179.365034073 + }, + "one_more_day": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 2978.0845139123267, + "annual_modeled_benefits": 5809179.365034073 + } + }, + { + "state": "TN", + "sample_households": 1082, + "baseline": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 54836.32565583871, + "annual_modeled_benefits": 120178659.05015105 + }, + "no_modeled_irregular_hours": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 37178.86130036996, + "annual_modeled_benefits": 76918622.95069009 + }, + "one_fewer_day": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 54836.32565583871, + "annual_modeled_benefits": 120178659.05015105 + }, + "one_more_day": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 54836.32565583871, + "annual_modeled_benefits": 120178659.05015105 + } + }, + { + "state": "TX", + "sample_households": 1875, + "baseline": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 93309.70299506374, + "annual_modeled_benefits": 199602579.27443355 + }, + "no_modeled_irregular_hours": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 72034.10924506374, + "annual_modeled_benefits": 172158000.8966679 + }, + "one_fewer_day": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 93309.70299506374, + "annual_modeled_benefits": 199602579.27443355 + }, + "one_more_day": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 93309.70299506374, + "annual_modeled_benefits": 208180895.03846782 + } + }, + { + "state": "UT", + "sample_households": 861, + "baseline": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66497469.149597794 + }, + "candidate": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66497469.149597794 + }, + "no_modeled_irregular_hours": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66497469.149597794 + }, + "one_fewer_day": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66497469.149597794 + }, + "one_more_day": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66497469.149597794 + } + }, + { + "state": "VT", + "sample_households": 496, + "baseline": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 78, + "weighted_positive_units": 32213.61921006818, + "annual_modeled_benefits": 526819840.50677323 + }, + "candidate": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 81, + "weighted_positive_units": 33402.23592408285, + "annual_modeled_benefits": 686206383.39497 + }, + "no_modeled_irregular_hours": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 81, + "weighted_positive_units": 33402.23592408285, + "annual_modeled_benefits": 686206383.39497 + }, + "one_fewer_day": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 81, + "weighted_positive_units": 33402.23592408285, + "annual_modeled_benefits": 686206383.39497 + }, + "one_more_day": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 81, + "weighted_positive_units": 33402.23592408285, + "annual_modeled_benefits": 686206383.39497 + } + }, + { + "state": "VA", + "sample_households": 1394, + "baseline": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 45187.34717369359, + "annual_modeled_benefits": 254330200.2860741 + }, + "no_modeled_irregular_hours": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 45187.34378196369, + "annual_modeled_benefits": 254330196.00231922 + }, + "one_fewer_day": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 45187.34717369359, + "annual_modeled_benefits": 254330157.19498563 + }, + "one_more_day": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 45187.34717369359, + "annual_modeled_benefits": 254330254.14993468 + } + }, + { + "state": "WA", + "sample_households": 1305, + "baseline": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + }, + "candidate": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + }, + "no_modeled_irregular_hours": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + }, + "one_fewer_day": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + }, + "one_more_day": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + } + }, + { + "state": "WV", + "sample_households": 845, + "baseline": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 5322.572984872386, + "annual_modeled_benefits": 13548522.496824618 + }, + "no_modeled_irregular_hours": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 4, + "weighted_positive_units": 2978.909898934886, + "annual_modeled_benefits": 9329928.942137118 + }, + "one_fewer_day": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 5322.572984872386, + "annual_modeled_benefits": 13548523.617533846 + }, + "one_more_day": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 5322.572984872386, + "annual_modeled_benefits": 18821763.44399871 + } + }, + { + "state": "WI", + "sample_households": 1232, + "baseline": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 33918.60478726821, + "annual_modeled_benefits": 249284653.88471013 + }, + "no_modeled_irregular_hours": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 33918.60478726821, + "annual_modeled_benefits": 249284653.88471013 + }, + "one_fewer_day": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 33918.60478726821, + "annual_modeled_benefits": 249284653.88471013 + }, + "one_more_day": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 33918.60478726821, + "annual_modeled_benefits": 249284653.88471013 + } + }, + { + "state": "WY", + "sample_households": 557, + "baseline": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 2962.834392214354, + "annual_modeled_benefits": 18103301.12153925 + }, + "no_modeled_irregular_hours": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 2962.8060375964124, + "annual_modeled_benefits": 18103216.918334827 + }, + "one_fewer_day": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 2962.834392214354, + "annual_modeled_benefits": 18103301.12153925 + }, + "one_more_day": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 2962.834392214354, + "annual_modeled_benefits": 18103302.078379974 + } + } + ], + "production_ready": false, + "interpretation": "assumption stress tests, not confidence intervals; potential modeled benefits, not calibrated spending", + "summary": { + "states_evaluated": 51, + "annual_potential_modeled_benefits": { + "baseline": 2253603947.6976757, + "candidate": 6205696565.309278, + "no_modeled_irregular_hours": 5984831321.251355, + "one_fewer_day": 6203274049.118688, + "one_more_day": 6235237933.571062 + }, + "sensitivity_flags": [ + { + "scenario": "no_modeled_irregular_hours", + "state": "SD", + "relative_change": -0.4970275388121817, + "absolute_change": -2887322.1223213975, + "flagged": true + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "TN", + "relative_change": -0.35996437671524, + "absolute_change": -43260036.09946096, + "flagged": true + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "WV", + "relative_change": -0.31136926965107936, + "absolute_change": -4218593.5546875, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "OK", + "relative_change": -0.40000005159976976, + "absolute_change": -2.0598506164868837, + "flagged": true + }, + { + "scenario": "one_more_day", + "state": "WV", + "relative_change": 0.3892115135366226, + "absolute_change": 5273240.947174091, + "flagged": true + } + ], + "comparisons": [ + { + "scenario": "no_modeled_irregular_hours", + "state": "US", + "relative_change": -0.035590725671730446, + "absolute_change": -220865244.05792236, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "AL", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "AK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "AZ", + "relative_change": 0.09568548407951132, + "absolute_change": 2022606.8661100045, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "AR", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "CA", + "relative_change": -0.13145158522461736, + "absolute_change": -123012301.1687243, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "CO", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "CT", + "relative_change": -4.8441717635025865e-08, + "absolute_change": -31.65541100502014, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "DE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "DC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "FL", + "relative_change": -0.051012249482424006, + "absolute_change": -16350408.75, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "GA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "HI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "ID", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "IL", + "relative_change": -0.009635512331510165, + "absolute_change": -1896136.3013213873, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "IN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "IA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "KS", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "KY", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "LA", + "relative_change": -0.0524188932261243, + "absolute_change": -3818315.91796875, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "ME", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MD", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MS", + "relative_change": -1.343320763490555e-07, + "absolute_change": -4.090397037565708, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MO", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NV", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NJ", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NM", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NY", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "ND", + "relative_change": -0.011297968792886796, + "absolute_change": -5.382686222510529, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "OH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "OK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "OR", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "PA", + "relative_change": -0.05171329759120778, + "absolute_change": -29.016328616520013, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "RI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "SC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "SD", + "relative_change": -0.4970275388121817, + "absolute_change": -2887322.1223213975, + "flagged": true + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "TN", + "relative_change": -0.35996437671524, + "absolute_change": -43260036.09946096, + "flagged": true + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "TX", + "relative_change": -0.13749611090962963, + "absolute_change": -27444578.377765656, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "UT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "VT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "VA", + "relative_change": -1.68432804298438e-08, + "absolute_change": -4.283754885196686, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "WA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "WV", + "relative_change": -0.31136926965107936, + "absolute_change": -4218593.5546875, + "flagged": true + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "WI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "WY", + "relative_change": -4.651262433181563e-06, + "absolute_change": -84.20320442318916, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "US", + "relative_change": -0.0003903697457803711, + "absolute_change": -2422516.190589905, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "AL", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "AK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "AZ", + "relative_change": -1.5313118205487516e-05, + "absolute_change": -323.6898294650018, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "AR", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "CA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "CO", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "CT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "DE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "DC", + "relative_change": -4.786141643741066e-10, + "absolute_change": -0.011446915566921234, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "FL", + "relative_change": -0.007553250927829238, + "absolute_change": -2420962.4416558146, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "GA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "HI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "ID", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "IL", + "relative_change": -6.484094955654378e-07, + "absolute_change": -127.59807059168816, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "IN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "IA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "KS", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "KY", + "relative_change": 0.03271163561094901, + "absolute_change": 5.506053298496624, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "LA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "ME", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MD", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MS", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MO", + "relative_change": 3.3244676879557186e-08, + "absolute_change": 1.4664233028888702, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NV", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NJ", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NM", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NY", + "relative_change": -2.757692892404338e-06, + "absolute_change": -1064.8765941262245, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "ND", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "OH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "OK", + "relative_change": -0.40000005159976976, + "absolute_change": -2.0598506164868837, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "OR", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "PA", + "relative_change": -0.000918267365689253, + "absolute_change": -0.5152397716210544, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "RI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "SC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "SD", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "TN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "TX", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "UT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "VT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "VA", + "relative_change": -1.6942969582584922e-07, + "absolute_change": -43.091088473796844, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "WA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "WV", + "relative_change": 8.27181877330683e-08, + "absolute_change": 1.120709227398038, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "WI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "WY", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "US", + "relative_change": 0.004760362990824428, + "absolute_change": 29541368.261784554, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "AL", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "AK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "AZ", + "relative_change": -0.04254747069772985, + "absolute_change": -899371.5943092518, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "AR", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "CA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "CO", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "CT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "DE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "DC", + "relative_change": -5.4787842155856995e-09, + "absolute_change": -0.1310349442064762, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "FL", + "relative_change": 0.05175373503634142, + "absolute_change": 16588069.155329645, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "GA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "HI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "ID", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "IL", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "IN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "IA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "KS", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "KY", + "relative_change": -0.026169311446625897, + "absolute_change": -4.404843136668205, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "LA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "ME", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MD", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MS", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MO", + "relative_change": -2.6595738767319386e-08, + "absolute_change": -1.1731385216116905, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NV", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NJ", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NM", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NY", + "relative_change": 2.7576961982711995e-06, + "absolute_change": 1064.8778706789017, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "ND", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "OH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "OK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "OR", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "PA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "RI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "SC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "SD", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "TN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "TX", + "relative_change": 0.04297697853012183, + "absolute_change": 8578315.764034271, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "UT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "VT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "VA", + "relative_change": 2.117871197237217e-07, + "absolute_change": 53.863860577344894, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "WA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "WV", + "relative_change": 0.3892115135366226, + "absolute_change": 5273240.947174091, + "flagged": true + }, + { + "scenario": "one_more_day", + "state": "WI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "WY", + "relative_change": 5.285448865536073e-08, + "absolute_change": 0.9568407237529755, + "flagged": false + } + ] + } +} diff --git a/experiments/us-childcare-attendance/review-fixes-source-stage.json b/experiments/us-childcare-attendance/review-fixes-source-stage.json new file mode 100644 index 000000000..a4e30b8f1 --- /dev/null +++ b/experiments/us-childcare-attendance/review-fixes-source-stage.json @@ -0,0 +1,2013 @@ +{ + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "calendar_bounds": { + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568", + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "missing_calendar": "uninformative 0--168 hours and 0--7 days" + }, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "source_child_count": 11745, + "source_attrition": [ + { + "status": "age_out_of_scope", + "n": 134, + "child_weight": 633390.6468148227 + }, + { + "status": "ambiguous_calendar", + "n": 882, + "child_weight": 3918044.035953992 + }, + { + "status": "complete", + "n": 7460, + "child_weight": 32249785.682044942 + }, + { + "status": "missing_calendar", + "n": 3095, + "child_weight": 14061828.648228496 + }, + { + "status": "partial_calendar", + "n": 174, + "child_weight": 847769.9869632281 + } + ], + "under13_complete_weight_share": 0.6313901604255374, + "seed": 915, + "evaluation_design": "fixed household diagnostic split; not final population certification", + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "training_children": 5988, + "heldout_children": 1472, + "unsupported_heldout_children": 30, + "unsupported_heldout_weight": 153817.788204796, + "household_overlap": 0, + "comparisons": [ + { + "grouping": "all", + "group": "all", + "n": 1442, + "observed": { + "participation": 0.47956011362829676, + "days_per_week": 1.94220990502671, + "hours_per_week": 14.670259928481958 + }, + "predicted": { + "participation": 0.4547372440086608, + "days_per_week": 1.7986704844660344, + "hours_per_week": 13.001295500494344 + } + }, + { + "grouping": "age", + "group": "0", + "n": 87, + "observed": { + "participation": 0.4749769477860246, + "days_per_week": 1.8705229048944185, + "hours_per_week": 15.234832555457738 + }, + "predicted": { + "participation": 0.21347668238234924, + "days_per_week": 0.7762397588546358, + "hours_per_week": 6.331944692101247 + } + }, + { + "grouping": "age", + "group": "1", + "n": 113, + "observed": { + "participation": 0.6026124718926947, + "days_per_week": 2.2004884644301415, + "hours_per_week": 16.058889950232714 + }, + "predicted": { + "participation": 0.5817111215090339, + "days_per_week": 2.3867359768549528, + "hours_per_week": 20.29503642359935 + } + }, + { + "grouping": "age", + "group": "2", + "n": 107, + "observed": { + "participation": 0.6827728698846081, + "days_per_week": 3.2446932739752876, + "hours_per_week": 32.643365116161064 + }, + "predicted": { + "participation": 0.721108922787169, + "days_per_week": 2.9279814704204314, + "hours_per_week": 25.4484971084278 + } + }, + { + "grouping": "age", + "group": "3", + "n": 105, + "observed": { + "participation": 0.5478113606887365, + "days_per_week": 2.4737318877881727, + "hours_per_week": 18.774571500322175 + }, + "predicted": { + "participation": 0.7525857598038783, + "days_per_week": 3.556893850206531, + "hours_per_week": 31.34897414405891 + } + }, + { + "grouping": "age", + "group": "4", + "n": 115, + "observed": { + "participation": 0.6853382748904278, + "days_per_week": 3.133535876664359, + "hours_per_week": 22.72675588135229 + }, + "predicted": { + "participation": 0.6264622224091229, + "days_per_week": 2.555534029105278, + "hours_per_week": 22.558086951188297 + } + }, + { + "grouping": "age", + "group": "5", + "n": 109, + "observed": { + "participation": 0.45965467004039157, + "days_per_week": 2.204288116474054, + "hours_per_week": 16.671100530443887 + }, + "predicted": { + "participation": 0.5197893305690322, + "days_per_week": 2.0628456061601703, + "hours_per_week": 14.660711473842793 + } + }, + { + "grouping": "age", + "group": "6", + "n": 121, + "observed": { + "participation": 0.37767600901948256, + "days_per_week": 1.4233675361325482, + "hours_per_week": 11.368361596236443 + }, + "predicted": { + "participation": 0.3812603191662228, + "days_per_week": 1.344172188177959, + "hours_per_week": 6.687190574415363 + } + }, + { + "grouping": "age", + "group": "7", + "n": 121, + "observed": { + "participation": 0.2903318905157446, + "days_per_week": 0.9137564001326794, + "hours_per_week": 4.425088819370026 + }, + "predicted": { + "participation": 0.3316072853951072, + "days_per_week": 1.3098426672238894, + "hours_per_week": 7.381236186215511 + } + }, + { + "grouping": "age", + "group": "8", + "n": 136, + "observed": { + "participation": 0.33161676756925296, + "days_per_week": 1.2251387657453359, + "hours_per_week": 6.71788070980216 + }, + "predicted": { + "participation": 0.35465278512495324, + "days_per_week": 1.3642638058954168, + "hours_per_week": 9.725344329820171 + } + }, + { + "grouping": "age", + "group": "9", + "n": 101, + "observed": { + "participation": 0.4569510479920196, + "days_per_week": 1.674346958462562, + "hours_per_week": 7.805739183708693 + }, + "predicted": { + "participation": 0.396876880067868, + "days_per_week": 1.3966673442424729, + "hours_per_week": 8.701466574792914 + } + }, + { + "grouping": "age", + "group": "10", + "n": 105, + "observed": { + "participation": 0.45503949077471245, + "days_per_week": 1.5782906105470733, + "hours_per_week": 12.426848636692846 + }, + "predicted": { + "participation": 0.17752112044794535, + "days_per_week": 0.6469841431239514, + "hours_per_week": 3.596759032644189 + } + }, + { + "grouping": "age", + "group": "11", + "n": 119, + "observed": { + "participation": 0.41662598750149954, + "days_per_week": 1.8643111020323588, + "hours_per_week": 12.941021091087745 + }, + "predicted": { + "participation": 0.4008574857176407, + "days_per_week": 1.339718142783517, + "hours_per_week": 7.024111200026524 + } + }, + { + "grouping": "age", + "group": "12", + "n": 103, + "observed": { + "participation": 0.46408861423609865, + "days_per_week": 1.4945247924023801, + "hours_per_week": 11.114322042194766 + }, + "predicted": { + "participation": 0.43591150819042584, + "days_per_week": 1.7008936429461807, + "hours_per_week": 7.10555160431239 + } + }, + { + "grouping": "region", + "group": "1", + "n": 187, + "observed": { + "participation": 0.5340539220646277, + "days_per_week": 2.4009930157522064, + "hours_per_week": 14.79000641069395 + }, + "predicted": { + "participation": 0.6359603067185889, + "days_per_week": 2.7160385976574153, + "hours_per_week": 21.24487930853725 + } + }, + { + "grouping": "region", + "group": "2", + "n": 335, + "observed": { + "participation": 0.46285701128880247, + "days_per_week": 1.8453473655274784, + "hours_per_week": 15.352184287431765 + }, + "predicted": { + "participation": 0.41283532735257467, + "days_per_week": 1.4868890394545802, + "hours_per_week": 9.329182591248077 + } + }, + { + "grouping": "region", + "group": "3", + "n": 470, + "observed": { + "participation": 0.4328632075166446, + "days_per_week": 1.8236781494293404, + "hours_per_week": 15.35364160426729 + }, + "predicted": { + "participation": 0.4184231306502971, + "days_per_week": 1.5947483523709618, + "hours_per_week": 10.342311458512322 + } + }, + { + "grouping": "region", + "group": "4", + "n": 450, + "observed": { + "participation": 0.5171827642556369, + "days_per_week": 1.8475690827448323, + "hours_per_week": 13.04393396272379 + }, + "predicted": { + "participation": 0.4063739455351018, + "days_per_week": 1.670368549893466, + "hours_per_week": 13.748230642009998 + } + }, + { + "grouping": "parent_work_status", + "group": "-1", + "n": 13, + "observed": { + "participation": 0.253295875991658, + "days_per_week": 0.8671327195533685, + "hours_per_week": 3.515415042668932 + }, + "predicted": { + "participation": 0.12949135028799522, + "days_per_week": 0.5134069370080796, + "hours_per_week": 3.2849650228565768 + } + }, + { + "grouping": "parent_work_status", + "group": "0", + "n": 150, + "observed": { + "participation": 0.2939873489805854, + "days_per_week": 1.1857568669020946, + "hours_per_week": 10.001769026104405 + }, + "predicted": { + "participation": 0.20052896295212805, + "days_per_week": 0.7861821143968067, + "hours_per_week": 6.547539835013359 + } + }, + { + "grouping": "parent_work_status", + "group": "1", + "n": 543, + "observed": { + "participation": 0.2512596429034898, + "days_per_week": 0.8664048151368835, + "hours_per_week": 5.612021341518408 + }, + "predicted": { + "participation": 0.30234830539829555, + "days_per_week": 0.9663278582430083, + "hours_per_week": 5.557806485223704 + } + }, + { + "grouping": "parent_work_status", + "group": "2", + "n": 736, + "observed": { + "participation": 0.6462583482271946, + "days_per_week": 2.714084969528804, + "hours_per_week": 21.02161873348801 + }, + "predicted": { + "participation": 0.5856324643226721, + "days_per_week": 2.4572831629804637, + "hours_per_week": 18.54158986890966 + } + } + ], + "production_ready": false, + "limitations": [ + "Only complete, unambiguous calendars enter this holdout; source selection remains unvalidated.", + "The diagnostic matches age and caller-specified covariates; it is not a nationally validated fitted model.", + "Sibling assignments, mixed providers, older-child care and scalar monthly conversion need validation.", + "No full Microcosm population build or state CCDF distribution is certified by this source-only report." + ], + "sibling_dependence": { + "rho": 0.7413149380294699, + "unconstrained_rho": 0.7413149380294699, + "households": 1941, + "observed_both_in_care": 0.32858869865910467, + "independent_both_in_care": 0.2585427028841666, + "shared_both_in_care": 0.3530315526045447, + "estimation": "youngest pair in fully observed households; household design weights" + }, + "selection_and_cross_validation": { + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "calendar_bounds": { + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568", + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "missing_calendar": "uninformative 0--168 hours and 0--7 days" + }, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "seed": 271828, + "design": "five-fold household-separated conditional-expectation diagnostic", + "coverage": [ + { + "grouping": "questionnaire_version", + "group": "1", + "n": 8516, + "weight": 37015599.704962164, + "usable_weight_share": 0.8712484989868113 + }, + { + "grouping": "questionnaire_version", + "group": "2", + "n": 1716, + "weight": 7945306.22844611, + "usable_weight_share": 0.0 + }, + { + "grouping": "questionnaire_version", + "group": "3", + "n": 1379, + "weight": 6116522.419782387, + "usable_weight_share": 0.0 + }, + { + "grouping": "age", + "group": "0", + "n": 709, + "weight": 3159547.2696341733, + "usable_weight_share": 0.6556513621184303 + }, + { + "grouping": "age", + "group": "1", + "n": 856, + "weight": 3710311.739747545, + "usable_weight_share": 0.6518631977426506 + }, + { + "grouping": "age", + "group": "2", + "n": 906, + "weight": 4112848.861546397, + "usable_weight_share": 0.6567885484115844 + }, + { + "grouping": "age", + "group": "3", + "n": 927, + "weight": 4191268.180093972, + "usable_weight_share": 0.5836151261043054 + }, + { + "grouping": "age", + "group": "4", + "n": 890, + "weight": 3761621.476875998, + "usable_weight_share": 0.6069150244376095 + }, + { + "grouping": "age", + "group": "5", + "n": 884, + "weight": 3759953.5032736305, + "usable_weight_share": 0.6441250249176611 + }, + { + "grouping": "age", + "group": "6", + "n": 954, + "weight": 4259102.717846392, + "usable_weight_share": 0.6213110691400029 + }, + { + "grouping": "age", + "group": "7", + "n": 944, + "weight": 4191490.05150999, + "usable_weight_share": 0.6014263712726516 + }, + { + "grouping": "age", + "group": "8", + "n": 925, + "weight": 3969583.419307067, + "usable_weight_share": 0.6776062606911202 + }, + { + "grouping": "age", + "group": "9", + "n": 921, + "weight": 4036325.188020362, + "usable_weight_share": 0.6661696977311178 + }, + { + "grouping": "age", + "group": "10", + "n": 884, + "weight": 3707790.894951107, + "usable_weight_share": 0.6220814618665044 + }, + { + "grouping": "age", + "group": "11", + "n": 908, + "weight": 4069233.422108399, + "usable_weight_share": 0.6084497314858798 + }, + { + "grouping": "age", + "group": "12", + "n": 903, + "weight": 4148351.6282756263, + "usable_weight_share": 0.6217216150291205 + }, + { + "grouping": "region", + "group": "1", + "n": 1468, + "weight": 8153076.12536276, + "usable_weight_share": 0.6401722331669089 + }, + { + "grouping": "region", + "group": "2", + "n": 2680, + "weight": 10714972.208999828, + "usable_weight_share": 0.6330942004076335 + }, + { + "grouping": "region", + "group": "3", + "n": 4275, + "weight": 20022339.81304313, + "usable_weight_share": 0.6249460927360144 + }, + { + "grouping": "region", + "group": "4", + "n": 3188, + "weight": 12187040.205784943, + "usable_weight_share": 0.634603874645437 + }, + { + "grouping": "parent_work_status", + "group": "-1", + "n": 188, + "weight": 819575.738509818, + "usable_weight_share": 0.646736557730207 + }, + { + "grouping": "parent_work_status", + "group": "0", + "n": 1470, + "weight": 5301911.400981113, + "usable_weight_share": 0.6698890755679009 + }, + { + "grouping": "parent_work_status", + "group": "1", + "n": 3380, + "weight": 14009836.058523985, + "usable_weight_share": 0.7212981495115555 + }, + { + "grouping": "parent_work_status", + "group": "2", + "n": 6573, + "weight": 30946105.155175745, + "usable_weight_share": 0.5836849144158337 + }, + { + "grouping": "income_band", + "group": "0", + "n": 120, + "weight": 497291.815717528, + "usable_weight_share": 0.602001589054288 + }, + { + "grouping": "income_band", + "group": "1", + "n": 2057, + "weight": 7466809.932490364, + "usable_weight_share": 0.6413274998297077 + }, + { + "grouping": "income_band", + "group": "2", + "n": 2904, + "weight": 10880663.16706181, + "usable_weight_share": 0.6487048847817203 + }, + { + "grouping": "income_band", + "group": "3", + "n": 2558, + "weight": 11325516.809686286, + "usable_weight_share": 0.6401496463974632 + }, + { + "grouping": "income_band", + "group": "4", + "n": 3134, + "weight": 15757011.988844048, + "usable_weight_share": 0.6309648019074636 + }, + { + "grouping": "income_band", + "group": "5", + "n": 838, + "weight": 5150134.639390623, + "usable_weight_share": 0.5652783862122169 + } + ], + "cross_validation": [ + { + "grouping": "all", + "group": "all", + "n": 7460, + "observed": { + "participation": 0.46514845107061753, + "days": 1.8750709563867467, + "hours": 14.240422572045741 + }, + "expected": { + "participation": 0.4654844290416027, + "days": 1.878527294011518, + "hours": 14.081114700859393 + } + }, + { + "grouping": "age", + "group": "0", + "n": 458, + "observed": { + "participation": 0.40007662898763713, + "days": 1.5207410031354076, + "hours": 12.391341719561105 + }, + "expected": { + "participation": 0.42043937266485903, + "days": 1.5581186938006875, + "hours": 12.778280226573155 + } + }, + { + "grouping": "age", + "group": "1", + "n": 585, + "observed": { + "participation": 0.5768442364096245, + "days": 2.3247221464109487, + "hours": 18.93194004904792 + }, + "expected": { + "participation": 0.5636534387398192, + "days": 2.2787632897750942, + "hours": 18.46136873433321 + } + }, + { + "grouping": "age", + "group": "2", + "n": 599, + "observed": { + "participation": 0.6119472630516792, + "days": 2.661365110302835, + "hours": 23.568671427585098 + }, + "expected": { + "participation": 0.615171451571855, + "days": 2.6668583554129937, + "hours": 24.008204825875836 + } + }, + { + "grouping": "age", + "group": "3", + "n": 597, + "observed": { + "participation": 0.6106570906701301, + "days": 2.6641302585227766, + "hours": 21.96346327818111 + }, + "expected": { + "participation": 0.6452189769582379, + "days": 2.8385499518769803, + "hours": 23.234965023661523 + } + }, + { + "grouping": "age", + "group": "4", + "n": 550, + "observed": { + "participation": 0.7046928755645677, + "days": 3.1467359328380096, + "hours": 25.30894736806148 + }, + "expected": { + "participation": 0.7168364294128767, + "days": 3.1704359925035326, + "hours": 25.23962440956216 + } + }, + { + "grouping": "age", + "group": "5", + "n": 581, + "observed": { + "participation": 0.5580840489623686, + "days": 2.527957605747102, + "hours": 20.351246817207983 + }, + "expected": { + "participation": 0.5580783794454302, + "days": 2.4817744855985993, + "hours": 19.696005730111843 + } + }, + { + "grouping": "age", + "group": "6", + "n": 611, + "observed": { + "participation": 0.38410943637037254, + "days": 1.5233703763582376, + "hours": 9.272995362839891 + }, + "expected": { + "participation": 0.3704517476571586, + "days": 1.4435320487985335, + "hours": 8.308626409800924 + } + }, + { + "grouping": "age", + "group": "7", + "n": 586, + "observed": { + "participation": 0.34047335603475937, + "days": 1.267585660002729, + "hours": 8.978033563109225 + }, + "expected": { + "participation": 0.32048663598972876, + "days": 1.2092330340598734, + "hours": 7.976819608666644 + } + }, + { + "grouping": "age", + "group": "8", + "n": 611, + "observed": { + "participation": 0.37000227568041516, + "days": 1.4234519706143929, + "hours": 8.822905923973602 + }, + "expected": { + "participation": 0.37441818500322505, + "days": 1.4678570808250095, + "hours": 8.581931573672641 + } + }, + { + "grouping": "age", + "group": "9", + "n": 590, + "observed": { + "participation": 0.3862968300759907, + "days": 1.373131779820256, + "hours": 9.825473717875598 + }, + "expected": { + "participation": 0.3658218612710925, + "days": 1.2745107095149821, + "hours": 9.212380152023707 + } + }, + { + "grouping": "age", + "group": "10", + "n": 541, + "observed": { + "participation": 0.39185689727904155, + "days": 1.3647219850376735, + "hours": 8.468134791861964 + }, + "expected": { + "participation": 0.3879904743599543, + "days": 1.313066433397897, + "hours": 7.6091158562940935 + } + }, + { + "grouping": "age", + "group": "11", + "n": 565, + "observed": { + "participation": 0.3768238596848206, + "days": 1.3633597325953704, + "hours": 8.143708694787577 + }, + "expected": { + "participation": 0.37027421084947587, + "days": 1.3896706621501198, + "hours": 8.180743029734462 + } + }, + { + "grouping": "age", + "group": "12", + "n": 586, + "observed": { + "participation": 0.35838594666001994, + "days": 1.3239431239565607, + "hours": 10.203528792841063 + }, + "expected": { + "participation": 0.37173621674013835, + "days": 1.447846572682685, + "hours": 10.94364602719194 + } + }, + { + "grouping": "region", + "group": "1", + "n": 929, + "observed": { + "participation": 0.4988625902951673, + "days": 2.101321934458425, + "hours": 14.697745432365767 + }, + "expected": { + "participation": 0.5341920187102704, + "days": 2.234373766910041, + "hours": 15.515545077772881 + } + }, + { + "grouping": "region", + "group": "2", + "n": 1654, + "observed": { + "participation": 0.495642471526947, + "days": 1.9378635600824832, + "hours": 14.438707404977198 + }, + "expected": { + "participation": 0.48657470779470846, + "days": 1.9053160452954483, + "hours": 13.830397580793818 + } + }, + { + "grouping": "region", + "group": "3", + "n": 2752, + "observed": { + "participation": 0.4310162776090592, + "days": 1.7482660126296112, + "hours": 14.16760866653331 + }, + "expected": { + "participation": 0.4254047590539008, + "days": 1.728432288982956, + "hours": 13.771990873343658 + } + }, + { + "grouping": "region", + "group": "4", + "n": 2125, + "observed": { + "participation": 0.470872102608504, + "days": 1.872465315119329, + "hours": 13.875678601794997 + }, + "expected": { + "participation": 0.46546295898430057, + "days": 1.857723153971244, + "hours": 13.833112421687238 + } + }, + { + "grouping": "parent_work_status", + "group": "-1", + "n": 122, + "observed": { + "participation": 0.34614706740243706, + "days": 1.1849281571656916, + "hours": 9.788566562075097 + }, + "expected": { + "participation": 0.373389275855184, + "days": 1.462386368172592, + "hours": 12.574282386813668 + } + }, + { + "grouping": "parent_work_status", + "group": "0", + "n": 1016, + "observed": { + "participation": 0.3096578455166947, + "days": 1.244408501915661, + "hours": 10.193456359940383 + }, + "expected": { + "participation": 0.2882996076692788, + "days": 1.1762845771341546, + "hours": 10.282450861819337 + } + }, + { + "grouping": "parent_work_status", + "group": "1", + "n": 2418, + "observed": { + "participation": 0.2864480974767621, + "days": 0.9529380212414282, + "hours": 6.42952602558992 + }, + "expected": { + "participation": 0.29059369126489437, + "days": 0.9858655333196232, + "hours": 6.764091600272923 + } + }, + { + "grouping": "parent_work_status", + "group": "2", + "n": 3904, + "observed": { + "participation": 0.5991891288528669, + "days": 2.535220374688929, + "hours": 19.536646150926547 + }, + "expected": { + "participation": 0.6008699918772364, + "days": 2.528223299633135, + "hours": 18.96579429859326 + } + }, + { + "grouping": "income_band", + "group": "0", + "n": 76, + "observed": { + "participation": 0.19070472825408744, + "days": 0.8431547354115522, + "hours": 5.587881885800679 + }, + "expected": { + "participation": 0.25300464764173586, + "days": 0.9988467887623982, + "hours": 7.43593331362669 + } + }, + { + "grouping": "income_band", + "group": "1", + "n": 1378, + "observed": { + "participation": 0.35684525807866907, + "days": 1.5280931021110342, + "hours": 12.098088591903252 + }, + "expected": { + "participation": 0.3773650597658377, + "days": 1.627338456412184, + "hours": 12.706694579809993 + } + }, + { + "grouping": "income_band", + "group": "2", + "n": 1922, + "observed": { + "participation": 0.4194011939997811, + "days": 1.7068232976926216, + "hours": 13.491053608546364 + }, + "expected": { + "participation": 0.4119472083085292, + "days": 1.7030609232530567, + "hours": 13.262000601507708 + } + }, + { + "grouping": "income_band", + "group": "3", + "n": 1632, + "observed": { + "participation": 0.4246978564102466, + "days": 1.7238735833385048, + "hours": 14.076591113511121 + }, + "expected": { + "participation": 0.4255788471352766, + "days": 1.704797441331804, + "hours": 13.264862389978802 + } + }, + { + "grouping": "income_band", + "group": "4", + "n": 1977, + "observed": { + "participation": 0.5221816116808028, + "days": 1.9968956951019248, + "hours": 14.35832226780555 + }, + "expected": { + "participation": 0.519705526319959, + "days": 1.9988673657729517, + "hours": 14.55106672367201 + } + }, + { + "grouping": "income_band", + "group": "5", + "n": 475, + "observed": { + "participation": 0.6883939484468758, + "days": 2.9203317046618578, + "hours": 20.476264713601847 + }, + "expected": { + "participation": 0.6762909354194406, + "days": 2.8292574855634296, + "hours": 19.43897806431697 + } + } + ], + "matching_levels": { + "age,region,parent_work_status,income_band": 7278, + "age,parent_work_status,income_band": 150, + "age,parent_work_status": 32 + }, + "sibling_validation": [ + { + "fold": 0, + "training_rho": 0.7504775690168417, + "households": 351, + "weight": 1627200.3809817089, + "observed_both": 0.3346110552302055, + "independent_both": 0.26023741618799584, + "coupled_both": 0.3228394147816889 + }, + { + "fold": 1, + "training_rho": 0.8095401305423818, + "households": 367, + "weight": 1640369.17044373, + "observed_both": 0.308478237709926, + "independent_both": 0.2538314963354507, + "coupled_both": 0.31777192913378116 + }, + { + "fold": 2, + "training_rho": 0.7176223341350483, + "households": 443, + "weight": 1849383.6729044288, + "observed_both": 0.3831182075641927, + "independent_both": 0.260592140353083, + "coupled_both": 0.3144997720634755 + }, + { + "fold": 3, + "training_rho": 0.8946850037821993, + "households": 398, + "weight": 1567825.4608580691, + "observed_both": 0.2954259187077949, + "independent_both": 0.2551329149477867, + "coupled_both": 0.3186981148017382 + }, + { + "fold": 4, + "training_rho": 0.8022505236076816, + "households": 382, + "weight": 1644777.832273697, + "observed_both": 0.3129856591731878, + "independent_both": 0.2695651435301845, + "coupled_both": 0.3411406780146054 + } + ], + "questionnaire_transport": [ + { + "questionnaire_version": 2, + "scored_children": 1690, + "unsupported_children": 0, + "observed": { + "regular_participation": 0.4166998042800092, + "regular_hours_per_week": 12.379208437570716 + }, + "expected": { + "regular_participation": 0.429264128691119, + "regular_hours_per_week": 14.800674181069196 + } + }, + { + "questionnaire_version": 3, + "scored_children": 1356, + "unsupported_children": 0, + "observed": { + "regular_participation": 0.38447915314763226, + "regular_hours_per_week": 10.163827277430636 + }, + "expected": { + "regular_participation": 0.40786334693307874, + "regular_hours_per_week": 13.921490221932158 + } + } + ], + "assumptions": [ + "Calendar selection is ignorable conditional on matching fields; not identified from these data.", + "Main reference-week schedules transfer to May/fall typical weeks; summer attendance is not observed.", + "Regular-care comparisons cannot validate days or irregular care in instruments without calendars." + ], + "production_ready": false + }, + "masked_calendar_validation": { + "seed": 161803, + "design": "whole-household masked-calendar test; regular weekly hours remain observed", + "comparisons": [ + { + "grouping": "all", + "group": "all", + "n": 1581, + "observed_days": 1.7176113066572272, + "imputed_days": 1.8010008506568833, + "observed_hours": 13.097316141278531, + "imputed_hours": 13.88548689950872 + }, + { + "grouping": "age", + "group": "0", + "n": 104, + "observed_days": 1.841126169101498, + "imputed_days": 1.7155709258903193, + "observed_hours": 17.766331967357488, + "imputed_hours": 18.060021757471628 + }, + { + "grouping": "age", + "group": "1", + "n": 113, + "observed_days": 2.37969546844872, + "imputed_days": 2.238095942159061, + "observed_hours": 19.829328945193588, + "imputed_hours": 19.1108645563332 + }, + { + "grouping": "age", + "group": "2", + "n": 141, + "observed_days": 2.4591773765558673, + "imputed_days": 2.513649003783342, + "observed_hours": 22.536051090399965, + "imputed_hours": 21.954590139823193 + }, + { + "grouping": "age", + "group": "3", + "n": 123, + "observed_days": 2.3763627081083216, + "imputed_days": 2.4413645269610935, + "observed_hours": 20.251977914853146, + "imputed_hours": 20.142661302712924 + }, + { + "grouping": "age", + "group": "4", + "n": 115, + "observed_days": 3.137397964036117, + "imputed_days": 3.3032151052457945, + "observed_hours": 23.68360614421261, + "imputed_hours": 25.45979594267697 + }, + { + "grouping": "age", + "group": "5", + "n": 113, + "observed_days": 2.2242008794879244, + "imputed_days": 2.8874743140551375, + "observed_hours": 15.760856040214335, + "imputed_hours": 24.9499438984932 + }, + { + "grouping": "age", + "group": "6", + "n": 130, + "observed_days": 1.1830651060264654, + "imputed_days": 1.5127783403894393, + "observed_hours": 7.042175416036001, + "imputed_hours": 7.241980015558179 + }, + { + "grouping": "age", + "group": "7", + "n": 131, + "observed_days": 1.4073709771017413, + "imputed_days": 1.2667237724301017, + "observed_hours": 10.083939201157254, + "imputed_hours": 9.891690761289606 + }, + { + "grouping": "age", + "group": "8", + "n": 126, + "observed_days": 1.057579033652681, + "imputed_days": 1.0242609251134895, + "observed_hours": 8.256788366496435, + "imputed_hours": 6.971083491156134 + }, + { + "grouping": "age", + "group": "9", + "n": 118, + "observed_days": 1.4349301372689758, + "imputed_days": 1.20915603900853, + "observed_hours": 10.733568940718998, + "imputed_hours": 9.968682065794441 + }, + { + "grouping": "age", + "group": "10", + "n": 124, + "observed_days": 1.2058459898990705, + "imputed_days": 1.2184622017593358, + "observed_hours": 4.1774445652404655, + "imputed_hours": 4.378598134956982 + }, + { + "grouping": "age", + "group": "11", + "n": 120, + "observed_days": 0.9483350107584563, + "imputed_days": 1.2340597164150218, + "observed_hours": 5.566349482238208, + "imputed_hours": 5.986332786079906 + }, + { + "grouping": "age", + "group": "12", + "n": 123, + "observed_days": 1.1181905452629102, + "imputed_days": 1.271942733975096, + "observed_hours": 8.079018679724042, + "imputed_hours": 11.093992734455059 + }, + { + "grouping": "parent_work_status", + "group": "-1", + "n": 33, + "observed_days": 1.5430497710033617, + "imputed_days": 1.847082458214411, + "observed_hours": 12.754941207431992, + "imputed_hours": 14.212849249137319 + }, + { + "grouping": "parent_work_status", + "group": "0", + "n": 233, + "observed_days": 1.3163214930511598, + "imputed_days": 1.4883107558373656, + "observed_hours": 9.57367968242547, + "imputed_hours": 10.147531300541837 + }, + { + "grouping": "parent_work_status", + "group": "1", + "n": 529, + "observed_days": 0.8935323002915262, + "imputed_days": 1.044203922701497, + "observed_hours": 6.370457810059637, + "imputed_hours": 8.615629262680223 + }, + { + "grouping": "parent_work_status", + "group": "2", + "n": 786, + "observed_days": 2.3152602893352414, + "imputed_days": 2.3300691025449733, + "observed_hours": 17.994069548324816, + "imputed_hours": 17.92138056591039 + } + ], + "regular_hours_preserved": true, + "limitations": "Tests reconstruction where calendars exist; not a direct test of unobserved days in the other questionnaire instruments." + }, + "sibling_schedule_validation": { + "design": "household-separated partitions; exact integration of the implemented shared-rank donor CDFs", + "seed": 271828, + "validation_seed": null, + "partition": "all", + "splits": [ + { + "training_households": 5100, + "evaluation_households": 1269, + "household_overlap": 0 + }, + { + "training_households": 5108, + "evaluation_households": 1261, + "household_overlap": 0 + }, + { + "training_households": 5055, + "evaluation_households": 1314, + "household_overlap": 0 + }, + { + "training_households": 5071, + "evaluation_households": 1298, + "household_overlap": 0 + }, + { + "training_households": 5142, + "evaluation_households": 1227, + "household_overlap": 0 + } + ], + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "fallback_match_columns": [ + [ + "age", + "parent_work_status", + "income_band" + ], + [ + "age", + "parent_work_status" + ], + [ + "age" + ] + ], + "matching_counts": { + "age,region,parent_work_status,income_band": 4682, + "age,parent_work_status,income_band": 87, + "age,parent_work_status": 20 + }, + "training_rho": [ + 0.7504775690168417, + 0.8095401305423818, + 0.7176223341350483, + 0.8946850037821993, + 0.8022505236076816 + ], + "youngest_pairs": { + "households": 1941, + "household_weight": 8329556.517461634, + "observed": { + "participation": { + "joint_product": 0.3285886986591048, + "correlation": 0.577510777815278 + }, + "days": { + "joint_product": 5.9171615700449145, + "correlation": 0.5798886366650429 + }, + "weekly_hours": { + "joint_product": 367.6804958137289, + "correlation": 0.523457187358221 + } + }, + "independent": { + "participation": { + "joint_product": 0.2599357218299179, + "correlation": 0.14356484664250233 + }, + "days": { + "joint_product": 4.562554958882675, + "correlation": 0.1514064619097721 + }, + "weekly_hours": { + "joint_product": 274.5482618143516, + "correlation": 0.1290575794049498 + } + }, + "coupled": { + "participation": { + "joint_product": 0.3228241594928079, + "correlation": 0.39662161163709453 + }, + "days": { + "joint_product": 6.168391228908872, + "correlation": 0.44224735414975214 + }, + "weekly_hours": { + "joint_product": 393.50536137310974, + "correlation": 0.35635277128820114 + } + } + }, + "youngest_pairs_in_3plus_households": { + "households": 661, + "household_weight": 2458669.150522002, + "observed": { + "participation": { + "joint_product": 0.2728957065164463, + "correlation": 0.5341073068866067 + }, + "days": { + "joint_product": 5.084876229689592, + "correlation": 0.5617680576612079 + }, + "weekly_hours": { + "joint_product": 337.34705105325276, + "correlation": 0.5623528715201395 + } + }, + "independent": { + "participation": { + "joint_product": 0.26594831103314626, + "correlation": 0.1768906778018396 + }, + "days": { + "joint_product": 4.755017625871223, + "correlation": 0.1796772530434437 + }, + "weekly_hours": { + "joint_product": 288.78160178706247, + "correlation": 0.15022942733210107 + } + }, + "coupled": { + "participation": { + "joint_product": 0.32461663032314914, + "correlation": 0.41320572283269663 + }, + "days": { + "joint_product": 6.243213912824172, + "correlation": 0.44765187465853035 + }, + "weekly_hours": { + "joint_product": 406.53469377347056, + "correlation": 0.3715598543103152 + } + } + }, + "larger_households": { + "households": 661, + "observed": { + "mean_total_days": 4.509647234214243, + "mean_total_weekly_hours": 33.085374473048084, + "sd_total_days": 5.765302178946849, + "sd_total_weekly_hours": 56.21651776123905, + "all_children_attend": 0.18568592787006075 + }, + "independent": { + "mean_total_days": 5.652805180994538, + "mean_total_weekly_hours": 40.814235235209445, + "sd_total_days": 4.742171858563125, + "sd_total_weekly_hours": 43.69183090611876, + "all_children_attend": 0.10870430564775237 + }, + "coupled": { + "mean_total_days": 5.652805180994538, + "mean_total_weekly_hours": 40.814235235209445, + "sd_total_days": 5.826012333228911, + "sd_total_weekly_hours": 52.0732028760817, + "all_children_attend": 0.19850142013240785 + } + }, + "production_ready": false, + "diagnostic_screen": { + "passed": false, + "checks": [ + { + "metric": "youngest_pairs.participation.joint_product", + "absolute_gap": 0.005764539166296878, + "relative": false, + "limit": 0.05, + "passed": true + }, + { + "metric": "youngest_pairs.days.correlation", + "absolute_gap": 0.13764128251529073, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs.weekly_hours.correlation", + "absolute_gap": 0.16710441607001986, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs.days.joint_product", + "absolute_gap": 0.04245779938404666, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs.weekly_hours.joint_product", + "absolute_gap": 0.07023724634135614, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.participation.joint_product", + "absolute_gap": 0.051720923806702845, + "relative": false, + "limit": 0.05, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.days.correlation", + "absolute_gap": 0.11411618300267751, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.correlation", + "absolute_gap": 0.19079301720982428, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.days.joint_product", + "absolute_gap": 0.22780056599436455, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.joint_product", + "absolute_gap": 0.20509336751041, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.mean_total_days", + "absolute_gap": 0.2534916563112233, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.mean_total_weekly_hours", + "absolute_gap": 0.23360354492760613, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.sd_total_days", + "absolute_gap": 0.010530264051684455, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.sd_total_weekly_hours", + "absolute_gap": 0.07370280213290151, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.all_children_attend", + "absolute_gap": 0.0128154922623471, + "relative": false, + "limit": 0.05, + "passed": true + } + ], + "interpretation": "provisional diagnostic screens; not publication authorization" + } + }, + "noncalendar_bridge": { + "seed": 915, + "completed_children": 3046, + "unsupported_children": 0, + "matching_levels": { + "age": 46, + "age,parent_work_status": 331, + "age,parent_work_status,income_band": 1287, + "age,region,parent_work_status,income_band": 1382 + }, + "observed": "regular weekly hours from May/fall questionnaire", + "imputed": "attended days and irregular care jointly from nearest regular-hour calendar donors", + "assumption": "conditional calendar pattern and irregular care transfer across questionnaire instruments" + }, + "candidate_frame_written": true, + "environment": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "microcosm-build": "0.1.0", + "microcosm-frame": "0.1.0", + "policyengine-us": "2.2.1", + "python": "3.13.5" + }, + "code_sha256": { + "prepare_us_childcare_attendance.py": "19eabbe3b972bf751aa64892fb8a4f06d7d40bf05a742c9546d5b1b3e54fd2fb", + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "nsece_childcare.py": "e11eef389f47433a2d407aaf7c01214dbefccb702b3fefe8fa6502c7e947ab4d", + "nsece_childcare_bridge.py": "517b3c3ae02e2316b028fd15bc60a090e7962d716d46b80e3e73067f08d5ff29", + "nsece_childcare_sibling_validation.py": "abd2a4c88d3c4585e055fae93be3ac00c060405fc6e24bb079b67196aa88e422", + "nsece_childcare_dependence.py": "1c5123a77f84460ba517d2b4c6c3e04ae658bf36e9cf54ed69ddbcacc85efc09", + "childcare_attendance_stage.py": "c5243b7f23865c352acee8f5946bb8c7b578645c7b5e56c24632fa94dd9dbecb", + "childcare_attendance_receipt.py": "d93ecfe1725bef2c0b87a137eaab88856fa9a76e601227089ceb94daa4335865", + "nsece_childcare_qrf.py": "f8ae9695a648bd163e04ae2ab92a9cd08ce9c29e7e19ed293c118934ff6ef0b1", + "childcare_sensitivity.py": "17a684c51ed48f164006d485aa2177d8c1f03609290e96eae377c625bb6d93cf", + "nsece_childcare_assessment.py": "537d5d839ce9df4f1772ee887597811990aab5b7f10a863b70fe6630583fa3b7", + "nsece_childcare_pooling.py": "a779a0db7fddbb9e33aa7f8c8f7752b5f4a083309bb7d8f03d6ab72555a439f2", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "childcare.py": "a8502e1fc15457a7f120936a8940fbb51cba3e2299d92ca9cd69b749f6deea2f", + "childcare_attendance_source.json": "c5beeeb09ab330c305e3250bc7db5a5003336d26fa508872211cb18958ab9e97", + "education_assistance_source.py": "e259e3fce64fdcab62953f79a1aa41719f81c64c7c5dc1a63f8b1e493ff5f83a", + "geography_constants.py": "96938b5dd6bba8f10d0f52d10a9cdcbc16ae9506c4424f58e10347998ff02a8a", + "uv.lock": "eb328a5cf6cc0bc567c209fce03294f4f3b0b5e59adf47dfa7ff4173545e03be" + }, + "candidate_checkpoint_sha256": "5cb9aa418768b5a82ee351e8b737f58c8989212f1ffbee36d605c22887e989a5", + "parent_population_sha256": "48b9d479fb4fd1c3537f9383ce4697d130b6f618658409d74f6233c43b994c7e", + "production_stage_executed": true, + "candidate_receipts": { + "nsece_childcare_attendance": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "calendar_bounds": { + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568", + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "missing_calendar": "uninformative 0--168 hours and 0--7 days" + }, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ], + "noncalendar_bridge": { + "seed": 915, + "completed_children": 3046, + "unsupported_children": 0, + "matching_levels": { + "age": 46, + "age,parent_work_status": 331, + "age,parent_work_status,income_band": 1287, + "age,region,parent_work_status,income_band": 1382 + }, + "observed": "regular weekly hours from May/fall questionnaire", + "imputed": "attended days and irregular care jointly from nearest regular-hour calendar donors", + "assumption": "conditional calendar pattern and irregular care transfer across questionnaire instruments" + }, + "seed": 915, + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "fallback_match_columns": [ + [ + "age", + "parent_work_status", + "income_band" + ], + [ + "age", + "parent_work_status" + ], + [ + "age" + ] + ], + "sibling_dependence": 0.7413149380294699, + "candidate_only": true + }, + "childcare_predictor_harmonization": { + "source": "ASEC resident parent line pointers", + "parent_universe": "parents of any child age 0 through 12 in household", + "work_measure": "hours_worked_last_week > 0", + "geography": "Census region from target state_fips", + "income_source_receipts": [ + { + "income_year": 2022, + "sha256": "19b56537e50e7663f954361ef2bb5ce9cef8d9d45f156fe1a69a99b654198ffe", + "matched_people": 54464, + "source_rows": 146133 + }, + { + "income_year": 2023, + "sha256": "21a2b9e0e4b08534563578a45acad77868af4ae9a7d46f23776b707d4a559aa7", + "matched_people": 54654, + "source_rows": 144265 + }, + { + "income_year": 2024, + "sha256": "06921fe83fc66c907e6c7b86b82255dc70458ee7d76258fc48297cb34f0c06b5", + "matched_people": 57203, + "source_rows": 142125 + } + ], + "income": "Household sum of measured ASEC PTOTVAL, CPI-U adjusted from source year to 2023 dollars" + }, + "childcare_outside_domain_baseline": { + "engine_version": "2.2.1", + "values": { + "childcare_attending_days_per_month": 0.0, + "childcare_days_per_week": 0.0, + "childcare_hours_per_day": 0.0 + }, + "inherited_counts": { + "childcare_attending_days_per_month": 134432, + "childcare_days_per_week": 134432, + "childcare_hours_per_day": 134432 + }, + "interpretation": "baseline retained; not evidence of nonattendance outside ages 0-12" + }, + "childcare_attendance_stage": { + "stage": "nsece_childcare_attendance", + "outputs": [ + "childcare_attending_days_per_month", + "childcare_days_per_week", + "childcare_hours_per_day" + ], + "seed": 915, + "operations": [ + { + "kind": "derive_childcare_inputs", + "operation": "calendar_attendance", + "age_min": 0, + "age_max": 12 + }, + { + "kind": "fit", + "operation": "fit_sibling_dependence", + "rho": 0.7413149380294699 + }, + { + "kind": "derive_childcare_inputs", + "operation": "regular_hours_schedule_bridge", + "nearest_donors": 10 + }, + { + "kind": "derive", + "operation": "harmonize_asec_childcare_predictors" + }, + { + "kind": "derive_childcare_inputs", + "operation": "joint_weighted_schedule_transfer", + "preserve_observed": true + }, + { + "kind": "export_policy", + "operation": "inherit_engine_baseline" + } + ], + "sibling_dependence": { + "rho": 0.7413149380294699, + "unconstrained_rho": 0.7413149380294699, + "households": 1941, + "observed_both_in_care": 0.32858869865910467, + "independent_both_in_care": 0.2585427028841666, + "shared_both_in_care": 0.3530315526045447, + "estimation": "youngest pair in fully observed households; household design weights" + }, + "modeled_age_domain": [ + 0, + 12 + ], + "outside_domain_policy": "inherit_engine_baseline" + }, + "childcare_attendance_binding": { + "schema_version": 1, + "binding_sha256": "5a67c4cdbefa261a6ba7be056ef37afbf6a20755c649432c10020026a7f1e9a2", + "execution_sha256": "a9c0c33d4eac2a876e7cee52c65b8e2ad3d2200bed62d91bc0465c05f590cc27", + "source_people": 166321, + "retained_people": 166321, + "execution": { + "recipe": { + "contract_sha256": "ae648c6cb0e2838fdf142975e9c536eb0683d9630fd1738096d524222ffb01dc", + "runtime_versions": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "policyengine-us": "2.2.1" + }, + "code_sha256": { + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "nsece_childcare.py": "e11eef389f47433a2d407aaf7c01214dbefccb702b3fefe8fa6502c7e947ab4d", + "nsece_childcare_bridge.py": "517b3c3ae02e2316b028fd15bc60a090e7962d716d46b80e3e73067f08d5ff29", + "nsece_childcare_dependence.py": "1c5123a77f84460ba517d2b4c6c3e04ae658bf36e9cf54ed69ddbcacc85efc09", + "childcare_attendance_stage.py": "c5243b7f23865c352acee8f5946bb8c7b578645c7b5e56c24632fa94dd9dbecb", + "childcare_attendance_receipt.py": "d93ecfe1725bef2c0b87a137eaab88856fa9a76e601227089ceb94daa4335865" + } + }, + "context": { + "nsece_childcare_attendance": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "calendar_bounds": { + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568", + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "missing_calendar": "uninformative 0--168 hours and 0--7 days" + }, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ], + "noncalendar_bridge": { + "seed": 915, + "completed_children": 3046, + "unsupported_children": 0, + "matching_levels": { + "age": 46, + "age,parent_work_status": 331, + "age,parent_work_status,income_band": 1287, + "age,region,parent_work_status,income_band": 1382 + }, + "observed": "regular weekly hours from May/fall questionnaire", + "imputed": "attended days and irregular care jointly from nearest regular-hour calendar donors", + "assumption": "conditional calendar pattern and irregular care transfer across questionnaire instruments" + }, + "seed": 915, + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "fallback_match_columns": [ + [ + "age", + "parent_work_status", + "income_band" + ], + [ + "age", + "parent_work_status" + ], + [ + "age" + ] + ], + "sibling_dependence": 0.7413149380294699, + "candidate_only": true + }, + "childcare_predictor_harmonization": { + "source": "ASEC resident parent line pointers", + "parent_universe": "parents of any child age 0 through 12 in household", + "work_measure": "hours_worked_last_week > 0", + "geography": "Census region from target state_fips", + "income_source_receipts": [ + { + "income_year": 2022, + "sha256": "19b56537e50e7663f954361ef2bb5ce9cef8d9d45f156fe1a69a99b654198ffe", + "matched_people": 54464, + "source_rows": 146133 + }, + { + "income_year": 2023, + "sha256": "21a2b9e0e4b08534563578a45acad77868af4ae9a7d46f23776b707d4a559aa7", + "matched_people": 54654, + "source_rows": 144265 + }, + { + "income_year": 2024, + "sha256": "06921fe83fc66c907e6c7b86b82255dc70458ee7d76258fc48297cb34f0c06b5", + "matched_people": 57203, + "source_rows": 142125 + } + ], + "income": "Household sum of measured ASEC PTOTVAL, CPI-U adjusted from source year to 2023 dollars" + }, + "childcare_outside_domain_baseline": { + "engine_version": "2.2.1", + "values": { + "childcare_attending_days_per_month": 0.0, + "childcare_days_per_week": 0.0, + "childcare_hours_per_day": 0.0 + }, + "inherited_counts": { + "childcare_attending_days_per_month": 134432, + "childcare_days_per_week": 134432, + "childcare_hours_per_day": 134432 + }, + "interpretation": "baseline retained; not evidence of nonattendance outside ages 0-12" + }, + "childcare_attendance_stage": { + "stage": "nsece_childcare_attendance", + "outputs": [ + "childcare_attending_days_per_month", + "childcare_days_per_week", + "childcare_hours_per_day" + ], + "seed": 915, + "operations": [ + { + "kind": "derive_childcare_inputs", + "operation": "calendar_attendance", + "age_min": 0, + "age_max": 12 + }, + { + "kind": "fit", + "operation": "fit_sibling_dependence", + "rho": 0.7413149380294699 + }, + { + "kind": "derive_childcare_inputs", + "operation": "regular_hours_schedule_bridge", + "nearest_donors": 10 + }, + { + "kind": "derive", + "operation": "harmonize_asec_childcare_predictors" + }, + { + "kind": "derive_childcare_inputs", + "operation": "joint_weighted_schedule_transfer", + "preserve_observed": true + }, + { + "kind": "export_policy", + "operation": "inherit_engine_baseline" + } + ], + "sibling_dependence": { + "rho": 0.7413149380294699, + "unconstrained_rho": 0.7413149380294699, + "households": 1941, + "observed_both_in_care": 0.32858869865910467, + "independent_both_in_care": 0.2585427028841666, + "shared_both_in_care": 0.3530315526045447, + "estimation": "youngest pair in fully observed households; household design weights" + }, + "modeled_age_domain": [ + 0, + 12 + ], + "outside_domain_policy": "inherit_engine_baseline" + } + } + } + } + }, + "native_candidate_written": true, + "native_candidate_sha256": "26e8811d2f6822ae555280fea06d1231d868c12764a20ab8e66086fec017f4db" +} diff --git a/experiments/us-childcare-attendance/review-fixes-verification.json b/experiments/us-childcare-attendance/review-fixes-verification.json new file mode 100644 index 000000000..b4d6978da --- /dev/null +++ b/experiments/us-childcare-attendance/review-fixes-verification.json @@ -0,0 +1,39 @@ +{ + "parent_sha256": "48b9d479fb4fd1c3537f9383ce4697d130b6f618658409d74f6233c43b994c7e", + "checkpoint_sha256": "5cb9aa418768b5a82ee351e8b737f58c8989212f1ffbee36d605c22887e989a5", + "native_sha256": "26e8811d2f6822ae555280fea06d1231d868c12764a20ab8e66086fec017f4db", + "source_stage_report_sha256": "eb1f20876a4b5d41d045b1fb65cc5a0029c0fad3b800e26e7d6e83833c6be743", + "verification_code_sha256": "3b4cd482f6465325f66d1d8e1b3d680b281073d7dcb6b4bbedc7899e16d27ed4", + "attendance_recipe": { + "code_sha256": { + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "childcare_attendance_receipt.py": "d93ecfe1725bef2c0b87a137eaab88856fa9a76e601227089ceb94daa4335865", + "childcare_attendance_stage.py": "c5243b7f23865c352acee8f5946bb8c7b578645c7b5e56c24632fa94dd9dbecb", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "nsece_childcare.py": "e11eef389f47433a2d407aaf7c01214dbefccb702b3fefe8fa6502c7e947ab4d", + "nsece_childcare_bridge.py": "517b3c3ae02e2316b028fd15bc60a090e7962d716d46b80e3e73067f08d5ff29", + "nsece_childcare_dependence.py": "1c5123a77f84460ba517d2b4c6c3e04ae658bf36e9cf54ed69ddbcacc85efc09" + }, + "contract_sha256": "ae648c6cb0e2838fdf142975e9c536eb0683d9630fd1738096d524222ffb01dc", + "runtime_versions": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "policyengine-us": "2.2.1" + } + }, + "content_binding_sha256": "5a67c4cdbefa261a6ba7be056ef37afbf6a20755c649432c10020026a7f1e9a2", + "engine_version": "2.2.1", + "core_version": "3.32.5", + "people": 166321, + "households": 57240, + "under13_children": 31889, + "verified_native_loaders": [ + "microcosm.build.us_runtime.h5_io.load_legacy_calibrated_us_h5", + "microcosm.build.us_runtime.l0_refit_export.load_us_frame" + ], + "all_original_columns_and_weights_preserved": true, + "all_attendance_values_preserved_on_native_reload": true, + "comparison": "exact values and dtypes, normalizing only pandas string storage backend", + "interpretation": "artifact integrity and preservation only; no statistical certification or publication", + "production_ready": false +} diff --git a/experiments/us-childcare-attendance/review-source-stage-validation.json b/experiments/us-childcare-attendance/review-source-stage-validation.json new file mode 100644 index 000000000..e23bab723 --- /dev/null +++ b/experiments/us-childcare-attendance/review-source-stage-validation.json @@ -0,0 +1,1921 @@ +{ + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "source_child_count": 11745, + "source_attrition": [ + { + "status": "age_out_of_scope", + "n": 134, + "child_weight": 633390.6468148227 + }, + { + "status": "ambiguous_calendar", + "n": 882, + "child_weight": 3918044.035953992 + }, + { + "status": "complete", + "n": 7460, + "child_weight": 32249785.682044942 + }, + { + "status": "missing_calendar", + "n": 3095, + "child_weight": 14061828.648228496 + }, + { + "status": "partial_calendar", + "n": 174, + "child_weight": 847769.9869632281 + } + ], + "under13_complete_weight_share": 0.6313901604255374, + "seed": 915, + "evaluation_design": "fixed household diagnostic split; not final population certification", + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "training_children": 5988, + "heldout_children": 1472, + "unsupported_heldout_children": 30, + "unsupported_heldout_weight": 153817.788204796, + "household_overlap": 0, + "comparisons": [ + { + "grouping": "all", + "group": "all", + "n": 1442, + "observed": { + "participation": 0.47956011362829676, + "days_per_week": 1.94220990502671, + "hours_per_week": 14.670259928481958 + }, + "predicted": { + "participation": 0.4547372440086608, + "days_per_week": 1.7986704844660344, + "hours_per_week": 13.001295500494344 + } + }, + { + "grouping": "age", + "group": "0", + "n": 87, + "observed": { + "participation": 0.4749769477860246, + "days_per_week": 1.8705229048944185, + "hours_per_week": 15.234832555457738 + }, + "predicted": { + "participation": 0.21347668238234924, + "days_per_week": 0.7762397588546358, + "hours_per_week": 6.331944692101247 + } + }, + { + "grouping": "age", + "group": "1", + "n": 113, + "observed": { + "participation": 0.6026124718926947, + "days_per_week": 2.2004884644301415, + "hours_per_week": 16.058889950232714 + }, + "predicted": { + "participation": 0.5817111215090339, + "days_per_week": 2.3867359768549528, + "hours_per_week": 20.29503642359935 + } + }, + { + "grouping": "age", + "group": "2", + "n": 107, + "observed": { + "participation": 0.6827728698846081, + "days_per_week": 3.2446932739752876, + "hours_per_week": 32.643365116161064 + }, + "predicted": { + "participation": 0.721108922787169, + "days_per_week": 2.9279814704204314, + "hours_per_week": 25.4484971084278 + } + }, + { + "grouping": "age", + "group": "3", + "n": 105, + "observed": { + "participation": 0.5478113606887365, + "days_per_week": 2.4737318877881727, + "hours_per_week": 18.774571500322175 + }, + "predicted": { + "participation": 0.7525857598038783, + "days_per_week": 3.556893850206531, + "hours_per_week": 31.34897414405891 + } + }, + { + "grouping": "age", + "group": "4", + "n": 115, + "observed": { + "participation": 0.6853382748904278, + "days_per_week": 3.133535876664359, + "hours_per_week": 22.72675588135229 + }, + "predicted": { + "participation": 0.6264622224091229, + "days_per_week": 2.555534029105278, + "hours_per_week": 22.558086951188297 + } + }, + { + "grouping": "age", + "group": "5", + "n": 109, + "observed": { + "participation": 0.45965467004039157, + "days_per_week": 2.204288116474054, + "hours_per_week": 16.671100530443887 + }, + "predicted": { + "participation": 0.5197893305690322, + "days_per_week": 2.0628456061601703, + "hours_per_week": 14.660711473842793 + } + }, + { + "grouping": "age", + "group": "6", + "n": 121, + "observed": { + "participation": 0.37767600901948256, + "days_per_week": 1.4233675361325482, + "hours_per_week": 11.368361596236443 + }, + "predicted": { + "participation": 0.3812603191662228, + "days_per_week": 1.344172188177959, + "hours_per_week": 6.687190574415363 + } + }, + { + "grouping": "age", + "group": "7", + "n": 121, + "observed": { + "participation": 0.2903318905157446, + "days_per_week": 0.9137564001326794, + "hours_per_week": 4.425088819370026 + }, + "predicted": { + "participation": 0.3316072853951072, + "days_per_week": 1.3098426672238894, + "hours_per_week": 7.381236186215511 + } + }, + { + "grouping": "age", + "group": "8", + "n": 136, + "observed": { + "participation": 0.33161676756925296, + "days_per_week": 1.2251387657453359, + "hours_per_week": 6.71788070980216 + }, + "predicted": { + "participation": 0.35465278512495324, + "days_per_week": 1.3642638058954168, + "hours_per_week": 9.725344329820171 + } + }, + { + "grouping": "age", + "group": "9", + "n": 101, + "observed": { + "participation": 0.4569510479920196, + "days_per_week": 1.674346958462562, + "hours_per_week": 7.805739183708693 + }, + "predicted": { + "participation": 0.396876880067868, + "days_per_week": 1.3966673442424729, + "hours_per_week": 8.701466574792914 + } + }, + { + "grouping": "age", + "group": "10", + "n": 105, + "observed": { + "participation": 0.45503949077471245, + "days_per_week": 1.5782906105470733, + "hours_per_week": 12.426848636692846 + }, + "predicted": { + "participation": 0.17752112044794535, + "days_per_week": 0.6469841431239514, + "hours_per_week": 3.596759032644189 + } + }, + { + "grouping": "age", + "group": "11", + "n": 119, + "observed": { + "participation": 0.41662598750149954, + "days_per_week": 1.8643111020323588, + "hours_per_week": 12.941021091087745 + }, + "predicted": { + "participation": 0.4008574857176407, + "days_per_week": 1.339718142783517, + "hours_per_week": 7.024111200026524 + } + }, + { + "grouping": "age", + "group": "12", + "n": 103, + "observed": { + "participation": 0.46408861423609865, + "days_per_week": 1.4945247924023801, + "hours_per_week": 11.114322042194766 + }, + "predicted": { + "participation": 0.43591150819042584, + "days_per_week": 1.7008936429461807, + "hours_per_week": 7.10555160431239 + } + }, + { + "grouping": "region", + "group": "1", + "n": 187, + "observed": { + "participation": 0.5340539220646277, + "days_per_week": 2.4009930157522064, + "hours_per_week": 14.79000641069395 + }, + "predicted": { + "participation": 0.6359603067185889, + "days_per_week": 2.7160385976574153, + "hours_per_week": 21.24487930853725 + } + }, + { + "grouping": "region", + "group": "2", + "n": 335, + "observed": { + "participation": 0.46285701128880247, + "days_per_week": 1.8453473655274784, + "hours_per_week": 15.352184287431765 + }, + "predicted": { + "participation": 0.41283532735257467, + "days_per_week": 1.4868890394545802, + "hours_per_week": 9.329182591248077 + } + }, + { + "grouping": "region", + "group": "3", + "n": 470, + "observed": { + "participation": 0.4328632075166446, + "days_per_week": 1.8236781494293404, + "hours_per_week": 15.35364160426729 + }, + "predicted": { + "participation": 0.4184231306502971, + "days_per_week": 1.5947483523709618, + "hours_per_week": 10.342311458512322 + } + }, + { + "grouping": "region", + "group": "4", + "n": 450, + "observed": { + "participation": 0.5171827642556369, + "days_per_week": 1.8475690827448323, + "hours_per_week": 13.04393396272379 + }, + "predicted": { + "participation": 0.4063739455351018, + "days_per_week": 1.670368549893466, + "hours_per_week": 13.748230642009998 + } + }, + { + "grouping": "parent_work_status", + "group": "-1", + "n": 13, + "observed": { + "participation": 0.253295875991658, + "days_per_week": 0.8671327195533685, + "hours_per_week": 3.515415042668932 + }, + "predicted": { + "participation": 0.12949135028799522, + "days_per_week": 0.5134069370080796, + "hours_per_week": 3.2849650228565768 + } + }, + { + "grouping": "parent_work_status", + "group": "0", + "n": 150, + "observed": { + "participation": 0.2939873489805854, + "days_per_week": 1.1857568669020946, + "hours_per_week": 10.001769026104405 + }, + "predicted": { + "participation": 0.20052896295212805, + "days_per_week": 0.7861821143968067, + "hours_per_week": 6.547539835013359 + } + }, + { + "grouping": "parent_work_status", + "group": "1", + "n": 543, + "observed": { + "participation": 0.2512596429034898, + "days_per_week": 0.8664048151368835, + "hours_per_week": 5.612021341518408 + }, + "predicted": { + "participation": 0.30234830539829555, + "days_per_week": 0.9663278582430083, + "hours_per_week": 5.557806485223704 + } + }, + { + "grouping": "parent_work_status", + "group": "2", + "n": 736, + "observed": { + "participation": 0.6462583482271946, + "days_per_week": 2.714084969528804, + "hours_per_week": 21.02161873348801 + }, + "predicted": { + "participation": 0.5856324643226721, + "days_per_week": 2.4572831629804637, + "hours_per_week": 18.54158986890966 + } + } + ], + "production_ready": false, + "limitations": [ + "Only complete, unambiguous calendars enter this holdout; source selection remains unvalidated.", + "The diagnostic matches age and caller-specified covariates; it is not a nationally validated fitted model.", + "Sibling assignments, mixed providers, older-child care and scalar monthly conversion need validation.", + "No full Microcosm population build or state CCDF distribution is certified by this source-only report." + ], + "sibling_dependence": { + "rho": 0.7413149380294699, + "unconstrained_rho": 0.7413149380294699, + "households": 1941, + "observed_both_in_care": 0.32858869865910467, + "independent_both_in_care": 0.2585427028841666, + "shared_both_in_care": 0.3530315526045447, + "estimation": "youngest pair in fully observed households; household design weights" + }, + "selection_and_cross_validation": { + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "seed": 271828, + "design": "five-fold household-separated conditional-expectation diagnostic", + "coverage": [ + { + "grouping": "questionnaire_version", + "group": "1", + "n": 8516, + "weight": 37015599.704962164, + "usable_weight_share": 0.8712484989868113 + }, + { + "grouping": "questionnaire_version", + "group": "2", + "n": 1716, + "weight": 7945306.22844611, + "usable_weight_share": 0.0 + }, + { + "grouping": "questionnaire_version", + "group": "3", + "n": 1379, + "weight": 6116522.419782387, + "usable_weight_share": 0.0 + }, + { + "grouping": "age", + "group": "0", + "n": 709, + "weight": 3159547.2696341733, + "usable_weight_share": 0.6556513621184303 + }, + { + "grouping": "age", + "group": "1", + "n": 856, + "weight": 3710311.739747545, + "usable_weight_share": 0.6518631977426506 + }, + { + "grouping": "age", + "group": "2", + "n": 906, + "weight": 4112848.861546397, + "usable_weight_share": 0.6567885484115844 + }, + { + "grouping": "age", + "group": "3", + "n": 927, + "weight": 4191268.180093972, + "usable_weight_share": 0.5836151261043054 + }, + { + "grouping": "age", + "group": "4", + "n": 890, + "weight": 3761621.476875998, + "usable_weight_share": 0.6069150244376095 + }, + { + "grouping": "age", + "group": "5", + "n": 884, + "weight": 3759953.5032736305, + "usable_weight_share": 0.6441250249176611 + }, + { + "grouping": "age", + "group": "6", + "n": 954, + "weight": 4259102.717846392, + "usable_weight_share": 0.6213110691400029 + }, + { + "grouping": "age", + "group": "7", + "n": 944, + "weight": 4191490.05150999, + "usable_weight_share": 0.6014263712726516 + }, + { + "grouping": "age", + "group": "8", + "n": 925, + "weight": 3969583.419307067, + "usable_weight_share": 0.6776062606911202 + }, + { + "grouping": "age", + "group": "9", + "n": 921, + "weight": 4036325.188020362, + "usable_weight_share": 0.6661696977311178 + }, + { + "grouping": "age", + "group": "10", + "n": 884, + "weight": 3707790.894951107, + "usable_weight_share": 0.6220814618665044 + }, + { + "grouping": "age", + "group": "11", + "n": 908, + "weight": 4069233.422108399, + "usable_weight_share": 0.6084497314858798 + }, + { + "grouping": "age", + "group": "12", + "n": 903, + "weight": 4148351.6282756263, + "usable_weight_share": 0.6217216150291205 + }, + { + "grouping": "region", + "group": "1", + "n": 1468, + "weight": 8153076.12536276, + "usable_weight_share": 0.6401722331669089 + }, + { + "grouping": "region", + "group": "2", + "n": 2680, + "weight": 10714972.208999828, + "usable_weight_share": 0.6330942004076335 + }, + { + "grouping": "region", + "group": "3", + "n": 4275, + "weight": 20022339.81304313, + "usable_weight_share": 0.6249460927360144 + }, + { + "grouping": "region", + "group": "4", + "n": 3188, + "weight": 12187040.205784943, + "usable_weight_share": 0.634603874645437 + }, + { + "grouping": "parent_work_status", + "group": "-1", + "n": 188, + "weight": 819575.738509818, + "usable_weight_share": 0.646736557730207 + }, + { + "grouping": "parent_work_status", + "group": "0", + "n": 1470, + "weight": 5301911.400981113, + "usable_weight_share": 0.6698890755679009 + }, + { + "grouping": "parent_work_status", + "group": "1", + "n": 3380, + "weight": 14009836.058523985, + "usable_weight_share": 0.7212981495115555 + }, + { + "grouping": "parent_work_status", + "group": "2", + "n": 6573, + "weight": 30946105.155175745, + "usable_weight_share": 0.5836849144158337 + }, + { + "grouping": "income_band", + "group": "0", + "n": 120, + "weight": 497291.815717528, + "usable_weight_share": 0.602001589054288 + }, + { + "grouping": "income_band", + "group": "1", + "n": 2057, + "weight": 7466809.932490364, + "usable_weight_share": 0.6413274998297077 + }, + { + "grouping": "income_band", + "group": "2", + "n": 2904, + "weight": 10880663.16706181, + "usable_weight_share": 0.6487048847817203 + }, + { + "grouping": "income_band", + "group": "3", + "n": 2558, + "weight": 11325516.809686286, + "usable_weight_share": 0.6401496463974632 + }, + { + "grouping": "income_band", + "group": "4", + "n": 3134, + "weight": 15757011.988844048, + "usable_weight_share": 0.6309648019074636 + }, + { + "grouping": "income_band", + "group": "5", + "n": 838, + "weight": 5150134.639390623, + "usable_weight_share": 0.5652783862122169 + } + ], + "cross_validation": [ + { + "grouping": "all", + "group": "all", + "n": 7460, + "observed": { + "participation": 0.46514845107061753, + "days": 1.8750709563867467, + "hours": 14.240422572045741 + }, + "expected": { + "participation": 0.4654844290416027, + "days": 1.878527294011518, + "hours": 14.081114700859393 + } + }, + { + "grouping": "age", + "group": "0", + "n": 458, + "observed": { + "participation": 0.40007662898763713, + "days": 1.5207410031354076, + "hours": 12.391341719561105 + }, + "expected": { + "participation": 0.42043937266485903, + "days": 1.5581186938006875, + "hours": 12.778280226573155 + } + }, + { + "grouping": "age", + "group": "1", + "n": 585, + "observed": { + "participation": 0.5768442364096245, + "days": 2.3247221464109487, + "hours": 18.93194004904792 + }, + "expected": { + "participation": 0.5636534387398192, + "days": 2.2787632897750942, + "hours": 18.46136873433321 + } + }, + { + "grouping": "age", + "group": "2", + "n": 599, + "observed": { + "participation": 0.6119472630516792, + "days": 2.661365110302835, + "hours": 23.568671427585098 + }, + "expected": { + "participation": 0.615171451571855, + "days": 2.6668583554129937, + "hours": 24.008204825875836 + } + }, + { + "grouping": "age", + "group": "3", + "n": 597, + "observed": { + "participation": 0.6106570906701301, + "days": 2.6641302585227766, + "hours": 21.96346327818111 + }, + "expected": { + "participation": 0.6452189769582379, + "days": 2.8385499518769803, + "hours": 23.234965023661523 + } + }, + { + "grouping": "age", + "group": "4", + "n": 550, + "observed": { + "participation": 0.7046928755645677, + "days": 3.1467359328380096, + "hours": 25.30894736806148 + }, + "expected": { + "participation": 0.7168364294128767, + "days": 3.1704359925035326, + "hours": 25.23962440956216 + } + }, + { + "grouping": "age", + "group": "5", + "n": 581, + "observed": { + "participation": 0.5580840489623686, + "days": 2.527957605747102, + "hours": 20.351246817207983 + }, + "expected": { + "participation": 0.5580783794454302, + "days": 2.4817744855985993, + "hours": 19.696005730111843 + } + }, + { + "grouping": "age", + "group": "6", + "n": 611, + "observed": { + "participation": 0.38410943637037254, + "days": 1.5233703763582376, + "hours": 9.272995362839891 + }, + "expected": { + "participation": 0.3704517476571586, + "days": 1.4435320487985335, + "hours": 8.308626409800924 + } + }, + { + "grouping": "age", + "group": "7", + "n": 586, + "observed": { + "participation": 0.34047335603475937, + "days": 1.267585660002729, + "hours": 8.978033563109225 + }, + "expected": { + "participation": 0.32048663598972876, + "days": 1.2092330340598734, + "hours": 7.976819608666644 + } + }, + { + "grouping": "age", + "group": "8", + "n": 611, + "observed": { + "participation": 0.37000227568041516, + "days": 1.4234519706143929, + "hours": 8.822905923973602 + }, + "expected": { + "participation": 0.37441818500322505, + "days": 1.4678570808250095, + "hours": 8.581931573672641 + } + }, + { + "grouping": "age", + "group": "9", + "n": 590, + "observed": { + "participation": 0.3862968300759907, + "days": 1.373131779820256, + "hours": 9.825473717875598 + }, + "expected": { + "participation": 0.3658218612710925, + "days": 1.2745107095149821, + "hours": 9.212380152023707 + } + }, + { + "grouping": "age", + "group": "10", + "n": 541, + "observed": { + "participation": 0.39185689727904155, + "days": 1.3647219850376735, + "hours": 8.468134791861964 + }, + "expected": { + "participation": 0.3879904743599543, + "days": 1.313066433397897, + "hours": 7.6091158562940935 + } + }, + { + "grouping": "age", + "group": "11", + "n": 565, + "observed": { + "participation": 0.3768238596848206, + "days": 1.3633597325953704, + "hours": 8.143708694787577 + }, + "expected": { + "participation": 0.37027421084947587, + "days": 1.3896706621501198, + "hours": 8.180743029734462 + } + }, + { + "grouping": "age", + "group": "12", + "n": 586, + "observed": { + "participation": 0.35838594666001994, + "days": 1.3239431239565607, + "hours": 10.203528792841063 + }, + "expected": { + "participation": 0.37173621674013835, + "days": 1.447846572682685, + "hours": 10.94364602719194 + } + }, + { + "grouping": "region", + "group": "1", + "n": 929, + "observed": { + "participation": 0.4988625902951673, + "days": 2.101321934458425, + "hours": 14.697745432365767 + }, + "expected": { + "participation": 0.5341920187102704, + "days": 2.234373766910041, + "hours": 15.515545077772881 + } + }, + { + "grouping": "region", + "group": "2", + "n": 1654, + "observed": { + "participation": 0.495642471526947, + "days": 1.9378635600824832, + "hours": 14.438707404977198 + }, + "expected": { + "participation": 0.48657470779470846, + "days": 1.9053160452954483, + "hours": 13.830397580793818 + } + }, + { + "grouping": "region", + "group": "3", + "n": 2752, + "observed": { + "participation": 0.4310162776090592, + "days": 1.7482660126296112, + "hours": 14.16760866653331 + }, + "expected": { + "participation": 0.4254047590539008, + "days": 1.728432288982956, + "hours": 13.771990873343658 + } + }, + { + "grouping": "region", + "group": "4", + "n": 2125, + "observed": { + "participation": 0.470872102608504, + "days": 1.872465315119329, + "hours": 13.875678601794997 + }, + "expected": { + "participation": 0.46546295898430057, + "days": 1.857723153971244, + "hours": 13.833112421687238 + } + }, + { + "grouping": "parent_work_status", + "group": "-1", + "n": 122, + "observed": { + "participation": 0.34614706740243706, + "days": 1.1849281571656916, + "hours": 9.788566562075097 + }, + "expected": { + "participation": 0.373389275855184, + "days": 1.462386368172592, + "hours": 12.574282386813668 + } + }, + { + "grouping": "parent_work_status", + "group": "0", + "n": 1016, + "observed": { + "participation": 0.3096578455166947, + "days": 1.244408501915661, + "hours": 10.193456359940383 + }, + "expected": { + "participation": 0.2882996076692788, + "days": 1.1762845771341546, + "hours": 10.282450861819337 + } + }, + { + "grouping": "parent_work_status", + "group": "1", + "n": 2418, + "observed": { + "participation": 0.2864480974767621, + "days": 0.9529380212414282, + "hours": 6.42952602558992 + }, + "expected": { + "participation": 0.29059369126489437, + "days": 0.9858655333196232, + "hours": 6.764091600272923 + } + }, + { + "grouping": "parent_work_status", + "group": "2", + "n": 3904, + "observed": { + "participation": 0.5991891288528669, + "days": 2.535220374688929, + "hours": 19.536646150926547 + }, + "expected": { + "participation": 0.6008699918772364, + "days": 2.528223299633135, + "hours": 18.96579429859326 + } + }, + { + "grouping": "income_band", + "group": "0", + "n": 76, + "observed": { + "participation": 0.19070472825408744, + "days": 0.8431547354115522, + "hours": 5.587881885800679 + }, + "expected": { + "participation": 0.25300464764173586, + "days": 0.9988467887623982, + "hours": 7.43593331362669 + } + }, + { + "grouping": "income_band", + "group": "1", + "n": 1378, + "observed": { + "participation": 0.35684525807866907, + "days": 1.5280931021110342, + "hours": 12.098088591903252 + }, + "expected": { + "participation": 0.3773650597658377, + "days": 1.627338456412184, + "hours": 12.706694579809993 + } + }, + { + "grouping": "income_band", + "group": "2", + "n": 1922, + "observed": { + "participation": 0.4194011939997811, + "days": 1.7068232976926216, + "hours": 13.491053608546364 + }, + "expected": { + "participation": 0.4119472083085292, + "days": 1.7030609232530567, + "hours": 13.262000601507708 + } + }, + { + "grouping": "income_band", + "group": "3", + "n": 1632, + "observed": { + "participation": 0.4246978564102466, + "days": 1.7238735833385048, + "hours": 14.076591113511121 + }, + "expected": { + "participation": 0.4255788471352766, + "days": 1.704797441331804, + "hours": 13.264862389978802 + } + }, + { + "grouping": "income_band", + "group": "4", + "n": 1977, + "observed": { + "participation": 0.5221816116808028, + "days": 1.9968956951019248, + "hours": 14.35832226780555 + }, + "expected": { + "participation": 0.519705526319959, + "days": 1.9988673657729517, + "hours": 14.55106672367201 + } + }, + { + "grouping": "income_band", + "group": "5", + "n": 475, + "observed": { + "participation": 0.6883939484468758, + "days": 2.9203317046618578, + "hours": 20.476264713601847 + }, + "expected": { + "participation": 0.6762909354194406, + "days": 2.8292574855634296, + "hours": 19.43897806431697 + } + } + ], + "matching_levels": { + "age,region,parent_work_status,income_band": 7278, + "age,parent_work_status,income_band": 150, + "age,parent_work_status": 32 + }, + "sibling_validation": [ + { + "fold": 0, + "training_rho": 0.7504775690168417, + "households": 351, + "weight": 1627200.3809817089, + "observed_both": 0.3346110552302055, + "independent_both": 0.26023741618799584, + "coupled_both": 0.3228394147816889 + }, + { + "fold": 1, + "training_rho": 0.8095401305423818, + "households": 367, + "weight": 1640369.17044373, + "observed_both": 0.308478237709926, + "independent_both": 0.2538314963354507, + "coupled_both": 0.31777192913378116 + }, + { + "fold": 2, + "training_rho": 0.7176223341350483, + "households": 443, + "weight": 1849383.6729044288, + "observed_both": 0.3831182075641927, + "independent_both": 0.260592140353083, + "coupled_both": 0.3144997720634755 + }, + { + "fold": 3, + "training_rho": 0.8946850037821993, + "households": 398, + "weight": 1567825.4608580691, + "observed_both": 0.2954259187077949, + "independent_both": 0.2551329149477867, + "coupled_both": 0.3186981148017382 + }, + { + "fold": 4, + "training_rho": 0.8022505236076816, + "households": 382, + "weight": 1644777.832273697, + "observed_both": 0.3129856591731878, + "independent_both": 0.2695651435301845, + "coupled_both": 0.3411406780146054 + } + ], + "questionnaire_transport": [ + { + "questionnaire_version": 2, + "scored_children": 1690, + "unsupported_children": 0, + "observed": { + "regular_participation": 0.4166998042800092, + "regular_hours_per_week": 12.379208437570716 + }, + "expected": { + "regular_participation": 0.429264128691119, + "regular_hours_per_week": 14.800674181069196 + } + }, + { + "questionnaire_version": 3, + "scored_children": 1356, + "unsupported_children": 0, + "observed": { + "regular_participation": 0.38447915314763226, + "regular_hours_per_week": 10.163827277430636 + }, + "expected": { + "regular_participation": 0.40786334693307874, + "regular_hours_per_week": 13.921490221932158 + } + } + ], + "assumptions": [ + "Calendar selection is ignorable conditional on matching fields; not identified from these data.", + "Main reference-week schedules transfer to May/fall typical weeks; summer attendance is not observed.", + "Regular-care comparisons cannot validate days or irregular care in instruments without calendars." + ], + "production_ready": false + }, + "masked_calendar_validation": { + "seed": 161803, + "design": "whole-household masked-calendar test; regular weekly hours remain observed", + "comparisons": [ + { + "grouping": "all", + "group": "all", + "n": 1581, + "observed_days": 1.7176113066572272, + "imputed_days": 1.7931671544992573, + "observed_hours": 13.097316141278531, + "imputed_hours": 13.161738723028055 + }, + { + "grouping": "age", + "group": "0", + "n": 104, + "observed_days": 1.841126169101498, + "imputed_days": 1.757972840808916, + "observed_hours": 17.766331967357488, + "imputed_hours": 18.04127357697798 + }, + { + "grouping": "age", + "group": "1", + "n": 113, + "observed_days": 2.37969546844872, + "imputed_days": 2.466724275790995, + "observed_hours": 19.829328945193588, + "imputed_hours": 19.122886717221327 + }, + { + "grouping": "age", + "group": "2", + "n": 141, + "observed_days": 2.4591773765558673, + "imputed_days": 2.5150278262191854, + "observed_hours": 22.536051090399965, + "imputed_hours": 22.20070627284854 + }, + { + "grouping": "age", + "group": "3", + "n": 123, + "observed_days": 2.3763627081083216, + "imputed_days": 2.276649667113583, + "observed_hours": 20.251977914853146, + "imputed_hours": 19.002839959330025 + }, + { + "grouping": "age", + "group": "4", + "n": 115, + "observed_days": 3.137397964036117, + "imputed_days": 3.2507274717120613, + "observed_hours": 23.68360614421261, + "imputed_hours": 24.493916641155817 + }, + { + "grouping": "age", + "group": "5", + "n": 113, + "observed_days": 2.2242008794879244, + "imputed_days": 2.6293843819994196, + "observed_hours": 15.760856040214335, + "imputed_hours": 17.46780844312604 + }, + { + "grouping": "age", + "group": "6", + "n": 130, + "observed_days": 1.1830651060264654, + "imputed_days": 1.4124105587435267, + "observed_hours": 7.042175416036001, + "imputed_hours": 6.515374725210956 + }, + { + "grouping": "age", + "group": "7", + "n": 131, + "observed_days": 1.4073709771017413, + "imputed_days": 1.2967131682238184, + "observed_hours": 10.083939201157254, + "imputed_hours": 9.618996783594744 + }, + { + "grouping": "age", + "group": "8", + "n": 126, + "observed_days": 1.057579033652681, + "imputed_days": 1.0820232296805903, + "observed_hours": 8.256788366496435, + "imputed_hours": 6.9299612873656375 + }, + { + "grouping": "age", + "group": "9", + "n": 118, + "observed_days": 1.4349301372689758, + "imputed_days": 1.2570443106530333, + "observed_hours": 10.733568940718998, + "imputed_hours": 11.528485757775337 + }, + { + "grouping": "age", + "group": "10", + "n": 124, + "observed_days": 1.2058459898990705, + "imputed_days": 1.2067301677274491, + "observed_hours": 4.1774445652404655, + "imputed_hours": 4.342805855105561 + }, + { + "grouping": "age", + "group": "11", + "n": 120, + "observed_days": 0.9483350107584563, + "imputed_days": 1.2273618861530076, + "observed_hours": 5.566349482238208, + "imputed_hours": 6.3416466466885835 + }, + { + "grouping": "age", + "group": "12", + "n": 123, + "observed_days": 1.1181905452629102, + "imputed_days": 1.3377626847259545, + "observed_hours": 8.079018679724042, + "imputed_hours": 9.278796503817835 + }, + { + "grouping": "parent_work_status", + "group": "-1", + "n": 33, + "observed_days": 1.5430497710033617, + "imputed_days": 1.3274872915746017, + "observed_hours": 12.754941207431992, + "imputed_hours": 12.147679308677683 + }, + { + "grouping": "parent_work_status", + "group": "0", + "n": 233, + "observed_days": 1.3163214930511598, + "imputed_days": 1.4661772450887058, + "observed_hours": 9.57367968242547, + "imputed_hours": 9.490248507911081 + }, + { + "grouping": "parent_work_status", + "group": "1", + "n": 529, + "observed_days": 0.8935323002915262, + "imputed_days": 1.0535312696492358, + "observed_hours": 6.370457810059637, + "imputed_hours": 7.0815725747740155 + }, + { + "grouping": "parent_work_status", + "group": "2", + "n": 786, + "observed_days": 2.3152602893352414, + "imputed_days": 2.332856367184494, + "observed_hours": 17.994069548324816, + "imputed_hours": 17.722049473088507 + } + ], + "regular_hours_preserved": true, + "limitations": "Tests reconstruction where calendars exist; not a direct test of unobserved days in the other questionnaire instruments." + }, + "sibling_schedule_validation": { + "design": "five household-separated folds; exact integration of the implemented shared-rank donor CDFs", + "seed": 271828, + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "training_rho": [ + 0.7504775690168417, + 0.8095401305423818, + 0.7176223341350483, + 0.8946850037821993, + 0.8022505236076816 + ], + "youngest_pairs": { + "households": 1941, + "household_weight": 8329556.517461634, + "observed": { + "participation": { + "joint_product": 0.3285886986591048, + "correlation": 0.577510777815278 + }, + "days": { + "joint_product": 5.9171615700449145, + "correlation": 0.5798886366650429 + }, + "weekly_hours": { + "joint_product": 367.6804958137289, + "correlation": 0.523457187358221 + } + }, + "independent": { + "participation": { + "joint_product": 0.2599357218299179, + "correlation": 0.14356484664250233 + }, + "days": { + "joint_product": 4.562554958882675, + "correlation": 0.1514064619097721 + }, + "weekly_hours": { + "joint_product": 274.5482618143516, + "correlation": 0.1290575794049498 + } + }, + "coupled": { + "participation": { + "joint_product": 0.3228241594928079, + "correlation": 0.39662161163709453 + }, + "days": { + "joint_product": 6.168391228908872, + "correlation": 0.44224735414975214 + }, + "weekly_hours": { + "joint_product": 393.50536137310974, + "correlation": 0.35635277128820114 + } + } + }, + "youngest_pairs_in_3plus_households": { + "households": 661, + "household_weight": 2458669.150522002, + "observed": { + "participation": { + "joint_product": 0.2728957065164463, + "correlation": 0.5341073068866067 + }, + "days": { + "joint_product": 5.084876229689592, + "correlation": 0.5617680576612079 + }, + "weekly_hours": { + "joint_product": 337.34705105325276, + "correlation": 0.5623528715201395 + } + }, + "independent": { + "participation": { + "joint_product": 0.26594831103314626, + "correlation": 0.1768906778018396 + }, + "days": { + "joint_product": 4.755017625871223, + "correlation": 0.1796772530434437 + }, + "weekly_hours": { + "joint_product": 288.78160178706247, + "correlation": 0.15022942733210107 + } + }, + "coupled": { + "participation": { + "joint_product": 0.32461663032314914, + "correlation": 0.41320572283269663 + }, + "days": { + "joint_product": 6.243213912824172, + "correlation": 0.44765187465853035 + }, + "weekly_hours": { + "joint_product": 406.53469377347056, + "correlation": 0.3715598543103152 + } + } + }, + "larger_households": { + "households": 661, + "observed": { + "mean_total_days": 4.509647234214243, + "mean_total_weekly_hours": 33.085374473048084, + "sd_total_days": 5.765302178946849, + "sd_total_weekly_hours": 56.21651776123905, + "all_children_attend": 0.18568592787006075 + }, + "independent": { + "mean_total_days": 5.652805180994538, + "mean_total_weekly_hours": 40.814235235209445, + "sd_total_days": 4.742171858563125, + "sd_total_weekly_hours": 43.69183090611876, + "all_children_attend": 0.10870430564775237 + }, + "coupled": { + "mean_total_days": 5.652805180994538, + "mean_total_weekly_hours": 40.814235235209445, + "sd_total_days": 5.826012333228911, + "sd_total_weekly_hours": 52.0732028760817, + "all_children_attend": 0.19850142013240785 + } + }, + "production_ready": false, + "diagnostic_screen": { + "passed": false, + "checks": [ + { + "metric": "youngest_pairs.participation.joint_product", + "absolute_gap": 0.005764539166296878, + "relative": false, + "limit": 0.05, + "passed": true + }, + { + "metric": "youngest_pairs.days.correlation", + "absolute_gap": 0.13764128251529073, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs.weekly_hours.correlation", + "absolute_gap": 0.16710441607001986, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs.days.joint_product", + "absolute_gap": 0.04245779938404666, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs.weekly_hours.joint_product", + "absolute_gap": 0.07023724634135614, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "youngest_pairs_in_3plus_households.participation.joint_product", + "absolute_gap": 0.051720923806702845, + "relative": false, + "limit": 0.05, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.days.correlation", + "absolute_gap": 0.11411618300267751, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.correlation", + "absolute_gap": 0.19079301720982428, + "relative": false, + "limit": 0.1, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.days.joint_product", + "absolute_gap": 0.22780056599436455, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "youngest_pairs_in_3plus_households.weekly_hours.joint_product", + "absolute_gap": 0.20509336751041, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.mean_total_days", + "absolute_gap": 0.2534916563112233, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.mean_total_weekly_hours", + "absolute_gap": 0.23360354492760613, + "relative": true, + "limit": 0.2, + "passed": false + }, + { + "metric": "larger_households.sd_total_days", + "absolute_gap": 0.010530264051684455, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.sd_total_weekly_hours", + "absolute_gap": 0.07370280213290151, + "relative": true, + "limit": 0.2, + "passed": true + }, + { + "metric": "larger_households.all_children_attend", + "absolute_gap": 0.0128154922623471, + "relative": false, + "limit": 0.05, + "passed": true + } + ], + "interpretation": "provisional diagnostic screens; not publication authorization" + } + }, + "noncalendar_bridge": { + "seed": 915, + "completed_children": 3046, + "unsupported_children": 0, + "observed": "regular weekly hours from May/fall questionnaire", + "imputed": "attended days and irregular care jointly from nearest regular-hour calendar donors", + "assumption": "conditional calendar pattern and irregular care transfer across questionnaire instruments" + }, + "candidate_frame_written": true, + "environment": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "microcosm-build": "0.1.0", + "microcosm-frame": "0.1.0", + "policyengine-us": "1.819.0", + "python": "3.13.5" + }, + "code_sha256": { + "prepare_us_childcare_attendance.py": "ca4f504a652a9005f692cbd008f430fff0a25bbe32629b75eca80f0be0c7fa51", + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "nsece_childcare.py": "affc8ac5a3ce853e2ef8b062c51a1801a15573cbcbf6eacc2c093334a1d12c11", + "nsece_childcare_bridge.py": "70a7edea8b28c6da21ff4fa9bb220766a3e6cd714926684af29bdba1a8421b0a", + "nsece_childcare_sibling_validation.py": "791cf8171b9a673889d42ea9d43cf7396364a097308ae156acbb66b19a4523b1", + "nsece_childcare_dependence.py": "bf9ff3a1992d16c75fc74b8c17634791739669f0ecab4382fdf59a6e6c3c424c", + "childcare_attendance_stage.py": "42e777b0edfc813d79204bc2932fe429d6a48cd2866397560a7386cbee54dadb", + "childcare_attendance_receipt.py": "0950fce7f372ca4b240cd055c931f5f8fe070223fd68504a3ea9cfbc4e16c645", + "childcare_sensitivity.py": "a3d370bcaf78b609d81c542dc774b7dab0202ea02f53f80135417320840e06ac", + "nsece_childcare_assessment.py": "537d5d839ce9df4f1772ee887597811990aab5b7f10a863b70fe6630583fa3b7", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "childcare.py": "a8502e1fc15457a7f120936a8940fbb51cba3e2299d92ca9cd69b749f6deea2f", + "childcare_attendance_source.json": "c5beeeb09ab330c305e3250bc7db5a5003336d26fa508872211cb18958ab9e97", + "education_assistance_source.py": "e259e3fce64fdcab62953f79a1aa41719f81c64c7c5dc1a63f8b1e493ff5f83a", + "geography_constants.py": "dc31ec6aa913d638d51ccc8e3fda11edee6c3f508ea5d2e27690bdb43e081fd2", + "uv.lock": "751d5ef5d25406bbae1798667f0e29890d4aad933d323c12912c7d45d8809bb9" + }, + "candidate_checkpoint_sha256": "e9d363aa5a10a611c751c704017edd47c6ec8c2ba583bb7124b27514ba15d69e", + "parent_population_sha256": "48b9d479fb4fd1c3537f9383ce4697d130b6f618658409d74f6233c43b994c7e", + "production_stage_executed": true, + "candidate_receipts": { + "nsece_childcare_attendance": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ], + "noncalendar_bridge": { + "seed": 915, + "completed_children": 3046, + "unsupported_children": 0, + "observed": "regular weekly hours from May/fall questionnaire", + "imputed": "attended days and irregular care jointly from nearest regular-hour calendar donors", + "assumption": "conditional calendar pattern and irregular care transfer across questionnaire instruments" + }, + "seed": 915, + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "fallback_match_columns": [ + [ + "age", + "parent_work_status", + "income_band" + ], + [ + "age", + "parent_work_status" + ], + [ + "age" + ] + ], + "sibling_dependence": 0.7413149380294699, + "candidate_only": true + }, + "childcare_predictor_harmonization": { + "source": "ASEC resident parent line pointers", + "parent_universe": "parents of any child age 0 through 12 in household", + "work_measure": "hours_worked_last_week > 0", + "geography": "Census region from target state_fips", + "income_source_receipts": [ + { + "income_year": 2022, + "sha256": "19b56537e50e7663f954361ef2bb5ce9cef8d9d45f156fe1a69a99b654198ffe", + "matched_people": 54464, + "source_rows": 146133 + }, + { + "income_year": 2023, + "sha256": "21a2b9e0e4b08534563578a45acad77868af4ae9a7d46f23776b707d4a559aa7", + "matched_people": 54654, + "source_rows": 144265 + }, + { + "income_year": 2024, + "sha256": "06921fe83fc66c907e6c7b86b82255dc70458ee7d76258fc48297cb34f0c06b5", + "matched_people": 57203, + "source_rows": 142125 + } + ], + "income": "Household sum of measured ASEC PTOTVAL, CPI-U adjusted from source year to 2023 dollars" + }, + "childcare_outside_domain_baseline": { + "engine_version": "1.819.0", + "values": { + "childcare_attending_days_per_month": 0.0, + "childcare_days_per_week": 0.0, + "childcare_hours_per_day": 0.0 + }, + "inherited_counts": { + "childcare_attending_days_per_month": 134432, + "childcare_days_per_week": 134432, + "childcare_hours_per_day": 134432 + }, + "interpretation": "baseline retained; not evidence of nonattendance outside ages 0-12" + }, + "childcare_attendance_stage": { + "stage": "nsece_childcare_attendance", + "outputs": [ + "childcare_attending_days_per_month", + "childcare_days_per_week", + "childcare_hours_per_day" + ], + "seed": 915, + "operations": [ + { + "kind": "derive_childcare_inputs", + "operation": "calendar_attendance", + "age_min": 0, + "age_max": 12 + }, + { + "kind": "fit", + "operation": "fit_sibling_dependence", + "rho": 0.7413149380294699 + }, + { + "kind": "derive_childcare_inputs", + "operation": "regular_hours_schedule_bridge", + "nearest_donors": 10 + }, + { + "kind": "derive", + "operation": "harmonize_asec_childcare_predictors" + }, + { + "kind": "derive_childcare_inputs", + "operation": "joint_weighted_schedule_transfer", + "preserve_observed": true + }, + { + "kind": "export_policy", + "operation": "inherit_engine_baseline" + } + ], + "sibling_dependence": { + "rho": 0.7413149380294699, + "unconstrained_rho": 0.7413149380294699, + "households": 1941, + "observed_both_in_care": 0.32858869865910467, + "independent_both_in_care": 0.2585427028841666, + "shared_both_in_care": 0.3530315526045447, + "estimation": "youngest pair in fully observed households; household design weights" + }, + "modeled_age_domain": [ + 0, + 12 + ], + "outside_domain_policy": "inherit_engine_baseline" + }, + "childcare_attendance_binding": { + "schema_version": 1, + "binding_sha256": "db79754d13221f083d9ee56bd2efbc293039790468c8145ceea4755aa3b21d41", + "execution_sha256": "24a6971551002db8dc279f0f352cd16675101f5e668f3b04af16ce8c3411dfa8", + "source_people": 166321, + "retained_people": 166321, + "execution": { + "recipe": { + "contract_sha256": "ae648c6cb0e2838fdf142975e9c536eb0683d9630fd1738096d524222ffb01dc", + "runtime_versions": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "policyengine-us": "1.819.0" + }, + "code_sha256": { + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "nsece_childcare.py": "affc8ac5a3ce853e2ef8b062c51a1801a15573cbcbf6eacc2c093334a1d12c11", + "nsece_childcare_bridge.py": "70a7edea8b28c6da21ff4fa9bb220766a3e6cd714926684af29bdba1a8421b0a", + "nsece_childcare_dependence.py": "bf9ff3a1992d16c75fc74b8c17634791739669f0ecab4382fdf59a6e6c3c424c", + "childcare_attendance_stage.py": "42e777b0edfc813d79204bc2932fe429d6a48cd2866397560a7386cbee54dadb", + "childcare_attendance_receipt.py": "0950fce7f372ca4b240cd055c931f5f8fe070223fd68504a3ea9cfbc4e16c645" + } + }, + "context": { + "nsece_childcare_attendance": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ], + "noncalendar_bridge": { + "seed": 915, + "completed_children": 3046, + "unsupported_children": 0, + "observed": "regular weekly hours from May/fall questionnaire", + "imputed": "attended days and irregular care jointly from nearest regular-hour calendar donors", + "assumption": "conditional calendar pattern and irregular care transfer across questionnaire instruments" + }, + "seed": 915, + "match_columns": [ + "age", + "region", + "parent_work_status", + "income_band" + ], + "fallback_match_columns": [ + [ + "age", + "parent_work_status", + "income_band" + ], + [ + "age", + "parent_work_status" + ], + [ + "age" + ] + ], + "sibling_dependence": 0.7413149380294699, + "candidate_only": true + }, + "childcare_predictor_harmonization": { + "source": "ASEC resident parent line pointers", + "parent_universe": "parents of any child age 0 through 12 in household", + "work_measure": "hours_worked_last_week > 0", + "geography": "Census region from target state_fips", + "income_source_receipts": [ + { + "income_year": 2022, + "sha256": "19b56537e50e7663f954361ef2bb5ce9cef8d9d45f156fe1a69a99b654198ffe", + "matched_people": 54464, + "source_rows": 146133 + }, + { + "income_year": 2023, + "sha256": "21a2b9e0e4b08534563578a45acad77868af4ae9a7d46f23776b707d4a559aa7", + "matched_people": 54654, + "source_rows": 144265 + }, + { + "income_year": 2024, + "sha256": "06921fe83fc66c907e6c7b86b82255dc70458ee7d76258fc48297cb34f0c06b5", + "matched_people": 57203, + "source_rows": 142125 + } + ], + "income": "Household sum of measured ASEC PTOTVAL, CPI-U adjusted from source year to 2023 dollars" + }, + "childcare_outside_domain_baseline": { + "engine_version": "1.819.0", + "values": { + "childcare_attending_days_per_month": 0.0, + "childcare_days_per_week": 0.0, + "childcare_hours_per_day": 0.0 + }, + "inherited_counts": { + "childcare_attending_days_per_month": 134432, + "childcare_days_per_week": 134432, + "childcare_hours_per_day": 134432 + }, + "interpretation": "baseline retained; not evidence of nonattendance outside ages 0-12" + }, + "childcare_attendance_stage": { + "stage": "nsece_childcare_attendance", + "outputs": [ + "childcare_attending_days_per_month", + "childcare_days_per_week", + "childcare_hours_per_day" + ], + "seed": 915, + "operations": [ + { + "kind": "derive_childcare_inputs", + "operation": "calendar_attendance", + "age_min": 0, + "age_max": 12 + }, + { + "kind": "fit", + "operation": "fit_sibling_dependence", + "rho": 0.7413149380294699 + }, + { + "kind": "derive_childcare_inputs", + "operation": "regular_hours_schedule_bridge", + "nearest_donors": 10 + }, + { + "kind": "derive", + "operation": "harmonize_asec_childcare_predictors" + }, + { + "kind": "derive_childcare_inputs", + "operation": "joint_weighted_schedule_transfer", + "preserve_observed": true + }, + { + "kind": "export_policy", + "operation": "inherit_engine_baseline" + } + ], + "sibling_dependence": { + "rho": 0.7413149380294699, + "unconstrained_rho": 0.7413149380294699, + "households": 1941, + "observed_both_in_care": 0.32858869865910467, + "independent_both_in_care": 0.2585427028841666, + "shared_both_in_care": 0.3530315526045447, + "estimation": "youngest pair in fully observed households; household design weights" + }, + "modeled_age_domain": [ + 0, + 12 + ], + "outside_domain_policy": "inherit_engine_baseline" + } + } + } + } + }, + "native_candidate_written": true, + "native_candidate_sha256": "937c0c0c9798f0cf9e015fc4d5bed204342480bf93a415d94d3080d66f20cb6f" +} diff --git a/experiments/us-childcare-attendance/review-transport-sensitivity.json b/experiments/us-childcare-attendance/review-transport-sensitivity.json new file mode 100644 index 000000000..5e344b69b --- /dev/null +++ b/experiments/us-childcare-attendance/review-transport-sensitivity.json @@ -0,0 +1,3214 @@ +{ + "parent_sha256": "48b9d479fb4fd1c3537f9383ce4697d130b6f618658409d74f6233c43b994c7e", + "source": { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": false, + "artifacts": [ + { + "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2", + "size_bytes": 122764947 + }, + { + "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e", + "size_bytes": 269542239 + } + ] + }, + "recipe": { + "contract_sha256": "ae648c6cb0e2838fdf142975e9c536eb0683d9630fd1738096d524222ffb01dc", + "runtime_versions": { + "numpy": "2.4.6", + "pandas": "3.0.3", + "policyengine-us": "1.819.0" + }, + "code_sha256": { + "childcare_attendance.py": "da00ef1fb45232a731bd4a3b33d93cd0aeac0682b28d50e4d53cb79db12ce96e", + "childcare_population.py": "19fef5e4cc1838734783c2eb911f556596256cf093fb1063a403a6eadf49d04e", + "nsece_childcare.py": "affc8ac5a3ce853e2ef8b062c51a1801a15573cbcbf6eacc2c093334a1d12c11", + "nsece_childcare_bridge.py": "70a7edea8b28c6da21ff4fa9bb220766a3e6cd714926684af29bdba1a8421b0a", + "nsece_childcare_dependence.py": "bf9ff3a1992d16c75fc74b8c17634791739669f0ecab4382fdf59a6e6c3c424c", + "childcare_attendance_stage.py": "8705b891c1bcbab8eb852d1b15c3dd51c496ceabd08924dfbe193d85c79edc2c", + "childcare_attendance_receipt.py": "2e914760d6012878d15bf32c4ca24426bb6fbbf86345b939a7945b4cdf0a251c" + } + }, + "seed": 915, + "engine_version": "1.819.0", + "policy_year": 2026, + "code_sha256": { + "validate_us_childcare_sensitivity.py": "59d41bf8b6192f9d4d01976e9a3b464446ade56d67f7493cb611ef3d8c01d07c", + "childcare_sensitivity.py": "a3d370bcaf78b609d81c542dc774b7dab0202ea02f53f80135417320840e06ac" + }, + "population": "fixed BuildP source ages/incomes; no aging or uprating", + "assumptions": { + "candidate": {}, + "no_modeled_irregular_hours": { + "include_modeled_irregular_hours": false, + "modeled_day_shift": 0, + "measured_regular_hours_preserved": true + }, + "one_fewer_day": { + "include_modeled_irregular_hours": true, + "modeled_day_shift": -1, + "measured_regular_hours_preserved": true + }, + "one_more_day": { + "include_modeled_irregular_hours": true, + "modeled_day_shift": 1, + "measured_regular_hours_preserved": true + } + }, + "changed_children": { + "candidate": 0, + "no_modeled_irregular_hours": 1809, + "one_fewer_day": 5705, + "one_more_day": 6683 + }, + "screens": { + "national_relative_change": 0.1, + "state_relative_change": 0.2 + }, + "states": [ + { + "state": "AL", + "sample_households": 1061, + "baseline": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13061.764184842585, + "annual_modeled_benefits": 32688921.398814265 + }, + "no_modeled_irregular_hours": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13061.764184842585, + "annual_modeled_benefits": 32688921.398814265 + }, + "one_fewer_day": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13061.764184842585, + "annual_modeled_benefits": 32688921.398814265 + }, + "one_more_day": { + "variable": "al_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13061.764184842585, + "annual_modeled_benefits": 32688921.398814265 + } + }, + { + "state": "AK", + "sample_households": 826, + "baseline": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + }, + "candidate": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + }, + "no_modeled_irregular_hours": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + }, + "one_fewer_day": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + }, + "one_more_day": { + "variable": "ak_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 1390.1623900386767, + "annual_modeled_benefits": 6435797.486872292 + } + }, + { + "state": "AZ", + "sample_households": 1164, + "baseline": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 18733.37486637244, + "annual_modeled_benefits": 23159527.697095435 + }, + "no_modeled_irregular_hours": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18733.29978438327, + "annual_modeled_benefits": 23159479.981134396 + }, + "one_fewer_day": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 18733.37486637244, + "annual_modeled_benefits": 23159508.09361713 + }, + "one_more_day": { + "variable": "az_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 18733.37486637244, + "annual_modeled_benefits": 22260467.45209273 + } + }, + { + "state": "AR", + "sample_households": 952, + "baseline": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 17289.894029146235, + "annual_modeled_benefits": 50793417.58586023 + }, + "no_modeled_irregular_hours": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 17289.87330874073, + "annual_modeled_benefits": 50793412.084522665 + }, + "one_fewer_day": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 17289.894029146235, + "annual_modeled_benefits": 47298738.19780214 + }, + "one_more_day": { + "variable": "ar_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 17289.894029146235, + "annual_modeled_benefits": 73116589.09583077 + } + }, + { + "state": "CA", + "sample_households": 2659, + "baseline": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "no_modeled_irregular_hours": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "one_fewer_day": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "one_more_day": { + "variable": "ca_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + } + }, + { + "state": "CO", + "sample_households": 1164, + "baseline": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 19, + "weighted_positive_units": 30914.695305580855, + "annual_modeled_benefits": 252602567.65021172 + }, + "candidate": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18502.53110225743, + "annual_modeled_benefits": 236445530.32343873 + }, + "no_modeled_irregular_hours": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 18502.54616478004, + "annual_modeled_benefits": 236445566.4573961 + }, + "one_fewer_day": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18502.53110225743, + "annual_modeled_benefits": 236445530.32343873 + }, + "one_more_day": { + "variable": "co_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 18502.53110225743, + "annual_modeled_benefits": 236445530.32343873 + } + }, + { + "state": "CT", + "sample_households": 908, + "baseline": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 405879416.70427954 + }, + "candidate": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 636244010.8081238 + }, + "no_modeled_irregular_hours": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 636244010.8081238 + }, + "one_fewer_day": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 636244010.8081238 + }, + "one_more_day": { + "variable": "ct_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 23, + "weighted_positive_units": 79449.487583021, + "annual_modeled_benefits": 636244010.8081238 + } + }, + { + "state": "DE", + "sample_households": 1068, + "baseline": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + }, + "candidate": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + }, + "no_modeled_irregular_hours": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + }, + "one_fewer_day": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + }, + "one_more_day": { + "variable": "de_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 13026.181364486925, + "annual_modeled_benefits": 42150126.00852959 + } + }, + { + "state": "DC", + "sample_households": 551, + "baseline": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 3288.0395223266023, + "annual_modeled_benefits": 23916792.31200898 + }, + "no_modeled_irregular_hours": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 3288.0395223266023, + "annual_modeled_benefits": 23916792.31200898 + }, + "one_fewer_day": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 3288.0395223266023, + "annual_modeled_benefits": 23916792.31200898 + }, + "one_more_day": { + "variable": "dc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 3288.0395223266023, + "annual_modeled_benefits": 23916792.31200898 + } + }, + { + "state": "FL", + "sample_households": 1642, + "baseline": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 87314.34071851184, + "annual_modeled_benefits": 336693781.677099 + }, + "no_modeled_irregular_hours": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 76833.30946851184, + "annual_modeled_benefits": 320195353.52476215 + }, + "one_fewer_day": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 60231.18556508084, + "annual_modeled_benefits": 320401507.8530382 + }, + "one_more_day": { + "variable": "fl_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 60231.18556508084, + "annual_modeled_benefits": 324178392.2600601 + } + }, + { + "state": "GA", + "sample_households": 1215, + "baseline": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + }, + "candidate": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + }, + "no_modeled_irregular_hours": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + }, + "one_fewer_day": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + }, + "one_more_day": { + "variable": "ga_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 13, + "weighted_positive_units": 28445.463818153017, + "annual_modeled_benefits": 130565867.0594202 + } + }, + { + "state": "HI", + "sample_households": 838, + "baseline": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 2554.6082648136944, + "annual_modeled_benefits": 15688867.198366832 + }, + "no_modeled_irregular_hours": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 2554.6082648136944, + "annual_modeled_benefits": 15688867.198366832 + }, + "one_fewer_day": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 2554.6082648136944, + "annual_modeled_benefits": 15688867.198366832 + }, + "one_more_day": { + "variable": "hi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 2554.6082648136944, + "annual_modeled_benefits": 15688867.198366832 + } + }, + { + "state": "ID", + "sample_households": 746, + "baseline": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 2, + "weighted_positive_units": 2335.738774359226, + "annual_modeled_benefits": 10651259.924815893 + }, + "no_modeled_irregular_hours": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 2, + "weighted_positive_units": 2335.738774359226, + "annual_modeled_benefits": 10651259.924815893 + }, + "one_fewer_day": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 2, + "weighted_positive_units": 2335.738774359226, + "annual_modeled_benefits": 10651259.924815893 + }, + "one_more_day": { + "variable": "id_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 2, + "weighted_positive_units": 2335.738774359226, + "annual_modeled_benefits": 10651167.105942965 + } + }, + { + "state": "IL", + "sample_households": 1668, + "baseline": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 62767.78443156066, + "annual_modeled_benefits": 196786246.13666055 + }, + "no_modeled_irregular_hours": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 62767.78443156066, + "annual_modeled_benefits": 196786246.13666055 + }, + "one_fewer_day": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 62767.78443156066, + "annual_modeled_benefits": 196786122.30308777 + }, + "one_more_day": { + "variable": "il_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 62767.78443156066, + "annual_modeled_benefits": 196786118.53858995 + } + }, + { + "state": "IN", + "sample_households": 1141, + "baseline": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + }, + "candidate": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + }, + "no_modeled_irregular_hours": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + }, + "one_fewer_day": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + }, + "one_more_day": { + "variable": "in_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 20, + "weighted_positive_units": 9694.763750434155, + "annual_modeled_benefits": 25856735.988747887 + } + }, + { + "state": "IA", + "sample_households": 973, + "baseline": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13277.069981029548, + "annual_modeled_benefits": 54542065.75748161 + }, + "no_modeled_irregular_hours": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13277.069981029548, + "annual_modeled_benefits": 54542065.75748161 + }, + "one_fewer_day": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13277.069981029548, + "annual_modeled_benefits": 87267295.53406624 + }, + "one_more_day": { + "variable": "ia_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 13277.069981029548, + "annual_modeled_benefits": 54542065.75748161 + } + }, + { + "state": "KS", + "sample_households": 921, + "baseline": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 21785.09440057905, + "annual_modeled_benefits": 57457564.33302226 + }, + "no_modeled_irregular_hours": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 21785.09440057905, + "annual_modeled_benefits": 57457564.33302226 + }, + "one_fewer_day": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 21785.09440057905, + "annual_modeled_benefits": 29101934.00209515 + }, + "one_more_day": { + "variable": "ks_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 21785.09440057905, + "annual_modeled_benefits": 58709158.015559085 + } + }, + { + "state": "KY", + "sample_households": 776, + "baseline": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.02885724022053182, + "annual_modeled_benefits": 147.92350896229354 + }, + "no_modeled_irregular_hours": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.02885724022053182, + "annual_modeled_benefits": 147.92350896229354 + }, + "one_fewer_day": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.02885724022053182, + "annual_modeled_benefits": 157.98810727270265 + }, + "one_more_day": { + "variable": "ky_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 0.02885724022053182, + "annual_modeled_benefits": 146.34993561158112 + } + }, + { + "state": "LA", + "sample_households": 1000, + "baseline": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 37176.93537535961, + "annual_modeled_benefits": 72842360.51107226 + }, + "no_modeled_irregular_hours": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 37176.93537535961, + "annual_modeled_benefits": 69024044.59310351 + }, + "one_fewer_day": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 37176.93812166341, + "annual_modeled_benefits": 72842353.11263487 + }, + "one_more_day": { + "variable": "la_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 37176.93537535961, + "annual_modeled_benefits": 72842360.51107226 + } + }, + { + "state": "ME", + "sample_households": 785, + "baseline": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683663.687080294 + }, + "candidate": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683670.942570195 + }, + "no_modeled_irregular_hours": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683670.942570195 + }, + "one_fewer_day": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683670.942570195 + }, + "one_more_day": { + "variable": "me_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 17, + "weighted_positive_units": 11874.206514407007, + "annual_modeled_benefits": 46683670.942570195 + } + }, + { + "state": "MD", + "sample_households": 1091, + "baseline": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "no_modeled_irregular_hours": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "one_fewer_day": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "one_more_day": { + "variable": "md_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + } + }, + { + "state": "MA", + "sample_households": 1522, + "baseline": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 0.0716373446630314, + "annual_modeled_benefits": 212.01572016369738 + }, + "no_modeled_irregular_hours": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 0.0716373446630314, + "annual_modeled_benefits": 212.01572016369738 + }, + "one_fewer_day": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 0.0716373446630314, + "annual_modeled_benefits": 212.01572016369738 + }, + "one_more_day": { + "variable": "ma_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 0.0716373446630314, + "annual_modeled_benefits": 212.01572016369738 + } + }, + { + "state": "MI", + "sample_households": 1478, + "baseline": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + }, + "candidate": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + }, + "no_modeled_irregular_hours": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + }, + "one_fewer_day": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + }, + "one_more_day": { + "variable": "mi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 42453.16293835803, + "annual_modeled_benefits": 167344216.73651382 + } + }, + { + "state": "MN", + "sample_households": 1166, + "baseline": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 21289.402694451623, + "annual_modeled_benefits": 274850426.86324066 + }, + "no_modeled_irregular_hours": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 21289.401307827327, + "annual_modeled_benefits": 274850426.2413397 + }, + "one_fewer_day": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 21289.402694451623, + "annual_modeled_benefits": 274850426.86324066 + }, + "one_more_day": { + "variable": "mn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 21289.402694451623, + "annual_modeled_benefits": 274850426.86324066 + } + }, + { + "state": "MS", + "sample_households": 882, + "baseline": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 7256.952556610806, + "annual_modeled_benefits": 30449890.664512668 + }, + "no_modeled_irregular_hours": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 7256.951193145127, + "annual_modeled_benefits": 30449886.57411563 + }, + "one_fewer_day": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 7256.952556610806, + "annual_modeled_benefits": 9247129.336387664 + }, + "one_more_day": { + "variable": "ms_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 7256.952556610806, + "annual_modeled_benefits": 30449890.664512668 + } + }, + { + "state": "MO", + "sample_households": 1013, + "baseline": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 9981.891486888984, + "annual_modeled_benefits": 44110014.74611533 + }, + "no_modeled_irregular_hours": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 9981.891486888984, + "annual_modeled_benefits": 44110014.74611533 + }, + "one_fewer_day": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 9981.891486888984, + "annual_modeled_benefits": 44110017.00214956 + }, + "one_more_day": { + "variable": "mo_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 9981.891486888984, + "annual_modeled_benefits": 44110014.31673183 + } + }, + { + "state": "MT", + "sample_households": 744, + "baseline": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + }, + "candidate": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + }, + "no_modeled_irregular_hours": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + }, + "one_fewer_day": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + }, + "one_more_day": { + "variable": "mt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 3, + "weighted_positive_units": 4.609087781107519, + "annual_modeled_benefits": 343.68633474948 + } + }, + { + "state": "NE", + "sample_households": 884, + "baseline": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 754.4826039844379 + }, + "candidate": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 752.3048707440652 + }, + "no_modeled_irregular_hours": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 750.2732835703686 + }, + "one_fewer_day": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 752.3048707440652 + }, + "one_more_day": { + "variable": "ne_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 6, + "weighted_positive_units": 1.0507851635920815, + "annual_modeled_benefits": 752.3048707440652 + } + }, + { + "state": "NV", + "sample_households": 952, + "baseline": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "no_modeled_irregular_hours": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "one_fewer_day": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "one_more_day": { + "variable": "nv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + } + }, + { + "state": "NH", + "sample_households": 840, + "baseline": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + }, + "candidate": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + }, + "no_modeled_irregular_hours": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + }, + "one_fewer_day": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + }, + "one_more_day": { + "variable": "nh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 6328.660297448034, + "annual_modeled_benefits": 16452735.29621234 + } + }, + { + "state": "NJ", + "sample_households": 1651, + "baseline": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 54783391.64412939 + }, + "candidate": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 39399036.82068616 + }, + "no_modeled_irregular_hours": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 39399036.82068616 + }, + "one_fewer_day": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 39399036.82068616 + }, + "one_more_day": { + "variable": "nj_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 47645.06307415466, + "annual_modeled_benefits": 39399036.82068616 + } + }, + { + "state": "NM", + "sample_households": 902, + "baseline": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 40276267.46262546 + }, + "candidate": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 59646231.852653645 + }, + "no_modeled_irregular_hours": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 59644459.68607285 + }, + "one_fewer_day": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 59646236.386424586 + }, + "one_more_day": { + "variable": "nm_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 32, + "weighted_positive_units": 14416.283866321406, + "annual_modeled_benefits": 59647120.40554538 + } + }, + { + "state": "NY", + "sample_households": 2166, + "baseline": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 84809.87077922659, + "annual_modeled_benefits": 386150016.03633535 + }, + "no_modeled_irregular_hours": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 84809.87077922659, + "annual_modeled_benefits": 386150016.03633535 + }, + "one_fewer_day": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 84809.87077922659, + "annual_modeled_benefits": 386147637.05533403 + }, + "one_more_day": { + "variable": "ny_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 28, + "weighted_positive_units": 84809.87077922659, + "annual_modeled_benefits": 386150016.03633535 + } + }, + { + "state": "NC", + "sample_households": 1337, + "baseline": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + }, + "candidate": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + }, + "no_modeled_irregular_hours": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + }, + "one_fewer_day": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + }, + "one_more_day": { + "variable": "nc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 28725.60765656957, + "annual_modeled_benefits": 161822256.86665964 + } + }, + { + "state": "ND", + "sample_households": 682, + "baseline": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 409.12895149587507 + }, + "candidate": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 471.04686684011335 + }, + "no_modeled_irregular_hours": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 465.6641840398204 + }, + "one_fewer_day": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 474.0045400403885 + }, + "one_more_day": { + "variable": "nd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.1099370562878903, + "annual_modeled_benefits": 515.8170557760147 + } + }, + { + "state": "OH", + "sample_households": 1531, + "baseline": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 57197.27386227145, + "annual_modeled_benefits": 109086186.25780228 + }, + "no_modeled_irregular_hours": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 57197.27386227145, + "annual_modeled_benefits": 109086186.25780228 + }, + "one_fewer_day": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 57197.27386227145, + "annual_modeled_benefits": 109086186.25780228 + }, + "one_more_day": { + "variable": "oh_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 57197.27386227145, + "annual_modeled_benefits": 109088290.29528335 + } + }, + { + "state": "OK", + "sample_households": 918, + "baseline": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0031096774619072676, + "annual_modeled_benefits": 5.149625876918435 + }, + "no_modeled_irregular_hours": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0031096774619072676, + "annual_modeled_benefits": 5.149625876918435 + }, + "one_fewer_day": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0031096774619072676, + "annual_modeled_benefits": 3.0897752604315514 + }, + "one_more_day": { + "variable": "ok_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 1, + "weighted_positive_units": 0.0031096774619072676, + "annual_modeled_benefits": 5.149625876918435 + } + }, + { + "state": "OR", + "sample_households": 1152, + "baseline": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + }, + "candidate": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + }, + "no_modeled_irregular_hours": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + }, + "one_fewer_day": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + }, + "one_more_day": { + "variable": "or_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 16, + "weighted_positive_units": 15165.681869102991, + "annual_modeled_benefits": 33054937.630309362 + } + }, + { + "state": "PA", + "sample_households": 1999, + "baseline": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.2005278345895931, + "annual_modeled_benefits": 561.099948525683 + }, + "no_modeled_irregular_hours": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.2005278345895931, + "annual_modeled_benefits": 561.099948525683 + }, + "one_fewer_day": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.2005278345895931, + "annual_modeled_benefits": 561.099948525683 + }, + "one_more_day": { + "variable": "pa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 0.2005278345895931, + "annual_modeled_benefits": 561.099948525683 + } + }, + { + "state": "RI", + "sample_households": 804, + "baseline": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429808.7526231185 + }, + "candidate": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429813.4984327066 + }, + "no_modeled_irregular_hours": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429813.4984327066 + }, + "one_fewer_day": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429813.4984327066 + }, + "one_more_day": { + "variable": "ri_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 5, + "weighted_positive_units": 4049.67838506322, + "annual_modeled_benefits": 2429813.4984327066 + } + }, + { + "state": "SC", + "sample_households": 955, + "baseline": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 27915.89938246878, + "annual_modeled_benefits": 77088809.79821464 + }, + "no_modeled_irregular_hours": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 27854.604704734404, + "annual_modeled_benefits": 77020404.93038082 + }, + "one_fewer_day": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 27915.89938246878, + "annual_modeled_benefits": 77088803.73884593 + }, + "one_more_day": { + "variable": "sc_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 11, + "weighted_positive_units": 27915.89938246878, + "annual_modeled_benefits": 77088809.79821464 + } + }, + { + "state": "SD", + "sample_households": 866, + "baseline": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 2978.0845139123267, + "annual_modeled_benefits": 5809177.944389787 + }, + "no_modeled_irregular_hours": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 2978.0845139123267, + "annual_modeled_benefits": 5809177.944389787 + }, + "one_fewer_day": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 2978.0845139123267, + "annual_modeled_benefits": 5809177.483422956 + }, + "one_more_day": { + "variable": "sd_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 2978.0845139123267, + "annual_modeled_benefits": 5809179.365034073 + } + }, + { + "state": "TN", + "sample_households": 1082, + "baseline": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 54836.32565583871, + "annual_modeled_benefits": 120178664.890383 + }, + "no_modeled_irregular_hours": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 12, + "weighted_positive_units": 37178.86130036996, + "annual_modeled_benefits": 76918628.29417688 + }, + "one_fewer_day": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 14, + "weighted_positive_units": 54836.32565583871, + "annual_modeled_benefits": 120178652.73669359 + }, + "one_more_day": { + "variable": "tn_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 58319.75094880746, + "annual_modeled_benefits": 139207804.7182324 + } + }, + { + "state": "TX", + "sample_households": 1875, + "baseline": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 72034.10924506374, + "annual_modeled_benefits": 172158000.8966679 + }, + "no_modeled_irregular_hours": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 72034.10924506374, + "annual_modeled_benefits": 172158000.8966679 + }, + "one_fewer_day": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 72034.10924506374, + "annual_modeled_benefits": 172158000.8966679 + }, + "one_more_day": { + "variable": "tx_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 15, + "weighted_positive_units": 72034.10924506374, + "annual_modeled_benefits": 172158000.8966679 + } + }, + { + "state": "UT", + "sample_households": 861, + "baseline": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66285594.41326967 + }, + "candidate": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66285594.41326967 + }, + "no_modeled_irregular_hours": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66285594.41326967 + }, + "one_fewer_day": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66285594.41326967 + }, + "one_more_day": { + "variable": "ut_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 23851.249713434547, + "annual_modeled_benefits": 66285594.41326967 + } + }, + { + "state": "VT", + "sample_households": 496, + "baseline": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 78, + "weighted_positive_units": 32213.61921006818, + "annual_modeled_benefits": 526819840.50677323 + }, + "candidate": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 80, + "weighted_positive_units": 32213.669151621914, + "annual_modeled_benefits": 720606373.2116799 + }, + "no_modeled_irregular_hours": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 80, + "weighted_positive_units": 32213.669151621914, + "annual_modeled_benefits": 707106120.8814734 + }, + "one_fewer_day": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 80, + "weighted_positive_units": 32213.669151621914, + "annual_modeled_benefits": 723295768.2248663 + }, + "one_more_day": { + "variable": "vt_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 81, + "weighted_positive_units": 32213.82430987344, + "annual_modeled_benefits": 735348229.2533482 + } + }, + { + "state": "VA", + "sample_households": 1394, + "baseline": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 45187.34717369359, + "annual_modeled_benefits": 249203866.21813098 + }, + "no_modeled_irregular_hours": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 45187.34378196369, + "annual_modeled_benefits": 249203861.9343761 + }, + "one_fewer_day": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 45187.34717369359, + "annual_modeled_benefits": 218587967.72536415 + }, + "one_more_day": { + "variable": "va_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 10, + "weighted_positive_units": 45187.52193577867, + "annual_modeled_benefits": 254330473.5103389 + } + }, + { + "state": "WA", + "sample_households": 1305, + "baseline": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + }, + "candidate": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + }, + "no_modeled_irregular_hours": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + }, + "one_fewer_day": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + }, + "one_more_day": { + "variable": "wa_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 18, + "weighted_positive_units": 34613.59633511363, + "annual_modeled_benefits": 273947341.7692 + } + }, + { + "state": "WV", + "sample_households": 845, + "baseline": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 4, + "weighted_positive_units": 2978.909898934886, + "annual_modeled_benefits": 9329928.243193686 + }, + "no_modeled_irregular_hours": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 4, + "weighted_positive_units": 2978.909898934886, + "annual_modeled_benefits": 9329923.422902562 + }, + "one_fewer_day": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 4, + "weighted_positive_units": 2978.909898934886, + "annual_modeled_benefits": 9329930.062846346 + }, + "one_more_day": { + "variable": "wv_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 4, + "weighted_positive_units": 2978.909898934886, + "annual_modeled_benefits": 10521487.168013036 + } + }, + { + "state": "WI", + "sample_households": 1232, + "baseline": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 33918.60478726821, + "annual_modeled_benefits": 249284653.88471013 + }, + "no_modeled_irregular_hours": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 33918.60478726821, + "annual_modeled_benefits": 249284653.88471013 + }, + "one_fewer_day": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 33918.60478726821, + "annual_modeled_benefits": 249284617.12617347 + }, + "one_more_day": { + "variable": "wi_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 9, + "weighted_positive_units": 33918.61217102362, + "annual_modeled_benefits": 210174118.98339957 + } + }, + { + "state": "WY", + "sample_households": 557, + "baseline": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 0, + "weighted_positive_units": 0.0, + "annual_modeled_benefits": 0.0 + }, + "candidate": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 2962.834392214354, + "annual_modeled_benefits": 18103301.12153925 + }, + "no_modeled_irregular_hours": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 8, + "weighted_positive_units": 2962.834582739495, + "annual_modeled_benefits": 18103300.895859934 + }, + "one_fewer_day": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 2962.834392214354, + "annual_modeled_benefits": 18103301.12153925 + }, + "one_more_day": { + "variable": "wy_child_care_subsidies", + "entity": "spm_unit", + "positive_sample_units": 7, + "weighted_positive_units": 2962.834392214354, + "annual_modeled_benefits": 18834318.50135846 + } + } + ], + "production_ready": false, + "interpretation": "assumption stress tests, not confidence intervals; potential modeled benefits, not calibrated spending", + "summary": { + "states_evaluated": 51, + "annual_potential_modeled_benefits": { + "baseline": 2253392072.9613476, + "candidate": 5286396512.037729, + "no_modeled_irregular_hours": 5209249263.466962, + "one_fewer_day": 5221847327.786389, + "one_more_day": 5298269288.494554 + }, + "sensitivity_flags": [ + { + "scenario": "no_modeled_irregular_hours", + "state": "TN", + "relative_change": -0.3599643633557116, + "absolute_change": -43260036.59620613, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "IA", + "relative_change": 0.5999998225607299, + "absolute_change": 32725229.776584633, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "KS", + "relative_change": -0.49350560992419995, + "absolute_change": -28355630.330927107, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "MS", + "relative_change": -0.6963165011569457, + "absolute_change": -21202761.328125004, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "OK", + "relative_change": -0.40000005159976976, + "absolute_change": -2.0598506164868837, + "flagged": true + }, + { + "scenario": "one_more_day", + "state": "AR", + "relative_change": 0.43948945692098534, + "absolute_change": 22323171.50997054, + "flagged": true + } + ], + "comparisons": [ + { + "scenario": "no_modeled_irregular_hours", + "state": "US", + "relative_change": -0.014593541819100081, + "absolute_change": -77147248.5707674, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "AL", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "AK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "AZ", + "relative_change": -2.0603166723927034e-06, + "absolute_change": -47.715961039066315, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "AR", + "relative_change": -1.0830808059296869e-07, + "absolute_change": -5.501337565481663, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "CA", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "CO", + "relative_change": 1.5282148622892612e-07, + "absolute_change": 36.13395735621452, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "CT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "DE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "DC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "FL", + "relative_change": -0.04900128559000059, + "absolute_change": -16498428.152336836, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "GA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "HI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "ID", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "IL", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "IN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "IA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "KS", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "KY", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "LA", + "relative_change": -0.0524188932261243, + "absolute_change": -3818315.91796875, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "ME", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MD", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MN", + "relative_change": -2.262688775133818e-09, + "absolute_change": -0.6219009757041931, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MS", + "relative_change": -1.343320763490555e-07, + "absolute_change": -4.090397037565708, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MO", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "MT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NE", + "relative_change": -0.002700483876552961, + "absolute_change": -2.0315871736966074, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NV", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NJ", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NM", + "relative_change": -2.9711291489026368e-05, + "absolute_change": -1772.1665807962418, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NY", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "NC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "ND", + "relative_change": -0.011427064224842841, + "absolute_change": -5.382682800292969, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "OH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "OK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "OR", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "PA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "RI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "SC", + "relative_change": -0.0008873514588288169, + "absolute_change": -68404.86783382297, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "SD", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "TN", + "relative_change": -0.3599643633557116, + "absolute_change": -43260036.59620613, + "flagged": true + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "TX", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "UT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "VT", + "relative_change": -0.01873457248239016, + "absolute_change": -13500252.330206513, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "VA", + "relative_change": -1.7189760938327763e-08, + "absolute_change": -4.283754885196686, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "WA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "WV", + "relative_change": -5.166482526594711e-07, + "absolute_change": -4.820291124284267, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "WI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "no_modeled_irregular_hours", + "state": "WY", + "relative_change": -1.2466196861638054e-08, + "absolute_change": -0.22567931562662125, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "US", + "relative_change": -0.012210431832790832, + "absolute_change": -64549184.25133991, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "AL", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "AK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "AZ", + "relative_change": -8.464541488685182e-07, + "absolute_change": -19.60347830504179, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "AR", + "relative_change": -0.06880181634068526, + "absolute_change": -3494679.3880580887, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "CA", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "CO", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "CT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "DE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "DC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "FL", + "relative_change": -0.04838899531469712, + "absolute_change": -16292273.824060798, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "GA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "HI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "ID", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "IL", + "relative_change": -6.29279612809565e-07, + "absolute_change": -123.8335727751255, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "IN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "IA", + "relative_change": 0.5999998225607299, + "absolute_change": 32725229.776584633, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "KS", + "relative_change": -0.49350560992419995, + "absolute_change": -28355630.330927107, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "KY", + "relative_change": 0.06803920743236715, + "absolute_change": 10.06459831040911, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "LA", + "relative_change": -1.015677875316422e-07, + "absolute_change": -7.398437395691872, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "ME", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MD", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MS", + "relative_change": -0.6963165011569457, + "absolute_change": -21202761.328125004, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "MO", + "relative_change": 5.114562408698159e-08, + "absolute_change": 2.256034232676029, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "MT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NV", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NJ", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NM", + "relative_change": 7.601102031722338e-08, + "absolute_change": 4.533770941197872, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NY", + "relative_change": -6.160768878729368e-06, + "absolute_change": -2378.981001317501, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "NC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "ND", + "relative_change": 0.006278936149423715, + "absolute_change": 2.957673200275167, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "OH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "OK", + "relative_change": -0.40000005159976976, + "absolute_change": -2.0598506164868837, + "flagged": true + }, + { + "scenario": "one_fewer_day", + "state": "OR", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "PA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "RI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "SC", + "relative_change": -7.860244217741888e-08, + "absolute_change": -6.059368714690208, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "SD", + "relative_change": -7.935147357416053e-08, + "absolute_change": -0.46096683014184237, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "TN", + "relative_change": -1.0113017502190059e-07, + "absolute_change": -12.153689414262772, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "TX", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "UT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "VT", + "relative_change": 0.0037321277096120254, + "absolute_change": 2689395.0131863356, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "VA", + "relative_change": -0.122854829491162, + "absolute_change": -30615898.492766827, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "WA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "WV", + "relative_change": 1.9503393942456014e-07, + "absolute_change": 1.81965265981853, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "WI", + "relative_change": -1.474560751887755e-07, + "absolute_change": -36.7585366666317, + "flagged": false + }, + { + "scenario": "one_fewer_day", + "state": "WY", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "US", + "relative_change": 0.002245911071897205, + "absolute_change": 11872776.456824303, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "AL", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "AK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "AZ", + "relative_change": -0.038820318650775495, + "absolute_change": -899060.2450027056, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "AR", + "relative_change": 0.43948945692098534, + "absolute_change": 22323171.50997054, + "flagged": true + }, + { + "scenario": "one_more_day", + "state": "CA", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "CO", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "CT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "DE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "DC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "FL", + "relative_change": -0.037171430237584874, + "absolute_change": -12515389.417038918, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "GA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "HI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "ID", + "relative_change": -8.714356196712921e-06, + "absolute_change": -92.81887292861938, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "IL", + "relative_change": -6.484094955654378e-07, + "absolute_change": -127.59807059168816, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "IN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "IA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "KS", + "relative_change": 0.02178292270244223, + "absolute_change": 1251593.6825368255, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "KY", + "relative_change": -0.010637750292372622, + "absolute_change": -1.5735733507124223, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "LA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "ME", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MD", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MN", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MS", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MO", + "relative_change": -9.734376568026846e-09, + "absolute_change": -0.4293834939599037, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "MT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NE", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NV", + "relative_change": null, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NH", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NJ", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NM", + "relative_change": 1.4897049891328236e-05, + "absolute_change": 888.5528917387128, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NY", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "NC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "ND", + "relative_change": 0.09504402234161904, + "absolute_change": 44.77018893590139, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "OH", + "relative_change": 1.9287845264817622e-05, + "absolute_change": 2104.037481069565, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "OK", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "OR", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "PA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "RI", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "SC", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "SD", + "relative_change": 2.445516903920343e-07, + "absolute_change": 1.4206442860886455, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "TN", + "relative_change": 0.15834041628941534, + "absolute_change": 19029139.827849388, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "TX", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "UT", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "VT", + "relative_change": 0.020457570998109725, + "absolute_change": 14741856.041668296, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "VA", + "relative_change": 0.020571941238345593, + "absolute_change": 5126607.2922079265, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "WA", + "relative_change": 0.0, + "absolute_change": 0.0, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "WV", + "relative_change": 0.1277136215585162, + "absolute_change": 1191558.9248193502, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "WI", + "relative_change": -0.1568910652614762, + "absolute_change": -39110534.90131056, + "flagged": false + }, + { + "scenario": "one_more_day", + "state": "WY", + "relative_change": 0.04038033587970585, + "absolute_change": 731017.3798192106, + "flagged": false + } + ] + } +} diff --git a/experiments/us-childcare-attendance/review-validation-criteria.txt b/experiments/us-childcare-attendance/review-validation-criteria.txt new file mode 100644 index 000000000..42b390bc9 --- /dev/null +++ b/experiments/us-childcare-attendance/review-validation-criteria.txt @@ -0,0 +1,5 @@ +Revision validation criteria set before expanded results, 2026-09-15. +Engineering (required): exact row/recipe receipt, fail on missing/tampered metadata or values; changed source/seed/policy rejected; final attendance complete and internally valid; missing household identities rejected; observed zeros preserved by primitive; original population columns/weights/period unchanged. +Statistical diagnostic screens (provisional, not release authorization): youngest-pair participation absolute gap <=5 percentage points; pair days/hour correlation absolute gap <=0.10; joint days/hour product relative gap <=20%; 3+ household mean and SD total days/hours relative gap <=20%, all-attend gap <=5 percentage points. Report sample counts, every failure and independent-draw comparison. Screens informed by previously viewed marginal diagnostics; no untouched validation claim. Failure prevents treating household process as statistically qualified; do not tune to these folds and claim new acceptance. +Transport sensitivity: preserve each child's observed regular hours. Compare donor-day baseline with (a) zero imputed irregular hours, (b) one fewer and one more attended day, bounded by observed-hours feasibility and seven days. Keep matching fields, random seed and original population fixed; retransfer altered bridge donors and measure all state CCDF outcomes. Report relative benefit changes; >10% national or >20% state with positive baseline is an unresolved sensitivity flag. These are assumption stress tests, not confidence intervals or identification of missing days. +Publication remains production_ready:false without independent held-out evidence and normal release gates. diff --git a/packages/microcosm-build/src/microcosm/build/frame_serializer_registry.py b/packages/microcosm-build/src/microcosm/build/frame_serializer_registry.py index 00ddd7612..8445b3797 100644 --- a/packages/microcosm-build/src/microcosm/build/frame_serializer_registry.py +++ b/packages/microcosm-build/src/microcosm/build/frame_serializer_registry.py @@ -47,6 +47,17 @@ class HdfWriteExclusion: FRAME_TABLE_SERIALIZERS = ( + FrameSerializerSpec( + serializer_id="nsece_childcare_native_candidate", + writer=HdfWriteSite( + "packages/microcosm-build/src/microcosm/build/us_runtime/childcare_attendance_stage.py", + "_write_childcare_candidate_person_table", + ), + backend="pandas.HDFStore table", + routes=("NSECE attendance native population candidate",), + version_owner="NSECE native candidate payload contract", + nullable_boolean_storage="numpy_bool_or_object_pd_na_v1", + ), FrameSerializerSpec( serializer_id="frame_checkpoint", writer=HdfWriteSite( @@ -194,6 +205,15 @@ class HdfWriteExclusion: ), reason="Copies Microcosm-owned root attributes only.", ), + HdfWriteExclusion( + exclusion_id="nsece_childcare_native_receipt", + writer=HdfWriteSite( + "packages/microcosm-build/src/microcosm/build/us_runtime/" + "childcare_attendance_receipt.py", + "write_native_childcare_receipt", + ), + reason="Adds one JSON receipt key; never writes an entity table.", + ), HdfWriteExclusion( exclusion_id="acs_transfer_raw_draw_bank", writer=HdfWriteSite( diff --git a/packages/microcosm-build/src/microcosm/build/spec_engine/field_usage.py b/packages/microcosm-build/src/microcosm/build/spec_engine/field_usage.py index 56f39195c..9c2e8702e 100644 --- a/packages/microcosm-build/src/microcosm/build/spec_engine/field_usage.py +++ b/packages/microcosm-build/src/microcosm/build/spec_engine/field_usage.py @@ -26,9 +26,9 @@ ) from .schemas import load_schema_registry -EXPECTED_AUTHORED_FIELD_COUNT = 32_404 +EXPECTED_AUTHORED_FIELD_COUNT = 32_407 EXPECTED_RESOLVED_BINDING_FIELD_COUNT = 9_780 -EXPECTED_CONFIGURATION_FIELD_COUNT = 42_184 +EXPECTED_CONFIGURATION_FIELD_COUNT = 42_187 class FieldUsageError(AssertionError): @@ -372,9 +372,10 @@ def _path_inventory(rows: Sequence[tuple[str, object]]) -> tuple[int, str]: 5, "64182b6be1ea6d95bff345b30a2aa046b6fa7e8ee61a282b225dfa49c28fbfdc", ), + # The NSECE source-extension descriptor adds kind/path/schema_id leaves. "country_manifest": ( - 104, - "8a186065f5b8ffc59bc3f62fe927975e6f36bc1e913aa61761652c9a8aa67988", + 107, + "2c2099d3d5ef3d664f74a2e732870391022a852cf49d5cf96810c9a984d2b20b", ), "generated_authorities": ( 8_614, diff --git a/packages/microcosm-build/src/microcosm/build/us/childcare_attendance_source.json b/packages/microcosm-build/src/microcosm/build/us/childcare_attendance_source.json new file mode 100644 index 000000000..26dd567f1 --- /dev/null +++ b/packages/microcosm-build/src/microcosm/build/us/childcare_attendance_source.json @@ -0,0 +1,22 @@ +{ + "stage": "nsece_childcare_attendance", + "survey": "2024 NSECE household DS5 and calendar DS4, ICPSR39466.v1", + "source": "https://www.childandfamilydataarchive.org/cfda/archives/cfda/studies/39466/datadocumentation", + "grain": "person", + "artifacts": [ + {"dataset": "DS5", "format": "tsv", "sha256": "b42c69874de627273cdf698e4b8cdd39d3d4fdfef7d1295c239772cbc4e6c5a2"}, + {"dataset": "DS4", "format": "tsv", "sha256": "c2e04a7a3eb6e187dc6d4496be1de77508354e05c6249725ae072f8a5f2ce18e"} + ], + "operations": [ + {"kind": "derive_childcare_inputs", "operation": "calendar_attendance", "age_min": 0, "age_max": 12}, + {"kind": "derive_childcare_inputs", "operation": "regular_hours_schedule_bridge", "nearest_donors": 10}, + {"kind": "derive_childcare_inputs", "operation": "joint_weighted_schedule_transfer", "preserve_observed": true} + ], + "outputs": ["childcare_attending_days_per_month", "childcare_days_per_week", "childcare_hours_per_day"], + "nonnegative_outputs": ["childcare_attending_days_per_month", "childcare_days_per_week", "childcare_hours_per_day"], + "income_reference_year": 2023, + "income_band_upper_bounds": [0, 25000, 50000, 100000, 200000], + "cpi_u_annual_average": {"2022": 292.655, "2023": 304.702, "2024": 313.689}, + "cpi_source": "https://www.bls.gov/cpi/tables/supplemental-files/historical-cpi-u-202412.pdf", + "notes": "Local licensed-source build extension. Scope is ages 0-12. Unresolved records outside the source domain are not observations of zero care. Calendar and bridge provenance must accompany population outputs. Publication is separate from source preparation." +} diff --git a/packages/microcosm-build/src/microcosm/build/us/country_package.json b/packages/microcosm-build/src/microcosm/build/us/country_package.json index 5e14125c8..4888f3824 100644 --- a/packages/microcosm-build/src/microcosm/build/us/country_package.json +++ b/packages/microcosm-build/src/microcosm/build/us/country_package.json @@ -171,6 +171,11 @@ "path": "tax_expenditure_reforms.json", "kind": "legacy_json", "schema_id": "legacy_json" + }, + { + "path": "childcare_attendance_source.json", + "kind": "legacy_json", + "schema_id": "legacy_json" } ] } diff --git a/packages/microcosm-build/src/microcosm/build/us/release_input_coverage_manifest.json b/packages/microcosm-build/src/microcosm/build/us/release_input_coverage_manifest.json index 79218461f..1ad201780 100644 --- a/packages/microcosm-build/src/microcosm/build/us/release_input_coverage_manifest.json +++ b/packages/microcosm-build/src/microcosm/build/us/release_input_coverage_manifest.json @@ -47,6 +47,18 @@ "child_support_received": { "status": "required" }, + "childcare_attending_days_per_month": { + "note": "Person-level NSECE attendance source extension (#915): requires persisted signal; missing inputs must not silently become engine defaults. The modeled age domain and outside-domain baseline policy are recorded in source coverage.", + "status": "required" + }, + "childcare_days_per_week": { + "note": "Person-level NSECE attendance source extension (#915): requires persisted signal; missing inputs must not silently become engine defaults. The modeled age domain and outside-domain baseline policy are recorded in source coverage.", + "status": "required" + }, + "childcare_hours_per_day": { + "note": "Person-level NSECE attendance source extension (#915): requires persisted signal; missing inputs must not silently become engine defaults. The modeled age domain and outside-domain baseline policy are recorded in source coverage.", + "status": "required" + }, "congressional_district_geoid": { "status": "required" }, @@ -550,11 +562,11 @@ } }, "counts": { - "required": 167, + "required": 170, "reviewed_exclusion": 7, - "total": 174 + "total": 177 }, - "derivation": "Required surface = input columns in the pinned, sha-verified ecps_parity_reference.json populated layers, plus the documented post-reference fsla_overtime_premium, qualified_passenger_vehicle_loan_interest, five desired retirement-contribution inputs, meets_ssi_disability_criteria required by shipped validation probes, the #282 Schedule-D capital-gain-distributions route leg schedule_d_capital_gain_distributions (PolicyEngine/microcosm#462), the three ASEC reported-receipt inputs receives_wic, receives_snap, receives_tanf that the ACS local-area transfer requires in its donor (PolicyEngine/microcosm#978 option 1), and the engine's declared dataset source input is_spm_independent_minor_role (the spm_independence_role base-builder stage; PolicyEngine/microcosm#893). status='reviewed_exclusion' for ecps_parity_known_gaps.json entries (reason+issue from that register); EXCEPT every primary-source restoration pinned by RESTORED_REFERENCE_ECPS_REQUIRED_INPUTS (including the Section 199A QBI family), and the SSI countable-resource asset inputs (bank_account_assets, stock_assets, bond_assets), which are status='required' with NO exclusion per PolicyEngine/microcosm#368 so the gate fails on today's artifacts and asset restoration (Deliverable 2) turns it green. All other populated layers are 'required'. Regenerate with tools/build_us_release_input_coverage_manifest.py.", + "derivation": "Required surface = input columns in the pinned, sha-verified ecps_parity_reference.json populated layers, plus the documented post-reference fsla_overtime_premium, qualified_passenger_vehicle_loan_interest, five desired retirement-contribution inputs, meets_ssi_disability_criteria required by shipped validation probes, the three NSECE child attendance inputs (#915), and the #282 Schedule-D capital-gain-distributions route leg schedule_d_capital_gain_distributions (PolicyEngine/microcosm#462), the three ASEC reported-receipt inputs receives_wic, receives_snap, receives_tanf that the ACS local-area transfer requires in its donor (PolicyEngine/microcosm#978 option 1), and the engine's declared dataset source input is_spm_independent_minor_role (the spm_independence_role base-builder stage; PolicyEngine/microcosm#893). status='reviewed_exclusion' for ecps_parity_known_gaps.json entries (reason+issue from that register); EXCEPT every primary-source restoration pinned by RESTORED_REFERENCE_ECPS_REQUIRED_INPUTS (including the Section 199A QBI family), and the SSI countable-resource asset inputs (bank_account_assets, stock_assets, bond_assets), which are status='required' with NO exclusion per PolicyEngine/microcosm#368 so the gate fails on today's artifacts and asset restoration (Deliverable 2) turns it green. All other populated layers are 'required'. Regenerate with tools/build_us_release_input_coverage_manifest.py.", "description": "Declared full-coverage contract for a US release: every input column the reference eCPS exports must be persisted as a key with non-default signal, or carry a reviewed exclusion. Enforced as a hard release gate (microcosm.build.us_runtime.release_input_coverage) that generalizes assert_required_us_release_source_columns from 5 columns to the full eCPS input surface.", "issue": "PolicyEngine/microcosm#368", "reference": { diff --git a/packages/microcosm-build/src/microcosm/build/us_annual_static_aging.py b/packages/microcosm-build/src/microcosm/build/us_annual_static_aging.py index 1022364ec..65815cdae 100644 --- a/packages/microcosm-build/src/microcosm/build/us_annual_static_aging.py +++ b/packages/microcosm-build/src/microcosm/build/us_annual_static_aging.py @@ -21,6 +21,11 @@ import pandas as pd +from microcosm.build.us_runtime.childcare_attendance_receipt import ( + ATTENDANCE_RECEIPT_KEY, + restore_native_childcare_receipt, + write_native_childcare_receipt, +) from microcosm.calibrate import ( SeriesProjection, ssa_population_projection, @@ -178,10 +183,30 @@ def _verify(path: Path, tables: Mapping[str, pd.DataFrame], year: int) -> dict: pd.testing.assert_frame_equal( getattr(native, entity), external, check_dtype=False, check_exact=True ) - return {"logical_tables": True, "native_loader": True, "time_period": year} + # Static aging retains ages, identities, and attendance; changing weights or + # monetary inputs must neither discard nor reseal the original receipt. + weights = Weights( + tables["household"]["household_weight"].to_numpy(dtype=float), + WeightKind.CALIBRATED, + ) + verified = restore_native_childcare_receipt( + path, Frame(tables, US_SCHEMA, {"household": weights}) + ) + receipt = {"logical_tables": True, "native_loader": True, "time_period": year} + if ATTENDANCE_RECEIPT_KEY in verified.metadata: + receipt["childcare_attendance_binding_sha256"] = verified.metadata[ + ATTENDANCE_RECEIPT_KEY + ]["binding_sha256"] + return receipt -def _write_year(path: Path, tables: Mapping[str, pd.DataFrame], year: int) -> dict: +def _write_year( + path: Path, + tables: Mapping[str, pd.DataFrame], + year: int, + *, + frame_metadata: Mapping[str, Any] | None = None, +) -> dict: temporary = path.with_suffix(".tmp.h5") with pd.HDFStore(temporary, "w") as store: for entity, table in tables.items(): @@ -189,6 +214,8 @@ def _write_year(path: Path, tables: Mapping[str, pd.DataFrame], year: int) -> di store, entity, table, preferred_format="table", data_columns=True ) store.put("_time_period", pd.Series([year]), format="table") + if frame_metadata and ATTENDANCE_RECEIPT_KEY in frame_metadata: + write_native_childcare_receipt(temporary, frame_metadata) receipt = _verify(temporary, tables, year) temporary.replace(path) return receipt @@ -261,13 +288,14 @@ def build_annual_static_aging( frame = Frame( tables, US_SCHEMA, {"household": Weights(weights, WeightKind.CALIBRATED)} ) + frame = restore_native_childcare_receipt(base, frame) base_tables = { entity: table.loc[:, columns[entity]] for entity, table in engine_tables( frame, weighted_entities=("household",) ).items() } - _verify(base, base_tables, base_year) + base_round_trip = _verify(base, base_tables, base_year) del tables, base_tables demographics = ssa_population_projection(ssa, age_top=85, age_bands={80: 84}) for year in range(base_year, end_year + 1): @@ -332,11 +360,7 @@ def build_annual_static_aging( if year == base_year: shutil.copyfile(base, path) _check_pin(path, base_sha256) - round_trip = { - "logical_tables": True, - "native_loader": True, - "time_period": year, - } + round_trip = dict(base_round_trip) projection_receipt = None else: result = static_aging( @@ -363,7 +387,9 @@ def build_annual_static_aging( entity: getattr(dataset, entity).loc[:, columns[entity]] for entity in frame.entities } - round_trip = _write_year(path, projected_tables, year) + round_trip = _write_year( + path, projected_tables, year, frame_metadata=frame.metadata + ) receipt_path = output / f"projection_{year}.json" _json( receipt_path, diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/childcare_attendance.py b/packages/microcosm-build/src/microcosm/build/us_runtime/childcare_attendance.py new file mode 100644 index 000000000..ec7cfbaf8 --- /dev/null +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/childcare_attendance.py @@ -0,0 +1,280 @@ +"""Joint, weighted child-care attendance transfer from normalized child donors. + +This is an opt-in preparation primitive, not an enabled US build stage. Source +adapters must supply validated child records, survey weights and shared matching +fields. See docs/us-childcare-attendance.md for the source/activation gates. +""" + +from __future__ import annotations + +import hashlib +import json +from importlib.resources import files + +import numpy as np +import pandas as pd + +from microcosm.frame import Weights + +US_CHILDCARE_ATTENDANCE_COLUMNS = ( + "childcare_attending_days_per_month", + "childcare_days_per_week", + "childcare_hours_per_day", +) + + +def childcare_attendance_contract() -> dict: + return json.loads( + files("microcosm.build.us") + .joinpath("childcare_attendance_source.json") + .read_text() + ) + + +def childcare_income_band(income): + """Band household income expressed in the contract's reference-year dollars.""" + values = np.asarray(income, dtype=float) + if not np.isfinite(values).all(): + raise ValueError("Childcare income must be observed and finite.") + return np.searchsorted( + childcare_attendance_contract()["income_band_upper_bounds"], values, side="left" + ) + + +def _validate_attendance(table: pd.DataFrame, *, complete: bool) -> None: + values = table[list(US_CHILDCARE_ATTENDANCE_COLUMNS)].to_numpy( + dtype=float, na_value=np.nan + ) + if complete and np.isnan(values).any(): + raise ValueError("Childcare donor attendance must be complete.") + if np.isinf(values).any() or (values < 0).any(): + raise ValueError("Childcare attendance must be finite and nonnegative.") + if (values > np.array([31, 7, 24])).any(): + raise ValueError("Childcare attendance exceeds calendar bounds.") + monthly = values[:, 0] + if (monthly[np.isfinite(monthly)] % 1 != 0).any(): + raise ValueError("Childcare attending days per month must be integral.") + if ((values == 0).any(axis=1) & (values > 0).any(axis=1)).any(): + raise ValueError("Childcare attendance mixes nonattendance and positive care.") + + +def _ids(table: pd.DataFrame, column: str, *, unique: bool) -> pd.Series: + ids = table[column] + if ( + ids.isna().any() + or not ids.map( + lambda value: isinstance(value, str) and bool(value.strip()) + ).all() + ): + raise ValueError(f"{column} must contain nonempty canonical string IDs.") + if unique and ids.duplicated().any(): + raise ValueError(f"{column} must be unique; donors cannot contain clones.") + return ids + + +def impute_us_childcare_attendance( + person: pd.DataFrame, + donor: pd.DataFrame, + *, + donor_weights: Weights, + match_columns: tuple[str, ...], + seed: int, + fallback_match_columns: tuple[tuple[str, ...], ...] = (), + sibling_dependence: float = 0.0, +) -> pd.DataFrame: + """Fill missing attendance for ages 0–12 by a joint weighted donor draw. + + ``donor_weights`` aligns positionally to the donor table. Exact matching must + include age; other fields (e.g. parental work and region) are supplied by a + source adapter. No implicit relaxation of an unsupported cell is allowed. + Nonparticipants belong in the donor pool with three observed zeros. Costs, + employment, CCDF eligibility and receipt are never used as participation + flags here. + + Draw once per canonical ``person_source_id``. Merge compatible observations + across support clones before matching, retaining every observed cell. The + selected donor supplies all remaining cells jointly, including nonattendance. + Donor row order, recipient row order and chunk boundaries do not affect the + draw (provided each source person's clones stay together). + + Return a copy with per-variable ``_source`` provenance. Missing + cells outside the source age domain remain null, not inferred zeros. Calling + this primitive on its own output preserves that provenance and is idempotent. + """ + if ( + not match_columns + or "age" not in match_columns + or len(set(match_columns)) != len(match_columns) + or set(match_columns) & set(US_CHILDCARE_ATTENDANCE_COLUMNS) + ): + raise ValueError("Unique matching columns must include age, not attendance.") + if not np.isfinite(sibling_dependence) or not 0 <= sibling_dependence <= 1: + raise ValueError("Sibling dependence must be between zero and one.") + if sibling_dependence > 0: + _ids(person, "childcare_source_household_id", unique=False) + if ( + person.childcare_source_household_id.str.strip() + .str.lower() + .isin(["nan", "none", ""]) + .any() + ): + raise ValueError( + "Childcare household source identities cannot be missing-value strings." + ) + levels = (match_columns, *fallback_match_columns) + if any( + "age" not in level + or len(set(level)) != len(level) + or not set(level).issubset(match_columns) + for level in levels + ): + raise ValueError( + "Childcare fallback fields must be unique subsets retaining age." + ) + for table, required in ( + (person, ("person_source_id", *match_columns)), + (donor, ("donor_id", *match_columns, *US_CHILDCARE_ATTENDANCE_COLUMNS)), + ): + missing = sorted(set(required) - set(table.columns)) + if missing: + raise ValueError(f"Childcare attendance requires columns: {missing}.") + if not table.columns.is_unique: + raise ValueError("Childcare attendance requires unique column names.") + _ids(person, "person_source_id", unique=False) + _ids(donor, "donor_id", unique=True) + if not isinstance(donor_weights, Weights): + raise TypeError("Childcare donors require typed survey Weights.") + if len(donor_weights) != len(donor): + raise ValueError("Childcare donor weights must align with donor rows.") + + result = person.copy(deep=True).reset_index(drop=True) + pool = donor.copy(deep=True).reset_index(drop=True) + for table in (result, pool): + age = pd.to_numeric(table["age"], errors="raise").to_numpy( + dtype=float, na_value=np.nan + ) + if not np.isfinite(age).all() or (age < 0).any() or (age % 1 != 0).any(): + raise ValueError("Childcare attendance requires finite whole-year ages.") + table["age"] = age + if (pool["age"] > 12).any(): + raise ValueError("Childcare donors must be children aged 0–12.") + children = result["age"] <= 12 + if ( + pool[list(match_columns)].isna().any().any() + or result.loc[children, list(match_columns)].isna().any().any() + ): + raise ValueError("Childcare matching fields must be complete for children.") + for column in US_CHILDCARE_ATTENDANCE_COLUMNS: + if column not in result: + result[column] = np.nan + for table in (result, pool): + table[column] = pd.to_numeric(table[column], errors="raise").astype(float) + provenance = f"{column}_source" + if provenance not in result: + result[provenance] = pd.Series(pd.NA, index=result.index, dtype="string") + observed = result[column].notna() & result[provenance].isna() + result.loc[observed, provenance] = "observed" + _validate_attendance(result, complete=False) + _validate_attendance(pool, complete=True) + pool["_donor_weight"] = donor_weights.values + order = ( + [ + US_CHILDCARE_ATTENDANCE_COLUMNS[1], + US_CHILDCARE_ATTENDANCE_COLUMNS[2], + "donor_id", + ] + if sibling_dependence > 0 + else ["donor_id"] + ) + pool = pool.sort_values(order).reset_index(drop=True) + groups = [ + pool.groupby(list(level), sort=False, dropna=False).indices for level in levels + ] + if fallback_match_columns and "childcare_attendance_match_level" not in result: + result["childcare_attendance_match_level"] = pd.Series( + pd.NA, index=result.index, dtype="string" + ) + + for source_id, rows in result.groupby( + "person_source_id", sort=False + ).groups.items(): + replicas = result.loc[rows] + if replicas[list(match_columns)].drop_duplicates().shape[0] != 1: + raise ValueError(f"Childcare clone matching fields disagree: {source_id}.") + if replicas["age"].iloc[0] > 12: + continue + known: dict[str, float] = {} + for column in US_CHILDCARE_ATTENDANCE_COLUMNS: + observed = replicas[column].dropna().unique() + if len(observed) > 1: + raise ValueError(f"Childcare clone observations disagree: {source_id}.") + if len(observed): + known[column] = float(observed[0]) + _validate_attendance( + pd.DataFrame([known], columns=US_CHILDCARE_ATTENDANCE_COLUMNS), + complete=False, + ) + missing = replicas[list(US_CHILDCARE_ATTENDANCE_COLUMNS)].isna() + if not missing.any().any(): + continue + if len(known) == len(US_CHILDCARE_ATTENDANCE_COLUMNS): + selected = known + source = f"source_person:{source_id}" + else: + for level, group in zip(levels, groups, strict=True): + key = tuple(replicas[column].iloc[0] for column in level) + group_key = key[0] if len(key) == 1 else key + candidates = pool.iloc[group.get(group_key, [])] + candidates = candidates.loc[candidates["_donor_weight"] > 0] + for column, value in known.items(): + candidates = candidates.loc[candidates[column] == value] + if not candidates.empty: + break + if candidates.empty: + raise ValueError( + f"No compatible positive-weight childcare donor: {source_id}." + ) + # Scale before summing to avoid overflow from large survey weights. + weights = candidates["_donor_weight"].to_numpy(dtype=float) + weights = weights / weights.max() + cumulative = np.cumsum(weights / weights.sum()) + payload = json.dumps([int(seed), "childcare_attendance", source_id]) + if sibling_dependence > 0: + household_ids = replicas.childcare_source_household_id.unique() + if len(household_ids) != 1: + raise ValueError( + "Childcare source clones disagree about household identity." + ) + household = household_ids[0] + selection = hashlib.sha256( + json.dumps([int(seed), "sibling_mixture", household]).encode() + ).digest() + if ( + int.from_bytes(selection[:8], "big") >> 11 + ) / 2**53 < sibling_dependence: + payload = json.dumps( + [int(seed), "childcare_household_rank", household] + ) + digest = hashlib.sha256(payload.encode()).digest() + draw = (int.from_bytes(digest[:8], "big") >> 11) / 2**53 + position = min( + int(np.searchsorted(cumulative, draw, side="right")), + len(candidates) - 1, + ) + selected = candidates.iloc[position] + source = f"donor:{selected['donor_id']}" + if fallback_match_columns: + result.loc[rows, "childcare_attendance_match_level"] = ",".join(level) + for column in US_CHILDCARE_ATTENDANCE_COLUMNS: + empty_rows = replicas.index[replicas[column].isna()] + result.loc[empty_rows, column] = selected[column] + result.loc[empty_rows, f"{column}_source"] = source + + _validate_attendance(result, complete=False) + result[US_CHILDCARE_ATTENDANCE_COLUMNS[0]] = result[ + US_CHILDCARE_ATTENDANCE_COLUMNS[0] + ].astype("Int64") + # Preserve caller indices, ordering and all unrelated source columns. + result.index = person.index + result["age"] = person["age"] + return result diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/childcare_attendance_receipt.py b/packages/microcosm-build/src/microcosm/build/us_runtime/childcare_attendance_receipt.py new file mode 100644 index 000000000..be67e3c7c --- /dev/null +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/childcare_attendance_receipt.py @@ -0,0 +1,250 @@ +"""Content-bound attendance lineage across checkpoints, selection and native H5. + +Hashes detect changed values or execution metadata, not maliciously forged +receipts. Publication authorization and independent source review are separate. +Weights may change and whole-household exports may select/reorder people; each +retained person's identity, age, membership and attendance must remain exact. +""" + +from __future__ import annotations + +import hashlib +import json +from importlib.metadata import PackageNotFoundError, version +from pathlib import Path + +import numpy as np +import pandas as pd + +from microcosm.build.us_runtime.childcare_attendance import ( + US_CHILDCARE_ATTENDANCE_COLUMNS, + childcare_attendance_contract, +) +from microcosm.frame import Frame + +ATTENDANCE_RECEIPT_KEY = "childcare_attendance_binding" +ATTENDANCE_H5_KEY = "_childcare_attendance_receipt" +ATTENDANCE_CONTEXT_KEYS = ( + "nsece_childcare_attendance", + "childcare_predictor_harmonization", + "childcare_outside_domain_baseline", + "childcare_attendance_stage", +) + + +def _plain(value): + return json.loads(json.dumps(value, default=dict, allow_nan=False)) + + +def _digest(value): + return hashlib.sha256( + json.dumps( + value, sort_keys=True, separators=(",", ":"), allow_nan=False + ).encode() + ).hexdigest() + + +def attendance_recipe_identity(): + """Bind the packaged source contract and the code implementing its recipe.""" + directory = Path(__file__).parent + names = ( + "childcare_attendance.py", + "childcare_population.py", + "nsece_childcare.py", + "nsece_childcare_bridge.py", + "nsece_childcare_dependence.py", + "childcare_attendance_stage.py", + "childcare_attendance_receipt.py", + ) + versions = {} + for name in ("numpy", "pandas", "policyengine-us"): + try: + versions[name] = version(name) + except PackageNotFoundError: + versions[name] = None + return { + "contract_sha256": _digest(childcare_attendance_contract()), + "runtime_versions": versions, + "code_sha256": { + name: hashlib.sha256((directory / name).read_bytes()).hexdigest() + for name in names + }, + } + + +def _context(frame): + return _plain( + { + key: frame.metadata[key] + for key in ATTENDANCE_CONTEXT_KEYS + if key in frame.metadata + } + ) + + +def _row_digests(people, execution_sha256): + required = [ + "person_id", + "person_household_id", + "age", + *US_CHILDCARE_ATTENDANCE_COLUMNS, + ] + if not set(required).issubset(people): + raise ValueError( + "Attendance binding requires person IDs, household links, age and all outputs." + ) + if ( + people.reindex(columns=required[:3]).isna().any().any() + or people.person_id.duplicated().any() + ): + raise ValueError( + "Attendance binding requires unique person IDs and complete identity/age." + ) + result = {} + for row in people.reindex(columns=required).itertuples(index=False, name=None): + key = str(row[0]) + if key in result: + raise ValueError( + "Attendance person IDs have ambiguous canonical representations." + ) + result[key] = _digest( + [ + execution_sha256, + key, + str(row[1]), + *[None if pd.isna(x) else float(x) for x in row[2:]], + ] + ) + return result + + +def bind_childcare_attendance(frame): + """Seal a freshly executed source stage; never use this to bless loaded values.""" + context = _context(frame) + if "nsece_childcare_attendance" not in context: + raise ValueError("Cannot bind attendance without a source execution receipt.") + execution = {"recipe": attendance_recipe_identity(), "context": context} + execution_sha256 = _digest(execution) + binding = { + "schema_version": 1, + "execution": execution, + "execution_sha256": execution_sha256, + # Frame metadata uses small immutable mappings with linear key lookup. + # A sequence keeps freezing/serializing a population-sized inventory + # linear; construct a temporary dict only while verifying it. + "rows": list(_row_digests(frame.table("person"), execution_sha256).items()), + } + binding["binding_sha256"] = _digest(binding) + return Frame( + {e: frame.table(e) for e in frame.entities}, + frame.schema, + {e: frame.weights_for(e) for e in frame.weighted_entities}, + frame.strata, + mass_log=frame.mass_log, + metadata={**frame.metadata, ATTENDANCE_RECEIPT_KEY: binding}, + ) + + +def assert_bound_childcare_attendance(frame, *, require_stage=True): + """Validate the exact retained values and recipe; reject stale/unbound inputs.""" + binding = _plain(frame.metadata.get(ATTENDANCE_RECEIPT_KEY, {})) + if binding.get("schema_version") != 1: + raise ValueError( + "Attendance needs a content-bound source receipt; rebuild from the original parent." + ) + claimed = binding.pop("binding_sha256", None) + if claimed != _digest(binding): + raise ValueError("Attendance receipt content hash mismatch.") + execution = binding["execution"] + if binding["execution_sha256"] != _digest(execution): + raise ValueError("Attendance execution hash mismatch.") + if execution["context"] != _context(frame): + raise ValueError("Attendance metadata disagrees with its bound execution.") + context = execution["context"] + if require_stage: + # Code/runtime identity gates binding and release export. Read-only + # ingress checks content only, so a released H5 stays loadable after a + # dependency bump or an edit to the recipe modules. + if execution["recipe"] != attendance_recipe_identity(): + raise ValueError( + "Attendance recipe changed; rebuild from the original parent." + ) + stage = context.get("childcare_attendance_stage", {}) + source = context.get("nsece_childcare_attendance", {}) + expected = [x["sha256"] for x in childcare_attendance_contract()["artifacts"]] + if ( + [x.get("sha256") for x in source.get("artifacts", [])] != expected + or stage.get("stage") != "nsece_childcare_attendance" + or stage.get("seed") != source.get("seed") + or stage.get("modeled_age_domain") != [0, 12] + or stage.get("outside_domain_policy") + not in ("require_observed", "inherit_engine_baseline") + ): + raise ValueError( + "Attendance release requires the pinned production source stage receipt." + ) + rows = dict(binding["rows"]) + if len(rows) != len(binding["rows"]): + raise ValueError("Attendance receipt contains duplicate person identities.") + for person, digest in _row_digests( + frame.table("person"), binding["execution_sha256"] + ).items(): + if rows.get(person) != digest: + raise ValueError( + "Attendance values, identities or membership differ from the source receipt." + ) + return { + "schema_version": 1, + "binding_sha256": claimed, + "execution_sha256": binding["execution_sha256"], + "source_people": len(binding["rows"]), + "retained_people": len(frame.table("person")), + "execution": execution, + } + + +def attendance_receipt_payload(metadata): + """Only the attendance context and binding; never unrelated frame metadata.""" + keys = (*ATTENDANCE_CONTEXT_KEYS, ATTENDANCE_RECEIPT_KEY) + return _plain({key: metadata[key] for key in keys if key in metadata}) + + +def write_native_childcare_receipt(path, metadata): + """Append the receipt key to a written native H5; entity tables are untouched.""" + payload = json.dumps(attendance_receipt_payload(metadata), allow_nan=False) + with pd.HDFStore(path, mode="a") as store: + store.put(ATTENDANCE_H5_KEY, pd.Series([payload])) + + +def restore_native_childcare_receipt(path, frame): + """Load the receipt through either native ingress, preserving its validation.""" + with pd.HDFStore(path, mode="r") as store: + metadata = ( + attendance_receipt_payload(json.loads(store[ATTENDANCE_H5_KEY].iloc[0])) + if ATTENDANCE_H5_KEY in store + else {} + ) + if metadata: + frame = Frame( + {e: frame.table(e) for e in frame.entities}, + frame.schema, + {e: frame.weights_for(e) for e in frame.weighted_entities}, + frame.strata, + mass_log=frame.mass_log, + metadata={**frame.metadata, **metadata}, + ) + assert_bound_childcare_attendance(frame, require_stage=False) + else: + people = frame.table("person") + columns = [c for c in US_CHILDCARE_ATTENDANCE_COLUMNS if c in people] + if columns and np.any(people[columns].fillna(0).to_numpy(dtype=float) != 0): + raise ValueError( + "Native attendance values lack a bound receipt; rebuild from the original parent." + ) + return frame + + +def childcare_attendance_public_metadata(frame): + """Aggregate-only evidence: never publish the private person hash inventory.""" + summary = assert_bound_childcare_attendance(frame, require_stage=False) + return {**_context(frame), ATTENDANCE_RECEIPT_KEY: summary} diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/childcare_attendance_stage.py b/packages/microcosm-build/src/microcosm/build/us_runtime/childcare_attendance_stage.py new file mode 100644 index 000000000..adb6a3970 --- /dev/null +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/childcare_attendance_stage.py @@ -0,0 +1,326 @@ +"""Build-stage orchestration for the licensed NSECE attendance source extension. + +The existing generation-0 source manifest is byte-frozen. This extension has a +separate packaged SourceStageSpec and runs after the childcare-expense and hours +producers (the harmonizer reads raw parent pointers and last-week hours). +It is also callable on an exact native parent for candidate qualification. +""" + +from __future__ import annotations + +import json +import shutil +from importlib.metadata import version +from pathlib import Path + +import numpy as np +import pandas as pd + +from microcosm.build.serialization_dtypes import canonicalize_table_string_dtypes +from microcosm.build.source_manifest import SourceStageSpec +from microcosm.build.us_runtime.childcare_attendance import ( + US_CHILDCARE_ATTENDANCE_COLUMNS, + childcare_attendance_contract, +) +from microcosm.build.us_runtime.childcare_attendance_receipt import ( + ATTENDANCE_H5_KEY, + assert_bound_childcare_attendance, + attendance_receipt_payload, + bind_childcare_attendance, + write_native_childcare_receipt, +) +from microcosm.build.us_runtime.childcare_population import ( + harmonize_asec_childcare_predictors, +) +from microcosm.build.us_runtime.nsece_childcare import ( + NSECE_CHILDCARE_FALLBACK_COLUMNS, + NSECE_CHILDCARE_MATCH_COLUMNS, + assert_childcare_attendance_exportable, + load_nsece_childcare, + with_us_nsece_childcare_attendance, +) +from microcosm.build.us_runtime.nsece_childcare_bridge import ( + bridge_nsece_noncalendar_attendance, +) +from microcosm.build.us_runtime.nsece_childcare_dependence import ( + fit_nsece_sibling_dependence, +) +from microcosm.frame import Frame, put_frame_table + + +def inherit_outside_domain_attendance_baseline(frame: Frame) -> Frame: + """Explicit export policy: retain engine baseline only outside modeled ages. + + This does NOT infer measured nonattendance for teens or disabled older + children. Receipts identify the inherited values and source-domain limits. + Observed values are preserved and all under-13 records must be resolved. + """ + from policyengine_us import CountryTaxBenefitSystem + + assert_bound_childcare_attendance(frame, require_stage=False) + people = frame.table("person").copy() + system = CountryTaxBenefitSystem() + outside = ~people.age.between(0, 12) + defaults, inherited = {}, {} + for column in US_CHILDCARE_ATTENDANCE_COLUMNS: + if column not in people: + raise ValueError( + "Attendance must be imputed before inheriting the outside-domain baseline." + ) + if people.loc[~outside, column].isna().any(): + raise ValueError( + "Cannot inherit baseline for unresolved under-13 attendance." + ) + default = system.variables[column].default_value + if not np.isfinite(default): + raise ValueError("The pinned engine attendance baseline must be finite.") + missing = outside & people[column].isna() + people.loc[missing, column] = default + people.loc[missing, f"{column}_source"] = ( + "inherited_engine_baseline_outside_age_0_12" + ) + defaults[column] = float(default) + inherited[column] = int(missing.sum()) + tables = {entity: frame.table(entity) for entity in frame.entities} + tables["person"] = people + return bind_childcare_attendance( + Frame( + tables, + frame.schema, + {entity: frame.weights_for(entity) for entity in frame.weighted_entities}, + frame.strata, + mass_log=frame.mass_log, + metadata={ + **frame.metadata, + "childcare_outside_domain_baseline": { + "engine_version": version("policyengine-us"), + "values": defaults, + "inherited_counts": inherited, + "interpretation": "baseline retained; not evidence of nonattendance outside ages 0-12", + }, + }, + ) + ) + + +def with_us_childcare_attendance_inputs( + frame: Frame, + *, + household_tsv: str | Path, + calendar_tsv: str | Path, + asec_source_cache: str | Path | None, + seed: int, + inherit_outside_domain_baseline: bool = False, +) -> Frame: + """Run the source/bridge/target recipe and enforce the export contract.""" + contract = childcare_attendance_contract() + spec = SourceStageSpec.from_mapping(contract) + if tuple(spec.outputs) != US_CHILDCARE_ATTENDANCE_COLUMNS: + raise ValueError( + "Childcare source-stage outputs drifted from the engine inputs." + ) + source = load_nsece_childcare(household_tsv, calendar_tsv) + outside_policy = ( + "inherit_engine_baseline" + if inherit_outside_domain_baseline + else "require_observed" + ) + if "childcare_attendance_stage" in frame.metadata: + assert_bound_childcare_attendance(frame) + previous = frame.metadata["childcare_attendance_stage"] + if ( + previous["seed"] != seed + or previous["outside_domain_policy"] != outside_policy + ): + raise ValueError( + "Attendance settings changed; rebuild from the original parent." + ) + assert_childcare_attendance_exportable(frame) + return frame + people = frame.table("person") + existing = [c for c in US_CHILDCARE_ATTENDANCE_COLUMNS if c in people] + if existing and people.loc[people.age.between(0, 12), existing].notna().any().any(): + raise ValueError( + "Pre-existing child attendance lacks a production receipt; rebuild from the original parent." + ) + outside = people.loc[~people.age.between(0, 12)] + if ( + not inherit_outside_domain_baseline + and len(outside) + and ( + len(existing) < len(US_CHILDCARE_ATTENDANCE_COLUMNS) + or outside[existing].isna().any().any() + ) + ): + # Fail before the bridge and donor draw: only ages 0-12 are modeled. + raise ValueError( + "Persons outside ages 0-12 have no observed attendance and the " + "require_observed policy cannot export them; pass " + "inherit_outside_domain_baseline=True " + "(--childcare-attendance-inherit-outside-domain-baseline)." + ) + dependence = fit_nsece_sibling_dependence(source.children) + source = bridge_nsece_noncalendar_attendance(source, seed=seed) + normalized = harmonize_asec_childcare_predictors( + frame, source_cache=asec_source_cache + ) + candidate = with_us_nsece_childcare_attendance( + normalized, + source, + seed=seed, + match_columns=NSECE_CHILDCARE_MATCH_COLUMNS, + fallback_match_columns=NSECE_CHILDCARE_FALLBACK_COLUMNS, + sibling_dependence=dependence["rho"], + ) + if inherit_outside_domain_baseline: + candidate = inherit_outside_domain_attendance_baseline(candidate) + assert_childcare_attendance_exportable(candidate) + return bind_childcare_attendance( + Frame( + {entity: candidate.table(entity) for entity in candidate.entities}, + candidate.schema, + { + entity: candidate.weights_for(entity) + for entity in candidate.weighted_entities + }, + candidate.strata, + mass_log=candidate.mass_log, + metadata={ + **candidate.metadata, + "childcare_attendance_stage": { + "stage": spec.stage, + "outputs": spec.outputs, + "seed": seed, + "operations": [ + { + "kind": spec.operations[0].kind, + **spec.operations[0].parameters, + }, + { + "kind": "fit", + "operation": "fit_sibling_dependence", + "rho": dependence["rho"], + }, + { + "kind": spec.operations[1].kind, + **spec.operations[1].parameters, + }, + { + "kind": "derive", + "operation": "harmonize_asec_childcare_predictors", + }, + { + "kind": spec.operations[2].kind, + **spec.operations[2].parameters, + }, + {"kind": "export_policy", "operation": outside_policy}, + ], + "sibling_dependence": dependence, + "modeled_age_domain": [0, 12], + "outside_domain_policy": "inherit_engine_baseline" + if inherit_outside_domain_baseline + else "require_observed", + }, + }, + ) + ) + + +def export_native_childcare_candidate( + parent_path: str | Path, candidate: Frame, output_path: str | Path +) -> Path: + """Add only attendance inputs to a new native H5, verifying every old column. + + The parent and its period are preserved. This is a local candidate export, + not a source-enrichment release or a publication/certification operation. + """ + from policyengine_us.data import USSingleYearDataset + + parent_path, output_path = Path(parent_path), Path(output_path) + if output_path.exists() or parent_path.resolve() == output_path.resolve(): + raise ValueError("Native childcare output must be a new path.") + assert_childcare_attendance_exportable(candidate) + assert_bound_childcare_attendance(candidate, require_stage=False) + parent = USSingleYearDataset(file_path=str(parent_path)) + attendance = set(US_CHILDCARE_ATTENDANCE_COLUMNS) + for entity in candidate.entities: + old = getattr(parent, entity) + reference = old.drop(columns=["household_weight"], errors="ignore") + columns = [c for c in reference if c not in attendance] + pd.testing.assert_frame_equal( + canonicalize_table_string_dtypes( + reference[columns], + boundary="native_childcare_export", + table_name=entity, + ), + canonicalize_table_string_dtypes( + candidate.table(entity)[columns], + boundary="native_childcare_export", + table_name=entity, + ), + ) + np.testing.assert_array_equal( + parent.household.household_weight.to_numpy(), + candidate.weights_for("household").values, + ) + people = parent.person.copy() + for column in US_CHILDCARE_ATTENDANCE_COLUMNS: + people[column] = candidate.table("person")[column] + output_path.parent.mkdir(parents=True, exist_ok=True) + temporary = output_path.with_name(output_path.name + ".partial.h5") + if temporary.exists(): + raise ValueError("Native childcare temporary path already exists.") + try: + shutil.copyfile(parent_path, temporary) + _write_childcare_candidate_person_table(temporary, people, candidate.metadata) + loaded = USSingleYearDataset(file_path=str(temporary)) + pd.testing.assert_frame_equal(loaded.person, people) + for entity in candidate.schema.group_entities: + pd.testing.assert_frame_equal( + getattr(loaded, entity), getattr(parent, entity) + ) + if loaded.time_period != parent.time_period: + raise ValueError("Native childcare export changed the parent's period.") + temporary.rename(output_path) + finally: + temporary.unlink(missing_ok=True) + return output_path + + +def _write_childcare_candidate_person_table( + path: Path, people: pd.DataFrame, receipt: dict +) -> None: + """Replace the prepared person table through the shared dtype boundary. + + The caller owns the temporary copy and verifies the native dataset reload. + Keep nullable booleans and their masks intact if the person table has them. + """ + payload = json.dumps(attendance_receipt_payload(receipt), allow_nan=False) + with pd.HDFStore(path, mode="a") as store: + put_frame_table( + store, "person", people, preferred_format="table", data_columns=True + ) + store.put(ATTENDANCE_H5_KEY, pd.Series([payload])) + + +def persist_native_childcare_receipt(path: str | Path, frame: Frame) -> dict: + """Persist final release evidence and verify the actual serialized attendance.""" + from policyengine_us.data import USSingleYearDataset + + from microcosm.build.us_runtime.childcare_attendance_receipt import ( + restore_native_childcare_receipt, + ) + + assert_childcare_attendance_exportable(frame) + summary = assert_bound_childcare_attendance(frame) + # The engine already wrote every entity table; only the receipt key is added. + write_native_childcare_receipt(path, frame.metadata) + # Use the written values, not the pre-export arrays, for the binding check. + dataset = USSingleYearDataset(file_path=str(path)) + tables = {e: getattr(dataset, e).copy() for e in frame.entities} + tables["household"] = tables["household"].drop(columns="household_weight") + written = Frame( + tables, frame.schema, {e: frame.weights_for(e) for e in frame.weighted_entities} + ) + restore_native_childcare_receipt(path, written) + return summary diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/childcare_population.py b/packages/microcosm-build/src/microcosm/build/us_runtime/childcare_population.py new file mode 100644 index 000000000..f6fd73b99 --- /dev/null +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/childcare_population.py @@ -0,0 +1,232 @@ +"""Harmonize measured ASEC parent relationships for child attendance candidates. + +The source adapter resolves Census PEPAR1/PEPAR2 within physical households. +It never equates all adults with parents. The downstream donor kernel consumes +only normalized age, region and parent-work fields, independent of source spine. +""" + +from __future__ import annotations + +import hashlib +from pathlib import Path + +import numpy as np +import pandas as pd + +from microcosm.build.us_runtime.childcare_attendance import ( + childcare_attendance_contract, + childcare_income_band, +) +from microcosm.build.us_runtime.education_assistance_source import ( + ASEC_EDUCATION_ASSISTANCE_ARCHIVES, +) +from microcosm.calibrate.geography_constants import ( + US_STATE_NUMERIC_FIPS_TO_CENSUS_REGION, +) +from microcosm.frame import US_SCHEMA, Frame + + +def harmonize_asec_childcare_predictors( + frame: Frame, *, source_cache: str | Path | None = None +) -> Frame: + """Normalize parents of *any* under-13 child, matching NSECE's household unit. + + Census documents PEPAR1/PEPAR2 as parent line numbers and A_LINENO as the + unique person line number. Nonpositive pointers mean no resident parent; + positive pointers must resolve in the same household. Current-week work is + measured by hours_worked_last_week, not annual earnings or usual hours. + https://api.census.gov/data/2025/cps/asec/mar/variables.html + """ + if frame.schema != US_SCHEMA: + raise ValueError("Childcare source harmonization requires a US Frame.") + person = frame.table("person").copy() + required = ( + "person_household_id", + "person_source_id", + "age", + "A_LINENO", + "PEPAR1", + "PEPAR2", + "hours_worked_last_week", + "PTOTVAL", + "source_year", + ) + missing = sorted(set(required) - set(person)) + if missing: + raise ValueError(f"ASEC childcare source fields are missing: {missing}.") + if person.duplicated(["person_household_id", "A_LINENO"]).any(): + raise ValueError("ASEC person line numbers must be unique within households.") + values = person[ + ["age", "A_LINENO", "PEPAR1", "PEPAR2", "hours_worked_last_week"] + ].to_numpy(dtype=float) + if not np.isfinite(values).all() or (values[:, [0, 4]] < 0).any(): + raise ValueError( + "ASEC childcare predictors must be finite with nonnegative age/hours." + ) + if ( + (values[:, :4] % 1 != 0).any() + or (values[:, 1] <= 0).any() + or (values[:, 2:4] < -1).any() + ): + raise ValueError("ASEC ages and parent/person line numbers are invalid.") + young = person.age.between(0, 12) + refs = person.loc[young, ["person_household_id", "PEPAR1", "PEPAR2"]].melt( + id_vars="person_household_id", value_name="A_LINENO" + )[["person_household_id", "A_LINENO"]] + refs = refs.loc[refs.A_LINENO > 0].drop_duplicates() + parents = refs.merge( + person[["person_household_id", "A_LINENO", "hours_worked_last_week"]], + on=["person_household_id", "A_LINENO"], + how="left", + validate="one_to_one", + indicator=True, + ) + if parents._merge.ne("both").any(): + raise ValueError( + "A positive ASEC parent pointer does not resolve within its household." + ) + parents["worked"] = parents.hours_worked_last_week > 0 + counts = parents.groupby("person_household_id").worked.agg(["size", "sum"]) + number = person.person_household_id.map(counts["size"]).fillna(0).to_numpy() + worked = person.person_household_id.map(counts["sum"]).fillna(0).to_numpy() + status = np.select( + [number == 0, worked == 0, worked == number], [-1, 0, 2], default=1 + ) + household = frame.table("household") + if "household_source_id" in household: + identities = household.set_index("household_id").household_source_id + if not identities.index.is_unique or identities.isna().any(): + raise ValueError( + "Childcare household identities must be complete and uniquely linked." + ) + mapped = person.person_household_id.map(identities) + if mapped.isna().any(): + raise ValueError("Childcare person-to-household link does not resolve.") + if not mapped.map( + lambda value: ( + ( + isinstance(value, str) + and value.strip().lower() not in ("", "nan", "none", "") + ) + or ( + isinstance(value, (int, np.integer)) and not isinstance(value, bool) + ) + ) + ).all(): + raise ValueError( + "Childcare household identities must be canonical strings or integers." + ) + person["childcare_source_household_id"] = mapped.astype(str) + contract = childcare_attendance_contract() + prices = { + int(year): value for year, value in contract["cpi_u_annual_average"].items() + } + source_prices = person.source_year.map(prices) + income_values, income_receipts = _income_source_values(person, source_cache) + if source_prices.isna().any() or not np.isfinite(income_values).all(): + raise ValueError( + "ASEC childcare income needs finite PTOTVAL; supply the pinned ASEC source cache for omitted raw fields." + ) + real_income = ( + income_values * prices[contract["income_reference_year"]] / source_prices + ) + income = real_income.groupby(person.person_household_id).sum() + income_band = childcare_income_band(person.person_household_id.map(income)) + states = household.set_index("household_id").state_fips + region = person.person_household_id.map(states).map( + US_STATE_NUMERIC_FIPS_TO_CENSUS_REGION + ) + if region.isna().any(): + raise ValueError( + "Childcare target contains an unknown household/state/region link." + ) + for name, data in ( + ("parent_work_status", status), + ("region", region.to_numpy()), + ("income_band", income_band), + ): + if name in person and not np.array_equal(person[name].to_numpy(), data): + raise ValueError( + f"Existing childcare predictor {name} disagrees with source harmonization." + ) + person[name] = data + tables = {entity: frame.table(entity) for entity in frame.entities} + tables["person"] = person + return Frame( + tables, + frame.schema, + {entity: frame.weights_for(entity) for entity in frame.weighted_entities}, + frame.strata, + mass_log=frame.mass_log, + metadata={ + **frame.metadata, + "childcare_predictor_harmonization": { + "source": "ASEC resident parent line pointers", + "parent_universe": "parents of any child age 0 through 12 in household", + "work_measure": "hours_worked_last_week > 0", + "geography": "Census region from target state_fips", + "income_source_receipts": income_receipts, + "income": "Household sum of measured ASEC PTOTVAL, CPI-U adjusted from source year to 2023 dollars", + }, + }, + ) + + +def _income_source_values(person, source_cache): + values = person.PTOTVAL.copy() + receipts = [] + if source_cache is None: + return values, receipts + for year in sorted(person.source_year.unique()): + if year not in ASEC_EDUCATION_ASSISTANCE_ARCHIVES: + raise ValueError("No pinned ASEC source covers this income year.") + pin = ASEC_EDUCATION_ASSISTANCE_ARCHIVES[year] + path = Path(source_cache) / pin.member + with path.open("rb") as stream: + digest = hashlib.file_digest(stream, "sha256").hexdigest() + if digest != pin.member_sha256 or path.stat().st_size != pin.member_size_bytes: + raise ValueError("ASEC childcare income source identity mismatch.") + raw = pd.read_csv( + path, + usecols=["PERIDNUM", "PTOTVAL", "A_LINENO", "A_AGE"], + dtype={"PERIDNUM": str}, + ) + if len(raw) != pin.rows or raw.PERIDNUM.duplicated().any(): + raise ValueError( + "ASEC childcare income source person keys/count are invalid." + ) + selected = person.source_year.eq(year) + keys = person.loc[selected, "PERIDNUM"] + if not keys.astype(str).str.fullmatch(r"[0-9]{22}").all(): + raise ValueError( + "ASEC childcare income join requires exact 22-digit PERIDNUM." + ) + joined = raw.set_index("PERIDNUM").reindex(keys) + if ( + joined.isna().any().any() + or not np.array_equal( + joined.A_LINENO.to_numpy(), person.loc[selected, "A_LINENO"].to_numpy() + ) + or not np.array_equal( + joined.A_AGE.to_numpy(), person.loc[selected, "A_AGE"].to_numpy() + ) + ): + raise ValueError( + "ASEC childcare income join fails person/line/age reconciliation." + ) + observed = values.loc[selected].notna().to_numpy() + if not np.array_equal( + values.loc[selected].to_numpy()[observed], + joined.PTOTVAL.to_numpy()[observed], + ): + raise ValueError("Observed ASEC PTOTVAL disagrees with pinned source.") + values.loc[selected] = joined.PTOTVAL.to_numpy() + receipts.append( + { + "income_year": int(year), + "sha256": digest, + "matched_people": int(selected.sum()), + "source_rows": len(raw), + } + ) + return values, receipts diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/childcare_sensitivity.py b/packages/microcosm-build/src/microcosm/build/us_runtime/childcare_sensitivity.py new file mode 100644 index 000000000..f7d10a0ee --- /dev/null +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/childcare_sensitivity.py @@ -0,0 +1,181 @@ +"""Assumption stress tests for noncalendar schedules; never source observations.""" + +from __future__ import annotations + +import gc + +import numpy as np +import pandas as pd + +from microcosm.build.us_runtime.childcare_attendance import ( + US_CHILDCARE_ATTENDANCE_COLUMNS, + _ids, + _validate_attendance, +) +from microcosm.build.us_runtime.nsece_childcare import NSECEChildcareSource +from microcosm.calibrate.geography_constants import US_STATE_NUMERIC_FIPS_TO_POSTAL + + +def paired_noncalendar_attendance(people, source, alternative): + """Apply an assumption change to the same selected donor, preserving observations. + + Quantile-coupled retransfers can change donor identities when schedules change + sort order. This contrast instead conditions on the realized donor assignment. + It is an assumption diagnostic, not a replacement population or receipt. + """ + columns = list(US_CHILDCARE_ATTENDANCE_COLUMNS) + before = source.children.set_index("donor_id", drop=False).sort_index() + after = alternative.children.set_index("donor_id", drop=False).sort_index() + _ids(before, "donor_id", unique=True) + _ids(after, "donor_id", unique=True) + if not before.index.equals(after.index): + raise ValueError("Paired sensitivity requires the same donor identities.") + # These are the only reconstructed fields the scenario may change. + modeled = [*columns, "ece_hours_per_week", "irregular_hours_per_week"] + pd.testing.assert_frame_equal( + before.drop(columns=modeled, errors="ignore"), + after.drop(columns=modeled, errors="ignore"), + check_exact=True, + ) + fixed = before.attendance_status.ne("summary_bridge") + pd.testing.assert_frame_equal( + before.loc[fixed, columns], after.loc[fixed, columns], check_exact=True + ) + _validate_attendance(before, complete=False) + _validate_attendance(after, complete=False) + _validate_attendance(people, complete=False) + result = ( + people.reindex(columns=columns).to_numpy(dtype=float, na_value=np.nan).copy() + ) + original = result.copy() + labels = people.reindex(columns=[f"{c}_source" for c in columns]).astype("string") + selected = labels.apply(lambda col: col.str.startswith("donor:", na=False)) + donor_ids = labels.where(selected).apply(lambda col: col.str.removeprefix("donor:")) + if donor_ids.nunique(axis=1).gt(1).any(): + raise ValueError("Paired sensitivity found mixed donor lineage within a child.") + row_donor = donor_ids.bfill(axis=1).iloc[:, 0] + uses_donor = selected.any(axis=1).to_numpy() + if (uses_donor & ~people.age.between(0, 12).to_numpy()).any(): + raise ValueError("Paired sensitivity found an out-of-domain donor assignment.") + if ( + row_donor.loc[uses_donor].isna().any() + or not row_donor.loc[uses_donor].isin(before.index).all() + ): + raise ValueError("Paired sensitivity cannot resolve a selected donor.") + expected = before.reindex(row_donor).reindex(columns=columns).to_numpy(dtype=float) + changed = after.reindex(row_donor).reindex(columns=columns).to_numpy(dtype=float) + mask = selected.to_numpy(dtype=bool) + if not np.array_equal(original[mask], expected[mask]): + raise ValueError("Candidate attendance does not match its selected donor.") + # Observed/clone-inherited constraints must remain compatible with the donor. + constrained = uses_donor[:, None] & ~mask & np.isfinite(original) + if not np.array_equal(original[constrained], changed[constrained]): + raise ValueError("Paired scenario conflicts with observed attendance.") + result[mask] = changed[mask] + _validate_attendance(pd.DataFrame(result, columns=columns), complete=False) + modified = np.any(~np.isclose(result, original, equal_nan=True), axis=1) + bridge = row_donor.map(before.attendance_status).eq("summary_bridge").to_numpy() + if (modified & ~bridge).any(): + raise ValueError("Paired scenario changed a measured-calendar assignment.") + return result, { + "donor_assigned_people": int(uses_donor.sum()), + "bridge_assigned_people": int(bridge.sum()), + "changed_people": int(modified.sum()), + "measured_calendar_assignments_changed": 0, + "donor_assignment": "held fixed and validated against candidate values", + } + + +def noncalendar_sensitivity_source(source, *, irregular_hours=True, day_shift=0): + """Change only modeled bridge components, keeping measured regular hours. + + The selected donor's days shift by one, bounded by 1--7 and the minimum + feasible days at 24 hours/day. Zero total hours always means zero days. + These brackets are stress tests, not confidence intervals. + """ + if day_shift not in (-1, 0, 1): + raise ValueError("The sensitivity day shift must be -1, 0 or 1.") + children = source.children.copy() + rows = children.attendance_status.eq("summary_bridge") + month, days, hours = US_CHILDCARE_ATTENDANCE_COLUMNS + regular = children.loc[rows, "regular_hours_per_week"].to_numpy(dtype=float) + irregular = children.loc[rows, "irregular_hours_per_week"].to_numpy(dtype=float) + if not irregular_hours: + irregular = np.zeros_like(irregular) + total = regular + irregular + attended = np.clip(children.loc[rows, days].to_numpy(dtype=float) + day_shift, 1, 7) + attended = np.where(total > 0, np.maximum(attended, np.ceil(total / 24)), 0) + children.loc[rows, days] = attended + children.loc[rows, month] = np.floor(attended * 52 / 12 + 0.5) + children.loc[rows, hours] = np.divide( + total, attended, out=np.zeros_like(total), where=attended > 0 + ) + children.loc[rows, "ece_hours_per_week"] = total + children.loc[rows, "irregular_hours_per_week"] = irregular + return NSECEChildcareSource( + children, + source.weights, + { + **source.source_receipt, + "transport_sensitivity": { + "include_modeled_irregular_hours": irregular_hours, + "modeled_day_shift": day_shift, + "measured_regular_hours_preserved": True, + }, + }, + ) + + +def compare_childcare_scenarios(parent, scenarios, *, year=2026): + """Yield state comparisons on one fixed population; vary only attendance.""" + from policyengine_us import Microsimulation + from policyengine_us.data import USSingleYearDataset + + people = parent.table("person") + young = people.age.between(0, 12).to_numpy() + for name, values in scenarios.items(): + if np.shape(values) != (len(people), 3) or not np.isfinite(values[young]).all(): + raise ValueError(f"Invalid scenario attendance: {name}") + households = parent.table("household").copy() + households["household_weight"] = parent.weights_for("household").values + for fips, group in households.groupby("state_fips", sort=True): + state = US_STATE_NUMERIC_FIPS_TO_POSTAL[int(fips)] + selected = people.person_household_id.isin(group.household_id) + state_people = people.loc[selected].copy() + tables = {"person": state_people, "household": group} + for entity in parent.schema.group_entities: + if entity != "household": + table = parent.table(entity) + tables[entity] = table.loc[ + table[f"{entity}_id"].isin(state_people[f"person_{entity}_id"]) + ] + result = {"state": state, "sample_households": len(group)} + for name, attendance in {"baseline": None, **scenarios}.items(): + sim = Microsimulation( + dataset=USSingleYearDataset(**tables, time_period=year) + ) + if attendance is not None: + for i, column in enumerate(US_CHILDCARE_ATTENDANCE_COLUMNS): + values = np.asarray(sim.calculate(column, year)).copy() + specified = attendance[selected, i] + known = np.isfinite(specified) + values[known] = specified[known] + sim.set_input(column, year, values) + variable = f"{state.lower()}_child_care_subsidies" + definition = sim.tax_benefit_system.variables[variable] + amount = np.asarray(sim.calculate(variable, year), dtype=float) + weights = np.asarray( + sim.calculate(f"{definition.entity.key}_weight", year), dtype=float + ) + if not np.isfinite(amount).all(): + raise ValueError(f"Nonfinite state benefit: {state}/{name}") + result[name] = { + "variable": variable, + "entity": definition.entity.key, + "positive_sample_units": int((amount > 0).sum()), + "weighted_positive_units": float(weights[amount > 0].sum()), + "annual_modeled_benefits": float(amount @ weights), + } + del sim + gc.collect() + yield result diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/h5_io.py b/packages/microcosm-build/src/microcosm/build/us_runtime/h5_io.py index 48b87cb2b..b7b0d8f96 100644 --- a/packages/microcosm-build/src/microcosm/build/us_runtime/h5_io.py +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/h5_io.py @@ -948,6 +948,12 @@ def load_legacy_calibrated_us_h5(path: str | Path) -> Frame: }, ) assert_h5_unchanged(path, sha256, consumer=consumer) + from microcosm.build.us_runtime.childcare_attendance_receipt import ( + restore_native_childcare_receipt, + ) + + frame = restore_native_childcare_receipt(path, frame) + assert_h5_unchanged(path, sha256, consumer=consumer) refuse_denied_frame(frame, consumer=consumer) return canonicalize_frame_string_dtypes( frame, diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/l0_refit_export.py b/packages/microcosm-build/src/microcosm/build/us_runtime/l0_refit_export.py index ce76b4384..aa2492546 100644 --- a/packages/microcosm-build/src/microcosm/build/us_runtime/l0_refit_export.py +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/l0_refit_export.py @@ -523,6 +523,12 @@ def load_us_frame(path: str | Path) -> Frame: US_SCHEMA, {"household": Weights(weights, WeightKind.CALIBRATED)}, ) + from microcosm.build.us_runtime.childcare_attendance_receipt import ( + restore_native_childcare_receipt, + ) + + frame = restore_native_childcare_receipt(path, frame) + assert_h5_unchanged(path, sha256, consumer=consumer) refuse_denied_frame(frame, consumer=consumer) return frame @@ -620,6 +626,15 @@ def export_us_l0_refit_h5( destination = Path(output_h5) destination.parent.mkdir(parents=True, exist_ok=True) PolicyEngineUSEngine().write_dataset(export_frame, destination, period=period) + from microcosm.build.us_runtime.childcare_attendance_receipt import ( + ATTENDANCE_RECEIPT_KEY, + write_native_childcare_receipt, + ) + + if ATTENDANCE_RECEIPT_KEY in export_frame.metadata: + # The selection keeps each retained person's bound attendance; without + # the receipt key the native loaders refuse this export. + write_native_childcare_receipt(destination, export_frame.metadata) copied_attrs = copy_microcosm_root_attrs(root_attrs_source, destination) summary = { "schema_version": 1, diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare.py b/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare.py new file mode 100644 index 000000000..43c2521bc --- /dev/null +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare.py @@ -0,0 +1,562 @@ +"""Read the pinned 2024 NSECE V1 household and child-calendar public files. + +Source: ICPSR 39466 V1, Household Data Files User's Guide, HH-57, HH-81, +HH-279--280, HH-334, HH-554 and HH-565--568. This adapter measures ECE +attendance (including unpaid care), excluding K-8 schooling. It does not +determine licensed-provider status or CCDF eligibility/receipt. +""" + +from __future__ import annotations + +import hashlib +import json +from dataclasses import dataclass +from pathlib import Path + +import numpy as np +import pandas as pd + +from microcosm.build.us_runtime.childcare_attendance import ( + US_CHILDCARE_ATTENDANCE_COLUMNS, + childcare_attendance_contract, + childcare_income_band, + impute_us_childcare_attendance, +) +from microcosm.frame import US_SCHEMA, Frame, WeightKind, Weights + +_SOURCE_ARTIFACTS = { + artifact["dataset"]: artifact + for artifact in childcare_attendance_contract()["artifacts"] +} +NSECE_2024_HOUSEHOLD_SHA256 = _SOURCE_ARTIFACTS["DS5"]["sha256"] +NSECE_2024_CALENDAR_SHA256 = _SOURCE_ARTIFACTS["DS4"]["sha256"] +NSECE_CHILD_INDICES = tuple(range(1, 10)) +NSECE_PROVIDER_INDICES = tuple(range(1, 16)) +NSECE_CALENDAR_BLOCKS = 672 +NSECE_CHILDCARE_MATCH_COLUMNS = ("age", "region", "parent_work_status", "income_band") +NSECE_CHILDCARE_FALLBACK_COLUMNS = ( + ("age", "parent_work_status", "income_band"), + ("age", "parent_work_status"), + ("age",), +) +# HH-280: individual regular paid/unpaid, center, other organizational, irregular. +NSECE_ECE_TYPES = frozenset({1, 2, 3, 4, 5, 7}) +# HH-566--568: parental care, self-care, or school only. Mixed/unclear gap-check +# codes are deliberately unresolved, even if part of the interval involved ECE. +NSECE_NON_ECE_CALENDAR_CODES = frozenset({0, 50, 53, 56, 57, 60, 65}) +NSECE_UNPAID_GAP_CODES = frozenset({54, 61, 62, 69}) +# HH-63, HH-483: the only substantive match-cell codes. Work status counts parents +# of any under-13 household child who attended work last week; -1 is "No parents", +# the same concept as the ASEC-side -1. HH-175: imputed income has a minimum of 0. +NSECE_REGION_CODES = frozenset({1, 2, 3, 4}) +NSECE_PARENT_WORK_STATUS_CODES = frozenset({-1, 0, 1, 2}) + + +@dataclass(frozen=True) +class NSECEChildcareSource: + """All source children, including explicit reasons for unresolved schedules.""" + + children: pd.DataFrame + weights: Weights + source_receipt: dict[str, object] + + def donors(self) -> tuple[pd.DataFrame, Weights]: + usable = ( + self.children["attendance_status"] + .isin(["complete", "summary_bridge"]) + .to_numpy() + ) + return ( + self.children.loc[usable].reset_index(drop=True).copy(), + Weights(self.weights.values[usable], self.weights.kind), + ) + + +def nsece_childcare_household_columns() -> tuple[str, ...]: + return ( + "HH4_METH_CASEID", + "HH4_METH_WEIGHT", + "HH4_METH_QUEXVERSION", + "HH4_REGION", + "HH4_PARWORK_STATUS", + "HH4_RPARENT", + "HH4_ECON_INCOME_ANNUAL", + *( + f"{prefix}_{child}" + for child in NSECE_CHILD_INDICES + for prefix in ( + "HHC4_AGE_AT_USAGE", + "HHC4_METH_WEIGHT", + "HH4_MISSING_STATUS_CC", + ) + ), + *( + f"HH4_TYPEOFCARE_AGG_{child}_{provider}" + for child in NSECE_CHILD_INDICES + for provider in NSECE_PROVIDER_INDICES + ), + *( + f"HHC4_NPC_HRSWEEK_TOC{kind}_{child}" + for child in NSECE_CHILD_INDICES + for kind in range(1, 10) + ), + ) + + +def nsece_childcare_calendar_columns() -> tuple[str, ...]: + return ( + "HH4_METH_CASEID", + *( + f"HH4_CHCAL_R_{child}_{block}" + for child in NSECE_CHILD_INDICES + for block in range(1, NSECE_CALENDAR_BLOCKS + 1) + ), + ) + + +def derive_nsece_childcare( + household: pd.DataFrame, calendar: pd.DataFrame +) -> NSECEChildcareSource: + """Normalize source children; never treat missing calendars as no care. + + A day is attended if any 15-minute ECE block occurs on that day. Average + daily hours are total ECE block-hours divided by attended days. Monthly + days use the explicit representative-week approximation floor(d * 52/12 + + 0.5). This is an approximation, not observed monthly attendance. Blocks + already encode a single final provider, so overlapping care is not added. + """ + for table, columns in ( + (household, nsece_childcare_household_columns()), + (calendar, nsece_childcare_calendar_columns()), + ): + missing = sorted(set(columns) - set(table.columns)) + if missing or not table.columns.is_unique: + raise ValueError(f"NSECE source columns invalid; missing={missing[:10]}.") + ids = table["HH4_METH_CASEID"] + if ids.isna().any() or ids.duplicated().any(): + raise ValueError("NSECE household IDs must be complete and unique.") + if set(household.HH4_METH_CASEID) != set(calendar.HH4_METH_CASEID): + raise ValueError("NSECE household/calendar ID sets must match exactly.") + hh = household.set_index("HH4_METH_CASEID").sort_index() + cal = calendar.set_index("HH4_METH_CASEID").reindex(hh.index) + parts = [] + for child in NSECE_CHILD_INDICES: + age_months = pd.to_numeric(hh[f"HHC4_AGE_AT_USAGE_{child}"], errors="raise") + if ( + not np.isfinite(age_months).all() + or (age_months != np.floor(age_months)).any() + or (~((age_months >= 0) | (age_months == -9))).any() + ): + raise ValueError("NSECE child age must be measured or the no-child code.") + present = age_months >= 0 + if not present.any(): + continue + rows = hh.loc[present] + values = cal.loc[ + present, + [f"HH4_CHCAL_R_{child}_{b}" for b in range(1, NSECE_CALENDAR_BLOCKS + 1)], + ].to_numpy(dtype=float) + types = rows[ + [f"HH4_TYPEOFCARE_AGG_{child}_{p}" for p in NSECE_PROVIDER_INDICES] + ].to_numpy(dtype=float) + status = rows[f"HH4_MISSING_STATUS_CC_{child}"].to_numpy(dtype=float) + if not np.isin(status, [0, 1, 2]).all(): + raise ValueError("Unknown NSECE calendar completeness code.") + ece = np.zeros(values.shape, dtype=bool) + known = np.isin(values, tuple(NSECE_NON_ECE_CALENDAR_CODES)) + # HH-314/566: respondent/spouse care depends on parent status. School + # without a provider type is not evidence of K-8 for preschool children. + respondent_parent = rows.HH4_RPARENT.to_numpy() + respondent_care = np.isin(values, [51, 52]) + ece |= np.isin(values, tuple(NSECE_UNPAID_GAP_CODES)) + ece |= respondent_care & (respondent_parent == 0)[:, None] + known |= ece | (respondent_care & (respondent_parent == 1)[:, None]) + known |= (values == 68) & (age_months.loc[present].to_numpy() >= 72)[:, None] + regular_ece = ece.copy() + provider_count = np.zeros(len(rows), dtype=int) + for p in NSECE_PROVIDER_INDICES: + used = values == p + ece_type = np.isin(types[:, p - 1], tuple(NSECE_ECE_TYPES)) + ece |= used & ece_type[:, None] + regular_ece |= used & np.isin(types[:, p - 1], [1, 2, 3, 4, 5])[:, None] + known |= used & (ece_type | (types[:, p - 1] == 6))[:, None] + provider_count += used.any(axis=1) & ece_type + age = np.floor(age_months.loc[present].to_numpy() / 12) + reason = np.select( + [age > 12, status == 0, status == 1, ~known.all(axis=1)], + [ + "age_out_of_scope", + "missing_calendar", + "partial_calendar", + "ambiguous_calendar", + ], + default="complete", + ) + complete = reason == "complete" + # HH-334: unreported time can be encoded as assumed parental care (0). + # For partial calendars those zeros are not observed nonattendance. + # Missing calendars contribute no informative bound, including when + # derived summaries misleadingly describe a parental-care-only week. + definite = ece & (status != 0)[:, None] + unresolved = ( + ~known | ((status == 1)[:, None] & (values == 0)) | (status == 0)[:, None] + ) + possible = definite | unresolved + summary_hours = rows[ + [f"HHC4_NPC_HRSWEEK_TOC{kind}_{child}" for kind in range(1, 10)] + ].to_numpy(dtype=float) + regular_hours = summary_hours[:, :5].sum(axis=1) + summary_known = ( + np.isfinite(summary_hours).all(axis=1) + & (summary_hours >= 0).all(axis=1) + & (summary_hours[:, 7] == 0) + & (regular_hours <= 168) + & (complete | rows.HH4_METH_QUEXVERSION.isin([2, 3]).to_numpy()) + ) + days = ece.reshape(-1, 7, 96).any(axis=2).sum(axis=1).astype(float) + weekly_hours = ece.sum(axis=1) / 4 + regular_hours = np.where(complete, regular_ece.sum(axis=1) / 4, regular_hours) + summary_known |= complete + hours = np.divide(weekly_hours, days, out=np.zeros(len(rows)), where=days > 0) + monthly = np.floor(days * 52 / 12 + 0.5) + weight = pd.to_numeric(rows[f"HHC4_METH_WEIGHT_{child}"], errors="raise") + if not np.isfinite(weight).all() or (weight <= 0).any(): + raise ValueError("Existing NSECE children require positive child weights.") + # Reserve codes (negative income, unlisted region/work status) must never + # become substantive matching cells. + income = pd.to_numeric(rows.HH4_ECON_INCOME_ANNUAL, errors="raise") + if ( + not rows.HH4_REGION.isin(NSECE_REGION_CODES).all() + or not rows.HH4_PARWORK_STATUS.isin(NSECE_PARENT_WORK_STATUS_CODES).all() + or not np.isfinite(income).all() + or (income < 0).any() + ): + raise ValueError( + "NSECE region, parent work status or income holds an unlisted or reserve code." + ) + part = pd.DataFrame( + { + "donor_id": [f"nsece2024:{case}:{child}" for case in rows.index], + "source_household_id": rows.index.astype(str), + "age": age.astype(int), + "region": rows.HH4_REGION.to_numpy(), + "parent_work_status": rows.HH4_PARWORK_STATUS.to_numpy(), + "household_income": rows.HH4_ECON_INCOME_ANNUAL.to_numpy(), + "income_band": childcare_income_band(rows.HH4_ECON_INCOME_ANNUAL), + "questionnaire_version": rows.HH4_METH_QUEXVERSION.to_numpy(), + "regular_hours_per_week": np.where( + summary_known, regular_hours, np.nan + ), + "irregular_hours_per_week": np.where( + complete, weekly_hours - regular_hours, np.nan + ), + "attendance_status": reason, + "calendar_status_code": status.astype(int), + "calendar_unknown_hours": unresolved.sum(axis=1) / 4, + "calendar_ece_hours_lower": definite.sum(axis=1) / 4, + "calendar_ece_hours_upper": possible.sum(axis=1) / 4, + "calendar_ece_days_lower": definite.reshape(-1, 7, 96) + .any(axis=2) + .sum(axis=1), + "calendar_ece_days_upper": possible.reshape(-1, 7, 96) + .any(axis=2) + .sum(axis=1), + "child_weight": weight.to_numpy(), + "household_weight": rows.HH4_METH_WEIGHT.to_numpy(), + "ece_provider_count": np.where(complete, provider_count, np.nan), + "ece_hours_per_week": np.where(complete, weekly_hours, np.nan), + } + ) + for column, data in zip( + US_CHILDCARE_ATTENDANCE_COLUMNS, (monthly, days, hours), strict=True + ): + part[column] = np.where(complete, data, np.nan) + parts.append(part) + if not parts: + raise ValueError("NSECE source contains no children.") + children = ( + pd.concat(parts, ignore_index=True) + .sort_values("donor_id") + .reset_index(drop=True) + ) + return NSECEChildcareSource( + children, + Weights(children.child_weight.to_numpy(), WeightKind.DESIGN), + { + "study": "ICPSR39466.v1", + "source_year": 2024, + "measurement": "union_of_ECE_calendar_blocks_excluding_K8", + "monthly_conversion": "floor(days_per_week * 52 / 12 + 0.5)", + "national_representativeness_validated": False, + "calendar_bounds": { + "source": "NSECE 2024 Household User Guide HH-334, HH-565--568", + "meaning": "definite and possible ECE blocks; not imputations or confidence intervals", + "partial_calendar_zero": "unresolved assumed parental care, not observed nonattendance", + "missing_calendar": "uninformative 0--168 hours and 0--7 days", + }, + }, + ) + + +def load_nsece_childcare( + household_path: str | Path, calendar_path: str | Path +) -> NSECEChildcareSource: + """Load locally downloaded, hash-verified V1 TSV files; no automatic download.""" + tables = [] + receipts = [] + for path, expected_hash, columns in ( + ( + household_path, + NSECE_2024_HOUSEHOLD_SHA256, + nsece_childcare_household_columns(), + ), + (calendar_path, NSECE_2024_CALENDAR_SHA256, nsece_childcare_calendar_columns()), + ): + path = Path(path) + with path.open("rb") as stream: + actual = hashlib.file_digest(stream, "sha256").hexdigest() + if actual != expected_hash: + raise ValueError(f"NSECE source hash mismatch: {path.name}.") + tables.append( + pd.read_csv(path, sep="\t", usecols=list(columns), na_values=[" "]) + ) + receipts.append({"sha256": actual, "size_bytes": path.stat().st_size}) + result = derive_nsece_childcare(*tables) + result.source_receipt["artifacts"] = receipts + return result + + +def with_us_nsece_childcare_attendance( + frame: Frame, + source: NSECEChildcareSource, + *, + seed: int, + match_columns: tuple[str, ...], + fallback_match_columns: tuple[tuple[str, ...], ...] = (), + sibling_dependence: float = 0.0, +) -> Frame: + """Apply the source to a candidate Frame, preserving links, weights and receipts. + + Matching fields must already be harmonized on person rows. This function + does not label all adults as parents or guess parental work from household + earnings. Missing values outside ages 0--12 remain unresolved. The caller + must pass ``assert_childcare_attendance_exportable`` before engine export. + This is not registered in the default production build. + """ + if frame.schema != US_SCHEMA: + raise ValueError("NSECE childcare attendance requires the US schema.") + from microcosm.build.us_runtime.childcare_attendance_receipt import ( + assert_bound_childcare_attendance, + bind_childcare_attendance, + ) + + receipt = { + **source.source_receipt, + "seed": int(seed), + "match_columns": match_columns, + "fallback_match_columns": fallback_match_columns, + "sibling_dependence": sibling_dependence, + "candidate_only": True, + } + if "nsece_childcare_attendance" in frame.metadata: + assert_bound_childcare_attendance(frame, require_stage=False) + previous = json.loads( + json.dumps(frame.metadata["nsece_childcare_attendance"], default=dict) + ) + if previous != json.loads(json.dumps(receipt)): + raise ValueError( + "Attendance source or settings changed; rebuild from the original parent." + ) + return frame + donor, weights = source.donors() + original_people = frame.table("person") + for column in US_CHILDCARE_ATTENDANCE_COLUMNS: + provenance = f"{column}_source" + if ( + provenance in original_people + and original_people[provenance] + .astype("string") + .str.startswith( + ("donor:", "source_person:", "inherited_engine_baseline"), na=False + ) + .any() + ): + raise ValueError( + "Imputed attendance lost its receipt; rebuild from the original parent." + ) + recipients = original_people.copy() + # Native BuildP IDs are exact int64, while the pure donor API uses strings. + # Encode integers losslessly for hashing, then restore the native column. + if "person_source_id" in recipients and pd.api.types.is_integer_dtype( + recipients.person_source_id + ): + if recipients.person_source_id.isna().any(): + raise ValueError("Childcare source person IDs cannot be missing.") + recipients["person_source_id"] = recipients.person_source_id.astype(str) + people = impute_us_childcare_attendance( + recipients, + donor, + donor_weights=weights, + seed=seed, + match_columns=match_columns, + fallback_match_columns=fallback_match_columns, + sibling_dependence=sibling_dependence, + ) + # Float storage supports unresolved nulls in ordinary Frame checkpoints; + # the monthly variable has already been validated to be integral when known. + for column in US_CHILDCARE_ATTENDANCE_COLUMNS: + people[column] = people[column].astype(float) + people["person_source_id"] = original_people.person_source_id + tables = {entity: frame.table(entity).copy() for entity in frame.entities} + tables["person"] = people + return bind_childcare_attendance( + Frame( + tables, + frame.schema, + {entity: frame.weights_for(entity) for entity in frame.weighted_entities}, + frame.strata, + mass_log=frame.mass_log, + metadata={**frame.metadata, "nsece_childcare_attendance": receipt}, + ) + ) + + +def assert_childcare_attendance_exportable(frame: Frame) -> None: + """Reject unresolved inputs before an engine can coerce them to default zero. + + This is a completeness check, not statistical or publication approval. + """ + people = frame.table("person") + missing = [c for c in US_CHILDCARE_ATTENDANCE_COLUMNS if c not in people] + if missing: + raise ValueError(f"Childcare export is missing inputs: {missing}.") + values = people[list(US_CHILDCARE_ATTENDANCE_COLUMNS)].to_numpy( + dtype=float, na_value=np.nan + ) + if not np.isfinite(values).all(): + raise ValueError( + "Childcare export has unresolved attendance; do not fill with zero." + ) + # Completeness alone is insufficient: preserve the joint nonattendance, + # calendar bounds and integral-month contract at the final boundary too. + from microcosm.build.us_runtime.childcare_attendance import _validate_attendance + + _validate_attendance(people, complete=True) + + +def nsece_childcare_validation_report( + source: NSECEChildcareSource, + *, + seed: int = 915, + match_columns: tuple[str, ...] = NSECE_CHILDCARE_MATCH_COLUMNS, +) -> dict[str, object]: + """Source attrition and a household-separated 20% holdout; never certification. + + Holdout households are excluded from the donor pool before any prediction. + Source selection and this diagnostic's limited covariates remain explicit. + Repeated use of this fixed holdout does not create fresh independent evidence. + """ + children = source.children + if children.attendance_status.eq("summary_bridge").any(): + raise ValueError( + "Validate original calendars before bridge completion to avoid leakage." + ) + donors, _ = source.donors() + in_domain = children.age.between(0, 12) + domain_mass = float(children.loc[in_domain, "child_weight"].sum()) + complete_mass = float(donors.child_weight.sum()) + split = donors.source_household_id.map( + lambda value: ( + int.from_bytes( + hashlib.sha256(f"{seed}:holdout:{value}".encode()).digest()[:8], "big" + ) + % 5 + == 0 + ) + ) + train = donors.loc[~split].reset_index(drop=True) + heldout = donors.loc[split].reset_index(drop=True) + if train.empty or heldout.empty: + raise ValueError("NSECE validation needs training and held-out households.") + train_cells = set(train[list(match_columns)].itertuples(index=False, name=None)) + supported = np.array( + [ + key in train_cells + for key in heldout[list(match_columns)].itertuples(index=False, name=None) + ] + ) + observed = heldout.loc[supported].reset_index(drop=True) + if observed.empty: + raise ValueError("NSECE holdout has no supported matching cells.") + recipients = observed.drop(columns=list(US_CHILDCARE_ATTENDANCE_COLUMNS)).assign( + person_source_id=observed.donor_id + ) + predicted = impute_us_childcare_attendance( + recipients, + train, + donor_weights=Weights(train.child_weight.to_numpy(), WeightKind.DESIGN), + match_columns=match_columns, + seed=seed, + ) + + def metrics(table: pd.DataFrame, weights: np.ndarray) -> dict[str, float]: + days = table[US_CHILDCARE_ATTENDANCE_COLUMNS[1]].to_numpy(dtype=float) + hours = table[US_CHILDCARE_ATTENDANCE_COLUMNS[2]].to_numpy(dtype=float) + return { + "participation": float(np.average(days > 0, weights=weights)), + "days_per_week": float(np.average(days, weights=weights)), + "hours_per_week": float(np.average(days * hours, weights=weights)), + } + + comparisons = [] + for grouping in (None, "age", "region", "parent_work_status"): + groups = ( + [("all", observed.index)] + if grouping is None + else observed.groupby(grouping).groups.items() + ) + for label, indices in groups: + weights = observed.loc[indices, "child_weight"].to_numpy() + comparisons.append( + { + "grouping": grouping or "all", + "group": str(label), + "n": len(indices), + "observed": metrics(observed.loc[indices], weights), + "predicted": metrics(predicted.loc[indices], weights), + } + ) + attrition = [ + { + "status": str(status), + "n": len(group), + "child_weight": float(group.child_weight.sum()), + } + for status, group in children.groupby("attendance_status", sort=True) + ] + return { + "source": source.source_receipt, + "source_child_count": len(children), + "source_attrition": attrition, + "under13_complete_weight_share": complete_mass / domain_mass, + "seed": seed, + "evaluation_design": "fixed household diagnostic split; not final population certification", + "match_columns": list(match_columns), + "training_children": len(train), + "heldout_children": len(heldout), + "unsupported_heldout_children": int((~supported).sum()), + "unsupported_heldout_weight": float( + heldout.loc[~supported, "child_weight"].sum() + ), + "household_overlap": len( + set(train.source_household_id) & set(heldout.source_household_id) + ), + "comparisons": comparisons, + "production_ready": False, + "limitations": [ + "Only complete, unambiguous calendars enter this holdout; source selection remains unvalidated.", + "The diagnostic matches age and caller-specified covariates; it is not a nationally validated fitted model.", + "Sibling assignments, mixed providers, older-child care and scalar monthly conversion need validation.", + "No full Microcosm population build or state CCDF distribution is certified by this source-only report.", + ], + } diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare_assessment.py b/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare_assessment.py new file mode 100644 index 000000000..d73dbd41f --- /dev/null +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare_assessment.py @@ -0,0 +1,292 @@ +"""Household cross-validation and questionnaire transport checks for attendance. + +These checks expose selection and sparse support. Conditional donor expectations +are used for prediction scoring so a single stochastic draw cannot hide bias. +They do not identify unobserved attendance under nonrandom calendar missingness. +""" + +from __future__ import annotations + +import hashlib + +import numpy as np +import pandas as pd + +from microcosm.build.us_runtime.nsece_childcare import ( + NSECE_CHILDCARE_FALLBACK_COLUMNS, + NSECE_CHILDCARE_MATCH_COLUMNS, + NSECEChildcareSource, +) +from microcosm.build.us_runtime.nsece_childcare_bridge import ( + bridge_nsece_noncalendar_attendance, +) +from microcosm.build.us_runtime.nsece_childcare_dependence import ( + complete_sibling_pairs, + fit_nsece_sibling_dependence, +) + + +def _conditional_expectations(train, target, outcomes): + """Weighted empirical expectation with a declared, age-preserving hierarchy.""" + result = pd.DataFrame(np.nan, index=target.index, columns=outcomes) + levels = pd.Series("unsupported", index=target.index, dtype="string") + for columns in (NSECE_CHILDCARE_MATCH_COLUMNS, *NSECE_CHILDCARE_FALLBACK_COLUMNS): + weighted = train.reindex(columns=columns).copy() + weighted["mass"] = train.child_weight + for outcome in outcomes: + weighted[outcome] = ( + train.reindex(columns=[outcome]).iloc[:, 0] * train.child_weight + ) + grouped = weighted.groupby(list(columns)).sum() + means = grouped[outcomes].div(grouped.mass, axis=0) + ids = levels.index[levels == "unsupported"] + keys = ( + pd.MultiIndex.from_frame(target.reindex(index=ids, columns=columns)) + if len(columns) > 1 + else target.reindex(index=ids, columns=columns).iloc[:, 0] + ) + values = means.reindex(keys).to_numpy() + supported = np.isfinite(values).all(axis=1) + result.loc[ids[supported]] = values[supported] + levels.loc[ids[supported]] = ",".join(columns) + return result, levels + + +def assess_nsece_childcare(source: NSECEChildcareSource, *, seed: int = 271828) -> dict: + children = source.children.loc[source.children.age.between(0, 12)].copy() + usable = children.attendance_status.eq("complete") + coverage = [] + for grouping in ( + "questionnaire_version", + "age", + "region", + "parent_work_status", + "income_band", + ): + for label, indices in children.groupby(grouping).groups.items(): + g = children.loc[indices] + coverage.append( + { + "grouping": grouping, + "group": str(label), + "n": len(g), + "weight": float(g.child_weight.sum()), + "usable_weight_share": float( + g.loc[usable.loc[indices], "child_weight"].sum() + / g.child_weight.sum() + ), + } + ) + donors = children.loc[usable].copy() + donors["participation"] = (donors.childcare_days_per_week > 0).astype(float) + donors["days"] = donors.childcare_days_per_week + donors["hours"] = donors.ece_hours_per_week + outcomes = ["participation", "days", "hours"] + folds = donors.source_household_id.map( + lambda x: ( + int.from_bytes(hashlib.sha256(f"{seed}:{x}".encode()).digest()[:8], "big") + % 5 + ) + ) + prediction = pd.DataFrame(np.nan, index=donors.index, columns=outcomes) + levels = pd.Series("", index=donors.index, dtype="string") + sibling_rows = [] + for fold in range(5): + train, target = donors.loc[folds != fold], donors.loc[folds == fold] + if train.empty or target.empty: + raise ValueError("Five-fold assessment requires households in every fold") + if not set(train.source_household_id).isdisjoint(target.source_household_id): + raise ValueError("Childcare assessment leaks households across folds") + predicted, matched = _conditional_expectations(train, target, outcomes) + prediction.loc[target.index] = predicted + levels.loc[target.index] = matched + heldout_households = set(target.source_household_id) + fitted = fit_nsece_sibling_dependence( + children.loc[~children.source_household_id.isin(heldout_households)] + ) + pairs = complete_sibling_pairs( + children.loc[children.source_household_id.isin(heldout_households)] + ) + if not pairs.empty: + probabilities = ( + predicted.loc[pairs.index, "participation"].to_numpy().reshape(-1, 2) + ) + actual = ( + (pairs.childcare_days_per_week.to_numpy() > 0) + .reshape(-1, 2) + .all(axis=1) + ) + weights = pairs.household_weight.to_numpy().reshape(-1, 2)[:, 0] + independent = probabilities.prod(axis=1) + coupled = (1 - fitted["rho"]) * independent + fitted[ + "rho" + ] * probabilities.min(axis=1) + sibling_rows.append( + { + "fold": fold, + "training_rho": fitted["rho"], + "households": len(weights), + "weight": float(weights.sum()), + "observed_both": float(np.average(actual, weights=weights)), + "independent_both": float(np.average(independent, weights=weights)), + "coupled_both": float(np.average(coupled, weights=weights)), + } + ) + comparisons = [] + for grouping in (None, "age", "region", "parent_work_status", "income_band"): + groups = ( + [("all", donors.index)] + if grouping is None + else donors.groupby(grouping).groups.items() + ) + for label, indices in groups: + g = donors.loc[indices] + comparisons.append( + { + "grouping": grouping or "all", + "group": str(label), + "n": len(g), + "observed": { + c: float(np.average(g[c], weights=g.child_weight)) + for c in outcomes + }, + "expected": { + c: float( + np.average( + prediction.loc[indices, c], weights=g.child_weight + ) + ) + for c in outcomes + }, + } + ) + # Independent questionnaire instruments have regular-care weekly hours but + # no days. Compare the common regular-care estimand, not all-ECE totals. + regular = children.loc[children.regular_hours_per_week.notna()].copy() + regular["regular_participation"] = (regular.regular_hours_per_week > 0).astype( + float + ) + regular_outcomes = ["regular_participation", "regular_hours_per_week"] + transport = [] + for questionnaire in (2, 3): + target = regular.loc[regular.questionnaire_version == questionnaire] + train = regular.loc[ + (regular.questionnaire_version == 1) + & regular.attendance_status.eq("complete") + ] + if target.empty or train.empty: + continue + predicted, matched = _conditional_expectations(train, target, regular_outcomes) + supported = matched != "unsupported" + target, predicted = target.loc[supported], predicted.loc[supported] + transport.append( + { + "questionnaire_version": questionnaire, + "scored_children": len(target), + "unsupported_children": int((~supported).sum()), + "observed": { + c: float(np.average(target[c], weights=target.child_weight)) + for c in regular_outcomes + }, + "expected": { + c: float(np.average(predicted[c], weights=target.child_weight)) + for c in regular_outcomes + }, + } + ) + return { + "source": source.source_receipt, + "seed": seed, + "design": "five-fold household-separated conditional-expectation diagnostic", + "coverage": coverage, + "cross_validation": comparisons, + "matching_levels": levels.value_counts().to_dict(), + "sibling_validation": sibling_rows, + "questionnaire_transport": transport, + "assumptions": [ + "Calendar selection is ignorable conditional on matching fields; not identified from these data.", + "Main reference-week schedules transfer to May/fall typical weeks; summer attendance is not observed.", + "Regular-care comparisons cannot validate days or irregular care in instruments without calendars.", + ], + "production_ready": False, + } + + +def assess_noncalendar_bridge( + source: NSECEChildcareSource, *, seed: int = 161803 +) -> dict: + """Mask whole-household calendars, keeping only the observed regular hours.""" + children = source.children.copy() + complete = children.attendance_status.eq("complete") + holdout = complete & children.source_household_id.map( + lambda x: ( + int.from_bytes(hashlib.sha256(f"{seed}:{x}".encode()).digest()[:8], "big") + % 5 + == 0 + ) + ) + truth = children.loc[holdout].copy() + children.loc[~complete, "regular_hours_per_week"] = np.nan + children.loc[holdout, "attendance_status"] = "missing_calendar" + children.loc[holdout, "questionnaire_version"] = 2 + children.loc[ + holdout, + [ + "childcare_attending_days_per_month", + "childcare_days_per_week", + "childcare_hours_per_day", + "ece_hours_per_week", + "irregular_hours_per_week", + ], + ] = np.nan + bridged = bridge_nsece_noncalendar_attendance( + NSECEChildcareSource(children, source.weights, source.source_receipt), seed=seed + ) + predicted = bridged.children.loc[holdout] + if not predicted.attendance_status.eq("summary_bridge").all(): + raise ValueError("Masked-calendar bridge has unsupported records") + errors = [] + for group in (None, "age", "parent_work_status"): + groups = ( + [("all", truth.index)] + if group is None + else truth.groupby(group).groups.items() + ) + for label, indices in groups: + w = truth.loc[indices, "child_weight"] + errors.append( + { + "grouping": group or "all", + "group": str(label), + "n": len(indices), + "observed_days": float( + np.average( + truth.loc[indices, "childcare_days_per_week"], weights=w + ) + ), + "imputed_days": float( + np.average( + predicted.loc[indices, "childcare_days_per_week"], weights=w + ) + ), + "observed_hours": float( + np.average(truth.loc[indices, "ece_hours_per_week"], weights=w) + ), + "imputed_hours": float( + np.average( + predicted.loc[indices, "ece_hours_per_week"], weights=w + ) + ), + } + ) + return { + "seed": seed, + "design": "whole-household masked-calendar test; regular weekly hours remain observed", + "comparisons": errors, + "regular_hours_preserved": bool( + np.array_equal( + predicted.regular_hours_per_week, truth.regular_hours_per_week + ) + ), + "limitations": "Tests reconstruction where calendars exist; not a direct test of unobserved days in the other questionnaire instruments.", + } diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare_bridge.py b/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare_bridge.py new file mode 100644 index 000000000..5f79adc5b --- /dev/null +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare_bridge.py @@ -0,0 +1,136 @@ +"""Complete noncalendar schedules conditional on measured regular-care hours. + +NSECE HH-10/11 describes the summer/fall instruments: regular weekly hours are +observed, days and irregular arrangements are not collected. Preserve those +hours and impute days/irregular intensity jointly from a compatible calendar. +Zero regular hours do not establish zero irregular care. No source observation +is replaced; completed rows have separate status and donor provenance. +""" + +from __future__ import annotations + +import hashlib + +import numpy as np + +from microcosm.build.us_runtime.childcare_attendance import ( + US_CHILDCARE_ATTENDANCE_COLUMNS, + childcare_attendance_contract, +) +from microcosm.build.us_runtime.nsece_childcare import ( + NSECE_CHILDCARE_FALLBACK_COLUMNS, + NSECE_CHILDCARE_MATCH_COLUMNS, + NSECEChildcareSource, +) + + +def bridge_nsece_noncalendar_attendance( + source: NSECEChildcareSource, *, seed: int +) -> NSECEChildcareSource: + """Use nearest regular-hour donors, retaining all ties at the cutoff. + + All matching levels require the same regular-care participation status. A + cell with fewer donors than the cutoff widens to the next matching level. + Hours cannot exceed 24 per attended day or 168 per week. The parent source + remains unchanged. Synthetic validation must mask whole households before + this function is called; it never learns from completed bridge records. + """ + children = source.children.copy() + nearest_donors = childcare_attendance_contract()["operations"][1]["nearest_donors"] + pool = ( + children.loc[ + children.attendance_status.eq("complete") + & children.regular_hours_per_week.notna() + ] + .sort_values("donor_id") + .copy() + ) + pool["has_regular_care"] = pool.regular_hours_per_week > 0 + target = children.loc[ + children.age.between(0, 12) + & children.attendance_status.eq("missing_calendar") + & children.questionnaire_version.isin([2, 3]) + & children.regular_hours_per_week.notna() + ] + unsupported = 0 + matching_levels: dict[str, int] = {} + month, days_column, hours_column = US_CHILDCARE_ATTENDANCE_COLUMNS + for index, child in target.iterrows(): + candidates, level = pool.iloc[:0], () + for columns in ( + NSECE_CHILDCARE_MATCH_COLUMNS, + *NSECE_CHILDCARE_FALLBACK_COLUMNS, + ): + mask = pool.has_regular_care.eq(child.regular_hours_per_week > 0) + for column in columns: + mask &= pool[column].eq(child[column]) + cell = pool.loc[ + mask + & ( + (pool.irregular_hours_per_week + child.regular_hours_per_week) + <= 168 + ) + ] + # A thin cell keeps every donor however distant in regular hours; + # widen until the nearest-donor cutoff can bind. + if len(cell) > len(candidates): + candidates, level = cell, columns + if len(candidates) >= nearest_donors: + break + if candidates.empty: + unsupported += 1 + continue + candidates = candidates.assign( + distance=np.abs( + np.log1p(candidates.regular_hours_per_week) + - np.log1p(child.regular_hours_per_week) + ) + ) + candidates = candidates.sort_values(["distance", "donor_id"]) + cutoff = candidates.distance.iloc[min(nearest_donors, len(candidates)) - 1] + candidates = candidates.loc[candidates.distance <= cutoff] + weights = candidates.child_weight.to_numpy() + cumulative = np.cumsum(weights / weights.sum()) + digest = hashlib.sha256( + f"{seed}:nsece_bridge:{child.donor_id}".encode() + ).digest() + draw = (int.from_bytes(digest[:8], "big") >> 11) / 2**53 + donor = candidates.iloc[ + min( + int(np.searchsorted(cumulative, draw, side="right")), + len(candidates) - 1, + ) + ] + total_hours = child.regular_hours_per_week + donor.irregular_hours_per_week + days = max(float(donor[days_column]), float(np.ceil(total_hours / 24))) + if total_hours == 0: + days = 0.0 + children.loc[index, [month, days_column, hours_column]] = [ + np.floor(days * 52 / 12 + 0.5), + days, + total_hours / days if days else 0.0, + ] + children.loc[index, "ece_hours_per_week"] = total_hours + children.loc[index, "irregular_hours_per_week"] = donor.irregular_hours_per_week + children.loc[index, "attendance_status"] = "summary_bridge" + children.loc[index, "schedule_bridge_donor"] = donor.donor_id + matched = ",".join(level) + children.loc[index, "schedule_bridge_match"] = matched + matching_levels[matched] = matching_levels.get(matched, 0) + 1 + completed = children.attendance_status.eq("summary_bridge") + return NSECEChildcareSource( + children, + source.weights, + { + **source.source_receipt, + "noncalendar_bridge": { + "seed": seed, + "completed_children": int(completed.sum()), + "unsupported_children": unsupported, + "matching_levels": dict(sorted(matching_levels.items())), + "observed": "regular weekly hours from May/fall questionnaire", + "imputed": "attended days and irregular care jointly from nearest regular-hour calendar donors", + "assumption": "conditional calendar pattern and irregular care transfer across questionnaire instruments", + }, + }, + ) diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare_dependence.py b/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare_dependence.py new file mode 100644 index 000000000..bbd5d26ba --- /dev/null +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare_dependence.py @@ -0,0 +1,80 @@ +"""Fit a household shared-rank mixture from measured sibling participation. + +The mixture retains each child's weighted conditional donor distribution. With +probability rho, siblings use a shared uniform rank in care-sorted donor pools; +otherwise they draw independently. It interpolates the pair's joint positive +probability between p1*p2 and min(p1,p2). This models dependence, not shared +provider identity, and must be checked on household-held-out pairs. +""" + +from __future__ import annotations + +import numpy as np + +from microcosm.build.us_runtime.nsece_childcare import NSECE_CHILDCARE_MATCH_COLUMNS + + +def complete_sibling_pairs(children): + children = children.loc[children.age.between(0, 12)].copy() + counts = children.groupby("source_household_id").attendance_status.agg( + lambda x: len(x) >= 2 and x.eq("complete").all() + ) + selected = children.source_household_id.isin(counts.index[counts]) + # One pair per household avoids giving large sibships disproportionate mass. + return ( + children.loc[selected] + .sort_values(["source_household_id", "age", "donor_id"]) + .groupby("source_household_id", sort=False) + .head(2) + ) + + +def fit_nsece_sibling_dependence( + children, *, match_columns=NSECE_CHILDCARE_MATCH_COLUMNS +) -> dict: + pool = children.loc[children.attendance_status.eq("complete")].copy() + pool["weighted_care"] = (pool.childcare_days_per_week > 0) * pool.child_weight + cells = pool.groupby(list(match_columns))[["weighted_care", "child_weight"]].sum() + cells["probability"] = cells.weighted_care / cells.child_weight + pairs = complete_sibling_pairs(children) + if pairs.empty: + return {"rho": 0.0, "households": 0, "status": "no measured sibling pairs"} + predicted = ( + pairs[list(match_columns)] + .merge( + cells[["probability"]], + left_on=list(match_columns), + right_index=True, + how="left", + validate="many_to_one", + ) + .probability.to_numpy() + .reshape(-1, 2) + ) + actual = (pairs.childcare_days_per_week.to_numpy() > 0).reshape(-1, 2) + weights = pairs.household_weight.to_numpy().reshape(-1, 2) + if ( + not np.isfinite(weights).all() + or (weights <= 0).any() + or not np.array_equal(weights[:, 0], weights[:, 1]) + ): + raise ValueError( + "Sibling dependence requires consistent positive household design weights." + ) + weights = weights[:, 0] + independent = predicted.prod(axis=1) + shared = predicted.min(axis=1) + observed = actual.all(axis=1) + denominator = float((shared - independent) @ weights) + unconstrained = ( + float((observed - independent) @ weights) / denominator if denominator else 0.0 + ) + return { + "rho": float(np.clip(unconstrained, 0, 1)), + "unconstrained_rho": unconstrained, + "households": len(weights), + "observed_both_in_care": float(np.average(observed, weights=weights)), + "independent_both_in_care": float(np.average(independent, weights=weights)), + "shared_both_in_care": float(np.average(shared, weights=weights)), + "estimation": "youngest pair in fully observed households; household design weights", + } diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare_pooling.py b/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare_pooling.py new file mode 100644 index 000000000..c1593cc67 --- /dev/null +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare_pooling.py @@ -0,0 +1,270 @@ +"""Experimental partial pooling of joint childcare schedule distributions. + +Sparse cells borrow strength from broader cells, always retaining exact age. +Only measured complete calendars are donors; missing outcomes are not zeros. +This module does not change the production build or correct calendar selection. +""" + +from __future__ import annotations + +from itertools import combinations + +import numpy as np + +from microcosm.build.us_runtime.childcare_attendance import ( + US_CHILDCARE_ATTENDANCE_COLUMNS, + _ids, + _validate_attendance, +) + +POOLED_CHILDCARE_MATCH_COLUMNS = ( + "age", + "childcare_household_size", + "parent_work_status", + "income_band", + "region", +) +POOLED_CHILDCARE_LEVELS = tuple( + POOLED_CHILDCARE_MATCH_COLUMNS[:n] + for n in range(1, len(POOLED_CHILDCARE_MATCH_COLUMNS) + 1) +) +POOLED_CHILDCARE_STRENGTH = 10.0 +COMPOSITION_CHILDCARE_MATCH_COLUMNS = ( + "age", + "childcare_household_size", + "childcare_under6_count", + "childcare_schoolage_count", + "childcare_youngest_age_band", + "childcare_has_younger_sibling", + "parent_work_status", + "income_band", + "region", +) +COMPOSITION_CHILDCARE_LEVELS = tuple( + COMPOSITION_CHILDCARE_MATCH_COLUMNS[:n] + for n in range(1, len(COMPOSITION_CHILDCARE_MATCH_COLUMNS) + 1) +) + + +def with_childcare_household_size(children): + """Count the full roster before selecting complete child calendars.""" + result = children.copy() + _ids(result, "source_household_id", unique=False) + age = result.age.to_numpy(dtype=float) + if not np.isfinite(age).all() or (age < 0).any() or (age % 1 != 0).any(): + raise ValueError("Household-size predictors require finite whole-year ages.") + result["childcare_household_size"] = ( + result.age.between(0, 12) + .groupby(result.source_household_id) + .transform("sum") + .clip(upper=3) + ) + for column, included in ( + ("childcare_under6_count", result.age.between(0, 5)), + ("childcare_schoolage_count", result.age.between(6, 12)), + ): + result[column] = ( + included.groupby(result.source_household_id).transform("sum").clip(upper=3) + ) + youngest = ( + result.age.where(result.age.between(0, 12)) + .groupby(result.source_household_id) + .transform("min") + ) + result["childcare_youngest_age_band"] = np.select( + [youngest < 3, youngest < 6], [0, 1], default=2 + ) + result["childcare_has_younger_sibling"] = (result.age > youngest).astype(int) + return result + + +class PooledScheduleDonors: + """Weighted mixture of nested empirical donor distributions. + + The support statistic uses households as clusters, not child-row counts. + Multiplying all survey weights by a common factor cannot change predictions. + """ + + def __init__( + self, children, *, strength=POOLED_CHILDCARE_STRENGTH, composition=False + ): + if not np.isfinite(strength) or strength <= 0: + raise ValueError("Pooling strength must be finite and positive.") + self.strength = strength + self.levels = ( + COMPOSITION_CHILDCARE_LEVELS if composition else POOLED_CHILDCARE_LEVELS + ) + self.match_columns = self.levels[-1] + required = [ + *self.match_columns, + "source_household_id", + "donor_id", + "child_weight", + "attendance_status", + *US_CHILDCARE_ATTENDANCE_COLUMNS, + ] + if not set(required).issubset(children): + raise ValueError("Pooled childcare donors need complete source predictors.") + if children.attendance_status.eq("summary_bridge").any(): + raise ValueError("Experimental pooled donors require original calendars.") + self.pool = children.loc[ + children.attendance_status.eq("complete") & children.age.between(0, 12) + ].copy() + if self.pool.empty or self.pool.reindex(columns=required).isna().any().any(): + raise ValueError("Pooled childcare donor fields must be complete.") + if self.pool.donor_id.duplicated().any(): + raise ValueError("Pooled childcare donor IDs must be unique.") + _ids(self.pool, "source_household_id", unique=False) + _ids(self.pool, "donor_id", unique=True) + predictors = self.pool.reindex(columns=self.match_columns).to_numpy(dtype=float) + if ( + not np.isfinite(predictors).all() + or (predictors % 1 != 0).any() + or not self.pool.childcare_household_size.isin([1, 2, 3]).all() + ): + raise ValueError( + "Pooled childcare predictors must be finite categorical values." + ) + weights = self.pool.child_weight.to_numpy(dtype=float) + if not np.isfinite(weights).all() or (weights <= 0).any(): + raise ValueError("Pooled childcare weights must be finite and positive.") + _validate_attendance(self.pool, complete=True) + _, days, hours = US_CHILDCARE_ATTENDANCE_COLUMNS + self.pool = self.pool.sort_values([days, hours, "donor_id"]).reset_index( + drop=True + ) + self.values = np.column_stack( + (self.pool[days] > 0, self.pool[days], self.pool[days] * self.pool[hours]) + ).astype(float) + self.weights = self.pool.child_weight.to_numpy(dtype=float) + self.households = self.pool.source_household_id.to_numpy() + self.groups = [ + self.pool.groupby(list(level), sort=False).indices for level in self.levels + ] + self.cache = {} + + def distribution(self, child, *, exclude_household=None): + """Return care-sorted values, cumulative probabilities and row masses.""" + key = tuple(child.reindex(self.match_columns)) + if not np.isfinite(np.asarray(key, dtype=float)).all(): + raise ValueError("Pooled target matching fields must be complete.") + if exclude_household is None and key in self.cache: + return self.cache[key] + age_indices = np.asarray(self.groups[0].get(key[0], []), dtype=int) + if exclude_household is not None: + age_indices = age_indices[self.households[age_indices] != exclude_household] + if not len(age_indices): + raise ValueError("No exact-age donor household remains after exclusion.") + probabilities = self.weights[age_indices].copy() + probabilities /= probabilities.sum() + for level, groups in zip(self.levels[1:], self.groups[1:], strict=True): + indices = np.asarray(groups.get(key[: len(level)], []), dtype=int) + if exclude_household is not None: + indices = indices[self.households[indices] != exclude_household] + if not len(indices): + continue + # Both arrays retain global care order, so local indices embed in + # the exact-age root without a second sort or a donor cross-join. + positions = np.searchsorted(age_indices, indices) + weights = self.weights[indices] + _, cluster = np.unique(self.households[indices], return_inverse=True) + cluster_weights = np.bincount(cluster, weights=weights) + effective = cluster_weights.sum() ** 2 / (cluster_weights @ cluster_weights) + fraction = effective / (effective + self.strength) + probabilities *= 1 - fraction + probabilities[positions] += fraction * weights / weights.sum() + probabilities /= probabilities.sum() + cumulative = probabilities.cumsum() + cumulative[-1] = 1.0 + result = (self.values[age_indices], cumulative, probabilities) + if exclude_household is None: + self.cache[key] = result + return result + + +def fit_pooled_sibling_dependence( + children, + *, + strength=POOLED_CHILDCARE_STRENGTH, + objective="pair_squared_error", + composition=False, +): + """Fit all measured pair cross-products with whole-household donor exclusion.""" + from microcosm.build.us_runtime.nsece_childcare_sibling_validation import ( + _joint_product, + ) + + if objective not in ("pair_squared_error", "population_moments"): + raise ValueError("Unknown pooled dependence objective.") + model = PooledScheduleDonors(children, strength=strength, composition=composition) + records = [] + households = 0 + incomplete_households = 0 + for household_id, roster in children.loc[children.age.between(0, 12)].groupby( + "source_household_id", sort=True + ): + observed = roster.loc[roster.attendance_status.eq("complete")].sort_values( + ["age", "donor_id"] + ) + if len(observed) < 2: + continue + weight = roster.household_weight.to_numpy(dtype=float) + if ( + not np.isfinite(weight).all() + or (weight <= 0).any() + or not (weight == weight[0]).all() + ): + raise ValueError("Pooled dependence requires consistent household weights.") + distributions = [ + model.distribution(row, exclude_household=household_id) + for _, row in observed.iterrows() + ] + means = [np.average(d[0], weights=d[2], axis=0) for d in distributions] + _, days, hours = US_CHILDCARE_ATTENDANCE_COLUMNS + actual = np.column_stack( + (observed[days] > 0, observed[days], observed[days] * observed[hours]) + ).astype(float) + pair_count = len(observed) * (len(observed) - 1) // 2 + for i, j in combinations(range(len(observed)), 2): + independent = means[i] * means[j] + shared = _joint_product(distributions[i][:2], distributions[j][:2]) + records.append( + ( + weight[0] / pair_count, + actual[i] * actual[j] - independent, + shared - independent, + (actual[i] ** 2 + actual[j] ** 2) / 2, + ) + ) + households += 1 + incomplete_households += int(len(observed) != len(roster)) + if not records: + raise ValueError("Pooled dependence requires observed sibling pairs.") + weights = np.array([r[0] for r in records]) + residual = np.array([r[1] for r in records]) + direction = np.array([r[2] for r in records]) + scales = np.average(np.array([r[3] for r in records]), weights=weights, axis=0) + active = scales > 0 + residual = residual[:, active] / scales[active] + direction = direction[:, active] / scales[active] + numerator = np.sum(weights[:, None] * residual * direction) + denominator = np.sum(weights[:, None] * direction**2) + mean_residual = np.average(residual, weights=weights, axis=0) + mean_direction = np.average(direction, weights=weights, axis=0) + if objective == "population_moments": + numerator = mean_residual @ mean_direction + denominator = mean_direction @ mean_direction + unconstrained = float(numerator / denominator) if denominator > 0 else 0.0 + return { + "rho": float(np.clip(unconstrained, 0, 1)), + "unconstrained_rho": unconstrained, + "households": households, + "households_with_unresolved_siblings": incomplete_households, + "observed_pairs": len(records), + "outcome_second_moments": scales.tolist(), + "objective": objective, + "normalized_mean_residual": mean_residual.tolist(), + "normalized_mean_shared_increment": mean_direction.tolist(), + "donor_household_overlap": 0, + "estimation": "least squares on participation/days/weekly-hours cross-products under the named objective; all observed pairs; household weight divided among pairs; leave whole fitting household out of donors", + } diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare_qrf.py b/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare_qrf.py new file mode 100644 index 000000000..168742bae --- /dev/null +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare_qrf.py @@ -0,0 +1,303 @@ +"""Diagnostic canonical-QRF matching of observed, exact-age joint schedules. + +This experiment has no production integration or calendar nonresponse correction. +An ordinal schedule code is decoded to an observed day/hour pair; it is not a +new attendance input. All catalog construction and fits use training data only. +""" + +from __future__ import annotations + +import numpy as np +import pandas as pd +from scipy.stats import qmc + +from microcosm.build.us_runtime.childcare_attendance import ( + US_CHILDCARE_ATTENDANCE_COLUMNS, + _ids, + _validate_attendance, +) +from microcosm.build.us_runtime.nsece_childcare_pooling import ( + COMPOSITION_CHILDCARE_MATCH_COLUMNS, +) +from microcosm.fit import fit + +QRF_CHILDCARE_PREDICTORS = ( + *COMPOSITION_CHILDCARE_MATCH_COLUMNS, + "household_income", + "household_members", + "resident_parent_count", +) +QRF_CHILDCARE_SCHEDULE_CODE = "childcare_schedule_code" +QRF_CHILDCARE_DAY_MULTIPLIER = 25.0 # Daily hours are bounded above by 24. +QRF_CHILDCARE_GRID_POWER = 7 # Fixed 128-point two-dimensional Sobol integration. +QRF_INTERVAL_DRAWS = 8 +QRF_INTERVAL_EMPIRICAL_MIX = 0.1 + + +def _interval_rows(children): + return ( + children.age.between(0, 12) + & children.questionnaire_version.eq(1) + & children.attendance_status.isin(["ambiguous_calendar", "partial_calendar"]) + ) + + +class QRFChildcareSchedules: + """Canonical weighted QRF with an age-specific empirical schedule decoder.""" + + def __init__( + self, children, *, seed=915, n_estimators=100, allow_interval_training=False + ): + if children.attendance_status.eq("summary_bridge").any(): + raise ValueError("QRF diagnostics require original measured calendars.") + self.training_households = frozenset(children.source_household_id) + self.interval_ids = ( + frozenset(children.loc[_interval_rows(children), "donor_id"]) + if "questionnaire_version" in children + else frozenset() + ) + interval = children.attendance_status.eq("interval_model") + if interval.any() and not allow_interval_training: + raise ValueError( + "Modeled interval rows require explicit experimental opt-in." + ) + if interval.any(): + rows = children.loc[interval] + days = rows.childcare_days_per_week + weekly = days * rows.childcare_hours_per_day + if not ( + days.between(rows.calendar_ece_days_lower, rows.calendar_ece_days_upper) + & weekly.between( + rows.calendar_ece_hours_lower - 1e-10, + rows.calendar_ece_hours_upper + 1e-10, + ) + ).all(): + raise ValueError("Modeled interval schedule violates measured bounds.") + pool = ( + children.loc[ + children.age.between(0, 12) + & (children.attendance_status.eq("complete") | interval) + ] + .sort_values("donor_id") + .copy() + ) + if pool.empty: + raise ValueError("QRF attendance requires observed training calendars.") + _ids(pool, "source_household_id", unique=False) + _ids(pool, "donor_id", unique=True) + _validate_attendance(pool, complete=True) + if not np.isfinite( + pool[list(QRF_CHILDCARE_PREDICTORS)].to_numpy(dtype=float) + ).all(): + raise ValueError("QRF attendance predictors must be finite.") + weights = pool.child_weight.to_numpy(dtype=float) + if not np.isfinite(weights).all() or (weights <= 0).any(): + raise ValueError("QRF attendance needs positive finite design weights.") + _, days, hours = US_CHILDCARE_ATTENDANCE_COLUMNS + pool[QRF_CHILDCARE_SCHEDULE_CODE] = ( + QRF_CHILDCARE_DAY_MULTIPLIER * pool[days] + pool[hours] + ) + self.catalogs = {} + self.empirical = {} + self.ages = frozenset(pool.age) + for age, group in pool.groupby("age"): + schedules, inverse = np.unique( + np.column_stack( + ( + group[days].gt(0).astype(float), + group[days], + group[days] * group[hours], + ) + ), + axis=0, + return_inverse=True, + ) + masses = np.bincount(inverse, weights=group.child_weight) + self.empirical[age] = (schedules, masses / masses.sum()) + for age, group in pool.loc[pool[days] > 0].groupby("age"): + group = group.sort_values(QRF_CHILDCARE_SCHEDULE_CODE).drop_duplicates( + QRF_CHILDCARE_SCHEDULE_CODE + ) + self.catalogs[age] = ( + group[QRF_CHILDCARE_SCHEDULE_CODE].to_numpy(), + np.column_stack( + (np.ones(len(group)), group[days], group[days] * group[hours]) + ), + ) + self.model = fit( + pool, + list(QRF_CHILDCARE_PREDICTORS), + [QRF_CHILDCARE_SCHEDULE_CODE], + weights="child_weight", + seed=seed, + n_estimators=n_estimators, + ) + self.cache = {} + self.decoder_movements = [] + + def prepare(self, children): + """Prepare held-out feature profiles in bounded, deterministic batches.""" + if self.training_households.intersection(children.source_household_id): + raise ValueError("QRF evaluation households overlap training households.") + self._prepare_profiles(children) + + def _prepare_profiles(self, children): + """Internal prediction shared by held-out scoring and training completion.""" + profiles = children.reindex(columns=QRF_CHILDCARE_PREDICTORS).drop_duplicates() + if not np.isfinite(profiles.to_numpy(dtype=float)).all(): + raise ValueError("QRF target predictors must be finite.") + if not set(profiles.age).issubset(self.ages): + raise ValueError("QRF target has no exact-age training support.") + uniforms = qmc.Sobol(2, scramble=False).random_base2(QRF_CHILDCARE_GRID_POWER) + count = len(uniforms) + for start in range(0, len(profiles), 64): + batch = profiles.iloc[start : start + 64] + repeated = batch.loc[batch.index.repeat(count)].reset_index(drop=True) + codes = ( + self.model.predict_from_uniforms( + repeated, + quantiles={ + QRF_CHILDCARE_SCHEDULE_CODE: np.tile(uniforms[:, 1], len(batch)) + }, + sign_uniforms={ + QRF_CHILDCARE_SCHEDULE_CODE: np.tile(uniforms[:, 0], len(batch)) + }, + )[QRF_CHILDCARE_SCHEDULE_CODE] + .to_numpy() + .reshape(len(batch), count) + ) + for row, draws in zip( + batch.itertuples(index=False, name=None), codes, strict=True + ): + values = np.zeros((count, 3)) + positive = draws > 0 + if positive.any(): + if row[0] not in self.catalogs: + raise ValueError( + "Positive QRF draw has no exact-age positive donor." + ) + catalog, schedules = self.catalogs[row[0]] + right = np.clip( + np.searchsorted(catalog, draws[positive]), 0, len(catalog) - 1 + ) + left = np.maximum(right - 1, 0) + chosen = np.where( + np.abs(catalog[left] - draws[positive]) + <= np.abs(catalog[right] - draws[positive]), + left, + right, + ) + values[positive] = schedules[chosen] + self.decoder_movements.extend( + np.abs(catalog[chosen] - draws[positive]).tolist() + ) + values, counts = np.unique(values, axis=0, return_counts=True) + probabilities = counts / count + cumulative = probabilities.cumsum() + cumulative[-1] = 1.0 + self.cache[row] = (values, cumulative, probabilities) + + def distribution(self, child): + """Return the prepared empirical integration distribution.""" + key = tuple(child.reindex(QRF_CHILDCARE_PREDICTORS)) + if child.source_household_id in self.training_households: + raise ValueError("QRF evaluation households overlap training households.") + return self.cache[key] + + +def interval_training_rows(children, model, *, tilt=0): + """One training-only interval completion pass; measured rows remain intact. + + The prior is a fixed QRF/empirical mixture, restricted to observed bounds. + This assumes conditional coarsening at random. Tilts expose sensitivity to + that assumption; completed rows must never enter observed-outcome scoring. + """ + if tilt not in (-1, 0, 1): + raise ValueError("Interval sensitivity tilt must be -1, 0 or 1.") + target = children.loc[_interval_rows(children)].copy() + bounds = target.reindex( + columns=[ + "calendar_ece_days_lower", + "calendar_ece_days_upper", + "calendar_ece_hours_lower", + "calendar_ece_hours_upper", + ] + ).to_numpy(dtype=float) + if ( + not np.isfinite(bounds).all() + or (bounds < 0).any() + or (bounds[:, :2] > 7).any() + or (bounds[:, 2:] > 168).any() + or (bounds[:, 0] > bounds[:, 1]).any() + or (bounds[:, 2] > bounds[:, 3]).any() + ): + raise ValueError("Training calendar bounds must be finite and ordered.") + if not set(target.donor_id).issubset(model.interval_ids): + raise ValueError("Interval completion includes children outside training.") + if not set(children.source_household_id).issubset(model.training_households): + raise ValueError("Interval completion includes households outside training.") + model._prepare_profiles(target) + rows, completed, unsupported = [], set(), [] + quantiles = (np.arange(QRF_INTERVAL_DRAWS) + 0.5) / QRF_INTERVAL_DRAWS + for _, child in target.iterrows(): + key = tuple(child.reindex(QRF_CHILDCARE_PREDICTORS)) + values, _, probability = model.cache[key] + empirical, mass = model.empirical[child.age] + combined, inverse = np.unique( + np.concatenate([values, empirical]), axis=0, return_inverse=True + ) + probability = np.bincount( + inverse, + weights=np.concatenate( + [ + (1 - QRF_INTERVAL_EMPIRICAL_MIX) * probability, + QRF_INTERVAL_EMPIRICAL_MIX * mass, + ] + ), + ) + allowed = ( + (combined[:, 1] >= child.calendar_ece_days_lower) + & (combined[:, 1] <= child.calendar_ece_days_upper) + & (combined[:, 2] >= child.calendar_ece_hours_lower - 1e-10) + & (combined[:, 2] <= child.calendar_ece_hours_upper + 1e-10) + ) + if not allowed.any(): + unsupported.append(float(child.child_weight)) + continue + schedules = combined[allowed] + probability = probability[allowed] * np.exp(tilt * schedules[:, 2] / 40) + probability /= probability.sum() + cumulative = probability.cumsum() + cumulative[-1] = 1 + chosen = schedules[np.searchsorted(cumulative, quantiles, side="right")] + for draw, (_, days, weekly) in enumerate(chosen): + row = child.copy() + row["donor_id"] = f"{child.donor_id}:interval:{draw}" + row["attendance_status"] = "interval_model" + row["child_weight"] = child.child_weight / QRF_INTERVAL_DRAWS + row["childcare_attending_days_per_month"] = np.floor(days * 52 / 12 + 0.5) + row["childcare_days_per_week"] = days + row["childcare_hours_per_day"] = weekly / days if days else 0.0 + row["ece_hours_per_week"] = weekly + rows.append(row) + completed.add(child.donor_id) + retained = children.loc[~children.donor_id.isin(completed)] + result = pd.concat([retained, pd.DataFrame(rows)], ignore_index=True) + if not np.isclose( + result.child_weight.sum(), children.child_weight.sum(), rtol=1e-12 + ): + raise ValueError("Interval completion changed design-weight mass.") + return result, { + "tilt": tilt, + "incomplete_training_children": len(target), + "completed_training_children": len(completed), + "unsupported_training_children": len(unsupported), + "unsupported_child_weight": float(sum(unsupported)), + "completed_child_weight": float( + target.loc[target.donor_id.isin(completed), "child_weight"].sum() + ), + "draws_per_child": QRF_INTERVAL_DRAWS, + "empirical_mixture_weight": QRF_INTERVAL_EMPIRICAL_MIX, + "design_weight_conserved": True, + "interpretation": "modeled training rows, not observations; conditional coarsening assumption", + } diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare_sibling_validation.py b/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare_sibling_validation.py new file mode 100644 index 000000000..102e080ad --- /dev/null +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/nsece_childcare_sibling_validation.py @@ -0,0 +1,760 @@ +"""Held-out joint schedule moments for the actual household rank mixture. + +Integrate the finite donor CDFs exactly, rather than selecting a favorable +simulation seed. Whole households are held out, including all larger sibships. +""" + +from __future__ import annotations + +import hashlib +from itertools import combinations + +import numpy as np +import pandas as pd + +from microcosm.build.us_runtime.childcare_attendance import ( + US_CHILDCARE_ATTENDANCE_COLUMNS, +) +from microcosm.build.us_runtime.nsece_childcare import ( + NSECE_CHILDCARE_FALLBACK_COLUMNS, + NSECE_CHILDCARE_MATCH_COLUMNS, + NSECEChildcareSource, +) +from microcosm.build.us_runtime.nsece_childcare_dependence import ( + fit_nsece_sibling_dependence, +) + + +def _joint_product( + first: tuple[np.ndarray, np.ndarray], second: tuple[np.ndarray, np.ndarray] +): + """E[XY] under one shared uniform, with arbitrary weighted discrete CDFs.""" + a, pa = first + b, pb = second + cuts = np.unique(np.r_[0, pa, pb, 1]) + midpoints = (cuts[:-1] + cuts[1:]) / 2 + x = a[np.minimum(np.searchsorted(pa, midpoints, side="right"), len(a) - 1)] + y = b[np.minimum(np.searchsorted(pb, midpoints, side="right"), len(b) - 1)] + return np.sum(x * y * np.diff(cuts)[:, None], axis=0) + + +def _moments(values, weights): + return np.average(values, weights=weights, axis=0) + + +def _pair_summary(records): + weights = np.array([r[0] for r in records]) + result = {} + for arm, index in (("observed", 1), ("independent", 2), ("coupled", 3)): + moments = _moments(np.array([r[index] for r in records]), weights) + metrics = {} + for j, name in enumerate(("participation", "days", "weekly_hours")): + x, y, xx, yy, xy = moments[:, j] + denominator = np.sqrt(max(0, xx - x * x) * max(0, yy - y * y)) + metrics[name] = { + "joint_product": float(xy), + "correlation": float((xy - x * y) / denominator) + if denominator > 0 + else None, + } + result[arm] = metrics + return { + "households": len(records), + "household_weight": float(weights.sum()), + **result, + } + + +def _household_splits(children, *, seed, validation_seed, partition): + """Keep the reserved households outside every development fit and donor pool.""" + if partition not in ("all", "development", "validation"): + raise ValueError("Unknown sibling assessment partition.") + if (partition == "all") != (validation_seed is None): + raise ValueError("A reserved assessment needs a validation seed and partition.") + households = children.source_household_id + reserved = ( + households.map( + lambda x: ( + int.from_bytes( + hashlib.sha256(f"{validation_seed}:reserved:{x}".encode()).digest()[ + :8 + ], + "big", + ) + % 5 + == 0 + ) + ) + if validation_seed is not None + else pd.Series(False, index=children.index) + ) + if partition == "validation": + return [(~reserved, reserved)] + development = ~reserved + folds = households.map( + lambda x: ( + int.from_bytes(hashlib.sha256(f"{seed}:{x}".encode()).digest()[:8], "big") + % 5 + ) + ) + return [ + (development & (folds != fold), development & (folds == fold)) + for fold in range(5) + ] + + +def assess_sibling_schedules( + source, + *, + seed=271828, + match_columns=NSECE_CHILDCARE_MATCH_COLUMNS, + fallback_match_columns=NSECE_CHILDCARE_FALLBACK_COLUMNS, + validation_seed=None, + partition="all", + pooled=False, + include_observed_children=False, + pooling_fit_objective="pair_squared_error", + composition=False, +): + """Evaluate pair intensity and larger-household totals with disjoint training. + + A reserved split separates model development from the final comparison. + Previously inspected source data do not become untouched external evidence + merely because a new split is used. + """ + children = source.children.loc[source.children.age.between(0, 12)].copy() + if composition and not pooled: + raise ValueError("Composition matching requires the pooled model.") + if pooled or include_observed_children: + from microcosm.build.us_runtime.nsece_childcare_pooling import ( + PooledScheduleDonors, + fit_pooled_sibling_dependence, + with_childcare_household_size, + ) + + children = with_childcare_household_size(children) + if children.attendance_status.eq("summary_bridge").any(): + raise ValueError("Sibling validation requires original measured calendars.") + levels = (match_columns, *fallback_match_columns) + splits = _household_splits( + children, seed=seed, validation_seed=validation_seed, partition=partition + ) + pairs, large_pairs, larger = [], [], [] + child_records, observed_pairs = [], [] + observed_pair_households = 0 + month, days, hours = US_CHILDCARE_ATTENDANCE_COLUMNS + del month + fold_fits, split_counts, matching_counts, dependence_fits = [], [], {}, [] + for training_mask, target_mask in splits: + training = children.loc[training_mask] + target = children.loc[target_mask] + if training.empty or target.empty: + raise ValueError( + "Sibling assessment requires nonempty household partitions." + ) + if not set(training.source_household_id).isdisjoint(target.source_household_id): + raise ValueError("Sibling assessment leaks households across partitions.") + split_counts.append( + { + "training_households": int(training.source_household_id.nunique()), + "evaluation_households": int(target.source_household_id.nunique()), + "household_overlap": 0, + } + ) + fitted = ( + fit_pooled_sibling_dependence( + training, objective=pooling_fit_objective, composition=composition + ) + if pooled + else fit_nsece_sibling_dependence(training, match_columns=match_columns) + ) + rho = fitted["rho"] + dependence_fits.append(fitted) + fold_fits.append(rho) + pooled_model = ( + PooledScheduleDonors(training, composition=composition) if pooled else None + ) + train = training.loc[training.attendance_status.eq("complete")].sort_values( + [days, hours, "donor_id"] + ) + groups = [ + (level, train.groupby(list(level), sort=False).indices) for level in levels + ] + cache = {} + + def distribution( + child: pd.Series, + cache: dict = cache, + groups: list = groups, + train: pd.DataFrame = train, + pooled_model=pooled_model, + ): + if pooled_model is not None: + matching_counts["partially_pooled"] = ( + matching_counts.get("partially_pooled", 0) + 1 + ) + return pooled_model.distribution(child) + key = tuple(child.reindex(match_columns)) + if key not in cache: + for level, indices in groups: + k = tuple(child.reindex(level)) + pool = train.iloc[indices.get(k[0] if len(k) == 1 else k, [])] + pool = pool.loc[pool.child_weight > 0] + if len(pool): + break + if pool.empty: + raise ValueError("Unsupported held-out sibling matching cell.") + probabilities = pool.child_weight.to_numpy(dtype=float, copy=True) + probabilities /= probabilities.sum() + values = np.column_stack( + (pool[days] > 0, pool[days], pool[days] * pool[hours]) + ).astype(float) + cumulative = probabilities.cumsum() + cumulative[-1] = 1 + cache[key] = (values, cumulative, probabilities, ",".join(level)) + *distribution_values, used_level = cache[key] + matching_counts[used_level] = matching_counts.get(used_level, 0) + 1 + return distribution_values + + for _, household in target.groupby("source_household_id"): + complete_household = bool(household.attendance_status.eq("complete").all()) + if not include_observed_children and ( + len(household) < 2 or not complete_household + ): + continue + roster_size = len(household) + household = household.loc[household.attendance_status.eq("complete")] + if household.empty: + continue + household = household.sort_values(["age", "donor_id"]) + w = household.household_weight.to_numpy(dtype=float) + if not np.isfinite(w).all() or (w <= 0).any() or not (w == w[0]).all(): + raise ValueError( + "Sibling assessment requires consistent household design weights." + ) + distributions = [distribution(row) for _, row in household.iterrows()] + means = np.array([_moments(d[0], d[2]) for d in distributions]) + seconds = np.array([_moments(d[0] ** 2, d[2]) for d in distributions]) + actual = np.column_stack( + ( + household[days] > 0, + household[days], + household[days] * household[hours], + ) + ).astype(float) + if include_observed_children: + for i, (_, child) in enumerate(household.iterrows()): + child_records.append( + ( + float(child.child_weight), + min(roster_size, 3), + complete_household, + actual[i], + means[i], + seconds[i], + ) + ) + if len(household) >= 2: + observed_pair_households += 1 + pair_weight = w[0] / (len(household) * (len(household) - 1) / 2) + for i, j in combinations(range(len(household)), 2): + independent_product = means[i] * means[j] + shared_product = _joint_product( + distributions[i][:2], distributions[j][:2] + ) + observed_pairs.append( + ( + pair_weight, + np.array( + [ + actual[i], + actual[j], + actual[i] ** 2, + actual[j] ** 2, + actual[i] * actual[j], + ] + ), + np.array( + [ + means[i], + means[j], + seconds[i], + seconds[j], + independent_product, + ] + ), + np.array( + [ + means[i], + means[j], + seconds[i], + seconds[j], + (1 - rho) * independent_product + + rho * shared_product, + ] + ), + ) + ) + if len(household) < 2 or not complete_household: + continue + joint = _joint_product(distributions[0][:2], distributions[1][:2]) + independent = means[0] * means[1] + observed = np.array( + [ + actual[0], + actual[1], + actual[0] ** 2, + actual[1] ** 2, + actual[0] * actual[1], + ] + ) + uncoupled = np.array( + [means[0], means[1], seconds[0], seconds[1], independent] + ) + coupled = np.array( + [ + means[0], + means[1], + seconds[0], + seconds[1], + (1 - rho) * independent + rho * joint, + ] + ) + record = (w[0], observed, uncoupled, coupled) + pairs.append(record) + if len(household) < 3: + continue + large_pairs.append(record) + sums = means.sum(axis=0) + sums_squared = { + "independent": seconds.sum(axis=0).copy(), + "coupled": seconds.sum(axis=0).copy(), + } + for i, j in combinations(range(len(household)), 2): + independent = means[i] * means[j] + joint = _joint_product(distributions[i][:2], distributions[j][:2]) + sums_squared["independent"] += 2 * independent + sums_squared["coupled"] += 2 * ((1 - rho) * independent + rho * joint) + independent_all = means[:, 0].prod() + larger.append( + ( + w[0], + { + "observed": np.r_[ + actual.sum(axis=0), + actual.sum(axis=0) ** 2, + actual[:, 0].prod(), + ], + "independent": np.r_[ + sums, sums_squared["independent"], independent_all + ], + "coupled": np.r_[ + sums, + sums_squared["coupled"], + (1 - rho) * independent_all + rho * means[:, 0].min(), + ], + }, + ) + ) + result = { + "design": "household-separated partitions; exact integration of the implemented shared-rank donor CDFs", + "seed": seed, + "validation_seed": validation_seed, + "partition": partition, + "splits": split_counts, + "match_columns": match_columns, + "fallback_match_columns": fallback_match_columns, + "matching_counts": matching_counts, + "training_rho": fold_fits, + "youngest_pairs": _pair_summary(pairs) if pairs else None, + "youngest_pairs_in_3plus_households": _pair_summary(large_pairs) + if large_pairs + else None, + "larger_households": {"households": len(larger)}, + "production_ready": False, + } + if larger: + weights = np.array([r[0] for r in larger]) + for arm in ("observed", "independent", "coupled"): + values = _moments(np.array([r[1][arm] for r in larger]), weights) + result["larger_households"][arm] = { + "mean_total_days": float(values[1]), + "mean_total_weekly_hours": float(values[2]), + "sd_total_days": float(np.sqrt(max(0, values[4] - values[1] ** 2))), + "sd_total_weekly_hours": float( + np.sqrt(max(0, values[5] - values[2] ** 2)) + ), + "all_children_attend": float(values[6]), + } + result["diagnostic_screen"] = sibling_schedule_screen(result) + if pooled: + from microcosm.build.us_runtime.nsece_childcare_pooling import ( + COMPOSITION_CHILDCARE_LEVELS, + POOLED_CHILDCARE_LEVELS, + POOLED_CHILDCARE_STRENGTH, + ) + + pooling_levels = ( + COMPOSITION_CHILDCARE_LEVELS if composition else POOLED_CHILDCARE_LEVELS + ) + result["model"] = { + "name": "partially_pooled_empirical_schedules", + "levels": pooling_levels, + "composition": composition, + "strength": POOLED_CHILDCARE_STRENGTH, + "dependence_objective": pooling_fit_objective, + "dependence_fits": dependence_fits, + } + result["match_columns"] = pooling_levels[-1] + result["fallback_match_columns"] = () + if include_observed_children: + result["matching_count_universe"] = ( + "every held-out child with an observed complete calendar" + ) + result["observed_child_validation"] = _observed_child_summary(child_records) + if observed_pairs: + summary = _pair_summary(observed_pairs) + summary["observed_pairs"] = summary.pop("households") + summary["households"] = observed_pair_households + summary["interpretation"] = ( + "all observed pairs including households with unresolved other siblings; household weight divided among observed pairs" + ) + result["all_observed_sibling_pairs"] = summary + else: + result["all_observed_sibling_pairs"] = None + return result + + +def _observed_child_summary(records): + if not records: + raise ValueError("Observed-child validation requires measured calendars.") + outcomes = ("participation", "days", "weekly_hours") + comparisons, checks = [], [] + for label, rows in ( + ("all", records), + *( + (f"household_size_{size}", [r for r in records if r[1] == size]) + for size in (1, 2, 3) + ), + ("complete_household", [r for r in records if r[2]]), + ("unresolved_siblings", [r for r in records if not r[2]]), + ): + if not rows: + comparisons.append({"group": label, "children": 0}) + checks.append( + {"group": label, "passed": False, "reason": "no observed children"} + ) + continue + weights = np.array([r[0] for r in rows]) + actual = np.array([r[3] for r in rows]) + means = np.array([r[4] for r in rows]) + seconds = np.array([r[5] for r in rows]) + observed = np.average(actual, weights=weights, axis=0) + expected = np.average(means, weights=weights, axis=0) + comparisons.append( + { + "group": label, + "children": len(rows), + "child_weight": float(weights.sum()), + "observed": dict(zip(outcomes, observed.tolist(), strict=True)), + "expected": dict(zip(outcomes, expected.tolist(), strict=True)), + "conditional_mean_squared_error": dict( + zip( + outcomes, + np.average( + (actual - means) ** 2, weights=weights, axis=0 + ).tolist(), + strict=True, + ) + ), + "expected_draw_squared_error": dict( + zip( + outcomes, + np.average( + actual**2 - 2 * actual * means + seconds, + weights=weights, + axis=0, + ).tolist(), + strict=True, + ) + ), + } + ) + for index, name in enumerate(outcomes): + relative = index != 0 + gap = float( + abs(expected[index] - observed[index]) + / (abs(observed[index]) if relative and observed[index] != 0 else 1) + ) + defined = bool(not relative or observed[index] != 0) + limit = 0.20 if relative else 0.05 + checks.append( + { + "group": label, + "metric": name, + "relative": relative, + "gap": gap if defined else None, + "limit": limit, + "passed": defined and gap <= limit, + } + ) + return { + "comparisons": comparisons, + "screen": {"passed": all(c["passed"] for c in checks), "checks": checks}, + "interpretation": "child-weighted predictions of observed calendars; missing children are not scored as zeros; previously used survey, not external validation", + } + + +def coupling_screen_compatibility(result): + """Check whether changing dependence alone could satisfy BOTH joint screens. + + Independent and coupled arms have identical marginal first/second moments. + Therefore correlation is affine in E[XY], regardless of the chosen copula. + Recover that line from the two arms and intersect the existing correlation + and cross-product screen intervals. Disjoint intervals prove those screens + require a change to marginal distributions, not merely a different rho. + This is conditional on the evaluated marginals, not an impossibility result + for other models or a claim that selected households represent the population. + """ + comparisons = [] + screens = {row["metric"]: row for row in result["diagnostic_screen"]["checks"]} + for population in ("youngest_pairs", "youngest_pairs_in_3plus_households"): + group = result.get(population) + for metric in ("days", "weekly_hours"): + entry = {"population": population, "metric": metric} + comparisons.append(entry) + if not group: + entry.update({"identified": False, "reason": "no evaluated pairs"}) + continue + observed = group["observed"][metric] + independent = group["independent"][metric] + coupled = group["coupled"][metric] + correlations = [ + arm["correlation"] for arm in (observed, independent, coupled) + ] + if any(c is None or not np.isfinite(c) for c in correlations) or np.isclose( + correlations[1], correlations[2] + ): + entry.update( + { + "identified": False, + "reason": "marginal scale not recoverable from the two arms", + } + ) + continue + scale = (coupled["joint_product"] - independent["joint_product"]) / ( + correlations[2] - correlations[1] + ) + if not np.isfinite(scale) or scale <= 0: + entry.update({"identified": False, "reason": "invalid marginal scale"}) + continue + product_of_means = independent["joint_product"] - correlations[1] * scale + # Consume the reported criteria so a screen change cannot leave + # this structural diagnostic silently using a different threshold. + correlation_limit = screens[f"{population}.{metric}.correlation"]["limit"] + product_limit = screens[f"{population}.{metric}.joint_product"]["limit"] + correlation_range = [ + max(-1, correlations[0] - correlation_limit), + min(1, correlations[0] + correlation_limit), + ] + required_product = [ + product_of_means + value * scale for value in correlation_range + ] + allowed_product = [ + (1 - product_limit) * observed["joint_product"], + (1 + product_limit) * observed["joint_product"], + ] + lower, upper = ( + max(required_product[0], allowed_product[0]), + min(required_product[1], allowed_product[1]), + ) + entry.update( + { + "identified": True, + "predicted_product_of_marginal_means": product_of_means, + "predicted_product_of_marginal_standard_deviations": scale, + "joint_product_required_by_correlation_screen": required_product, + "joint_product_allowed_by_product_screen": allowed_product, + "screen_intervals_overlap": lower <= upper, + "overlap_interval": [lower, upper] if lower <= upper else None, + } + ) + return { + "comparisons": comparisons, + "interpretation": "disjoint screen intervals rule out a dependence-only fix for these conditional marginals; overlapping intervals do not establish that a feasible joint distribution exists", + } + + +def sibling_schedule_screen(result): + """Developmental screens declared before this expanded assessment was run. + + Passing would not certify the survey transport or authorize publication. + Undefined metrics and empty subgroups are failures, not silent passes. + """ + checks = [] + + def check(name, observed, predicted, limit, relative=False): + gap = None + if observed is not None and predicted is not None: + if not relative or observed != 0: + gap = abs(predicted - observed) / (abs(observed) if relative else 1) + checks.append( + { + "metric": name, + "absolute_gap": gap, + "relative": relative, + "limit": limit, + "passed": gap is not None and gap <= limit, + } + ) + + for name in ("youngest_pairs", "youngest_pairs_in_3plus_households"): + values = result.get(name) or {} + for metric, moment, limit, relative in ( + ("participation", "joint_product", 0.05, False), + ("days", "correlation", 0.10, False), + ("weekly_hours", "correlation", 0.10, False), + ("days", "joint_product", 0.20, True), + ("weekly_hours", "joint_product", 0.20, True), + ): + observed = values.get("observed", {}).get(metric, {}).get(moment) + predicted = values.get("coupled", {}).get(metric, {}).get(moment) + check(f"{name}.{metric}.{moment}", observed, predicted, limit, relative) + larger = result["larger_households"] + for metric in ( + "mean_total_days", + "mean_total_weekly_hours", + "sd_total_days", + "sd_total_weekly_hours", + "all_children_attend", + ): + relative = metric != "all_children_attend" + check( + f"larger_households.{metric}", + larger.get("observed", {}).get(metric), + larger.get("coupled", {}).get(metric), + 0.20 if relative else 0.05, + relative, + ) + return { + "passed": all(c["passed"] for c in checks), + "checks": checks, + "interpretation": "provisional diagnostic screens; not publication authorization", + } + + +def compare_household_size_matching(source, *, partition, validation_seed=20260916): + """Evaluate one size-conditioned challenger without changing the build recipe. + + Count every rostered under-13 child before attendance selection. The + selection diagnostic uses only development households even when the + caller requests the separately reserved final comparison. + """ + if partition not in ("development", "validation"): + raise ValueError("Household-size comparison requires a reserved partition.") + children = source.children.copy() + children["childcare_household_size"] = ( + children.age.between(0, 12) + .groupby(children.source_household_id) + .transform("sum") + .clip(upper=3) + ) + revised_source = NSECEChildcareSource( + children, source.weights, source.source_receipt + ) + columns = ("age", "childcare_household_size", *NSECE_CHILDCARE_MATCH_COLUMNS[1:]) + fallbacks = tuple( + ("age", "childcare_household_size", *level[1:]) + for level in NSECE_CHILDCARE_FALLBACK_COLUMNS + ) + (("age",),) + settings = {"partition": partition, "validation_seed": validation_seed} + baseline = assess_sibling_schedules(source, **settings) + challenger = assess_sibling_schedules( + revised_source, + match_columns=columns, + fallback_match_columns=fallbacks, + **settings, + ) + return { + "source": source.source_receipt, + "partition": partition, + "validation_seed": validation_seed, + "legacy": baseline, + "household_size": challenger, + "development_selection": _household_selection_diagnostic( + children, match_columns=columns, validation_seed=validation_seed + ), + "production_recipe_changed": False, + "production_ready": False, + "interpretation": ( + "Prospective internal comparison on previously inspected survey data; " + "not untouched external acceptance evidence. Complete-household totals " + "do not identify totals for families with missing calendars." + ), + } + + +def _household_selection_diagnostic(children, *, match_columns, validation_seed): + children = children.loc[children.age.between(0, 12)] + development, _ = _household_splits( + children, seed=271828, validation_seed=validation_seed, partition="validation" + )[0] + children = children.loc[development].copy() + children["complete_household"] = children.groupby( + "source_household_id" + ).attendance_status.transform(lambda status: status.eq("complete").all()) + records = [] + complete = children.loc[children.attendance_status.eq("complete")] + for size, group in complete.groupby("childcare_household_size"): + for sample, rows in ( + ("all_observed_children", group), + ("children_in_complete_households", group.loc[group.complete_household]), + ( + "observed_children_with_unresolved_siblings", + group.loc[~group.complete_household], + ), + ): + if rows.empty: + continue + weights = rows.child_weight + records.append( + { + "household_size_capped_at_3": int(size), + "sample": sample, + "children": len(rows), + "households": int(rows.source_household_id.nunique()), + "child_weight": float(weights.sum()), + "mean_days": float( + np.average(rows.childcare_days_per_week, weights=weights) + ), + "mean_weekly_hours": float( + np.average( + rows.childcare_days_per_week * rows.childcare_hours_per_day, + weights=weights, + ) + ), + } + ) + support = {} + for name, columns in ( + ("legacy", NSECE_CHILDCARE_MATCH_COLUMNS), + ("household_size", match_columns), + ): + counts = complete.groupby(list(columns)).source_household_id.transform( + "nunique" + ) + support[name] = { + "children": len(complete), + "median_donor_households": float(counts.median()), + "children_in_cells_below_10_households": int((counts < 10).sum()), + "fraction_of_children_in_cells_below_10_households": float( + (counts < 10).mean() + ), + "definition": "Exact matching cells in the whole development pool; fold-training support can be smaller. Ten is a descriptive cutoff, not a tuned fallback rule.", + } + return { + "partition": "development only", + "observed_child_comparisons": records, + "donor_support": support, + "interpretation": "Descriptive differences under calendar selection; not a causal effect of missingness and not corrected population totals.", + } diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/release_input_coverage.py b/packages/microcosm-build/src/microcosm/build/us_runtime/release_input_coverage.py index 516c535e6..65987db8e 100644 --- a/packages/microcosm-build/src/microcosm/build/us_runtime/release_input_coverage.py +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/release_input_coverage.py @@ -60,6 +60,9 @@ US_CAPITAL_GAIN_DETAILS_OUTPUT_COLUMNS, ) from microcosm.build.us_runtime.child_support import US_CHILD_SUPPORT_OUTPUT_COLUMNS +from microcosm.build.us_runtime.childcare_attendance import ( + US_CHILDCARE_ATTENDANCE_COLUMNS, +) from microcosm.build.us_runtime.disability_benefits import ( US_DISABILITY_BENEFITS_OUTPUT_COLUMNS, ) @@ -155,6 +158,7 @@ # become structural zeroes. POST_REFERENCE_ECPS_REQUIRED_INPUTS = frozenset( { + *US_CHILDCARE_ATTENDANCE_COLUMNS, "fsla_overtime_premium", "qualified_passenger_vehicle_loan_interest", "traditional_401k_contributions_desired", @@ -650,7 +654,22 @@ def us_release_input_coverage_gate( present_values["household_weight"] = frame.weights_for("household").values degenerate, no_observed = _degenerate_columns(present_values, engine) - return input_column_coverage_gate( + attendance_details = None + attendance_failures = () + if set(US_CHILDCARE_ATTENDANCE_COLUMNS) & (required | set(present_values)): + from microcosm.build.us_runtime.childcare_attendance_receipt import ( + assert_bound_childcare_attendance, + ) + from microcosm.build.us_runtime.nsece_childcare import ( + assert_childcare_attendance_exportable, + ) + + try: + assert_childcare_attendance_exportable(frame) + attendance_details = assert_bound_childcare_attendance(frame) + except ValueError as error: + attendance_failures = (str(error),) + result = input_column_coverage_gate( present_values.keys(), required_columns=required, degenerate_columns=degenerate, @@ -658,6 +677,12 @@ def us_release_input_coverage_gate( reviewed_exclusions=reviewed, name="us_release_input_coverage", ) + return GateResult( + name=result.name, + passed=result.passed and not attendance_failures, + failures=(*result.failures, *attendance_failures), + details={**result.details, "childcare_attendance": attendance_details}, + ) def _coverage_engine() -> Any | None: diff --git a/packages/microcosm-build/tests/engine/us/test_spec_engine_coverage_tool.py b/packages/microcosm-build/tests/engine/us/test_spec_engine_coverage_tool.py index 7be8062b0..adbde278c 100644 --- a/packages/microcosm-build/tests/engine/us/test_spec_engine_coverage_tool.py +++ b/packages/microcosm-build/tests/engine/us/test_spec_engine_coverage_tool.py @@ -82,22 +82,22 @@ def test_us_coverage_is_exact_complete_and_honest( assert_coverage_complete(coverage_report) assert coverage_report["status"] == "pass" fields = coverage_report["field_usage"] - assert fields["configuration_field_count"] == 42_184 - assert fields["authored_normative_field_count"] == 32_404 + assert fields["configuration_field_count"] == 42_187 + assert fields["authored_normative_field_count"] == 32_407 assert fields["resolved_binding_field_count"] == 9_780 - assert fields["consumed_field_count"] == 42_184 + assert fields["consumed_field_count"] == 42_187 assert fields["unused_field_count"] == 0 assert fields["multiple_primary_use_field_count"] == 0 assert fields["claim_count"] == 49 assert fields["mode_counts"] == { "legacy_behavior": 14_010, "compiler_semantic": 27_717, - "front_end_validation": 354, + "front_end_validation": 357, "identity_only": 103, } assert fields["generation0_effect_counts"] == { "legacy_behavior": 38_498, - "no_generation0_effect": 3_686, + "no_generation0_effect": 3_689, } inventory = coverage_report["inventory_coverage"] diff --git a/packages/microcosm-build/tests/engine/us/test_us_annual_static_aging.py b/packages/microcosm-build/tests/engine/us/test_us_annual_static_aging.py index cb66df553..1fec078f4 100644 --- a/packages/microcosm-build/tests/engine/us/test_us_annual_static_aging.py +++ b/packages/microcosm-build/tests/engine/us/test_us_annual_static_aging.py @@ -144,6 +144,67 @@ def test_small_actual_calibration_exports_independent_years(inputs): assert receipt["column_series"]["employment_income_before_lsr"] in receipt["totals"] +def test_annual_projection_preserves_bound_attendance(inputs): + from microcosm.build.us_runtime.childcare_attendance import ( + US_CHILDCARE_ATTENDANCE_COLUMNS, + ) + from microcosm.build.us_runtime.childcare_attendance_receipt import ( + ATTENDANCE_RECEIPT_KEY, + assert_bound_childcare_attendance, + bind_childcare_attendance, + write_native_childcare_receipt, + ) + from microcosm.build.us_runtime.l0_refit_export import load_us_frame + from microcosm.frame import Frame + + base = inputs["base_h5"] + frame = load_us_frame(base) + person = frame.table("person") + for column, values in zip( + US_CHILDCARE_ATTENDANCE_COLUMNS, + ([22.0, 0.0, 13.0], [5.0, 0.0, 3.0], [8.0, 0.0, 4.0]), + strict=True, + ): + person[column] = values + frame = bind_childcare_attendance( + Frame( + {e: frame.table(e) for e in frame.entities}, + frame.schema, + {"household": frame.weights_for("household")}, + metadata={"nsece_childcare_attendance": {"synthetic_fixture": True}}, + ) + ) + with pd.HDFStore(base, "a") as store: + put_frame_table( + store, "person", person, preferred_format="table", data_columns=True + ) + write_native_childcare_receipt(base, frame.metadata) + inputs["base_sha256"] = annual._sha256(base) + annual.build_annual_static_aging(**inputs) + for year in (2024, 2025, 2026): + projected = load_us_frame(inputs["output_dir"] / f"populace_us_{year}.h5") + assert_bound_childcare_attendance(projected, require_stage=False) + assert ( + projected.metadata[ATTENDANCE_RECEIPT_KEY] + == frame.metadata[ATTENDANCE_RECEIPT_KEY] + ) + pd.testing.assert_frame_equal( + projected.table("person")[list(US_CHILDCARE_ATTENDANCE_COLUMNS)], + person[list(US_CHILDCARE_ATTENDANCE_COLUMNS)], + ) + # A changed schedule must fail before the annual file is finalized, even + # when the supplied receipt itself is valid for the original population. + from microcosm.frame.materialize import engine_tables + + tables = engine_tables(frame, weighted_entities=("household",)) + tables["person"] = tables["person"].copy() + tables["person"].loc[0, "childcare_days_per_week"] = 4 + invalid_output = inputs["output_dir"] / "invalid.h5" + with pytest.raises(ValueError, match="differ from the source receipt"): + annual._write_year(invalid_output, tables, 2027, frame_metadata=frame.metadata) + assert not invalid_output.exists() + + def test_base_h5_symlink_to_extensionless_cache_blob(inputs): base = inputs["base_h5"] blob = base.with_name("cached-blob-without-extension") diff --git a/packages/microcosm-build/tests/engine/us/test_us_childcare_attendance.py b/packages/microcosm-build/tests/engine/us/test_us_childcare_attendance.py new file mode 100644 index 000000000..5ad1f08cc --- /dev/null +++ b/packages/microcosm-build/tests/engine/us/test_us_childcare_attendance.py @@ -0,0 +1,26 @@ +"""Synthetic childcare contracts for the engine/us environment.""" + +# ruff: noqa: F403, F405 +from test_support.microcosm_build.us_childcare_attendance import * + + +def test_engine_accepts_child_inputs_and_derives_weekly_hours(): + from policyengine_us import Simulation + + result = _impute(_people(), weights=[0, 0, 1]) + year = 2026 + child = {"age": {year: 3}} + for column in US_CHILDCARE_ATTENDANCE_COLUMNS: + value = result.loc[0, column] + child[column] = {year: int(value) if column == MONTH else float(value)} + simulation = Simulation( + situation={ + "people": {"parent": {"age": {year: 30}}, "child": child}, + "households": {"household": {"members": ["parent", "child"]}}, + } + ) + assert simulation.calculate("childcare_hours_per_week", year).tolist() == [0, 40] + assert simulation.calculate(MONTH, year).tolist() == [0, 22] + # No mutation of the engine defaults by the dataset preparation function. + for column in US_CHILDCARE_ATTENDANCE_COLUMNS: + assert simulation.tax_benefit_system.variables[column].default_value == 0 diff --git a/packages/microcosm-build/tests/engine/us/test_us_multispine_pool_tool.py b/packages/microcosm-build/tests/engine/us/test_us_multispine_pool_tool.py index da909c4b4..0b587a790 100644 --- a/packages/microcosm-build/tests/engine/us/test_us_multispine_pool_tool.py +++ b/packages/microcosm-build/tests/engine/us/test_us_multispine_pool_tool.py @@ -338,7 +338,7 @@ def capture_equality(expected: object, actual: object) -> None: "country": "us", "schema_id": "country_spec", "schema_version": 1, - "spec_sha256": "1cf1f44d9a11458f59ea7d75dce68303816cab3e66668a6c6f6ecfe62d56f8dc", + "spec_sha256": "dde0912303e7ee8cfdcad306f0cdc0b92fbab047f99e01cf3ea8bba1aa855269", }, } diff --git a/packages/microcosm-build/tests/engine/us/test_us_nsece_childcare.py b/packages/microcosm-build/tests/engine/us/test_us_nsece_childcare.py new file mode 100644 index 000000000..f2c5415ce --- /dev/null +++ b/packages/microcosm-build/tests/engine/us/test_us_nsece_childcare.py @@ -0,0 +1,240 @@ +"""Synthetic childcare contracts for the engine/us environment.""" + +# ruff: noqa: F403, F405 +from test_support.microcosm_build.us_nsece_childcare import * + + +def test_real_engine_export_reload_preserves_child_attendance(tmp_path): + from policyengine_us import Microsimulation + from policyengine_us.data import USSingleYearDataset + + from microcosm.frame.adapters.policyengine_us import PolicyEngineUSEngine + + candidate = with_us_nsece_childcare_attendance( + _frame(), _source(), seed=915, match_columns=("age",) + ) + assert_childcare_attendance_exportable(candidate) + # Project canonical engine inputs; keep source provenance in the checkpoint. + tables = {e: candidate.table(e).copy() for e in candidate.entities} + tables["person"] = tables["person"].drop( + columns=[ + "person_source_id", + *(f"{c}_source" for c in US_CHILDCARE_ATTENDANCE_COLUMNS), + ] + ) + projected = Frame( + tables, + candidate.schema, + {"household": candidate.weights_for("household")}, + candidate.strata, + mass_log=candidate.mass_log, + metadata=candidate.metadata, + ) + path = tmp_path / "engine.h5" + PolicyEngineUSEngine().write_dataset(projected, path, period=2026) + dataset = USSingleYearDataset(file_path=str(path)) + assert dataset.person[MONTH].tolist() == [0, 22] + assert dataset.person[HOURS].tolist() == [0, 8] + sim = Microsimulation(dataset=dataset) + assert sim.calculate("childcare_hours_per_week", 2026).tolist() == [0, 40] + + +def test_native_export_explicitly_inherits_outside_baseline_and_preserves_parent( + tmp_path, +): + from policyengine_us.data import USSingleYearDataset + + from microcosm.build.us_runtime.childcare_attendance_stage import ( + export_native_childcare_candidate, + inherit_outside_domain_attendance_baseline, + ) + + frame = _frame(parent_observed=False) + tables = {e: frame.table(e).copy() for e in frame.entities} + tables["household"]["household_weight"] = frame.weights_for("household").values + parent = tmp_path / "parent.h5" + USSingleYearDataset(**tables, time_period=2026).save(str(parent)) + original = parent.read_bytes() + candidate = with_us_nsece_childcare_attendance( + frame, _source(), seed=915, match_columns=("age",) + ) + from microcosm.build.serialization_dtypes import canonicalize_frame_string_dtypes + + filled = inherit_outside_domain_attendance_baseline( + canonicalize_frame_string_dtypes( + candidate, boundary="test_childcare_native_export" + ) + ) + assert ( + filled.table("person").loc[0, f"{DAYS}_source"] + == "inherited_engine_baseline_outside_age_0_12" + ) + assert filled.table("person").loc[1, DAYS] == 5 + path = export_native_childcare_candidate(parent, filled, tmp_path / "candidate.h5") + result = USSingleYearDataset(file_path=str(path)) + assert result.person[DAYS].tolist() == [0, 5] + assert result.time_period == "2026" + assert parent.read_bytes() == original + + +@pytest.mark.parametrize("repair_factor", [1.0, 2.0]) +def test_registered_attendance_recipe_uses_real_transform_chain( + monkeypatch, tmp_path, repair_factor +): + import importlib.util + + from microcosm.build.us_runtime import childcare_attendance_stage as stage + + builder_path = REPOSITORY_ROOT / "tools" / "build_us_fiscal_refresh_release.py" + builder_spec = importlib.util.spec_from_file_location( + "attendance_fiscal_builder", builder_path + ) + builder = importlib.util.module_from_spec(builder_spec) + builder_spec.loader.exec_module(builder) + frame = _asec_frame() + frame.table("household")["household_source_id"] = "family" + for column in ( + *builder.US_SOCIAL_SECURITY_COMPONENT_TARGET_ROLES.values(), + "non_sch_d_capital_gains", + ): + frame.table("person")[column] = [1.0, 0.0] + hh, cal = _raw() + hh["HHC4_AGE_AT_USAGE_1"] = frame.table("person").loc[1, "age"] * 12 + hh["HH4_REGION"] = 1 + hh["HH4_PARWORK_STATUS"] = 2 + hh["HH4_ECON_INCOME_ANNUAL"] = 40000 + _care(cal, hours=3) + source = derive_nsece_childcare(hh, cal) + source.source_receipt["artifacts"] = stage.childcare_attendance_contract()[ + "artifacts" + ] + monkeypatch.setattr(stage, "load_nsece_childcare", lambda *args: source) + result = stage.with_us_childcare_attendance_inputs( + frame, + household_tsv="synthetic", + calendar_tsv="synthetic", + asec_source_cache=None, + seed=915, + inherit_outside_domain_baseline=True, + ) + assert result.table("person").loc[1, DAYS] == 1 + assert result.table("person").loc[1, HOURS] == 3 + assert ( + result.metadata["childcare_attendance_stage"]["stage"] + == "nsece_childcare_attendance" + ) + assert result.metadata["existing_receipt"] == "preserved" + np.testing.assert_array_equal( + result.weights_for("household").values, frame.weights_for("household").values + ) + assert_bound_childcare_attendance(result) + options = dict( + household_tsv="synthetic", + calendar_tsv="synthetic", + asec_source_cache=None, + seed=915, + inherit_outside_domain_baseline=True, + ) + assert stage.with_us_childcare_attendance_inputs(result, **options) is result + for changed in ({"seed": 916}, {"inherit_outside_domain_baseline": False}): + with pytest.raises(ValueError, match="settings changed"): + stage.with_us_childcare_attendance_inputs(result, **{**options, **changed}) + operations = result.metadata["childcare_attendance_stage"]["operations"] + assert [op["operation"] for op in operations] == [ + "calendar_attendance", + "fit_sibling_dependence", + "regular_hours_schedule_bridge", + "harmonize_asec_childcare_predictors", + "joint_weighted_schedule_transfer", + "inherit_engine_baseline", + ] + from policyengine_us.data import USSingleYearDataset + + from microcosm.build.us_runtime.l0_refit_export import load_us_frame + + tables = {e: result.table(e).copy() for e in result.entities} + tables["household"]["household_weight"] = result.weights_for("household").values + path = tmp_path / "final.h5" + USSingleYearDataset(**tables, time_period=2026).save(str(path)) + evidence = stage.persist_native_childcare_receipt(path, result) + assert evidence["retained_people"] == 2 + assert "rows" not in evidence + assert_bound_childcare_attendance(load_us_frame(path)) + + # Reusing a prepared native parent traverses these two repairs before the + # attendance stage. Both changed and unchanged repairs must retain lineage. + reused = builder._load_frame(path) + before = reused.table("person")[list(US_CHILDCARE_ATTENDANCE_COLUMNS)].copy() + ssa_targets = [ + SimpleNamespace(metadata={"target_role": role}, value=100.0 * repair_factor) + for role in builder.US_SOCIAL_SECURITY_COMPONENT_TARGET_ROLES + ] + cgd_target = SimpleNamespace( + name="irs_soi.ty2023.table_1_4.all.capital_gain_distributions_amount", + metadata={"aged_to": "2024"}, + value=100.0 * repair_factor, + ) + for repair, targets in ( + (builder._with_social_security_component_value_repair, ssa_targets), + (builder._with_non_sch_d_cgd_value_repair, [cgd_target]), + ): + reused, repair_receipt = repair(reused, targets) + assert repair_receipt["applied"] == (repair_factor != 1.0) + builder._require_bound_childcare_attendance(reused) + assert stage.with_us_childcare_attendance_inputs(reused, **options) is reused + repaired_path = tmp_path / "repaired.h5" + builder.PolicyEngineUSEngine().write_dataset(reused, repaired_path, period=2026) + stage.persist_native_childcare_receipt(repaired_path, reused) + reloaded = load_us_frame(repaired_path) + assert_bound_childcare_attendance(reloaded) + assert_frame_equal( + reloaded.table("person")[list(US_CHILDCARE_ATTENDANCE_COLUMNS)], before + ) + + +def test_native_reload_preserves_binding_and_detects_tampering(tmp_path): + from policyengine_us.data import USSingleYearDataset + + from microcosm.build.us_runtime.h5_io import load_legacy_calibrated_us_h5 + from microcosm.build.us_runtime.l0_refit_export import load_us_frame + + candidate = _candidate() + tables = {e: candidate.table(e).copy() for e in candidate.entities} + tables["household"]["household_weight"] = candidate.weights_for("household").values + # Native exports intentionally omit per-cell provenance columns. + tables["person"] = tables["person"].drop( + columns=[f"{c}_source" for c in US_CHILDCARE_ATTENDANCE_COLUMNS] + ) + path = tmp_path / "native.h5" + USSingleYearDataset(**tables, time_period=2026).save(str(path)) + for loader in (load_legacy_calibrated_us_h5, load_us_frame): + with pytest.raises(ValueError, match="lack a bound receipt"): + loader(path) + stage._write_childcare_candidate_person_table( + path, tables["person"], candidate.metadata + ) + for loader in (load_legacy_calibrated_us_h5, load_us_frame): + loaded = loader(path) + assert_bound_childcare_attendance(loaded, require_stage=False) + tables["person"].loc[1, DAYS] = 4 + stage._write_childcare_candidate_person_table( + path, tables["person"], candidate.metadata + ) + with pytest.raises(ValueError, match="differ from the source receipt"): + restore_native_childcare_receipt( + path, _replace(candidate, people=tables["person"], metadata={}) + ) + + +def test_production_stage_refuses_unbound_existing_values(monkeypatch): + monkeypatch.setattr(stage, "load_nsece_childcare", lambda *args: _source()) + frame = _asec_frame() + frame.table("person").loc[1, DAYS] = 5 + with pytest.raises(ValueError, match="Pre-existing child attendance"): + stage.with_us_childcare_attendance_inputs( + frame, + household_tsv="fake", + calendar_tsv="fake", + asec_source_cache=None, + seed=915, + ) diff --git a/packages/microcosm-build/tests/engine_free/shared/test_frame_serializer_registry.py b/packages/microcosm-build/tests/engine_free/shared/test_frame_serializer_registry.py index 18b7e5656..04b835696 100644 --- a/packages/microcosm-build/tests/engine_free/shared/test_frame_serializer_registry.py +++ b/packages/microcosm-build/tests/engine_free/shared/test_frame_serializer_registry.py @@ -12,10 +12,10 @@ def test_registry_classifies_every_writable_production_hdf_site() -> None: assert _discover_writable_hdf_sites() == classified -def test_registry_has_exactly_ten_unique_frame_table_serializers() -> None: - assert len(FRAME_TABLE_SERIALIZERS) == 10 - assert len({spec.serializer_id for spec in FRAME_TABLE_SERIALIZERS}) == 10 - assert len({spec.writer.key for spec in FRAME_TABLE_SERIALIZERS}) == 10 +def test_registry_has_exactly_eleven_unique_frame_table_serializers() -> None: + assert len(FRAME_TABLE_SERIALIZERS) == 11 + assert len({spec.serializer_id for spec in FRAME_TABLE_SERIALIZERS}) == 11 + assert len({spec.writer.key for spec in FRAME_TABLE_SERIALIZERS}) == 11 def test_round_trip_adapter_registry_exactly_matches_serializer_registry() -> None: diff --git a/packages/microcosm-build/tests/engine_free/shared/test_spec_engine_field_usage.py b/packages/microcosm-build/tests/engine_free/shared/test_spec_engine_field_usage.py index c5ec18bb5..99181a239 100644 --- a/packages/microcosm-build/tests/engine_free/shared/test_spec_engine_field_usage.py +++ b/packages/microcosm-build/tests/engine_free/shared/test_spec_engine_field_usage.py @@ -17,6 +17,7 @@ Generation0Effect, UsageMode, build_field_usage_ledger, + configuration_sources, default_usage_claims, ) from microcosm.build.spec_engine.legacy_adapter import ( @@ -95,22 +96,22 @@ def _mutated_bundle( def test_exact_complete_ledger_has_one_primary_mode_per_pointer(field_ledger) -> None: - assert len(field_ledger.fields) == EXPECTED_CONFIGURATION_FIELD_COUNT == 42_184 + assert len(field_ledger.fields) == EXPECTED_CONFIGURATION_FIELD_COUNT == 42_187 assert field_ledger.source_counts == { - "authored": 32_404, + "authored": 32_407, "resolved_bindings": 9_780, } assert field_ledger.mode_counts == { "legacy_behavior": 14_010, "compiler_semantic": 27_717, - "front_end_validation": 354, + "front_end_validation": 357, "identity_only": 103, } assert field_ledger.generation0_effect_counts == { "legacy_behavior": 38_498, - "no_generation0_effect": 3_686, + "no_generation0_effect": 3_689, } - assert len({field.pointer for field in field_ledger.fields}) == 42_184 + assert len({field.pointer for field in field_ledger.fields}) == 42_187 def test_eligibility_concepts_are_validation_not_generation0_behavior( @@ -436,3 +437,26 @@ def mutate(document: dict[str, object]) -> None: ).field("/authored/spec~1sources.yaml/sources/7/sha256") assert field.claim_id == "source_geography_identity" assert field.mode is UsageMode.LEGACY_BEHAVIOR + + +def test_nsece_source_descriptor_has_explicit_manifest_validation_claim( + resolved_us, field_ledger +): + manifest = configuration_sources(resolved_us)["authored"]["country_package.json"] + index, descriptor = next( + (index, descriptor) + for index, descriptor in enumerate(manifest["resources"]) + if descriptor["path"] == "childcare_attendance_source.json" + ) + assert descriptor == { + "path": "childcare_attendance_source.json", + "kind": "legacy_json", + "schema_id": "legacy_json", + } + for name in descriptor: + field = field_ledger.field( + f"/authored/country_package.json/resources/{index}/{name}" + ) + assert field.claim_id == "country_manifest" + assert field.mode is UsageMode.FRONT_END_VALIDATION + assert field.generation0_effect is Generation0Effect.NO_GENERATION0_EFFECT diff --git a/packages/microcosm-build/tests/engine_free/us/test_us_childcare_attendance.py b/packages/microcosm-build/tests/engine_free/us/test_us_childcare_attendance.py new file mode 100644 index 000000000..d654ab201 --- /dev/null +++ b/packages/microcosm-build/tests/engine_free/us/test_us_childcare_attendance.py @@ -0,0 +1,164 @@ +"""Synthetic childcare contracts for the engine_free/us environment.""" + +# ruff: noqa: F403, F405 +from test_support.microcosm_build.us_childcare_attendance import * + + +def test_joint_draw_respects_survey_weights_and_includes_nonparticipants(): + result = _impute(_people(1000), weights=[1, 0, 4]) + # Independent population behavior: 80% care, with sampling tolerance. + assert 0.75 < (result[DAYS] > 0).mean() < 0.85 + assert set(result[HOURS]) == {0, 8} + assert set(zip(result[MONTH], result[DAYS], result[HOURS], strict=True)) == { + (0, 0, 0), + (22, 5, 8), + } + assert str(result[MONTH].dtype) == "Int64" + + +def test_observed_zero_and_partial_positive_are_constraints_not_missing(): + person = _people(2).assign(**{DAYS: [0.0, 3.0]}) + original = person.copy(deep=True) + result = _impute(person) + assert result[MONTH].tolist() == [0, 13] + assert result[HOURS].tolist() == [0, 4] + assert result[f"{DAYS}_source"].tolist() == ["observed", "observed"] + assert_frame_equal(person, original) + assert_frame_equal(result, _impute(result)) + + +def test_expense_and_parental_work_are_not_participation_flags(): + people = _people(2).assign( + spm_unit_pre_subsidy_childcare_expenses=[0, 5000], + parent_hours_worked=[0, 40], + ) + cared_for = _impute(people, weights=[0, 0, 1]) + assert (cared_for[DAYS] == 5).all() + nonparticipants = _impute(people, weights=[1, 0, 0]) + assert (nonparticipants[DAYS] == 0).all() + + +def test_age_domain_and_person_level_values_leave_adults_and_older_children_null(): + people = _people(4).assign(age=[3, 35, 13, 16]) + people.loc[3, [MONTH, DAYS, HOURS]] = [13, 3, 4] + result = _impute(people, weights=[0, 1, 0]) + assert result.loc[0, DAYS] == 3 + assert result.loc[[1, 2], list(US_CHILDCARE_ATTENDANCE_COLUMNS)].isna().all().all() + assert result.loc[3, DAYS] == 3 # preserve observed older-child care + + +def test_clone_fanout_and_order_and_chunk_invariance(): + people = _people(8) + clones = people.iloc[:3].copy() + people = pd.concat([people, clones], ignore_index=True) + people["person_id"] = np.arange(len(people)) + donor = _donors() + expected = _impute(people, donor, weights=[1, 2, 3]) + shuffled = _impute( + people.sample(frac=1, random_state=12), + donor.iloc[::-1], + weights=[3, 2, 1], + ).sort_index() + assert_frame_equal(expected, shuffled) + for column in US_CHILDCARE_ATTENDANCE_COLUMNS: + assert (expected.groupby("person_source_id")[column].nunique() == 1).all() + # Keep all clones of a source person in the same chunk. + chunks = [ + people[people.person_source_id < "c:4"], + people[people.person_source_id >= "c:4"], + ] + actual = pd.concat( + [_impute(chunk, weights=[1, 2, 3]) for chunk in chunks] + ).sort_index() + assert_frame_equal(expected, actual) + + +def test_observations_on_one_clone_constrain_all_clones(): + people = pd.concat([_people(), _people()], ignore_index=True) + people.loc[1, DAYS] = 3 + result = _impute(people) + assert result[DAYS].tolist() == [3, 3] + assert result[HOURS].tolist() == [4, 4] + assert result.loc[1, f"{DAYS}_source"] == "observed" + + +def test_complete_clone_observations_need_no_donor_support(): + people = pd.concat([_people(), _people()], ignore_index=True) + people.loc[1, [MONTH, DAYS, HOURS]] = [17, 4, 6] + result = _impute(people) + assert result[MONTH].tolist() == [17, 17] + assert result.loc[0, f"{MONTH}_source"] == "source_person:c:0" + + +@pytest.mark.parametrize("column,value", [(DAYS, 5), ("age", 4)]) +def test_conflicting_clone_records_raise(column, value): + people = pd.concat([_people(), _people()], ignore_index=True).assign(**{DAYS: 3}) + people.loc[1, column] = value + with pytest.raises(ValueError, match="clone .* disagree"): + _impute(people) + + +def test_no_compatible_support_raises_without_overwriting_observed_values(): + person = _people().assign(**{DAYS: 4}) + with pytest.raises(ValueError, match="No compatible positive-weight"): + _impute(person) + assert person[DAYS].tolist() == [4] + + +def test_exact_covariate_matching_does_not_relax_to_another_group(): + people = _people().assign(parent_activity="working") + donor = _donors().assign(parent_activity=["not_working", "working", "not_working"]) + result = _impute(people, donor, match_columns=("age", "parent_activity")) + assert result[DAYS].tolist() == [3] + with pytest.raises(ValueError, match="No compatible positive-weight"): + _impute( + people, donor, weights=[1, 0, 1], match_columns=("age", "parent_activity") + ) + + +@pytest.mark.parametrize( + "column,value,message", + [ + (DAYS, -1, "nonnegative"), + (DAYS, 8, "calendar bounds"), + (HOURS, 25, "calendar bounds"), + (HOURS, np.inf, "finite"), + (MONTH, 13.5, "integral"), + (DAYS, np.nan, "complete"), + (HOURS, 0, "nonattendance"), + ("age", 13, "aged 0–12"), + ("age", np.nan, "whole-year ages"), + ], +) +def test_invalid_donor_records_raise(column, value, message): + donor = _donors() + donor[column] = donor[column].astype(float) + donor.loc[1, column] = value + with pytest.raises(ValueError, match=message): + _impute(_people(), donor) + + +def test_missing_matching_fields_and_duplicate_donor_ids_raise(): + with pytest.raises(ValueError, match="matching fields must be complete"): + _impute( + _people().assign(region=pd.NA), + _donors().assign(region="NE"), + match_columns=("age", "region"), + ) + donor = _donors() + donor.loc[1, "donor_id"] = "none" + with pytest.raises(ValueError, match="donors cannot contain clones"): + _impute(_people(), donor) + + +def test_weights_must_be_typed_and_aligned(): + with pytest.raises(ValueError, match="align"): + _impute(_people(), weights=[1, 1]) + with pytest.raises(TypeError, match="typed survey Weights"): + impute_us_childcare_attendance( + _people(), + _donors(), + donor_weights=np.ones(3), + match_columns=("age",), + seed=1, + ) diff --git a/packages/microcosm-build/tests/engine_free/us/test_us_childcare_pooling.py b/packages/microcosm-build/tests/engine_free/us/test_us_childcare_pooling.py new file mode 100644 index 000000000..4e73d8a0d --- /dev/null +++ b/packages/microcosm-build/tests/engine_free/us/test_us_childcare_pooling.py @@ -0,0 +1,308 @@ +"""Synthetic pooling/evaluation contracts; never load licensed survey records.""" + +import hashlib +import json + +import numpy as np +import pandas as pd +import pytest +from pandas.testing import assert_frame_equal + +from microcosm.build.us_runtime.childcare_attendance import ( + US_CHILDCARE_ATTENDANCE_COLUMNS, +) +from microcosm.build.us_runtime.nsece_childcare import NSECEChildcareSource +from microcosm.build.us_runtime.nsece_childcare_pooling import ( + COMPOSITION_CHILDCARE_LEVELS, + POOLED_CHILDCARE_LEVELS, + POOLED_CHILDCARE_MATCH_COLUMNS, + PooledScheduleDonors, + fit_pooled_sibling_dependence, + with_childcare_household_size, +) +from microcosm.build.us_runtime.nsece_childcare_sibling_validation import ( + assess_sibling_schedules, +) +from microcosm.frame import WeightKind, Weights + +MONTH, DAYS, HOURS = US_CHILDCARE_ATTENDANCE_COLUMNS + + +def _children(households=40): + records = [] + for household in range(households): + for child in range(3): + known = child != 2 or household % 4 != 0 + days = 5.0 if household % 2 else 0.0 + records.append( + { + "donor_id": f"h{household}:c{child}", + "source_household_id": f"h{household}", + "age": 3, + "region": household % 3 + 1, + "parent_work_status": 2, + "income_band": 1, + "attendance_status": "complete" if known else "partial_calendar", + "household_weight": 2.0, + "child_weight": 2.0, + MONTH: (22.0 if days else 0.0) if known else np.nan, + DAYS: days if known else np.nan, + HOURS: (8.0 if days else 0.0) if known else np.nan, + } + ) + return with_childcare_household_size(pd.DataFrame(records)) + + +def test_pooling_levels_have_one_definition_and_retain_age(): + assert POOLED_CHILDCARE_LEVELS[-1] == POOLED_CHILDCARE_MATCH_COLUMNS + assert POOLED_CHILDCARE_LEVELS[0] == ("age",) + for smaller, larger in zip( + POOLED_CHILDCARE_LEVELS, POOLED_CHILDCARE_LEVELS[1:], strict=False + ): + assert smaller == larger[:-1] + + +def test_sparse_cell_blends_distributions_with_household_cluster_support(): + rows = _children().iloc[[0, 1, 3]].copy() + rows["region"] = [1, 1, 2] + # Two zero-care child donors come from one household, so local effective + # support is ONE, not two. The positive root donor has one third of mass. + values, cumulative, probability = PooledScheduleDonors(rows).distribution( + rows.iloc[0] + ) + assert np.average(values[:, 0], weights=probability) == pytest.approx(10 / 33) + assert probability.sum() == pytest.approx(1) + assert cumulative[-1] == 1 + assert (probability > 0).all() + + +def test_entire_household_is_excluded_even_after_unexcluded_cache_lookup(): + rows = _children().iloc[[0, 1, 3]].copy() + model = PooledScheduleDonors(rows) + model.distribution(rows.iloc[0]) + values, _, weights = model.distribution(rows.iloc[0], exclude_household="h0") + assert values.tolist() == [[1, 5, 40]] + assert weights.tolist() == [1] + rows.loc[rows.source_household_id.eq("h1"), "age"] = 4 + with pytest.raises(ValueError, match="exact-age"): + PooledScheduleDonors(rows).distribution(rows.iloc[0], exclude_household="h0") + + +def test_pooling_is_row_order_and_weight_scale_invariant_and_keeps_joint_schedules(): + children = _children() + before = children.copy(deep=True) + target = children.iloc[0].copy() + target["region"] = 9 # No exact region; use the broader empirical mixture. + original = PooledScheduleDonors(children).distribution(target) + changed = children.iloc[::-1].copy() + changed["child_weight"] *= 1000 + reordered = PooledScheduleDonors(changed).distribution(target) + for a, b in zip(original, reordered, strict=True): + np.testing.assert_allclose(a, b) + assert set(map(tuple, original[0])) == {(0, 0, 0), (1, 5, 40)} + assert_frame_equal(children, before) + + +def test_roster_count_includes_unknown_attendance_but_not_older_children(): + children = _children(2).drop(columns="childcare_household_size") + children.loc[5, "age"] = 13 + counted = with_childcare_household_size(children) + assert counted.childcare_household_size.tolist() == [3, 3, 3, 2, 2, 2] + assert children.loc[2, "attendance_status"] == "partial_calendar" + assert "childcare_household_size" not in children + + +def test_composition_counts_full_roster_and_never_reads_attendance(): + rows = _children(1) + rows["age"] = [1, 4, 9] + rows.loc[2, "attendance_status"] = "partial_calendar" + counted = with_childcare_household_size(rows) + assert counted.childcare_under6_count.tolist() == [2, 2, 2] + assert counted.childcare_schoolage_count.tolist() == [1, 1, 1] + assert counted.childcare_youngest_age_band.tolist() == [0, 0, 0] + assert counted.childcare_has_younger_sibling.tolist() == [0, 1, 1] + rows["attendance_status"] = "missing_calendar" + changed = with_childcare_household_size(rows) + columns = COMPOSITION_CHILDCARE_LEVELS[-1] + assert_frame_equal(counted[list(columns)], changed[list(columns)]) + + +def test_composition_distributions_exclude_the_whole_household_and_retain_age(): + rows = _children() + model = PooledScheduleDonors(rows, composition=True) + values, _, weights = model.distribution(rows.iloc[0], exclude_household="h0") + assert model.levels == COMPOSITION_CHILDCARE_LEVELS + assert len(values) == len(model.pool.loc[model.pool.source_household_id.ne("h0")]) + assert weights.sum() == pytest.approx(1) + assert set(map(tuple, values)) == {(0, 0, 0), (1, 5, 40)} + + +def test_dependence_uses_observed_pairs_in_incomplete_households(monkeypatch): + original = PooledScheduleDonors.distribution + exclusions = [] + + def checked(self, child, *, exclude_household=None): + assert exclude_household == child.source_household_id + exclusions.append(exclude_household) + return original(self, child, exclude_household=exclude_household) + + monkeypatch.setattr(PooledScheduleDonors, "distribution", checked) + fit = fit_pooled_sibling_dependence(_children()) + assert fit["households"] == 40 + assert fit["households_with_unresolved_siblings"] == 10 + assert fit["observed_pairs"] == 100 + assert len(exclusions) == 110 + assert 0 <= fit["rho"] <= 1 + + +def test_outer_folds_refit_without_heldout_households_and_score_all_observed_children( + monkeypatch, +): + import microcosm.build.us_runtime.nsece_childcare_pooling as module + + children = _children() + source = NSECEChildcareSource( + children, Weights(children.child_weight.to_numpy(), WeightKind.DESIGN), {} + ) + original = module.fit_pooled_sibling_dependence + fold = 0 + + def checked(training, **kwargs): + nonlocal fold + heldout = { + household + for household in children.source_household_id.unique() + if int.from_bytes( + hashlib.sha256(f"271828:{household}".encode()).digest()[:8], "big" + ) + % 5 + == fold + } + assert set(training.source_household_id).isdisjoint(heldout) + fold += 1 + return original(training, **kwargs) + + monkeypatch.setattr(module, "fit_pooled_sibling_dependence", checked) + report = assess_sibling_schedules( + source, pooled=True, include_observed_children=True + ) + # An observed-zero subgroup has undefined relative-error screens. These + # must remain failed, JSON-serializable results, not numpy boolean objects. + json.dumps(report, allow_nan=False) + assert fold == 5 + groups = { + row["group"]: row for row in report["observed_child_validation"]["comparisons"] + } + assert groups["all"]["children"] == 110 + assert groups["unresolved_siblings"]["children"] == 20 + assert report["larger_households"]["households"] == 30 + assert report["all_observed_sibling_pairs"]["households"] == 40 + assert report["all_observed_sibling_pairs"]["observed_pairs"] == 100 + assert all(part["household_overlap"] == 0 for part in report["splits"]) + + +@pytest.mark.parametrize("strength", [0, -1, np.inf, np.nan]) +def test_invalid_pooling_strength_is_rejected(strength): + with pytest.raises(ValueError, match="strength"): + PooledScheduleDonors(_children(), strength=strength) + + +def test_reconstructed_calendars_never_enter_the_experimental_truth_pool(): + children = _children() + children.loc[0, "attendance_status"] = "summary_bridge" + with pytest.raises(ValueError, match="original calendars"): + PooledScheduleDonors(children) + + +def test_population_moment_objective_matches_its_analytic_coefficient(): + children = _children() + fitted = fit_pooled_sibling_dependence(children, objective="population_moments") + residual = np.array(fitted["normalized_mean_residual"]) + increment = np.array(fitted["normalized_mean_shared_increment"]) + optimum = residual @ increment / (increment @ increment) + assert fitted["unconstrained_rho"] == pytest.approx(optimum) + assert fitted["rho"] == pytest.approx(np.clip(optimum, 0, 1)) + # A population coefficient is one joint scalar, not a different rho picked + # for each outcome to force all the evaluation moments to match. + for alternative in ( + 0, + 1, + max(0, fitted["rho"] - 0.05), + min(1, fitted["rho"] + 0.05), + ): + chosen_loss = np.sum((residual - fitted["rho"] * increment) ** 2) + other_loss = np.sum((residual - alternative * increment) ** 2) + assert chosen_loss <= other_loss + 1e-12 + + +def test_dependence_objective_does_not_change_child_donor_distributions(): + children = _children() + before = children.copy(deep=True) + model = PooledScheduleDonors(children) + values = model.distribution(children.iloc[0]) + fit_pooled_sibling_dependence(children, objective="population_moments") + fit_pooled_sibling_dependence(children, objective="pair_squared_error") + for original, after in zip( + values, model.distribution(children.iloc[0]), strict=True + ): + np.testing.assert_array_equal(original, after) + assert_frame_equal(children, before) + + +def test_unknown_dependence_objective_is_rejected(): + with pytest.raises(ValueError, match="objective"): + fit_pooled_sibling_dependence(_children(), objective="unknown") + + +@pytest.mark.parametrize("observed_product,overlap", [(1.0, False), (3.0, True)]) +def test_dependence_screen_compatibility_uses_fixed_marginal_identity( + observed_product, overlap +): + from microcosm.build.us_runtime.nsece_childcare_sibling_validation import ( + coupling_screen_compatibility, + sibling_schedule_screen, + ) + + # Fixed E[X]E[Y]=1 and SD[X]SD[Y]=4: corr=(E[XY]-1)/4. + group = { + "observed": { + m: {"joint_product": observed_product, "correlation": 0.5} + for m in ("days", "weekly_hours") + }, + "independent": { + m: {"joint_product": 1.0, "correlation": 0.0} + for m in ("days", "weekly_hours") + }, + "coupled": { + m: {"joint_product": 3.0, "correlation": 0.5} + for m in ("days", "weekly_hours") + }, + } + evaluated = {"youngest_pairs": group, "larger_households": {}} + evaluated["diagnostic_screen"] = sibling_schedule_screen(evaluated) + report = coupling_screen_compatibility(evaluated) + result = report["comparisons"][0] + assert result["predicted_product_of_marginal_standard_deviations"] == 4 + assert result["joint_product_required_by_correlation_screen"] == pytest.approx( + [2.6, 3.4] + ) + assert result["screen_intervals_overlap"] == overlap + assert not report["comparisons"][-1]["identified"] + + +@pytest.mark.parametrize("age", [np.nan, np.inf, -1, 3.5]) +def test_unknown_or_invalid_roster_age_cannot_reduce_household_size(age): + children = _children() + children["age"] = children.age.astype(float) + children.loc[0, "age"] = age + with pytest.raises(ValueError, match="whole-year ages"): + with_childcare_household_size(children) + + +@pytest.mark.parametrize("field", ["region", "child_weight"]) +def test_nonfinite_donor_inputs_are_rejected(field): + children = _children() + children[field] = children[field].astype(float) + children.loc[0, field] = np.inf + with pytest.raises(ValueError, match="finite"): + PooledScheduleDonors(children) diff --git a/packages/microcosm-build/tests/engine_free/us/test_us_childcare_qrf.py b/packages/microcosm-build/tests/engine_free/us/test_us_childcare_qrf.py new file mode 100644 index 000000000..8517bbace --- /dev/null +++ b/packages/microcosm-build/tests/engine_free/us/test_us_childcare_qrf.py @@ -0,0 +1,198 @@ +"""Synthetic contracts for the experimental canonical-QRF schedule decoder.""" + +import numpy as np +import pandas as pd +import pytest + +from microcosm.build.us_runtime import nsece_childcare_qrf as module +from microcosm.build.us_runtime.childcare_attendance import ( + US_CHILDCARE_ATTENDANCE_COLUMNS, +) +from microcosm.build.us_runtime.nsece_childcare_pooling import ( + with_childcare_household_size, +) + +MONTH, DAYS, HOURS = US_CHILDCARE_ATTENDANCE_COLUMNS + + +def _rows(): + rows = pd.DataFrame( + { + "donor_id": ["a", "b", "c", "d"], + "source_household_id": ["a", "b", "c", "d"], + "age": [3, 3, 3, 4], + "region": 1, + "parent_work_status": 2, + "income_band": 1, + "household_income": 40000, + "household_members": 3, + "resident_parent_count": 2, + "attendance_status": "complete", + "child_weight": [1.0, 2.0, 3.0, 4.0], + MONTH: [0.0, 4.0, 9.0, 22.0], + DAYS: [0.0, 1.0, 2.0, 5.0], + HOURS: [0.0, 1.0, 2.0, 10.0], + } + ) + return with_childcare_household_size(rows) + + +class _FakeFit: + def predict_from_uniforms(self, rows, *, quantiles, sign_uniforms): + key = module.QRF_CHILDCARE_SCHEDULE_CODE + assert set(quantiles) == set(sign_uniforms) == {key} + return pd.DataFrame({key: np.resize([0.0, 39.0, 100.0], len(rows))}) + + +def test_decoder_retains_exact_age_joint_pairs_and_lower_ties(monkeypatch): + captured = [] + + def fit(rows, predictors, targets, **kwargs): + captured.append((rows.copy(), predictors, targets, kwargs)) + return _FakeFit() + + monkeypatch.setattr(module, "fit", fit) + model = module.QRFChildcareSchedules(_rows()) + target = _rows().iloc[[0]].assign(source_household_id="new") + model.prepare(target) + values, cumulative, weights = model.distribution(target.iloc[0]) + assert set(map(tuple, values)) == { + (0.0, 0.0, 0.0), + (1.0, 1.0, 1.0), + (1.0, 2.0, 4.0), + } + assert cumulative[-1] == 1 + assert weights.sum() == pytest.approx(1) + assert captured[0][3] == { + "weights": "child_weight", + "seed": 915, + "n_estimators": 100, + } + assert captured[0][1] == list(module.QRF_CHILDCARE_PREDICTORS) + + +def test_qrf_cannot_score_its_own_training_households(monkeypatch): + monkeypatch.setattr(module, "fit", lambda *a, **k: _FakeFit()) + rows = _rows() + model = module.QRFChildcareSchedules(rows) + with pytest.raises(ValueError, match="overlap"): + model.prepare(rows) + with pytest.raises(ValueError, match="overlap"): + model.distribution(rows.iloc[0]) + with pytest.raises(ValueError, match="exact-age"): + model.prepare(rows.iloc[[0]].assign(source_household_id="new", age=9)) + + +def test_qrf_excludes_unknown_calendars_and_rejects_reconstructed_truth(monkeypatch): + captured = [] + + def fit(rows, *args, **kwargs): + captured.append(rows.copy()) + return _FakeFit() + + monkeypatch.setattr(module, "fit", fit) + rows = _rows() + rows.loc[1, "attendance_status"] = "partial_calendar" + rows.loc[1, [MONTH, DAYS, HOURS]] = np.nan + module.QRFChildcareSchedules(rows) + assert captured[0].donor_id.tolist() == ["a", "c", "d"] + rows.loc[1, "attendance_status"] = "summary_bridge" + with pytest.raises(ValueError, match="original measured"): + module.QRFChildcareSchedules(rows) + + +def test_real_canonical_model_gives_valid_row_order_invariant_schedules(): + model = module.QRFChildcareSchedules(_rows(), n_estimators=4) + targets = _rows().iloc[[0, 3]].assign(source_household_id=["new1", "new2"]) + model.prepare(targets) + first = model.distribution(targets.iloc[0]) + model.prepare(targets.iloc[::-1]) + second = model.distribution(targets.iloc[0]) + for a, b in zip(first, second, strict=True): + np.testing.assert_array_equal(a, b) + assert set(map(tuple, first[0])).issubset( + {(0.0, 0.0, 0.0), (1.0, 1.0, 1.0), (1.0, 2.0, 4.0)} + ) + + +def _interval_fixture(): + rows = _rows().assign(questionnaire_version=1) + rows["calendar_ece_days_lower"] = rows[DAYS] + rows["calendar_ece_days_upper"] = rows[DAYS] + rows["calendar_ece_hours_lower"] = rows[DAYS] * rows[HOURS] + rows["calendar_ece_hours_upper"] = rows[DAYS] * rows[HOURS] + missing = ( + rows.iloc[[0]] + .copy() + .assign( + donor_id="u", + source_household_id="u", + attendance_status="partial_calendar", + child_weight=8.0, + calendar_ece_days_lower=1, + calendar_ece_days_upper=2, + calendar_ece_hours_lower=4.0, + calendar_ece_hours_upper=5.0, + ) + ) + missing[[MONTH, DAYS, HOURS]] = np.nan + return pd.concat([rows, missing], ignore_index=True) + + +def test_interval_completion_preserves_bounds_weights_and_measured_rows(monkeypatch): + monkeypatch.setattr(module, "fit", lambda *a, **k: _FakeFit()) + rows = _interval_fixture() + model = module.QRFChildcareSchedules(rows) + for tilt in (-1, 0, 1): + result, audit = module.interval_training_rows(rows, model, tilt=tilt) + pd.testing.assert_frame_equal(result.iloc[:4][rows.columns], rows.iloc[:4]) + modeled = result.loc[result.attendance_status.eq("interval_model")] + assert len(modeled) == module.QRF_INTERVAL_DRAWS + assert modeled.child_weight.sum() == 8 + assert (modeled[DAYS] == 2).all() + assert (modeled[HOURS] == 2).all() + assert audit["completed_training_children"] == 1 + assert audit["design_weight_conserved"] + with pytest.raises(ValueError, match="opt-in"): + module.QRFChildcareSchedules(result) + module.QRFChildcareSchedules(result, allow_interval_training=True) + + +def test_interval_completion_reports_unsupported_intervals_without_clipping( + monkeypatch, +): + monkeypatch.setattr(module, "fit", lambda *a, **k: _FakeFit()) + rows = _interval_fixture() + rows.loc[4, ["calendar_ece_hours_lower", "calendar_ece_hours_upper"]] = [100, 101] + model = module.QRFChildcareSchedules(rows) + result, audit = module.interval_training_rows(rows, model) + pd.testing.assert_frame_equal(result, rows) + assert audit["unsupported_training_children"] == 1 + assert audit["unsupported_child_weight"] == 8 + + +def test_interval_completion_cannot_import_heldout_households(monkeypatch): + monkeypatch.setattr(module, "fit", lambda *a, **k: _FakeFit()) + rows = _interval_fixture() + model = module.QRFChildcareSchedules(rows) + heldout = rows.copy() + heldout.loc[4, "source_household_id"] = "heldout" + with pytest.raises(ValueError, match="outside training"): + module.interval_training_rows(heldout, model) + heldout.loc[4, "donor_id"] = "heldout-child" + with pytest.raises(ValueError, match="outside training"): + module.interval_training_rows(heldout, model) + + +def test_interval_completion_rejects_invalid_bounds_and_false_observations(monkeypatch): + monkeypatch.setattr(module, "fit", lambda *a, **k: _FakeFit()) + rows = _interval_fixture() + model = module.QRFChildcareSchedules(rows) + bad = rows.copy() + bad.loc[4, "calendar_ece_hours_upper"] = np.nan + with pytest.raises(ValueError, match="finite and ordered"): + module.interval_training_rows(bad, model) + result, _ = module.interval_training_rows(rows, model) + result.loc[result.attendance_status.eq("interval_model"), HOURS] = 20 + with pytest.raises(ValueError, match="violates measured bounds"): + module.QRFChildcareSchedules(result, allow_interval_training=True) diff --git a/packages/microcosm-build/tests/engine_free/us/test_us_exact_k_ladder_launcher.py b/packages/microcosm-build/tests/engine_free/us/test_us_exact_k_ladder_launcher.py index 484e548f5..5d0616fed 100644 --- a/packages/microcosm-build/tests/engine_free/us/test_us_exact_k_ladder_launcher.py +++ b/packages/microcosm-build/tests/engine_free/us/test_us_exact_k_ladder_launcher.py @@ -226,8 +226,10 @@ def test_incumbent_and_target_surface_pins_fail_closed( ) +@pytest.mark.parametrize("inherit_baseline", [None, False, True]) def test_launcher_arguments_are_accepted_by_the_house_builder_parser( tmp_path: Path, + inherit_baseline: bool | None, ) -> None: launcher = _launcher_module() payload = _config_payload( @@ -236,6 +238,13 @@ def test_launcher_arguments_are_accepted_by_the_house_builder_parser( ) payload["targets"]["ssi_take_up_prior_weight_basis"] = "ssi.json" payload["targets"]["ssi_take_up_prior_weight_basis_sha256"] = "1" * 64 + if inherit_baseline is not None: + payload["childcare_attendance"] = { + "household_tsv": "household.tsv", + "calendar_tsv": str(tmp_path / "calendar.tsv"), + "asec_source_cache": "asec", + "inherit_outside_domain_baseline": inherit_baseline, + } config = launcher._read_config(_write_config(tmp_path, payload)) argv = launcher._builder_argv( @@ -253,6 +262,124 @@ def test_launcher_arguments_are_accepted_by_the_house_builder_parser( assert parsed.no_staging is True assert parsed.ssi_take_up_prior_weight_basis == tmp_path / "ssi.json" assert parsed.ssi_take_up_prior_weight_basis_sha256 == "1" * 64 + if inherit_baseline is None: + assert parsed.childcare_attendance_household_tsv is None + assert parsed.childcare_attendance_calendar_tsv is None + assert parsed.childcare_attendance_asec_cache is None + assert parsed.childcare_attendance_inherit_outside_domain_baseline is False + else: + assert parsed.childcare_attendance_household_tsv == tmp_path / "household.tsv" + assert parsed.childcare_attendance_calendar_tsv == tmp_path / "calendar.tsv" + assert parsed.childcare_attendance_asec_cache == tmp_path / "asec" + assert ( + parsed.childcare_attendance_inherit_outside_domain_baseline + is inherit_baseline + ) + + +@pytest.mark.parametrize( + "source", + [ + None, + {}, + {"household_tsv": "household.tsv"}, + {"calendar_tsv": "calendar.tsv"}, + { + "household_tsv": "h", + "calendar_tsv": "c", + "inherit_outside_domain_baseline": "false", + }, + { + "household_tsv": "h", + "calendar_tsv": "c", + "inherit_outside_domain_baseline": 1, + }, + { + "household_tsv": "h", + "calendar_tsv": "c", + "inherit_outside_domain_baseline": True, + "asec_source_cache": "", + }, + { + "household_tsv": "h", + "calendar_tsv": "c", + "inherit_outside_domain_baseline": True, + "unknown": True, + }, + ], +) +def test_attendance_config_rejects_incomplete_or_ambiguous_inputs(tmp_path, source): + payload = _config_payload() + payload["childcare_attendance"] = source + with pytest.raises(ValueError, match="childcare_attendance"): + _launcher_module()._read_config(_write_config(tmp_path, payload)) + + +@pytest.mark.parametrize("bad_source", [None, "household", "calendar", "cache"]) +def test_attendance_source_pins_are_checked_before_the_builder( + tmp_path, monkeypatch, bad_source +): + from microcosm.build.us_runtime import childcare_attendance + + launcher = _launcher_module() + (tmp_path / "ledger").mkdir() + incumbent = tmp_path / "incumbent.json" + incumbent.write_text(json.dumps({"target_surface": {"sha256": "e" * 64}})) + household = tmp_path / "household.tsv" + calendar = tmp_path / "calendar.tsv" + household.write_text("synthetic household fixture") + calendar.write_text("synthetic calendar fixture") + # Licensed source bytes stay out of CI; the real contract is pinned in + # test_source_stage_contract_pins_outputs_and_assets. + pins = {"DS5": _sha256(household), "DS4": _sha256(calendar)} + monkeypatch.setattr( + childcare_attendance, + "childcare_attendance_contract", + lambda: {"artifacts": [{"dataset": k, "sha256": v} for k, v in pins.items()]}, + ) + payload = _config_payload() + payload["targets"]["incumbent_diagnostics_sha256"] = _sha256(incumbent) + payload["childcare_attendance"] = { + "household_tsv": "household.tsv", + "calendar_tsv": "calendar.tsv", + "inherit_outside_domain_baseline": True, + } + if bad_source in ("household", "calendar"): + (tmp_path / f"{bad_source}.tsv").write_text("changed after pinning") + if bad_source == "cache": + payload["childcare_attendance"]["asec_source_cache"] = "missing-cache" + monkeypatch.setattr( + launcher, + "load_simulation_ready_us_multispine_pool_manifest", + lambda *a, **kw: { + "publication_run_id": "fixture-publication", + "agreement_gate": {"passed": True}, + "provenance_counts": {"household": {"rows": 8}}, + }, + ) + calls = [] + + def builder(argv): + parsed = launcher.fiscal_release._parse_args(argv) + assert parsed.childcare_attendance_household_tsv == household + assert parsed.childcare_attendance_calendar_tsv == calendar + assert parsed.childcare_attendance_asec_cache is None + assert parsed.childcare_attendance_inherit_outside_domain_baseline + calls.append(argv) + + kwargs = dict( + pool_manifest=tmp_path / "pool.manifest.json", + config_path=_write_config(tmp_path, payload), + out=tmp_path / "out", + release_builder=builder, + ) + if bad_source is None: + launcher.launch(**kwargs) + assert len(calls) == 1 + else: + with pytest.raises(ValueError, match="SHA-256 mismatch|must be a directory"): + launcher.launch(**kwargs) + assert calls == [] def test_launcher_delegates_to_house_builder_and_never_publishes( diff --git a/packages/microcosm-build/tests/engine_free/us/test_us_fiscal_refresh_builder.py b/packages/microcosm-build/tests/engine_free/us/test_us_fiscal_refresh_builder.py index 5a3a018a4..e209ef82d 100644 --- a/packages/microcosm-build/tests/engine_free/us/test_us_fiscal_refresh_builder.py +++ b/packages/microcosm-build/tests/engine_free/us/test_us_fiscal_refresh_builder.py @@ -1483,6 +1483,143 @@ def cache_digest(frame: Frame, commit: str) -> tuple[str, str]: assert changed[1] != baseline[1] +@pytest.mark.parametrize("change", ["values", "recipe"]) +def test_attendance_execution_invalidates_target_checkpoint_and_reform_cache( + monkeypatch, tmp_path, change +): + """A4: real receipt checks and durable caches across two source executions.""" + from microcosm.build.us_runtime import childcare_attendance_receipt as receipt + from test_support.microcosm_build.us_nsece_childcare import ( + HOURS, + _candidate, + _replace, + ) + + builder = _load_builder_module() + + def prepared_frame(hours=8.0): + frame = _candidate() + person = frame.table("person").copy() + person.loc[1, HOURS] = hours + source = dict(frame.metadata["nsece_childcare_attendance"]) + source["artifacts"] = receipt.childcare_attendance_contract()["artifacts"] + metadata = { + **frame.metadata, + "nsece_childcare_attendance": source, + "childcare_attendance_stage": { + "stage": "nsece_childcare_attendance", + "seed": source["seed"], + "modeled_age_domain": [0, 12], + "outside_domain_policy": "require_observed", + }, + } + # A synthetic source execution, never a repair of persisted input. + return receipt.bind_childcare_attendance( + _replace(frame, people=person, metadata=metadata) + ) + + target = TargetSpec( + name="fixture.care_hours", + entity="household", + measure="care_hours", + value=8.0, + source="Synthetic attendance", + ) + materialized = [] + + def materialize(frame, specs, **kwargs): + materialized.append(frame) + tables = {entity: frame.table(entity).copy() for entity in frame.entities} + tables["household"]["care_hours"] = frame.table("person")[HOURS].sum() + target_frame = Frame( + tables, + frame.schema, + {"household": frame.weights_for("household")}, + frame.strata, + metadata=frame.metadata, + ) + return target_frame, TargetRegistry(specs, country="us"), {} + + monkeypatch.setattr(builder, "_materialize_target_frame", materialize) + + def run(frame): + binding = builder._require_bound_childcare_attendance(frame) + identity = builder._target_frame_checkpoint_identity( + base_dataset_sha256="unchanged-parent", + policyengine_us_version="unchanged-engine", + seed=915, + target_period=builder.PERIOD, + target_registry_version="unchanged-registry", + weeks_unemployed_source_sha256="unchanged-weeks", + congressional_district_vintage_crosswalk_sha256=None, + ssi_take_up_assignment_sha256="unchanged-ssi", + selection_identities_sha256=None, + staged_frame_sha256=builder._staged_frame_sha256(frame), + childcare_attendance_binding_sha256=binding["binding_sha256"], + selection_mass_protections=(HOURS,), + ) + target_frame, _, compilation = builder._load_or_materialize_target_frame( + frame, + (target,), + target_frame_checkpoint_path=tmp_path / "targets.h5", + target_frame_checkpoint_identity=identity, + target_frame_checkpoint_build_commit="same-commit", + ) + cache_identity = builder._target_materialization_cache_identity( + context={ + "base_dataset_sha256": "unchanged-parent", + "target_frame_materializer_identity_sha256": ( + builder._target_frame_checkpoint_digest(identity) + ), + }, + reform_spec=SimpleNamespace( + measure="fixture_reform", neutralized_variable="fixture_credit" + ), + n_households=1, + ) + return identity, cache_identity, target_frame, compilation + + original = prepared_frame() + identity, cache, _, first = run(original) + assert first["target_frame_checkpoint"]["status"] == "miss_written" + builder._write_reform_income_tax_cache(tmp_path / "reforms", cache, np.array([1.0])) + assert run(original)[3]["target_frame_checkpoint"]["status"] == "hit" + assert ( + builder._read_reform_income_tax_cache( + tmp_path / "reforms", cache, n_households=1 + ) + is not None + ) + + if change == "recipe": + recipe = receipt.attendance_recipe_identity() + recipe["code_sha256"]["childcare_attendance.py"] = "f" * 64 + monkeypatch.setattr(receipt, "attendance_recipe_identity", lambda: recipe) + updated = prepared_frame(hours=6.0 if change == "values" else 8.0) + changed, new_cache, target_frame, second = run(updated) + assert (changed["staged_frame_sha256"] == identity["staged_frame_sha256"]) == ( + change == "recipe" + ) + assert second["target_frame_checkpoint"]["status"] == "miss_written" + assert len(materialized) == 2 + assert target_frame.table("household").care_hours.iloc[0] == ( + 6.0 if change == "values" else 8.0 + ) + assert ( + builder._read_reform_income_tax_cache( + tmp_path / "reforms", new_cache, n_households=1 + ) + is None + ) + + # Changed values cannot obtain a cache identity by retaining the old receipt. + tampered = updated.table("person").copy() + tampered.loc[1, HOURS] += 1 + with pytest.raises(RuntimeError, match="differ from the source receipt"): + run(_replace(updated, people=tampered)) + assert len(materialized) == 2 + + def test_runtime_versions_use_local_workspace_package_version( monkeypatch, tmp_path ) -> None: @@ -5979,6 +6116,11 @@ def _run_green_register_release( ``stored_input_mode`` injects one stored-input failure (microcosm#1026) into that otherwise green run; see :func:`_assert_stored_input_abort`. """ + from microcosm.build.us_runtime import ( + childcare_attendance_receipt, + childcare_attendance_stage, + nsece_childcare, + ) from microcosm.data.contract import ( _check_build_manifest, _check_local_artifact_hashes, @@ -5986,6 +6128,37 @@ def _run_green_register_release( ) from microcosm.data.release import _release_manifest_release_artifacts + # This harness has household-only fakes and a placeholder H5 writer. + # Real row/binding/native checks run in test_us_nsece_childcare.py; here + # preserve the boundary calls and prove the scorer binds the bytes AFTER + # attendance persistence, including when the smoke consumer is skipped. + def check_attendance_rows(frame): + captured.setdefault("attendance_export_checks", []).append("rows") + + def check_attendance_binding(frame): + captured.setdefault("attendance_export_checks", []).append("binding") + + def persist_attendance(path, frame): + assert captured["attendance_export_checks"] == ["rows", "binding"] + assert captured["written_dataset"] == Path(path) + path.write_bytes(path.read_bytes() + b"\nattendance receipt fixture") + captured["attendance_persisted"] = True + return {"binding_sha256": "attendance-binding-sentinel", "fixture": True} + + monkeypatch.setattr( + nsece_childcare, "assert_childcare_attendance_exportable", check_attendance_rows + ) + monkeypatch.setattr( + childcare_attendance_receipt, + "assert_bound_childcare_attendance", + check_attendance_binding, + ) + monkeypatch.setattr( + childcare_attendance_stage, + "persist_native_childcare_receipt", + persist_attendance, + ) + release_dir = out / "releases" / release_id # The harness stubs every hash to a constant. The run's own outputs, the # register and the export-mass reference hash for real, so the manifests @@ -6035,6 +6208,7 @@ class WrittenH5Scorer: hands each consumer a seam naming that file.""" def __init__(self, dataset_path, **kwargs): + assert captured["attendance_persisted"] self.dataset_path = Path(dataset_path) self.dataset_sha256 = builder._sha256(self.dataset_path) captured["scorer_opened_on"] = self.dataset_path @@ -6130,7 +6304,9 @@ def fake_smoke(*, simulate, period): (release_dir / "reform_coverage_smoke.json").read_text() )["post_export_scoring"] assert smoke_scoring == { - "dataset_sha256": hashlib.sha256(b"release h5").hexdigest(), + "dataset_sha256": hashlib.sha256( + b"release h5\nattendance receipt fixture" + ).hexdigest(), "consumer": "reform_coverage_smoke", } assert build_manifest["dataset"]["sha256"] == smoke_scoring["dataset_sha256"] @@ -7149,6 +7325,13 @@ def fake_capital_gain_details_signal_gate(frame): details={"checked": True}, ), ) + # The fake frame carries no NSECE attendance stage; the fail-fast refusal + # has its own test below. + monkeypatch.setattr( + builder, + "_require_bound_childcare_attendance", + lambda frame: {"binding_sha256": "attendance-binding-sentinel"}, + ) monkeypatch.setattr( builder, @@ -8543,6 +8726,7 @@ def fake_release_gate_failures(*args, **kwargs): ssi_take_up_assignment_sha256=cache_context["ssi_take_up_assignment_sha256"], selection_identities_sha256=cache_context["selection_identities_sha256"], staged_frame_sha256="staged-frame-sentinel", + childcare_attendance_binding_sha256="attendance-binding-sentinel", ) assert evidence_identity == dict(expected_evidence_identity) ids_block = final_weights_metadata.pop("household_ids") @@ -8895,6 +9079,7 @@ def fake_release_gate_failures(*args, **kwargs): ssi_take_up_assignment_sha256=cache_context["ssi_take_up_assignment_sha256"], selection_identities_sha256=cache_context["selection_identities_sha256"], staged_frame_sha256="staged-frame-sentinel", + childcare_attendance_binding_sha256="attendance-binding-sentinel", ) assert cache_context[ "target_frame_materializer_identity_sha256" @@ -10025,6 +10210,7 @@ class FakeFrame: schema = object() weighted_entities = () strata = None + metadata = {"upstream_receipt": "preserved"} def table(self, entity): assert entity == "tax_unit" @@ -10061,7 +10247,9 @@ def fake_run_source_stage( monkeypatch.setattr( builder, "Frame", - lambda tables, schema, weights, strata: SimpleNamespace(tables=tables), + lambda tables, schema, weights, strata, *, metadata=None: SimpleNamespace( + tables=tables, metadata=metadata + ), ) specs = ( @@ -10093,13 +10281,15 @@ def fake_run_source_stage( ), ) - builder._with_aca_marketplace_source_outputs( + result = builder._with_aca_marketplace_source_outputs( FakeFrame(), specs, seed=42, simulation=object(), ) + # Upstream receipts (e.g. the attendance binding) must survive this stage. + assert result.metadata == {"upstream_receipt": "preserved"} assert captured["stage"] == builder.US_ACA_MARKETPLACE_STAGE assert captured["stop_after"] is None target_tables = captured["tables"] @@ -15681,6 +15871,63 @@ def _ancestor_if_tests(node: ast.AST) -> list[str]: ) +@pytest.mark.parametrize( + "options", + [ + ["--childcare-attendance-household-tsv", "household.tsv"], + ["--childcare-attendance-calendar-tsv", "calendar.tsv"], + ["--childcare-attendance-inherit-outside-domain-baseline"], + ], +) +def test_attendance_source_cli_requires_paired_inputs(options): + builder = _load_builder_module() + with pytest.raises(SystemExit): + builder._parse_args( + ["--ledger-facts", "facts.jsonl", "--out", "release", *options] + ) + + +def test_build_without_attendance_source_is_refused_before_calibration(): + # No attendance columns and no receipt: what every base without the stage has. + frame = SimpleNamespace( + table=lambda entity: pd.DataFrame({"person_id": [1], "age": [4]}), + metadata={}, + ) + with pytest.raises(RuntimeError, match="--childcare-attendance-household-tsv"): + _load_builder_module()._require_bound_childcare_attendance(frame) + + +def test_attendance_integrity_is_unconditional_at_final_native_write(): + """Neither coverage overrides nor omitted TSV flags can skip integrity. + + Pair this ordering contract with the behavioral receipt, row validation, + and real native reload tests in test_us_nsece_childcare.py. + """ + import ast + + main = ast.parse(inspect.getsource(_load_builder_module()._main)).body[0] + calls = [] + # Direct body statements prove these checks are outside optional branches. + for statement in main.body: + value = getattr(statement, "value", None) + if isinstance(value, ast.Call): + function = value.func + name = ( + function.attr + if isinstance(function, ast.Attribute) + else getattr(function, "id", None) + ) + calls.append(name) + expected = [ + "assert_childcare_attendance_exportable", + "assert_bound_childcare_attendance", + "write_dataset", + "persist_native_childcare_receipt", + ] + positions = [calls.index(name) for name in expected] + assert positions == list(range(positions[0], positions[0] + 4)) + + # --------------------------------------------------------------------------- # The committed US Chronicle feed pin holds the release build's feed # --------------------------------------------------------------------------- diff --git a/packages/microcosm-build/tests/engine_free/us/test_us_nsece_childcare.py b/packages/microcosm-build/tests/engine_free/us/test_us_nsece_childcare.py new file mode 100644 index 000000000..2acd8fac5 --- /dev/null +++ b/packages/microcosm-build/tests/engine_free/us/test_us_nsece_childcare.py @@ -0,0 +1,988 @@ +"""Synthetic childcare contracts for the engine_free/us environment.""" + +# ruff: noqa: F403, F405 +from test_support.microcosm_build.us_nsece_childcare import * + + +def test_calendar_union_excludes_school_and_handles_multiple_providers(): + hh, cal = _raw() + hh["HH4_TYPEOFCARE_AGG_1_2"] = 6 # K-8 school is not ECE attendance. + hh["HH4_TYPEOFCARE_AGG_1_3"] = 3 # Unpaid care is still ECE. + _care(cal, day=0, hours=4) + _care(cal, day=1, hours=2, provider=3) + _care(cal, day=2, hours=6, provider=2) + before = (hh.copy(deep=True), cal.copy(deep=True)) + source = derive_nsece_childcare(hh, cal) + child = source.children.iloc[0] + assert child[DAYS] == 2 + assert child[HOURS] == 3 + assert child[MONTH] == 9 + assert child.ece_hours_per_week == 6 + assert child.ece_provider_count == 2 + assert source.weights.values.tolist() == [100] + assert_frame_equal(hh, before[0]) + assert_frame_equal(cal, before[1]) + + +@pytest.mark.parametrize( + "status,code,expected", + [ + (0, 0, "missing_calendar"), + (1, 0, "partial_calendar"), + (2, -1, "ambiguous_calendar"), + (2, 97, "ambiguous_calendar"), + (2, 77, "ambiguous_calendar"), + ], +) +def test_missing_or_ambiguous_calendar_never_becomes_observed_zero( + status, code, expected +): + hh, cal = _raw() + hh["HH4_MISSING_STATUS_CC_1"] = status + cal.loc[0, "HH4_CHCAL_R_1_1"] = code + source = derive_nsece_childcare(hh, cal) + assert source.children.attendance_status.tolist() == [expected] + assert source.children[list(US_CHILDCARE_ATTENDANCE_COLUMNS)].isna().all().all() + + +def test_complete_parental_care_is_a_weighted_zero_donor(): + hh, cal = _raw() + source = derive_nsece_childcare(hh, cal) + donors, weights = source.donors() + assert donors[list(US_CHILDCARE_ATTENDANCE_COLUMNS)].to_numpy().tolist() == [ + [0, 0, 0] + ] + assert weights.total == 100 + + +def test_calendar_bounds_preserve_measured_blocks_without_filling_ambiguous_time(): + hh, cal = _raw() + _care(cal, hours=4) + cal.loc[0, "HH4_CHCAL_R_1_200"] = 97 + child = derive_nsece_childcare(hh, cal).children.iloc[0] + assert child.calendar_ece_hours_lower == 4 + assert child.calendar_ece_hours_upper == 4.25 + assert child.calendar_ece_days_lower == 1 + assert child.calendar_ece_days_upper == 2 + assert child.calendar_unknown_hours == 0.25 + assert child.attendance_status == "ambiguous_calendar" + assert pd.isna(child[DAYS]) + + +def test_partial_calendar_assumed_parental_zeros_remain_unresolved(): + hh, cal = _raw() + _care(cal, hours=4) + hh["HH4_MISSING_STATUS_CC_1"] = 1 + child = derive_nsece_childcare(hh, cal).children.iloc[0] + assert child.calendar_ece_hours_lower == 4 + assert child.calendar_ece_hours_upper == 168 + assert child.calendar_ece_days_lower == 1 + assert child.calendar_ece_days_upper == 7 + assert child.calendar_unknown_hours == 164 + assert pd.isna(child.regular_hours_per_week) + assert pd.isna(child[HOURS]) + + +def test_missing_calendar_has_uninformative_bounds_not_observed_zeros(): + hh, cal = _raw() + hh["HH4_MISSING_STATUS_CC_1"] = 0 + child = derive_nsece_childcare(hh, cal).children.iloc[0] + assert child.calendar_ece_hours_lower == 0 + assert child.calendar_ece_hours_upper == 168 + assert child.calendar_ece_days_lower == 0 + assert child.calendar_ece_days_upper == 7 + assert pd.isna(child[DAYS]) + + +def test_complete_calendar_bounds_equal_the_observed_schedule(): + hh, cal = _raw() + _care(cal, hours=4) + child = derive_nsece_childcare(hh, cal).children.iloc[0] + assert child.calendar_ece_hours_lower == child.ece_hours_per_week + assert child.calendar_ece_hours_upper == child.ece_hours_per_week + assert child.calendar_ece_days_lower == child[DAYS] + assert child.calendar_ece_days_upper == child[DAYS] + assert child.calendar_unknown_hours == 0 + + +def test_unknown_provider_type_is_not_a_zero_schedule(): + hh, cal = _raw() + _care(cal) + hh["HH4_TYPEOFCARE_AGG_1_1"] = 8 + source = derive_nsece_childcare(hh, cal) + assert source.children.attendance_status.tolist() == ["ambiguous_calendar"] + + +def test_age_in_months_and_calendar_join_are_not_row_order_dependent(): + hh, cal = _raw(2) + hh.loc[1, "HHC4_AGE_AT_USAGE_1"] = 156 + _care(cal) + source = derive_nsece_childcare(hh, cal.iloc[::-1]) + assert source.children.age.tolist() == [3, 13] + assert source.children.attendance_status.tolist() == [ + "complete", + "age_out_of_scope", + ] + assert source.children.loc[0, DAYS] == 1 + + +def test_mismatched_or_duplicate_household_ids_raise(): + hh, cal = _raw(2) + cal.loc[0, "HH4_METH_CASEID"] = 3 + with pytest.raises(ValueError, match="ID sets"): + derive_nsece_childcare(hh, cal) + cal.loc[0, "HH4_METH_CASEID"] = 2 + with pytest.raises(ValueError, match="unique"): + derive_nsece_childcare(hh, cal) + + +def test_loader_refuses_unpinned_source(tmp_path): + path = tmp_path / "source.tsv" + path.write_text("wrong file\n") + with pytest.raises(ValueError, match="hash mismatch"): + load_nsece_childcare(path, path) + + +def test_candidate_frame_preserves_structure_weights_and_checkpoint_receipts(tmp_path): + frame = _frame() + before = frame.table("person").copy(deep=True) + candidate = with_us_nsece_childcare_attendance( + frame, _source(), seed=915, match_columns=("age",) + ) + assert_frame_equal(frame.table("person"), before) + assert candidate.table("person")[DAYS].tolist() == [0, 5] + assert candidate.metadata["existing_receipt"] == "preserved" + assert candidate.metadata["nsece_childcare_attendance"]["candidate_only"] is True + np.testing.assert_array_equal( + candidate.weights_for("household").values, frame.weights_for("household").values + ) + for entity in US_SCHEMA.group_entities: + assert_frame_equal(candidate.table(entity), frame.table(entity)) + path = tmp_path / "candidate.h5" + receipts = json.loads(json.dumps(candidate.metadata, default=dict)) + write_frame_checkpoint(path, candidate, metadata={"frame_metadata": receipts}) + stored = load_frame_checkpoint(path) + reloaded = load_frame_checkpoint( + path, frame_metadata=stored.metadata["frame_metadata"] + ).frame + # Checkpoint JSON sorts mapping keys; receipts retain the same content. + assert json.loads(json.dumps(reloaded.metadata, default=dict)) == receipts + assert_frame_equal(reloaded.table("person"), candidate.table("person")) + + +def test_candidate_export_refuses_unresolved_out_of_scope_inputs(): + candidate = with_us_nsece_childcare_attendance( + _frame(parent_observed=False), _source(), seed=915, match_columns=("age",) + ) + assert pd.isna(candidate.table("person").loc[0, DAYS]) + with pytest.raises(ValueError, match="unresolved"): + assert_childcare_attendance_exportable(candidate) + + +def test_validation_holds_out_whole_households_and_reports_exclusions(monkeypatch): + import microcosm.build.us_runtime.nsece_childcare as module + + hh, cal = _raw(30) + hh.loc[29, "HH4_MISSING_STATUS_CC_1"] = 0 + for row in range(29): + _care(cal, row=row) + source = derive_nsece_childcare(hh, cal) + original = module.impute_us_childcare_attendance + + def checked(recipient, donor, **kwargs): + assert set(recipient.source_household_id).isdisjoint(donor.source_household_id) + return original(recipient, donor, **kwargs) + + monkeypatch.setattr(module, "impute_us_childcare_attendance", checked) + report = nsece_childcare_validation_report(source) + assert report["household_overlap"] == 0 + assert report["production_ready"] is False + assert report["under13_complete_weight_share"] == pytest.approx(29 / 30) + assert report["comparisons"][0]["observed"] == report["comparisons"][0]["predicted"] + + +@pytest.mark.parametrize( + "code,parent,age,expected", + [ + (51, 1, 36, 0), + (51, 0, 36, 1), + (52, -1, 36, None), + (54, 1, 36, 1), + (61, 1, 36, 1), + (68, 1, 36, None), + (68, 1, 84, 0), + (70, 0, 36, None), + ], +) +def test_gap_care_uses_parent_status_and_school_age(code, parent, age, expected): + hh, cal = _raw() + hh["HH4_RPARENT"] = parent + hh["HHC4_AGE_AT_USAGE_1"] = age + cal.loc[0, "HH4_CHCAL_R_1_1"] = code + child = derive_nsece_childcare(hh, cal).children.iloc[0] + if expected is None: + assert pd.isna(child[DAYS]) + else: + assert child[DAYS] == expected + + +def test_asec_parent_work_and_region_come_from_measured_relationships(): + from microcosm.build.us_runtime.childcare_population import ( + harmonize_asec_childcare_predictors, + ) + + before = _asec_frame() + result = harmonize_asec_childcare_predictors(before) + assert result.table("person").parent_work_status.tolist() == [2, 2] + assert result.table("person").region.tolist() == [1, 1] + assert "parent_work_status" not in before.table("person") + assert result.metadata["existing_receipt"] == "preserved" + # A working adult without a parent link must not count as a working parent. + before.table("person")["PEPAR1"] = -1 + result = harmonize_asec_childcare_predictors(before) + assert result.table("person").parent_work_status.tolist() == [-1, -1] + + +def test_asec_dangling_parent_pointer_is_refused(): + from microcosm.build.us_runtime.childcare_population import ( + harmonize_asec_childcare_predictors, + ) + + frame = _asec_frame() + frame.table("person").loc[1, "PEPAR1"] = 99 + with pytest.raises(ValueError, match="does not resolve"): + harmonize_asec_childcare_predictors(frame) + + +def test_integer_source_ids_are_losslessly_encoded_and_restored(): + frame = _frame() + frame.table("person")["person_source_id"] = [2**60, 2**60 + 1] + result = with_us_nsece_childcare_attendance( + frame, _source(), seed=915, match_columns=("age",) + ) + pd.testing.assert_series_equal( + result.table("person").person_source_id, frame.table("person").person_source_id + ) + assert result.table("person")[DAYS].tolist() == [0, 5] + + +def test_sparse_matching_is_explicit_and_keeps_joint_schedule(): + from microcosm.build.us_runtime.nsece_childcare import ( + NSECE_CHILDCARE_FALLBACK_COLUMNS, + NSECE_CHILDCARE_MATCH_COLUMNS, + ) + + frame = _frame() + frame.table("person")["region"] = 4 + frame.table("person")["parent_work_status"] = 0 + frame.table("person")["income_band"] = 2 + with pytest.raises(ValueError, match="No compatible"): + with_us_nsece_childcare_attendance( + frame, _source(), seed=915, match_columns=NSECE_CHILDCARE_MATCH_COLUMNS + ) + result = with_us_nsece_childcare_attendance( + frame, + _source(), + seed=915, + match_columns=NSECE_CHILDCARE_MATCH_COLUMNS, + fallback_match_columns=NSECE_CHILDCARE_FALLBACK_COLUMNS, + ) + assert result.table("person").loc[1, "childcare_attendance_match_level"] == "age" + assert result.table("person").loc[1, [MONTH, DAYS, HOURS]].tolist() == [22, 5, 8] + + +def test_census_region_map_covers_all_states_once(): + from microcosm.calibrate.geography_constants import ( + US_STATE_NUMERIC_FIPS_TO_CENSUS_REGION, + US_STATE_NUMERIC_FIPS_TO_POSTAL, + ) + + assert set(US_STATE_NUMERIC_FIPS_TO_CENSUS_REGION) == set( + US_STATE_NUMERIC_FIPS_TO_POSTAL + ) + assert US_STATE_NUMERIC_FIPS_TO_CENSUS_REGION[11] == 3 + assert US_STATE_NUMERIC_FIPS_TO_CENSUS_REGION[17] == 2 + assert US_STATE_NUMERIC_FIPS_TO_CENSUS_REGION[6] == 4 + + +def test_noncalendar_bridge_preserves_measured_hours_without_asserting_days_observed(): + from microcosm.build.us_runtime.nsece_childcare_bridge import ( + bridge_nsece_noncalendar_attendance, + ) + + hh, cal = _raw(2) + for day in range(5): + _care(cal, row=0, day=day, hours=8) + hh.loc[1, "HH4_METH_QUEXVERSION"] = 2 + hh.loc[1, "HH4_MISSING_STATUS_CC_1"] = 0 + for kind in range(1, 10): + hh.loc[1, f"HHC4_NPC_HRSWEEK_TOC{kind}_1"] = 0 + hh.loc[1, "HHC4_NPC_HRSWEEK_TOC4_1"] = 12 + source = derive_nsece_childcare(hh, cal) + result = bridge_nsece_noncalendar_attendance(source, seed=915) + child = result.children.iloc[1] + assert child.attendance_status == "summary_bridge" + assert child.regular_hours_per_week == 12 + assert child[DAYS] == 5 + assert child[HOURS] == pytest.approx(2.4) + assert child.ece_hours_per_week == 12 + assert pd.isna(source.children.iloc[1][DAYS]) + assert len(result.donors()[0]) == 2 + with pytest.raises(ValueError, match="before bridge"): + nsece_childcare_validation_report(result) + + +def test_zero_regular_care_does_not_erase_unmeasured_irregular_care(): + from microcosm.build.us_runtime.nsece_childcare_bridge import ( + bridge_nsece_noncalendar_attendance, + ) + + hh, cal = _raw(2) + hh.loc[0, "HH4_TYPEOFCARE_AGG_1_1"] = 7 + _care(cal, row=0, hours=2) + hh.loc[1, "HH4_METH_QUEXVERSION"] = 3 + hh.loc[1, "HH4_MISSING_STATUS_CC_1"] = 0 + for kind in range(1, 10): + hh.loc[1, f"HHC4_NPC_HRSWEEK_TOC{kind}_1"] = 0 + result = bridge_nsece_noncalendar_attendance( + derive_nsece_childcare(hh, cal), seed=915 + ) + assert result.children.iloc[1].regular_hours_per_week == 0 + assert result.children.iloc[1].irregular_hours_per_week == 2 + assert result.children.iloc[1][DAYS] == 1 + + +def test_shared_household_rank_preserves_sibling_and_clone_coherence(): + from microcosm.build.us_runtime.childcare_attendance import ( + impute_us_childcare_attendance, + ) + + donor = pd.DataFrame( + { + "donor_id": ["a", "b"], + "age": [3, 3], + MONTH: [0, 22], + DAYS: [0, 5], + HOURS: [0, 8], + } + ) + recipients = pd.DataFrame( + { + "person_source_id": ["a", "b", "a", "b"], + "childcare_source_household_id": ["family"] * 4, + "age": [3] * 4, + } + ) + result = impute_us_childcare_attendance( + recipients, + donor, + donor_weights=Weights(np.array([1.0, 1.0]), WeightKind.DESIGN), + match_columns=("age",), + seed=915, + sibling_dependence=1, + ) + assert result[DAYS].nunique() == 1 + assert result[HOURS].nunique() == 1 + + +def test_source_stage_contract_pins_outputs_and_assets(): + from microcosm.build.source_manifest import SourceStageSpec + from microcosm.build.us_runtime.childcare_attendance import ( + childcare_attendance_contract, + childcare_income_band, + ) + from microcosm.build.us_runtime.nsece_childcare import ( + NSECE_2024_CALENDAR_SHA256, + NSECE_2024_HOUSEHOLD_SHA256, + ) + + contract = childcare_attendance_contract() + assert ( + SourceStageSpec.from_mapping(contract).outputs + == US_CHILDCARE_ATTENDANCE_COLUMNS + ) + assert [x["sha256"] for x in contract["artifacts"]] == [ + NSECE_2024_HOUSEHOLD_SHA256, + NSECE_2024_CALENDAR_SHA256, + ] + assert childcare_income_band([0, 25000, 25001, 200000, 200001]).tolist() == [ + 0, + 1, + 2, + 4, + 5, + ] + + +def test_asec_income_sidecar_checks_identity_and_preserves_raw_missingness( + tmp_path, monkeypatch +): + import hashlib + from types import SimpleNamespace + + from microcosm.build.us_runtime import childcare_population as population + + frame = _asec_frame() + people = frame.table("person") + people["PERIDNUM"] = ["1000000000000000000001", "1000000000000000000002"] + people["A_AGE"] = people.age + people["PTOTVAL"] = [np.nan, 0.0] + raw = people[["PERIDNUM", "A_AGE", "A_LINENO", "PTOTVAL"]].copy() + raw.loc[0, "PTOTVAL"] = 40000 + path = tmp_path / "source.csv" + raw.to_csv(path, index=False) + monkeypatch.setattr( + population, + "ASEC_EDUCATION_ASSISTANCE_ARCHIVES", + { + 2023: SimpleNamespace( + member=path.name, + member_sha256=hashlib.sha256(path.read_bytes()).hexdigest(), + member_size_bytes=path.stat().st_size, + rows=2, + ) + }, + ) + with pytest.raises(ValueError, match="finite PTOTVAL"): + population.harmonize_asec_childcare_predictors(frame) + result = population.harmonize_asec_childcare_predictors( + frame, source_cache=tmp_path + ) + assert result.table("person").income_band.tolist() == [2, 2] + assert pd.isna(result.table("person").loc[0, "PTOTVAL"]) + people.loc[1, "PTOTVAL"] = 1 + with pytest.raises(ValueError, match="disagrees with pinned source"): + population.harmonize_asec_childcare_predictors(frame, source_cache=tmp_path) + path.write_text("corrupt") + with pytest.raises(ValueError, match="identity mismatch"): + population.harmonize_asec_childcare_predictors(frame, source_cache=tmp_path) + + +def test_bridge_retains_all_equally_near_donors(): + from microcosm.build.us_runtime.nsece_childcare_bridge import ( + bridge_nsece_noncalendar_attendance, + ) + + hh, cal = _raw(13) + # Eleven donors have zero regular hours. Household 9 sorts last by ID + # and has irregular care and substantial weight; truncating equal-distance + # donors by their IDs would incorrectly erase that care distribution. + hh.loc[8, "HH4_TYPEOFCARE_AGG_1_1"] = 7 + hh.loc[8, "HHC4_METH_WEIGHT_1"] = 1e12 + _care(cal, row=8, hours=2) + for row in (11, 12): + hh.loc[row, "HH4_METH_QUEXVERSION"] = 3 + hh.loc[row, "HH4_MISSING_STATUS_CC_1"] = 0 + for kind in range(1, 10): + hh.loc[row, f"HHC4_NPC_HRSWEEK_TOC{kind}_1"] = 0 + source = derive_nsece_childcare(hh, cal) + result = bridge_nsece_noncalendar_attendance(source, seed=915) + bridged = result.children.loc[ + result.children.attendance_status.eq("summary_bridge") + ] + assert len(bridged) == 2 + assert bridged.irregular_hours_per_week.eq(2).all() + + +def test_bridge_widens_a_thin_cell_instead_of_keeping_distant_donors(): + from microcosm.build.us_runtime.nsece_childcare_bridge import ( + bridge_nsece_noncalendar_attendance, + ) + + hh, cal = _raw(12) + # The target's exact cell holds one donor with 1 regular hour on 1 day; + # ten donors in another region match its 40 regular hours over 5 days. + _care(cal, row=0, hours=1) + for row in range(1, 11): + hh.loc[row, "HH4_REGION"] = 2 + for day in range(5): + _care(cal, row=row, day=day, hours=8) + hh.loc[11, "HH4_METH_QUEXVERSION"] = 2 + hh.loc[11, "HH4_MISSING_STATUS_CC_1"] = 0 + for kind in range(1, 10): + hh.loc[11, f"HHC4_NPC_HRSWEEK_TOC{kind}_1"] = 0 + hh.loc[11, "HHC4_NPC_HRSWEEK_TOC4_1"] = 40 + result = bridge_nsece_noncalendar_attendance( + derive_nsece_childcare(hh, cal), seed=915 + ) + bridged = result.children.loc[ + result.children.attendance_status.eq("summary_bridge") + ] + assert len(bridged) == 1 + child = bridged.iloc[0] + assert child.schedule_bridge_match == "age,parent_work_status,income_band" + assert child[DAYS] == 5 + assert child[HOURS] == 8 + assert result.source_receipt["noncalendar_bridge"]["matching_levels"] == { + "age,parent_work_status,income_band": 1 + } + + +@pytest.mark.parametrize( + "column,value", + [(DAYS, 4), ("age", 4), ("person_id", 99), ("person_household_id", 99)], +) +def test_persisted_value_or_identity_change_fails_binding(column, value): + candidate = _candidate() + candidate.table("person").loc[1, column] = value + with pytest.raises(ValueError, match="differ from the source receipt"): + assert_bound_childcare_attendance(candidate, require_stage=False) + + +def test_receipt_loss_and_metadata_relabeling_are_rejected(): + candidate = _candidate() + with pytest.raises(ValueError, match="content-bound"): + assert_bound_childcare_attendance( + _replace(candidate, metadata={}), require_stage=False + ) + metadata = json.loads(json.dumps(candidate.metadata, default=dict)) + metadata["nsece_childcare_attendance"]["seed"] += 1 + with pytest.raises(ValueError, match="metadata disagrees"): + assert_bound_childcare_attendance( + _replace(candidate, metadata=metadata), require_stage=False + ) + + +def test_same_transfer_is_idempotent_but_seed_and_source_refresh_are_rejected(): + source = _source() + candidate = _candidate() + assert ( + with_us_nsece_childcare_attendance( + candidate, source, seed=915, match_columns=("age",) + ) + is candidate + ) + with pytest.raises(ValueError, match="settings changed"): + with_us_nsece_childcare_attendance( + candidate, source, seed=916, match_columns=("age",) + ) + source.source_receipt["source_year"] = 2025 + with pytest.raises(ValueError, match="source or settings changed"): + with_us_nsece_childcare_attendance( + candidate, source, seed=915, match_columns=("age",) + ) + + +def test_selection_order_and_calibration_do_not_invalidate_attendance(): + candidate = _candidate() + selected = _replace(candidate, people=candidate.table("person").iloc[::-1]) + assert_bound_childcare_attendance(selected, require_stage=False) + tables = {e: selected.table(e) for e in selected.entities} + calibrated = Frame( + tables, + selected.schema, + {"household": Weights(np.array([200.0]), WeightKind.CALIBRATED)}, + metadata=selected.metadata, + ) + assert_bound_childcare_attendance(calibrated, require_stage=False) + + +@pytest.mark.parametrize("value", [np.nan, None, "", "nan", ""]) +def test_invalid_household_source_identity_fails_before_string_conversion(value): + frame = _asec_frame() + frame.table("household")["household_source_id"] = value + with pytest.raises(ValueError, match="household identities"): + harmonize_asec_childcare_predictors(frame) + + +def test_unresolved_household_membership_is_rejected(): + frame = _asec_frame() + frame.table("household")["household_source_id"] = "household" + frame.table("person")["PEPAR1"] = -1 + frame.table("person").loc[1, "person_household_id"] = 999 + with pytest.raises(ValueError, match="link does not resolve"): + harmonize_asec_childcare_predictors(frame) + + +@pytest.mark.parametrize( + "column,value", + [(DAYS, np.nan), (DAYS, 8), (DAYS, 0), (US_CHILDCARE_ATTENDANCE_COLUMNS[0], 2.5)], +) +def test_final_boundary_rechecks_each_row_and_schedule(column, value): + candidate = _candidate() + candidate.table("person").loc[1, column] = value + with pytest.raises(ValueError): + assert_childcare_attendance_exportable(candidate) + manifest = ReleaseInputCoverageManifest( + reference={}, + columns=tuple( + ReleaseInputColumn(c, "required") for c in US_CHILDCARE_ATTENDANCE_COLUMNS + ), + ) + gate = us_release_input_coverage_gate( + candidate, + SimpleNamespace(default_values=lambda columns: {c: 0 for c in columns}), + manifest=manifest, + ) + assert not gate.passed + assert any("Childcare" in x or "Attendance" in x for x in gate.failures) + + +def test_default_outside_domain_policy_fails_early_and_names_the_flag(monkeypatch): + monkeypatch.setattr(stage, "load_nsece_childcare", lambda *args: _source()) + frame = _asec_frame() + # The adult has no observed attendance, as on every production parent. + frame.table("person").loc[0, list(US_CHILDCARE_ATTENDANCE_COLUMNS)] = np.nan + with pytest.raises(ValueError, match="inherit-outside-domain-baseline"): + stage.with_us_childcare_attendance_inputs( + frame, + household_tsv="fake", + calendar_tsv="fake", + asec_source_cache=None, + seed=915, + ) + + +@pytest.mark.parametrize( + "column,value", + [ + ("HH4_REGION", -1), + ("HH4_PARWORK_STATUS", -8), + ("HH4_ECON_INCOME_ANNUAL", -9), + ], +) +def test_reserve_codes_never_become_matching_cells(column, value): + hh, cal = _raw() + hh[column] = value + with pytest.raises(ValueError, match="reserve code"): + derive_nsece_childcare(hh, cal) + + +def test_final_gate_cannot_accept_unbound_nondegenerate_columns(): + candidate = _replace(_candidate(), metadata={}) + manifest = ReleaseInputCoverageManifest( + reference={}, + columns=tuple( + ReleaseInputColumn(c, "required") for c in US_CHILDCARE_ATTENDANCE_COLUMNS + ), + ) + gate = us_release_input_coverage_gate( + candidate, + SimpleNamespace(default_values=lambda columns: {c: 0 for c in columns}), + manifest=manifest, + ) + assert not gate.passed + assert any("content-bound" in x for x in gate.failures) + + +def test_receipt_loss_cannot_relabel_derived_values_as_observations(): + with pytest.raises(ValueError, match="lost its receipt"): + with_us_nsece_childcare_attendance( + _replace(_candidate(), metadata={}), + _source(), + seed=916, + match_columns=("age",), + ) + + +def test_changed_recipe_invalidates_receipt(monkeypatch): + from microcosm.build.us_runtime import childcare_attendance_receipt as receipts + + candidate = _candidate() + monkeypatch.setattr( + receipts, "attendance_recipe_identity", lambda: {"different": True} + ) + with pytest.raises(ValueError, match="recipe changed"): + assert_bound_childcare_attendance(candidate) + # Read-only ingress checks content only, so released files stay loadable. + assert_bound_childcare_attendance(candidate, require_stage=False) + + +def test_public_metadata_omits_person_hash_inventory(): + from microcosm.build.us_runtime.childcare_attendance_receipt import ( + ATTENDANCE_RECEIPT_KEY, + childcare_attendance_public_metadata, + ) + + candidate = _candidate() + public = childcare_attendance_public_metadata(candidate) + assert "rows" not in public[ATTENDANCE_RECEIPT_KEY] + assert public[ATTENDANCE_RECEIPT_KEY]["source_people"] == 2 + assert len(candidate.metadata[ATTENDANCE_RECEIPT_KEY]["rows"]) == 2 + # Population-sized mappings make immutable Frame metadata serialization + # quadratic. Keep the private row inventory as a sequence of ID/hash pairs. + assert isinstance(candidate.metadata[ATTENDANCE_RECEIPT_KEY]["rows"], tuple) + + +def test_retaining_a_subset_keeps_attendance_binding(): + candidate = _candidate() + selected = _replace(candidate, people=candidate.table("person").iloc[[1]]) + summary = assert_bound_childcare_attendance(selected, require_stage=False) + assert summary["source_people"] == 2 + assert summary["retained_people"] == 1 + + +def test_shared_rank_joint_moment_integrates_unequal_cdfs(): + from microcosm.build.us_runtime.nsece_childcare_sibling_validation import ( + _joint_product, + ) + + a = (np.array([[0.0], [2.0]]), np.array([0.25, 1])) + b = (np.array([[1.0], [3.0]]), np.array([0.5, 1])) + # [0,.25): 0; [.25,.5): 2; [.5,1): 6. + assert _joint_product(a, b) == pytest.approx([3.5]) + + +def test_undefined_sibling_metrics_do_not_pass_validation(): + from microcosm.build.us_runtime.nsece_childcare_sibling_validation import ( + sibling_schedule_screen, + ) + + result = sibling_schedule_screen({"larger_households": {}}) + assert not result["passed"] + assert all(not check["passed"] for check in result["checks"]) + + +def test_reserved_households_are_excluded_from_every_development_split(): + from microcosm.build.us_runtime.nsece_childcare_sibling_validation import ( + _household_splits, + ) + + children = _sibling_source().children + arguments = {"seed": 271828, "validation_seed": 20260916} + train, reserved = _household_splits(children, partition="validation", **arguments)[ + 0 + ] + heldout_ids = set(children.loc[reserved, "source_household_id"]) + assert heldout_ids + scored = set() + for training, evaluation in _household_splits( + children, partition="development", **arguments + ): + training_ids = set(children.loc[training, "source_household_id"]) + evaluation_ids = set(children.loc[evaluation, "source_household_id"]) + assert training_ids.isdisjoint(evaluation_ids | heldout_ids) + assert evaluation_ids.isdisjoint(heldout_ids | scored) + scored.update(evaluation_ids) + assert scored == set(children.loc[train, "source_household_id"]) + + +def test_household_size_changes_actual_validation_donors_and_not_only_rho(): + from microcosm.build.us_runtime.nsece_childcare_sibling_validation import ( + assess_sibling_schedules, + ) + + source = _sibling_source() + settings = { + "fallback_match_columns": (), + "validation_seed": 20260916, + "partition": "validation", + } + legacy = assess_sibling_schedules(source, match_columns=("age",), **settings) + conditioned = assess_sibling_schedules( + source, match_columns=("age", "childcare_household_size"), **settings + ) + assert legacy["larger_households"]["coupled"]["mean_total_days"] > 0 + assert conditioned["larger_households"]["coupled"]["mean_total_days"] == 0 + assert conditioned["matching_counts"] == { + "age,childcare_household_size": 3 + * conditioned["larger_households"]["households"] + } + + +def test_reserved_outcomes_cannot_influence_development(monkeypatch): + from microcosm.build.us_runtime import nsece_childcare_sibling_validation as module + + source = _sibling_source() + settings = {"validation_seed": 20260916, "partition": "development"} + _, reserved = module._household_splits( + source.children, seed=271828, validation_seed=20260916, partition="validation" + )[0] + reserved_ids = set(source.children.loc[reserved, "source_household_id"]) + original_fit = module.fit_nsece_sibling_dependence + + def checked_fit(children, **kwargs): + assert set(children.source_household_id).isdisjoint(reserved_ids) + return original_fit(children, **kwargs) + + monkeypatch.setattr(module, "fit_nsece_sibling_dependence", checked_fit) + before = module.assess_sibling_schedules(source, **settings) + source.children.loc[reserved, [MONTH, DAYS, HOURS]] = [30, 7, 24] + assert module.assess_sibling_schedules(source, **settings) == before + + +def test_sibling_assessment_rejects_reconstructed_calendars(): + from microcosm.build.us_runtime.nsece_childcare_sibling_validation import ( + assess_sibling_schedules, + ) + + source = _sibling_source() + source.children.loc[0, "attendance_status"] = "summary_bridge" + with pytest.raises(ValueError, match="original measured"): + assess_sibling_schedules(source) + + +def test_size_challenger_counts_missing_calendars_without_mutating_source(monkeypatch): + from microcosm.build.us_runtime import nsece_childcare_sibling_validation as module + + source = _sibling_source() + first_household = source.children.index[ + source.children.source_household_id.eq("h0") + ] + source.children.loc[first_household[1], "attendance_status"] = "missing_calendar" + source.children.loc[first_household[1], [MONTH, DAYS, HOURS]] = np.nan + source.children.loc[first_household[2], "age"] = 13 + before = source.children.copy(deep=True) + calls = [] + + def capture(candidate, **kwargs): + calls.append((candidate.children.copy(), kwargs)) + return {} + + monkeypatch.setattr(module, "assess_sibling_schedules", capture) + report = module.compare_household_size_matching(source, partition="development") + assert len(calls) == 2 + revised, settings = calls[1] + assert revised.loc[first_household, "childcare_household_size"].tolist() == [ + 2, + 2, + 2, + ] + assert "childcare_household_size" in settings["match_columns"] + assert settings["fallback_match_columns"][-2:] == ( + ("age", "childcare_household_size"), + ("age",), + ) + assert_frame_equal(source.children, before) + assert report["production_recipe_changed"] is False + + +@pytest.mark.parametrize( + "partition,validation_seed", [("unknown", 1), ("all", 1), ("validation", None)] +) +def test_sibling_partition_configuration_fails_closed(partition, validation_seed): + from microcosm.build.us_runtime.nsece_childcare_sibling_validation import ( + _household_splits, + ) + + with pytest.raises(ValueError): + _household_splits( + _sibling_source().children, + seed=1, + validation_seed=validation_seed, + partition=partition, + ) + + +@pytest.mark.parametrize( + "irregular,shift,expected_days,expected_hours", + [ + (False, 0, 5, 12), + (True, -1, 4, 13), + (True, 1, 6, 13), + ], +) +def test_schedule_sensitivity_preserves_measured_regular_hours( + irregular, shift, expected_days, expected_hours +): + from microcosm.build.us_runtime.childcare_sensitivity import ( + noncalendar_sensitivity_source, + ) + + source = _source() + source.children["attendance_status"] = "summary_bridge" + source.children["regular_hours_per_week"] = 12.0 + source.children["irregular_hours_per_week"] = 1.0 + original = source.children.copy(deep=True) + changed = noncalendar_sensitivity_source( + source, irregular_hours=irregular, day_shift=shift + ) + row = changed.children.iloc[0] + assert row.regular_hours_per_week == 12 + assert row[DAYS] == expected_days + assert row[DAYS] * row[HOURS] == pytest.approx(expected_hours) + assert_frame_equal(source.children, original) + observed = noncalendar_sensitivity_source( + _source(), irregular_hours=False, day_shift=-1 + ) + assert_frame_equal(observed.children, _source().children) + + +def test_paired_sensitivity_keeps_selected_donor_and_measured_hours(): + from microcosm.build.us_runtime.childcare_sensitivity import ( + noncalendar_sensitivity_source, + paired_noncalendar_attendance, + ) + + people, source = _paired_sensitivity_fixture() + original = people.copy(deep=True) + changed = noncalendar_sensitivity_source(source, day_shift=-1) + values, report = paired_noncalendar_attendance(people, source, changed) + assert values[0, 1] == people[DAYS].iloc[0] - 1 + assert values[0, 1] * values[0, 2] == pytest.approx(13) + assert report["changed_people"] == 1 + assert report["measured_calendar_assignments_changed"] == 0 + assert_frame_equal(people, original) + # Row order in the donor source has no effect on the identity lookup. + reversed_source = NSECEChildcareSource( + changed.children.iloc[::-1], changed.weights, changed.source_receipt + ) + np.testing.assert_array_equal( + values, paired_noncalendar_attendance(people, source, reversed_source)[0] + ) + + +@pytest.mark.parametrize( + "problem", ["unknown_donor", "mixed_donor", "wrong_value", "observed_conflict"] +) +def test_paired_sensitivity_rejects_invalid_lineage_and_observation_conflicts(problem): + from microcosm.build.us_runtime.childcare_sensitivity import ( + noncalendar_sensitivity_source, + paired_noncalendar_attendance, + ) + + people, source = _paired_sensitivity_fixture() + changed = noncalendar_sensitivity_source(source, day_shift=-1) + if problem == "unknown_donor": + for c in (MONTH, DAYS, HOURS): + people[f"{c}_source"] = "donor:missing" + elif problem == "mixed_donor": + people[f"{HOURS}_source"] = "donor:another" + elif problem == "wrong_value": + people[HOURS] += 0.1 + else: + people[f"{DAYS}_source"] = "observed" + with pytest.raises(ValueError): + paired_noncalendar_attendance(people, source, changed) + + +def test_paired_sensitivity_does_not_reassign_measured_donors_when_care_order_changes(): + from microcosm.build.us_runtime.childcare_sensitivity import ( + noncalendar_sensitivity_source, + paired_noncalendar_attendance, + ) + from microcosm.frame import WeightKind, Weights + + people, source = _paired_sensitivity_fixture() + measured = source.children.copy().assign( + donor_id="measured", + attendance_status="complete", + regular_hours_per_week=5.0, + irregular_hours_per_week=0.0, + ece_hours_per_week=5.0, + ) + measured[HOURS] = 1.0 + combined = NSECEChildcareSource( + pd.concat([source.children, measured], ignore_index=True), + Weights(np.array([1.0, 1.0]), WeightKind.DESIGN), + source.source_receipt, + ) + observed_recipient = people.copy() + observed_recipient[HOURS] = 1.0 + for c in (MONTH, DAYS, HOURS): + observed_recipient[f"{c}_source"] = "donor:measured" + outside = people.copy() + outside["age"] = 30 + for c in (MONTH, DAYS, HOURS): + outside[c] = 0.0 + outside[f"{c}_source"] = "inherited_engine_baseline" + people = pd.concat([people, observed_recipient, outside], ignore_index=True) + alternative = noncalendar_sensitivity_source(combined, day_shift=-1) + before_order = combined.children.sort_values([DAYS, HOURS]).donor_id.tolist() + after_order = alternative.children.sort_values([DAYS, HOURS]).donor_id.tolist() + assert before_order == after_order[::-1] + result, audit = paired_noncalendar_attendance(people, combined, alternative) + assert result[0, 1] == 4 + np.testing.assert_array_equal(result[1:], people.iloc[1:][[MONTH, DAYS, HOURS]]) + assert audit["changed_people"] == 1 + assert audit["bridge_assigned_people"] == 1 diff --git a/packages/microcosm-build/tests/engine_free/us/test_us_spine_blindness.py b/packages/microcosm-build/tests/engine_free/us/test_us_spine_blindness.py index 2c5a35548..cf2d54c4c 100644 --- a/packages/microcosm-build/tests/engine_free/us/test_us_spine_blindness.py +++ b/packages/microcosm-build/tests/engine_free/us/test_us_spine_blindness.py @@ -251,6 +251,13 @@ "block_ladder_sources.py", "capital_gain_distributions.py", "casualty_losses.py", + # Opt-in normalized-donor preparation; not a registered build stage. + # Still scanned for source-spine access by the all-runtime guard. + "childcare_attendance.py", + "childcare_attendance_receipt.py", # Artifact lineage and integrity; no treatment. + "childcare_attendance_stage.py", # Licensed source extension after relationship/hours inputs. + "childcare_population.py", # ASEC relationship harmonization for candidate builds. + "childcare_sensitivity.py", # Local assumption and benefit diagnostics. # Reviewed Chronicle feed pin loader; no population treatment. Remains # subject to the all-runtime source-identity scan. "chronicle_feed.py", @@ -274,6 +281,14 @@ "medicaid_take_up.py", "misc_itemized.py", "nonzero_shares.py", + # Hash-verified local NSECE source adapter and opt-in candidate Frame step. + "nsece_childcare.py", + "nsece_childcare_assessment.py", # Source selection and household validation. + "nsece_childcare_sibling_validation.py", # Whole-household schedule diagnostics. + "nsece_childcare_dependence.py", # Household dependence estimation. + "nsece_childcare_pooling.py", # Experimental donor pooling; no source-spine routing. + "nsece_childcare_qrf.py", # Experimental canonical conditional matching. + "nsece_childcare_bridge.py", # Source measurement completion; no spine routing. "operator_boundary.py", # Raw-stage validator; no population treatment. "org_wages.py", "parity_reference.py", @@ -3472,13 +3487,10 @@ def test_pool_build_tool_import_graph_is_source_spine_blind() -> None: for tool in _SPINE_BLIND_BUILD_TOOLS: runtime_graph, missing_modules = _us_runtime_import_graph(tool) - # 73 = main's 70 plus spm_independence_role.py, spm_role_source.py and - # spm_composition.py, reached because the pool's engine-input - # projection names the SPM role as a required source input (#893). - # All three are classified in _OTHER_US_RUNTIME_MODULES and scanned - # below like every other reached module. - assert len(runtime_graph) == 73, ( - f"{tool.name} must reach the pinned 73-module runtime graph; " + # Main's 73 modules plus the two attendance integrity modules. + # Every reached module remains classified and scanned below. + assert len(runtime_graph) == 75, ( + f"{tool.name} must reach the pinned 75-module runtime graph; " f"reached {len(runtime_graph)}" ) assert not missing_modules, ( diff --git a/packages/microcosm-calibrate/src/microcosm/calibrate/geography_constants.py b/packages/microcosm-calibrate/src/microcosm/calibrate/geography_constants.py index 058cd6c94..1478bf849 100644 --- a/packages/microcosm-calibrate/src/microcosm/calibrate/geography_constants.py +++ b/packages/microcosm-calibrate/src/microcosm/calibrate/geography_constants.py @@ -18,6 +18,7 @@ "US_STATE_FIPS_TO_POSTAL", "US_STATE_NUMERIC_FIPS_TO_POSTAL", "US_STATE_POSTAL_TO_NUMERIC_FIPS", + "US_STATE_NUMERIC_FIPS_TO_CENSUS_REGION", ] @@ -165,3 +166,37 @@ US_STATE_POSTAL_TO_NUMERIC_FIPS: Mapping[str, int] = MappingProxyType( {postal: fips for fips, postal in US_STATE_NUMERIC_FIPS_TO_POSTAL.items()} ) + + +# Census region codes, https://www2.census.gov/geo/pdfs/maps-data/maps/reference/us_regdiv.pdf +_US_CENSUS_REGION_POSTAL_CODES = { + 1: ("CT", "ME", "MA", "NH", "RI", "VT", "NJ", "NY", "PA"), + 2: ("IN", "IL", "MI", "OH", "WI", "IA", "KS", "MN", "MO", "NE", "ND", "SD"), + 3: ( + "DE", + "DC", + "FL", + "GA", + "MD", + "NC", + "SC", + "VA", + "WV", + "AL", + "KY", + "MS", + "TN", + "AR", + "LA", + "OK", + "TX", + ), + 4: ("AZ", "CO", "ID", "MT", "NV", "NM", "UT", "WY", "AK", "CA", "HI", "OR", "WA"), +} +US_STATE_NUMERIC_FIPS_TO_CENSUS_REGION: Mapping[int, int] = MappingProxyType( + { + US_STATE_POSTAL_TO_NUMERIC_FIPS[postal]: region + for region, states in _US_CENSUS_REGION_POSTAL_CODES.items() + for postal in states + } +) diff --git a/test_support/microcosm_build/frame_serializer_registry.py b/test_support/microcosm_build/frame_serializer_registry.py index c5ac485a6..f5fd5465c 100644 --- a/test_support/microcosm_build/frame_serializer_registry.py +++ b/test_support/microcosm_build/frame_serializer_registry.py @@ -359,20 +359,41 @@ def _round_trip_fiscal_checkpoint( ) +def _round_trip_childcare_candidate( + tmp_path: Path, nullable_case: str +) -> BooleanRoundTrip: + pytest.importorskip("tables") + from microcosm.build.us_runtime.childcare_attendance_stage import ( + _write_childcare_candidate_person_table, + ) + + source = _dtype_family_table(nullable_case) + before = source.copy(deep=True) + path = tmp_path / "childcare-candidate.h5" + receipt = {"childcare_attendance_stage": {"test_receipt": "preserved"}} + # Unrelated frame metadata must never reach the persisted receipt. + _write_childcare_candidate_person_table( + path, source, {**receipt, "unrelated_metadata": "dropped"} + ) + with pd.HDFStore(path, mode="r") as store: + loaded = read_frame_table(store, "person") + assert json.loads(store["_childcare_attendance_receipt"].iloc[0]) == receipt + return _semantic_observation(source, before, loaded) + + def _round_trip_us_annual_static_aging( tmp_path: Path, nullable_case: str ) -> BooleanRoundTrip: __import__("policyengine_us") from microcosm.build.us_annual_static_aging import _write_year + from microcosm.frame.materialize import engine_tables source = _dtype_family_table(nullable_case) before = source.copy(deep=True) frame = _us_frame(source) path = tmp_path / "annual.h5" try: - _write_year( - path, {entity: frame.table(entity) for entity in frame.entities}, 2025 - ) + _write_year(path, engine_tables(frame, weighted_entities=("household",)), 2025) finally: pd.testing.assert_frame_equal( source, before, check_exact=True, check_dtype=True @@ -398,6 +419,7 @@ def _round_trip_spm_role_projection( ROUND_TRIP_ADAPTERS: dict[str, RoundTripAdapter] = { + "nsece_childcare_native_candidate": _round_trip_childcare_candidate, "frame_checkpoint": _round_trip_frame_checkpoint, "nullable_us_h5": _round_trip_nullable_us_h5, "uk_single_year_h5": _round_trip_uk_single_year, diff --git a/test_support/microcosm_build/us_childcare_attendance.py b/test_support/microcosm_build/us_childcare_attendance.py new file mode 100644 index 000000000..11a15b768 --- /dev/null +++ b/test_support/microcosm_build/us_childcare_attendance.py @@ -0,0 +1,54 @@ +# ruff: noqa: F401 +"""Behavioral contracts for the opt-in childcare attendance donor primitive. + +All donors below are synthetic test records, not survey estimates. +""" + +import numpy as np +import pandas as pd +import pytest +from pandas.testing import assert_frame_equal + +from microcosm.build.us_runtime.childcare_attendance import ( + US_CHILDCARE_ATTENDANCE_COLUMNS, + impute_us_childcare_attendance, +) +from microcosm.frame import WeightKind, Weights + +MONTH, DAYS, HOURS = US_CHILDCARE_ATTENDANCE_COLUMNS + + +def _donors(): + return pd.DataFrame( + { + "donor_id": ["none", "part", "full"], + "age": [3, 3, 3], + MONTH: [0, 13, 22], + DAYS: [0.0, 3.0, 5.0], + HOURS: [0.0, 4.0, 8.0], + } + ) + + +def _people(count=1): + return pd.DataFrame( + {"person_source_id": [f"c:{i}" for i in range(count)], "age": [3] * count} + ) + + +def _impute(person, donor=None, weights=None, **kwargs): + donor = _donors() if donor is None else donor + return impute_us_childcare_attendance( + person, + donor, + donor_weights=Weights( + np.ones(len(donor)) if weights is None else np.asarray(weights), + WeightKind.DESIGN, + ), + match_columns=kwargs.pop("match_columns", ("age",)), + seed=kwargs.pop("seed", 42), + **kwargs, + ) + + +__all__ = [name for name in globals() if not name.startswith("__")] diff --git a/test_support/microcosm_build/us_nsece_childcare.py b/test_support/microcosm_build/us_nsece_childcare.py new file mode 100644 index 000000000..82ef68a0f --- /dev/null +++ b/test_support/microcosm_build/us_nsece_childcare.py @@ -0,0 +1,198 @@ +# ruff: noqa: F401 +"""Synthetic source-code and Frame/export contracts; no NSECE microdata in CI.""" + +import json +from types import SimpleNamespace + +import numpy as np +import pandas as pd +import pytest +from pandas.testing import assert_frame_equal + +from microcosm.build.frame_checkpoint import ( + load_frame_checkpoint, + write_frame_checkpoint, +) +from microcosm.build.us_runtime import childcare_attendance_stage as stage +from microcosm.build.us_runtime.childcare_attendance import ( + US_CHILDCARE_ATTENDANCE_COLUMNS, +) +from microcosm.build.us_runtime.childcare_attendance_receipt import ( + assert_bound_childcare_attendance, + restore_native_childcare_receipt, +) +from microcosm.build.us_runtime.childcare_population import ( + harmonize_asec_childcare_predictors, +) +from microcosm.build.us_runtime.nsece_childcare import ( + NSECE_CALENDAR_BLOCKS, + NSECE_CHILD_INDICES, + NSECE_PROVIDER_INDICES, + NSECEChildcareSource, + assert_childcare_attendance_exportable, + derive_nsece_childcare, + load_nsece_childcare, + nsece_childcare_calendar_columns, + nsece_childcare_household_columns, + nsece_childcare_validation_report, + with_us_nsece_childcare_attendance, +) +from microcosm.build.us_runtime.release_input_coverage import ( + ReleaseInputColumn, + ReleaseInputCoverageManifest, + us_release_input_coverage_gate, +) +from microcosm.frame import US_SCHEMA, Frame, WeightKind, Weights +from test_support.paths import paths_for + +MONTH, DAYS, HOURS = US_CHILDCARE_ATTENDANCE_COLUMNS + + +REPOSITORY_ROOT = paths_for("microcosm-build").repository + + +def _raw(n=1): + household = pd.DataFrame( + -9.0, index=range(n), columns=nsece_childcare_household_columns() + ) + calendar = pd.DataFrame( + -9.0, index=range(n), columns=nsece_childcare_calendar_columns() + ) + for table in (household, calendar): + table["HH4_METH_CASEID"] = np.arange(1, n + 1) + household["HH4_METH_QUEXVERSION"] = 1 + household["HH4_REGION"] = 1 + household["HH4_PARWORK_STATUS"] = 2 + household["HH4_RPARENT"] = 1 + household["HH4_METH_WEIGHT"] = 100.0 + household["HH4_ECON_INCOME_ANNUAL"] = 40_000 + for child in NSECE_CHILD_INDICES: + household[f"HHC4_METH_WEIGHT_{child}"] = np.nan + household[f"HH4_MISSING_STATUS_CC_{child}"] = 0 + household["HHC4_AGE_AT_USAGE_1"] = 36 + household["HHC4_METH_WEIGHT_1"] = 100.0 + household["HH4_MISSING_STATUS_CC_1"] = 2 + for provider in NSECE_PROVIDER_INDICES: + household[f"HH4_TYPEOFCARE_AGG_1_{provider}"] = -8 + household["HH4_TYPEOFCARE_AGG_1_1"] = 4 + for block in range(1, NSECE_CALENDAR_BLOCKS + 1): + calendar[f"HH4_CHCAL_R_1_{block}"] = 0 + return household, calendar + + +def _care(calendar, *, row=0, day=0, hours=4, provider=1): + start = day * 96 + 9 * 4 + 1 + columns = [f"HH4_CHCAL_R_1_{b}" for b in range(start, start + hours * 4)] + calendar.loc[row, columns] = provider + + +def _frame(*, parent_observed=True): + person = pd.DataFrame( + {"person_id": [1, 2], "person_source_id": ["adult", "child"], "age": [30, 3]} + ) + tables = {} + for entity in US_SCHEMA.group_entities: + person[f"person_{entity}_id"] = 1 + tables[entity] = pd.DataFrame({f"{entity}_id": [1]}) + if parent_observed: + for column in US_CHILDCARE_ATTENDANCE_COLUMNS: + person[column] = [0.0, np.nan] + tables["person"] = person + return Frame( + tables, + US_SCHEMA, + {"household": Weights(np.array([100.0]), WeightKind.DESIGN)}, + metadata={"existing_receipt": "preserved"}, + ) + + +def _source(): + hh, cal = _raw() + for day in range(5): + _care(cal, day=day, hours=8) + return derive_nsece_childcare(hh, cal) + + +def _asec_frame(): + frame = _frame() + tables = {e: frame.table(e).copy() for e in frame.entities} + tables["person"]["A_LINENO"] = [1, 2] + tables["person"]["PEPAR1"] = [-1, 1] + tables["person"]["PEPAR2"] = [-1, -1] + tables["person"]["hours_worked_last_week"] = [40, 0] + tables["person"]["PTOTVAL"] = [40000, 0] + tables["person"]["source_year"] = 2023 + tables["household"]["state_fips"] = 25 + return Frame( + tables, + frame.schema, + {"household": frame.weights_for("household")}, + metadata=frame.metadata, + ) + + +def _replace(frame, *, people=None, metadata=None): + tables = {e: frame.table(e).copy() for e in frame.entities} + if people is not None: + tables["person"] = people + return Frame( + tables, + frame.schema, + {e: frame.weights_for(e) for e in frame.weighted_entities}, + metadata=frame.metadata if metadata is None else metadata, + ) + + +def _candidate(): + return with_us_nsece_childcare_attendance( + _frame(), _source(), seed=915, match_columns=("age",) + ) + + +def _sibling_source(): + + rows = [] + for household in range(100): + size = 1 if household % 2 else 3 + for child in range(size): + days = 5.0 if size == 1 else 0.0 + rows.append( + { + "donor_id": f"h{household}:c{child}", + "source_household_id": f"h{household}", + "age": 3, + "childcare_household_size": size, + "region": 1, + "parent_work_status": 2, + "income_band": 1, + "attendance_status": "complete", + "household_weight": 1.0, + "child_weight": 1.0, + MONTH: 22.0 if days else 0.0, + DAYS: days, + HOURS: 8.0 if days else 0.0, + } + ) + children = pd.DataFrame(rows) + return NSECEChildcareSource( + children, Weights(np.ones(len(children)), WeightKind.DESIGN), {} + ) + + +def _paired_sensitivity_fixture(): + source = _source() + source.children["attendance_status"] = "summary_bridge" + source.children["regular_hours_per_week"] = 12.0 + source.children["irregular_hours_per_week"] = 1.0 + source.children[HOURS] = 13 / source.children[DAYS] + source.children["ece_hours_per_week"] = 13.0 + child = source.children.iloc[0] + people = pd.DataFrame( + {"age": [child.age], **{c: [child[c]] for c in (MONTH, DAYS, HOURS)}} + ) + for c in (MONTH, DAYS, HOURS): + people[f"{c}_source"] = f"donor:{child.donor_id}" + return people, source + + +__all__ = [name for name in globals() if not name.startswith("__")] diff --git a/tools/build_us_exact_k_ladder_release.py b/tools/build_us_exact_k_ladder_release.py index 17668c5e6..9ec20d607 100644 --- a/tools/build_us_exact_k_ladder_release.py +++ b/tools/build_us_exact_k_ladder_release.py @@ -40,6 +40,12 @@ ``ssi_take_up_prior_weight_basis`` and ``ssi_take_up_prior_weight_basis_sha256`` fields for the house one-retry delivery-gate protocol. + +The optional ``childcare_attendance`` object supplies ``household_tsv`` and +``calendar_tsv`` paths, an explicit ``inherit_outside_domain_baseline`` boolean, +and an optional ``asec_source_cache`` directory. Paths are relative to the config +file; survey hashes come from the packaged NSECE source contract. Without this +object, the pool must already carry valid, bound attendance inputs. """ # The sibling house builder is importable only after its tools directory is @@ -76,6 +82,16 @@ _RELEASE_ID = re.compile(r"[A-Za-z0-9-]+") +@dataclass(frozen=True) +class ChildcareAttendanceConfig: + """Local survey inputs; the source contract owns their immutable pins.""" + + household_tsv: Path + calendar_tsv: Path + inherit_outside_domain_baseline: bool + asec_source_cache: Path | None + + @dataclass(frozen=True) class LadderReleaseConfig: """Validated, path-resolved launcher configuration.""" @@ -101,6 +117,7 @@ class LadderReleaseConfig: refit_l2_lambda: float release_id: str repo_id: str + childcare_attendance: ChildcareAttendanceConfig | None = None def _parse_args(argv: Sequence[str] | None = None) -> argparse.Namespace: @@ -137,6 +154,7 @@ def _read_config(path: Path) -> LadderReleaseConfig: "calibration", "release", }, + optional={"childcare_attendance"}, label=f"ladder config {path}", ) if ( @@ -298,6 +316,45 @@ def _read_config(path: Path) -> LadderReleaseConfig: refit_l2_lambda=refit_l2_lambda, release_id=release_id, repo_id=repo_id, + childcare_attendance=( + _read_childcare_attendance(root["childcare_attendance"], config_dir) + if "childcare_attendance" in root + else None + ), + ) + + +def _read_childcare_attendance( + value: object, config_dir: Path +) -> ChildcareAttendanceConfig: + source = _object(value, label="childcare_attendance") + _keys( + source, + required={ + "household_tsv", + "calendar_tsv", + "inherit_outside_domain_baseline", + }, + optional={"asec_source_cache"}, + label="childcare_attendance", + ) + inherit = source["inherit_outside_domain_baseline"] + if not isinstance(inherit, bool): + raise ValueError( + "childcare_attendance.inherit_outside_domain_baseline must be a boolean." + ) + + def source_path(key: str) -> Path: + raw = _nonempty_string(source[key], label=f"childcare_attendance.{key}") + return (config_dir / raw).resolve() + + return ChildcareAttendanceConfig( + household_tsv=source_path("household_tsv"), + calendar_tsv=source_path("calendar_tsv"), + inherit_outside_domain_baseline=inherit, + asec_source_cache=( + source_path("asec_source_cache") if "asec_source_cache" in source else None + ), ) @@ -390,6 +447,32 @@ def _validate_pins_and_resolve_k( f"{observed_prior_basis_sha256}, expected " f"{config.ssi_take_up_prior_weight_basis_sha256}." ) + if config.childcare_attendance is not None: + from microcosm.build.us_runtime.childcare_attendance import ( + childcare_attendance_contract, + ) + + source = config.childcare_attendance + pins = { + artifact["dataset"]: artifact["sha256"] + for artifact in childcare_attendance_contract()["artifacts"] + } + for dataset, path in ( + ("DS5", source.household_tsv), + ("DS4", source.calendar_tsv), + ): + if _sha256(path) != pins[dataset]: + raise ValueError( + f"Childcare attendance {dataset} SHA-256 mismatch: {path}. " + "Use the TSV from the pinned NSECE release." + ) + if ( + source.asec_source_cache is not None + and not source.asec_source_cache.is_dir() + ): + raise ValueError( + "childcare_attendance.asec_source_cache must be a directory." + ) return k, pool_manifest @@ -452,6 +535,22 @@ def _builder_argv( str(config.ssi_take_up_prior_weight_basis_sha256), ] ) + if config.childcare_attendance is not None: + source = config.childcare_attendance + argv.extend( + [ + "--childcare-attendance-household-tsv", + str(source.household_tsv), + "--childcare-attendance-calendar-tsv", + str(source.calendar_tsv), + ] + ) + if source.asec_source_cache is not None: + argv.extend( + ["--childcare-attendance-asec-cache", str(source.asec_source_cache)] + ) + if source.inherit_outside_domain_baseline: + argv.append("--childcare-attendance-inherit-outside-domain-baseline") return argv diff --git a/tools/build_us_fiscal_refresh_release.py b/tools/build_us_fiscal_refresh_release.py index e421049cf..2b09e6cf0 100644 --- a/tools/build_us_fiscal_refresh_release.py +++ b/tools/build_us_fiscal_refresh_release.py @@ -1138,6 +1138,14 @@ def _parse_args(argv: Sequence[str] | None = None) -> argparse.Namespace: ) parser.add_argument("--out", type=Path, required=True) parser.add_argument("--release-id") + parser.add_argument("--childcare-attendance-household-tsv", type=Path) + parser.add_argument("--childcare-attendance-calendar-tsv", type=Path) + parser.add_argument("--childcare-attendance-asec-cache", type=Path) + parser.add_argument( + "--childcare-attendance-inherit-outside-domain-baseline", + action="store_true", + help="Retain the engine baseline outside modeled ages 0-12; does not assert older-child nonattendance", + ) parser.add_argument( "--incumbent-diagnostics", type=Path, @@ -1748,6 +1756,17 @@ def _parse_args(argv: Sequence[str] | None = None) -> argparse.Namespace: help="Minimum seconds between progress uploads to the staging repo.", ) args = parser.parse_args(argv) + if bool(args.childcare_attendance_household_tsv) != bool( + args.childcare_attendance_calendar_tsv + ): + parser.error("Both NSECE household and calendar TSV paths are required") + if ( + args.childcare_attendance_inherit_outside_domain_baseline + and not args.childcare_attendance_household_tsv + ): + parser.error( + "Outside-domain baseline policy requires an NSECE attendance build" + ) if args.congressional_district_vintage_crosswalk is None: # Every build compiles the same national + state + CD target surface, # translated through the canonical packaged vintage crosswalk unless @@ -2525,6 +2544,7 @@ def _target_frame_checkpoint_identity( ssi_take_up_assignment_sha256: str, selection_identities_sha256: str | None, staged_frame_sha256: str, + childcare_attendance_binding_sha256: str | None = None, selection_mass_protections: tuple[str, ...] = (), ssi_take_up_prior_weight_basis_sha256: object = None, ) -> dict[str, object]: @@ -2540,6 +2560,11 @@ def _target_frame_checkpoint_identity( # same frame still hits, and the writing commit is recorded beside # the identity as information only. "staged_frame_sha256": str(staged_frame_sha256), + # The staged values alone cannot distinguish two attendance recipes + # that happen to emit the same schedules. Bind the verified execution + # as well; reform-vector keys inherit this through the materializer + # identity digest. None is reserved for callers without attendance. + "childcare_attendance_binding_sha256": childcare_attendance_binding_sha256, "weeks_unemployed_source_sha256": str(weeks_unemployed_source_sha256), "policyengine_us_version": str(policyengine_us_version), "seed": int(seed), @@ -2993,7 +3018,31 @@ def _load_frame(path: Path, *, expected_sha256: str | None = None) -> Frame: {"household": Weights(weights, WeightKind.CALIBRATED)}, ) refuse_denied_frame(frame, consumer=consumer) - return frame + from microcosm.build.us_runtime.childcare_attendance_receipt import ( + restore_native_childcare_receipt, + ) + + return restore_native_childcare_receipt(path, frame) + + +def _require_bound_childcare_attendance(frame: Frame) -> dict[str, object]: + """Refuse before calibration a build that cannot export required attendance.""" + from microcosm.build.us_runtime.childcare_attendance_receipt import ( + assert_bound_childcare_attendance, + ) + from microcosm.build.us_runtime.nsece_childcare import ( + assert_childcare_attendance_exportable, + ) + + try: + assert_childcare_attendance_exportable(frame) + return assert_bound_childcare_attendance(frame) + except ValueError as error: + raise RuntimeError( + "Release gates failed: Childcare-attendance inputs failed: " + f"{error} Supply --childcare-attendance-household-tsv and " + "--childcare-attendance-calendar-tsv." + ) from error def _resolve_selection_source(args): @@ -3694,6 +3743,7 @@ def _with_aca_marketplace_source_outputs( frame.schema, {entity: frame.weights_for(entity) for entity in frame.weighted_entities}, frame.strata, + metadata=frame.metadata, ) @@ -8056,6 +8106,7 @@ def _with_social_security_component_value_repair( {entity: frame.weights_for(entity) for entity in frame.weighted_entities}, frame.strata, mass_log=frame.mass_log, + metadata=frame.metadata, ) return repaired, { "method": "rescale_social_security_component_leaves_to_ssa_targets", @@ -8141,6 +8192,7 @@ def _with_non_sch_d_cgd_value_repair( {entity: frame.weights_for(entity) for entity in frame.weighted_entities}, frame.strata, mass_log=frame.mass_log, + metadata=frame.metadata, ) return repaired, { "method": "rescale_non_sch_d_capital_gains_to_soi_table_1_4_fact", @@ -12241,6 +12293,25 @@ def _main(argv: Sequence[str] | None = None) -> None: for failure in hours_worked_gate.failures ) ) + # The attendance harmonizer reads hours_worked_last_week, so it follows the + # childcare-expense and hours producers. + if args.childcare_attendance_household_tsv is not None: + from microcosm.build.us_runtime.childcare_attendance_stage import ( + with_us_childcare_attendance_inputs, + ) + + base_frame = with_us_childcare_attendance_inputs( + base_frame, + household_tsv=args.childcare_attendance_household_tsv, + calendar_tsv=args.childcare_attendance_calendar_tsv, + asec_source_cache=args.childcare_attendance_asec_cache, + seed=args.seed, + inherit_outside_domain_baseline=args.childcare_attendance_inherit_outside_domain_baseline, + ) + else: + # Attendance is a required, non-waivable export input: without the + # source stage this run can only end red after calibration. + _require_bound_childcare_attendance(base_frame) if telemetry is not None: telemetry.stage( "snap_take_up_inputs", @@ -13367,6 +13438,8 @@ def _main(argv: Sequence[str] | None = None) -> None: target_specs = (*target_specs, *selection_mass_protection_specs) # microcosm#956: digest the very frame handed to the materializer below, # so a checkpoint hit proves the same staged inputs, not only the same base. + # Recheck after intervening stages and before any checkpoint/cache lookup. + attendance_binding = _require_bound_childcare_attendance(base_frame) staged_frame_sha256 = _staged_frame_sha256(base_frame) target_frame_checkpoint_identity = _target_frame_checkpoint_identity( base_dataset_sha256=base_dataset_sha256, @@ -13383,6 +13456,7 @@ def _main(argv: Sequence[str] | None = None) -> None: None if selection_source is None else selection_source.identities_sha256 ), staged_frame_sha256=staged_frame_sha256, + childcare_attendance_binding_sha256=attendance_binding["binding_sha256"], selection_mass_protections=selection_mass_protections, ssi_take_up_prior_weight_basis_sha256=( None @@ -14251,8 +14325,14 @@ def _main(argv: Sequence[str] | None = None) -> None: ) input_coverage_gate = None if input_coverage_gate is not None: - input_coverage_failed = ( - not input_coverage_gate.passed and not args.allow_input_coverage_gaps + # Attendance integrity is not waivable: keep its failure in the batched + # report so the run retains its weight evidence instead of dying at + # the final native write below. + attendance_unbound = ( + input_coverage_gate.details.get("childcare_attendance") is None + ) + input_coverage_failed = not input_coverage_gate.passed and ( + attendance_unbound or not args.allow_input_coverage_gaps ) if input_coverage_failed: terminal_gate_failures.extend( @@ -14507,7 +14587,23 @@ def _main(argv: Sequence[str] | None = None) -> None: # the batched pre-export raise so a gate-failed run never produces it. # microcosm#443: #437 dropped this call while inserting the batched raise, # so attempts 13/14 smoke-scored a stale artifact from a prior run. + from microcosm.build.us_runtime.childcare_attendance_receipt import ( + assert_bound_childcare_attendance, + ) + from microcosm.build.us_runtime.childcare_attendance_stage import ( + persist_native_childcare_receipt, + ) + from microcosm.build.us_runtime.nsece_childcare import ( + assert_childcare_attendance_exportable, + ) + + # Attendance integrity is not waivable by generic coverage/evidence flags. + assert_childcare_attendance_exportable(export_frame) + assert_bound_childcare_attendance(export_frame) release_engine.write_dataset(export_frame, dataset_path, period=PERIOD) + attendance_source_evidence = persist_native_childcare_receipt( + dataset_path, export_frame + ) # microcosm#1026: the stored-input gate above graded a model of the # writer's output; the written bytes are graded whatever the gate reached # and must earn the same verdict (no refusal, if the gate could not @@ -14677,6 +14773,7 @@ def _main(argv: Sequence[str] | None = None) -> None: }, ) coverage["fiscal_target_sources"] = _fiscal_target_source_provenance(target_specs) + coverage["childcare_attendance"] = attendance_source_evidence if congressional_district_vintage_crosswalk_metadata is not None: coverage["congressional_district_vintage_crosswalk"] = ( congressional_district_vintage_crosswalk_metadata diff --git a/tools/build_us_release_input_coverage_manifest.py b/tools/build_us_release_input_coverage_manifest.py index ee62c43c8..a72cca4c0 100644 --- a/tools/build_us_release_input_coverage_manifest.py +++ b/tools/build_us_release_input_coverage_manifest.py @@ -42,6 +42,9 @@ import json from pathlib import Path +from microcosm.build.us_runtime.childcare_attendance import ( + US_CHILDCARE_ATTENDANCE_COLUMNS, +) from microcosm.build.us_runtime.release_input_coverage import ( REFERENCE_ECPS_LAYER_RENAMES, project_ecps_parity_known_gap_names, @@ -75,6 +78,7 @@ # Schedule-D leg. These later inputs are hard requirements because the # shipped validation provisions must bind. POST_REFERENCE_ECPS_REQUIRED_INPUTS = ( + *US_CHILDCARE_ATTENDANCE_COLUMNS, "fsla_overtime_premium", "qualified_passenger_vehicle_loan_interest", "traditional_401k_contributions_desired", @@ -1548,6 +1552,10 @@ def build_manifest() -> dict: "gate fails until the asset stage is restored (Deliverable " "2). Currently absent — this is the intended red gate." ) + elif name in US_CHILDCARE_ATTENDANCE_COLUMNS: + column["note"] = ( + "Person-level NSECE attendance source extension (#915): requires persisted signal; missing inputs must not silently become engine defaults. The modeled age domain and outside-domain baseline policy are recorded in source coverage." + ) elif name in POST_REFERENCE_COLUMN_NOTES: column["note"] = POST_REFERENCE_COLUMN_NOTES[name] columns[name] = column @@ -1601,7 +1609,7 @@ def build_manifest() -> dict: "qualified_passenger_vehicle_loan_interest, five desired " "retirement-contribution inputs, " "meets_ssi_disability_criteria required by shipped validation " - "probes, the #282 Schedule-D capital-gain-distributions " + "probes, the three NSECE child attendance inputs (#915), and the #282 Schedule-D capital-gain-distributions " "route leg schedule_d_capital_gain_distributions " "(PolicyEngine/microcosm#462), the three ASEC reported-receipt " "inputs receives_wic, receives_snap, receives_tanf that the ACS " diff --git a/tools/generate_us_bundle_from_constants.py b/tools/generate_us_bundle_from_constants.py index 5dc45835d..60deba6c5 100644 --- a/tools/generate_us_bundle_from_constants.py +++ b/tools/generate_us_bundle_from_constants.py @@ -255,9 +255,11 @@ def country_manifest() -> dict[str, object]: } for kind in DOMAIN_KINDS ] + # The local source extension uses the existing SourceStageSpec compatibility + # interpreter; the three generation-0 projections remain byte-frozen. legacy_rows = [ {"path": path, "kind": "legacy_json", "schema_id": "legacy_json"} - for path in LEGACY_RESOURCE_PATHS + for path in (*LEGACY_RESOURCE_PATHS, "childcare_attendance_source.json") ] return {"schema_version": 1, "country": "us", "resources": typed_rows + legacy_rows} diff --git a/tools/prepare_us_childcare_attendance.py b/tools/prepare_us_childcare_attendance.py new file mode 100644 index 000000000..6937c0acc --- /dev/null +++ b/tools/prepare_us_childcare_attendance.py @@ -0,0 +1,296 @@ +#!/usr/bin/env python3 +"""Prepare a local NSECE attendance candidate and aggregate validation report. + +No source downloads, remote uploads or release publication occur. Download the +DS4/DS5 TSVs under the ICPSR terms first. A Frame checkpoint is optional; source +validation is useful before a population candidate is available. +""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import platform +from importlib.metadata import version +from pathlib import Path + +from microcosm.build.frame_checkpoint import ( + load_frame_checkpoint, + write_frame_checkpoint, +) +from microcosm.build.us_runtime import childcare_attendance, nsece_childcare +from microcosm.build.us_runtime.childcare_attendance_receipt import ( + childcare_attendance_public_metadata, +) +from microcosm.build.us_runtime.childcare_attendance_stage import ( + export_native_childcare_candidate, + inherit_outside_domain_attendance_baseline, + with_us_childcare_attendance_inputs, +) +from microcosm.build.us_runtime.childcare_population import ( + harmonize_asec_childcare_predictors, +) +from microcosm.build.us_runtime.h5_io import load_legacy_calibrated_us_h5 +from microcosm.build.us_runtime.nsece_childcare import ( + NSECE_CHILDCARE_FALLBACK_COLUMNS, + NSECE_CHILDCARE_MATCH_COLUMNS, + load_nsece_childcare, + nsece_childcare_validation_report, + with_us_nsece_childcare_attendance, +) +from microcosm.build.us_runtime.nsece_childcare_assessment import ( + assess_noncalendar_bridge, + assess_nsece_childcare, +) +from microcosm.build.us_runtime.nsece_childcare_bridge import ( + bridge_nsece_noncalendar_attendance, +) +from microcosm.build.us_runtime.nsece_childcare_dependence import ( + fit_nsece_sibling_dependence, +) +from microcosm.build.us_runtime.nsece_childcare_sibling_validation import ( + assess_sibling_schedules, +) +from microcosm.frame import Frame + + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--household-tsv", type=Path, required=True) + parser.add_argument("--calendar-tsv", type=Path, required=True) + parser.add_argument("--report", type=Path, required=True) + parser.add_argument("--seed", type=int, default=915) + parser.add_argument( + "--model-sibling-dependence", + action="store_true", + help="Fit measured household dependence for shared-rank schedule draws", + ) + parser.add_argument( + "--bridge-noncalendar", + action="store_true", + help="Use measured regular hours to impute missing days and irregular care", + ) + parser.add_argument( + "--extended-assessment", + action="store_true", + help="Run household cross-validation, instrument transport and masked-calendar checks", + ) + parser.add_argument( + "--match-columns", nargs="+", default=list(NSECE_CHILDCARE_MATCH_COLUMNS) + ) + inputs = parser.add_mutually_exclusive_group() + inputs.add_argument("--input-checkpoint", type=Path) + inputs.add_argument("--asec-population-h5", type=Path) + parser.add_argument( + "--asec-source-cache", + type=Path, + help="Verified Census pppub23/24/25.csv files for omitted PTOTVAL", + ) + parser.add_argument( + "--population-sha256", help="Required exact hash for --asec-population-h5" + ) + parser.add_argument( + "--sparse-cell-fallback", + action="store_true", + help="Explicitly use age/parent-work then age-only donor matches", + ) + parser.add_argument("--output-checkpoint", type=Path) + parser.add_argument("--output-native-h5", type=Path) + parser.add_argument( + "--inherit-outside-domain-baseline", + action="store_true", + help="Explicitly retain baseline outside ages 0-12 for export; not observed nonattendance", + ) + parser.add_argument( + "--production-stage", + action="store_true", + help="Run the same complete attendance stage used by the fiscal refresh builder", + ) + args = parser.parse_args() + if args.production_stage: + if not args.asec_population_h5: + parser.error( + "The production-stage qualification requires a native ASEC parent" + ) + args.bridge_noncalendar = args.model_sibling_dependence = ( + args.sparse_cell_fallback + ) = True + input_path = args.input_checkpoint or args.asec_population_h5 + if bool(input_path) != bool(args.output_checkpoint): + parser.error( + "A population input and --output-checkpoint must be supplied together" + ) + if args.asec_population_h5 and ( + not args.population_sha256 + or _sha256(args.asec_population_h5) != args.population_sha256 + ): + parser.error("The ASEC population must match --population-sha256") + if ( + args.sparse_cell_fallback + and tuple(args.match_columns) != NSECE_CHILDCARE_MATCH_COLUMNS + ): + parser.error("The reviewed fallback requires the canonical matching fields") + if args.output_native_h5 and ( + not args.asec_population_h5 or not args.output_checkpoint + ): + parser.error( + "Native output requires an exact ASEC population parent and checkpoint output" + ) + outputs = [ + p + for p in (args.report, args.output_checkpoint, args.output_native_h5) + if p is not None + ] + if any(p.exists() for p in outputs): + parser.error( + "Output paths must be new; existing artifacts will not be overwritten" + ) + if len({p.resolve() for p in outputs}) != len(outputs): + parser.error("Report and checkpoint paths must differ") + source = load_nsece_childcare(args.household_tsv, args.calendar_tsv) + report = nsece_childcare_validation_report( + source, seed=args.seed, match_columns=tuple(args.match_columns) + ) + sibling_fit = ( + fit_nsece_sibling_dependence( + source.children, match_columns=tuple(args.match_columns) + ) + if args.model_sibling_dependence + else {"rho": 0.0} + ) + report["sibling_dependence"] = sibling_fit + if args.extended_assessment: + report["selection_and_cross_validation"] = assess_nsece_childcare(source) + report["masked_calendar_validation"] = assess_noncalendar_bridge(source) + report["sibling_schedule_validation"] = assess_sibling_schedules(source) + if args.bridge_noncalendar: + source = bridge_nsece_noncalendar_attendance(source, seed=args.seed) + report["noncalendar_bridge"] = source.source_receipt["noncalendar_bridge"] + report["candidate_frame_written"] = False + report["environment"] = { + package: version(package) + for package in ( + "numpy", + "pandas", + "microcosm-build", + "microcosm-frame", + "policyengine-us", + ) + } + report["environment"]["python"] = platform.python_version() + report["code_sha256"] = { + path.name: _sha256(path) + for path in ( + Path(__file__), + Path(childcare_attendance.__file__), + Path(nsece_childcare.__file__), + *Path(childcare_attendance.__file__).parent.glob("*childcare*.py"), + Path(childcare_attendance.__file__).parent.parent + / "us" + / "childcare_attendance_source.json", + Path(childcare_attendance.__file__).parent + / "education_assistance_source.py", + Path(__file__).resolve().parents[1] + / "packages/microcosm-calibrate/src/microcosm/calibrate/geography_constants.py", + Path(__file__).resolve().parents[1] / "uv.lock", + ) + } + try: + if input_path is not None: + if args.asec_population_h5: + from microcosm.build.frame_checkpoint import LoadedFrameCheckpoint + + frame = load_legacy_calibrated_us_h5(input_path) + if not args.production_stage: + frame = harmonize_asec_childcare_predictors( + frame, source_cache=args.asec_source_cache + ) + original = LoadedFrameCheckpoint( + frame, {"parent_population_sha256": args.population_sha256} + ) + else: + original = load_frame_checkpoint(input_path) + # The checkpoint protocol deliberately stores Frame receipts as + # external metadata; restore them explicitly rather than dropping + # the parent build's source/ownership evidence. + parent = original.frame + parent = Frame( + {entity: parent.table(entity) for entity in parent.entities}, + parent.schema, + { + entity: parent.weights_for(entity) + for entity in parent.weighted_entities + }, + parent.strata, + mass_log=parent.mass_log, + metadata={ + **parent.metadata, + **original.metadata.get("frame_metadata", {}), + }, + ) + if args.production_stage: + candidate = with_us_childcare_attendance_inputs( + parent, + household_tsv=args.household_tsv, + calendar_tsv=args.calendar_tsv, + asec_source_cache=args.asec_source_cache, + seed=args.seed, + inherit_outside_domain_baseline=args.inherit_outside_domain_baseline, + ) + else: + candidate = with_us_nsece_childcare_attendance( + parent, + source, + seed=args.seed, + match_columns=tuple(args.match_columns), + fallback_match_columns=NSECE_CHILDCARE_FALLBACK_COLUMNS + if args.sparse_cell_fallback + else (), + sibling_dependence=sibling_fit["rho"], + ) + if args.inherit_outside_domain_baseline: + candidate = inherit_outside_domain_attendance_baseline(candidate) + write_frame_checkpoint( + args.output_checkpoint, + candidate, + metadata={ + "artifact_kind": "nsece_childcare_candidate", + "childcare_candidate_only": True, + "parent_checkpoint_metadata": original.metadata, + "parent_checkpoint_sha256": _sha256(input_path), + "frame_metadata": json.loads( + json.dumps(candidate.metadata, default=dict) + ), + }, + ) + report["candidate_frame_written"] = True + report["candidate_checkpoint_sha256"] = _sha256(args.output_checkpoint) + report["parent_population_sha256"] = _sha256(input_path) + report["production_stage_executed"] = args.production_stage + report["candidate_receipts"] = childcare_attendance_public_metadata( + candidate + ) + if args.output_native_h5: + export_native_childcare_candidate( + args.asec_population_h5, candidate, args.output_native_h5 + ) + report["native_candidate_written"] = True + report["native_candidate_sha256"] = _sha256(args.output_native_h5) + except Exception as exc: + report["candidate_error"] = f"{type(exc).__name__}: {exc}" + raise + finally: + args.report.parent.mkdir(parents=True, exist_ok=True) + args.report.write_text(json.dumps(report, indent=2, allow_nan=False) + "\n") + print(f"Validation report: {args.report}") + print("Candidate only; production readiness is not certified.") + + +def _sha256(path: Path) -> str: + with path.open("rb") as stream: + return hashlib.file_digest(stream, "sha256").hexdigest() + + +if __name__ == "__main__": + main() diff --git a/tools/spec_engine_coverage.py b/tools/spec_engine_coverage.py index c066d573c..03080f197 100644 --- a/tools/spec_engine_coverage.py +++ b/tools/spec_engine_coverage.py @@ -41,7 +41,7 @@ REPORT_SCHEMA_VERSION = 3 EXPECTED_POINTER_INVENTORY_SHA256 = ( - "8f655670b9794adae905ede64bdceba6395eeb8d642b6c5896d5c516f1f6a6a7" + "72c746d5f084f96c2b776c65d69acb82b53c26feaa591bfacf2d8d8c878ef01f" ) DEFAULT_REPORT_PATH = ( Path(__file__).resolve().parents[1] diff --git a/tools/validate_us_childcare_calendar_selection.py b/tools/validate_us_childcare_calendar_selection.py new file mode 100644 index 000000000..e3479d7da --- /dev/null +++ b/tools/validate_us_childcare_calendar_selection.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python3 +"""Audit calendar information loss and compare the declared composition model.""" + +from __future__ import annotations + +import argparse +import hashlib +import json +from pathlib import Path + +import numpy as np + +from microcosm.build.us_runtime import ( + nsece_childcare_pooling, + nsece_childcare_sibling_validation, +) +from microcosm.build.us_runtime.childcare_attendance_receipt import ( + attendance_recipe_identity, +) +from microcosm.build.us_runtime.nsece_childcare import load_nsece_childcare +from microcosm.build.us_runtime.nsece_childcare_sibling_validation import ( + assess_sibling_schedules, + coupling_screen_compatibility, +) + + +def calendar_bounds_report(children): + """Design-weighted identification intervals; no missing outcome imputation.""" + selected = children.loc[ + children.age.between(0, 12) & children.questionnaire_version.eq(1) + ] + rows = [] + for name, group in [ + ("all_regular_instrument", selected), + *selected.groupby("attendance_status"), + ]: + weights = group.child_weight.to_numpy() + rows.append( + { + "group": name, + "children": len(group), + "child_weight": float(weights.sum()), + "mean_hours_lower": float( + np.average(group.calendar_ece_hours_lower, weights=weights) + ), + "mean_hours_upper": float( + np.average(group.calendar_ece_hours_upper, weights=weights) + ), + "mean_days_lower": float( + np.average(group.calendar_ece_days_lower, weights=weights) + ), + "mean_days_upper": float( + np.average(group.calendar_ece_days_upper, weights=weights) + ), + "definitely_in_care_share": float( + np.average(group.calendar_ece_hours_lower.gt(0), weights=weights) + ), + "possibly_in_care_share": float( + np.average(group.calendar_ece_hours_upper.gt(0), weights=weights) + ), + "hours_interval_width_le_1_share": float( + np.average( + ( + group.calendar_ece_hours_upper + - group.calendar_ece_hours_lower + ).le(1), + weights=weights, + ) + ), + } + ) + return { + "interpretation": "regular questionnaire only; measured calendar classifications conditional on published completeness status; identification bounds, not confidence intervals or completed schedules", + "comparisons": rows, + } + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--household-tsv", type=Path, required=True) + parser.add_argument("--calendar-tsv", type=Path, required=True) + parser.add_argument("--report", type=Path, required=True) + args = parser.parse_args() + if args.report.exists(): + parser.error("Report path must be new") + source = load_nsece_childcare(args.household_tsv, args.calendar_tsv) + plan = ( + Path(__file__).resolve().parents[1] + / "experiments/us-childcare-attendance/calendar-selection-plan.txt" + ) + report = { + "source": source.source_receipt, + "plan_sha256": hashlib.sha256(plan.read_bytes()).hexdigest(), + "recipe": attendance_recipe_identity(), + "diagnostic_code_sha256": { + path.name: hashlib.sha256(path.read_bytes()).hexdigest() + for path in ( + Path(__file__), + Path(nsece_childcare_pooling.__file__), + Path(nsece_childcare_sibling_validation.__file__), + ) + }, + "production_ready": False, + "interpretation": "fixed model comparison on previously inspected development data; no independent validation claim", + "calendar_bounds": calendar_bounds_report(source.children), + } + print(json.dumps(report["calendar_bounds"]), flush=True) + for name, composition in (("pooled_moments", False), ("composition", True)): + arm = assess_sibling_schedules( + source, + pooled=True, + composition=composition, + include_observed_children=True, + pooling_fit_objective="population_moments", + ) + arm["dependence_only_screen_compatibility"] = coupling_screen_compatibility(arm) + report[name] = arm + print( + name, + "joint failures", + sum(not c["passed"] for c in arm["diagnostic_screen"]["checks"]), + "child failures", + sum( + not c["passed"] + for c in arm["observed_child_validation"]["screen"]["checks"] + ), + flush=True, + ) + args.report.write_text(json.dumps(report, indent=2, allow_nan=False) + "\n") + + +if __name__ == "__main__": + main() diff --git a/tools/validate_us_childcare_household_size.py b/tools/validate_us_childcare_household_size.py new file mode 100644 index 000000000..49283845a --- /dev/null +++ b/tools/validate_us_childcare_household_size.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +"""Compare the declared household-size challenger on separate survey partitions. + +Writes aggregate diagnostics only. It does not alter the population build, +publish artifacts, or turn previously inspected data into external evidence. +""" + +from __future__ import annotations + +import argparse +import hashlib +import json +from pathlib import Path + +from microcosm.build.us_runtime import nsece_childcare_sibling_validation +from microcosm.build.us_runtime.childcare_attendance_receipt import ( + attendance_recipe_identity, +) +from microcosm.build.us_runtime.nsece_childcare import load_nsece_childcare +from microcosm.build.us_runtime.nsece_childcare_sibling_validation import ( + compare_household_size_matching, +) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--household-tsv", type=Path, required=True) + parser.add_argument("--calendar-tsv", type=Path, required=True) + parser.add_argument( + "--partition", choices=("development", "validation"), required=True + ) + parser.add_argument("--report", type=Path, required=True) + args = parser.parse_args() + if args.report.exists(): + parser.error( + "Report path must be new; existing evidence will not be overwritten" + ) + source = load_nsece_childcare(args.household_tsv, args.calendar_tsv) + report = compare_household_size_matching(source, partition=args.partition) + root = Path(__file__).resolve().parents[1] + plan = root / "experiments/us-childcare-attendance/household-size-plan.txt" + report["plan_sha256"] = hashlib.sha256(plan.read_bytes()).hexdigest() + report["recipe"] = attendance_recipe_identity() + report["diagnostic_code_sha256"] = { + path.name: hashlib.sha256(path.read_bytes()).hexdigest() + for path in (Path(__file__), Path(nsece_childcare_sibling_validation.__file__)) + } + args.report.write_text(json.dumps(report, indent=2, allow_nan=False) + "\n") + for arm in ("legacy", "household_size"): + failures = [ + c["metric"] + for c in report[arm]["diagnostic_screen"]["checks"] + if not c["passed"] + ] + print(f"{arm}: {len(failures)}/15 screens failed") + print(json.dumps(report[arm]["larger_households"], indent=2)) + + +if __name__ == "__main__": + main() diff --git a/tools/validate_us_childcare_intervals.py b/tools/validate_us_childcare_intervals.py new file mode 100644 index 000000000..125d0845f --- /dev/null +++ b/tools/validate_us_childcare_intervals.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 +"""Evaluate declared interval-conditioned training and both assumption tilts.""" + +from __future__ import annotations + +import argparse +import hashlib +import json +from pathlib import Path + +import numpy as np +import validate_us_childcare_qrf as qrf_tool + +from microcosm.build.us_runtime import ( + nsece_childcare_pooling, + nsece_childcare_qrf, + nsece_childcare_sibling_validation, +) +from microcosm.build.us_runtime.childcare_attendance_receipt import ( + attendance_recipe_identity, +) +from microcosm.build.us_runtime.nsece_childcare_qrf import ( + QRFChildcareSchedules, + interval_training_rows, +) +from microcosm.build.us_runtime.nsece_childcare_sibling_validation import ( + _household_splits, + _observed_child_summary, +) + + +def _records(model, target, complete): + model.prepare(target) + for _, child in target.iterrows(): + values, _, probability = model.distribution(child) + yield ( + float(child.child_weight), + min(int(child.childcare_household_size), 3), + bool(complete.loc[child.source_household_id]), + np.array( + [ + float(child.childcare_days_per_week > 0), + child.childcare_days_per_week, + child.ece_hours_per_week, + ] + ), + np.average(values, axis=0, weights=probability), + np.average(values**2, axis=0, weights=probability), + ) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--household-tsv", type=Path, required=True) + parser.add_argument("--calendar-tsv", type=Path, required=True) + parser.add_argument("--report", type=Path, required=True) + args = parser.parse_args() + if args.report.exists(): + parser.error("Report path must be new") + source, children = qrf_tool.load_source_children( + args.household_tsv, args.calendar_tsv + ) + records = { + name: [] + for name in ("complete_only", "interval", "lower_hours", "higher_hours") + } + folds = [] + for fold, (train_mask, target_mask) in enumerate( + _household_splits(children, seed=271828, validation_seed=None, partition="all") + ): + train, target = children.loc[train_mask], children.loc[target_mask] + complete = target.groupby("source_household_id").attendance_status.agg( + lambda x: x.eq("complete").all() + ) + observed = target.loc[target.attendance_status.eq("complete")] + base = QRFChildcareSchedules(train) + records["complete_only"].extend(_records(base, observed, complete)) + detail = { + "fold": fold, + "evaluated_children": len(observed), + "household_overlap": 0, + "completions": {}, + } + for name, tilt in (("interval", 0), ("lower_hours", -1), ("higher_hours", 1)): + augmented, audit = interval_training_rows(train, base, tilt=tilt) + model = QRFChildcareSchedules(augmented, allow_interval_training=True) + records[name].extend(_records(model, observed, complete)) + detail["completions"][name] = audit + print("completed fold", fold, name, flush=True) + folds.append(detail) + repo = Path(__file__).resolve().parents[1] + plan = repo / "experiments/us-childcare-attendance/interval-and-paired-plan.txt" + paths = [ + Path(__file__), + Path(qrf_tool.__file__), + Path(nsece_childcare_qrf.__file__), + Path(nsece_childcare_pooling.__file__), + Path(nsece_childcare_sibling_validation.__file__), + ] + report = { + "source": source.source_receipt, + "recipe": attendance_recipe_identity(), + "plan_sha256": hashlib.sha256(plan.read_bytes()).hexdigest(), + "diagnostic_code_sha256": { + p.name: hashlib.sha256(p.read_bytes()).hexdigest() for p in paths + }, + "folds": folds, + "models": { + name: _observed_child_summary(rows) for name, rows in records.items() + }, + "production_ready": False, + "interpretation": "development comparison; completed training intervals remain modeled under declared coarsening assumptions; no held-out household contributes to completion or refitting", + } + args.report.write_text(json.dumps(report, indent=2, allow_nan=False) + "\n") + for name, result in report["models"].items(): + print( + name, + "failed child screens", + sum(not check["passed"] for check in result["screen"]["checks"]), + flush=True, + ) + + +if __name__ == "__main__": + main() diff --git a/tools/validate_us_childcare_pooling.py b/tools/validate_us_childcare_pooling.py new file mode 100644 index 000000000..4a71beaa5 --- /dev/null +++ b/tools/validate_us_childcare_pooling.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +"""Compare fixed partially pooled matching with the existing attendance model.""" + +from __future__ import annotations + +import argparse +import hashlib +import json +from pathlib import Path + +from microcosm.build.us_runtime import ( + nsece_childcare_pooling, + nsece_childcare_sibling_validation, +) +from microcosm.build.us_runtime.childcare_attendance_receipt import ( + attendance_recipe_identity, +) +from microcosm.build.us_runtime.nsece_childcare import load_nsece_childcare +from microcosm.build.us_runtime.nsece_childcare_sibling_validation import ( + assess_sibling_schedules, + coupling_screen_compatibility, +) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--household-tsv", type=Path, required=True) + parser.add_argument("--calendar-tsv", type=Path, required=True) + parser.add_argument("--report", type=Path, required=True) + parser.add_argument( + "--compare-moment-fit", + action="store_true", + help="Include the separately planned exploratory population-moment objective", + ) + args = parser.parse_args() + if args.report.exists(): + parser.error("Report path must be new") + source = load_nsece_childcare(args.household_tsv, args.calendar_tsv) + plan = ( + Path(__file__).resolve().parents[1] + / "experiments/us-childcare-attendance/pooled-matching-plan.txt" + ) + report = { + "source": source.source_receipt, + "plan_sha256": hashlib.sha256(plan.read_bytes()).hexdigest(), + "recipe": attendance_recipe_identity(), + "diagnostic_code_sha256": { + path.name: hashlib.sha256(path.read_bytes()).hexdigest() + for path in ( + Path(__file__), + Path(nsece_childcare_pooling.__file__), + Path(nsece_childcare_sibling_validation.__file__), + ) + }, + "production_ready": False, + "production_recipe_changed": False, + "interpretation": "five household-separated folds on previously inspected development data; no untouched evaluation claim; calendar selection remains unidentified", + } + arms = [ + ("legacy", False, "pair_squared_error"), + ("pooled", True, "pair_squared_error"), + ] + if args.compare_moment_fit: + extra_plan = plan.with_name("pooled-moments-plan.txt") + report["moment_plan_sha256"] = hashlib.sha256( + extra_plan.read_bytes() + ).hexdigest() + arms.append(("pooled_moments", True, "population_moments")) + for name, pooled, objective in arms: + report[name] = assess_sibling_schedules( + source, + pooled=pooled, + include_observed_children=True, + pooling_fit_objective=objective, + ) + report[name]["dependence_only_screen_compatibility"] = ( + coupling_screen_compatibility(report[name]) + ) + print(name, json.dumps(report[name]["larger_households"]), flush=True) + print( + "joint failures", + sum(not c["passed"] for c in report[name]["diagnostic_screen"]["checks"]), + flush=True, + ) + print( + "child failures", + sum( + not c["passed"] + for c in report[name]["observed_child_validation"]["screen"]["checks"] + ), + flush=True, + ) + args.report.write_text(json.dumps(report, indent=2, allow_nan=False) + "\n") + + +if __name__ == "__main__": + main() diff --git a/tools/validate_us_childcare_population.py b/tools/validate_us_childcare_population.py new file mode 100644 index 000000000..731dc89b3 --- /dev/null +++ b/tools/validate_us_childcare_population.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python3 +"""Compare a local attendance candidate with its exact parent under each state's model. + +Only finite, imputed child inputs change in this counterfactual. Unresolved +out-of-domain inputs retain their baseline engine behavior and are counted, +not certified as observed zeros. Results are potential modeled benefits, not +CCDF caseload or spending estimates. No microdata are published by this tool. +""" + +from __future__ import annotations + +import argparse +import hashlib +import json +from importlib.metadata import version +from pathlib import Path + +import numpy as np +import pandas as pd + +from microcosm.build.frame_checkpoint import load_frame_checkpoint +from microcosm.build.us_runtime.childcare_attendance import ( + US_CHILDCARE_ATTENDANCE_COLUMNS, +) +from microcosm.build.us_runtime.childcare_attendance_receipt import ( + childcare_attendance_public_metadata, +) +from microcosm.build.us_runtime.childcare_sensitivity import compare_childcare_scenarios +from microcosm.build.us_runtime.h5_io import load_legacy_calibrated_us_h5 +from microcosm.frame import Frame + + +def _sha256(path: Path) -> str: + with path.open("rb") as stream: + return hashlib.file_digest(stream, "sha256").hexdigest() + + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--parent-h5", type=Path, required=True) + parser.add_argument("--parent-sha256", required=True) + parser.add_argument("--candidate-checkpoint", type=Path, required=True) + parser.add_argument("--year", type=int, default=2026) + parser.add_argument("--report", type=Path, required=True) + args = parser.parse_args() + if args.report.exists(): + parser.error("The report path must be new") + with args.parent_h5.open("rb") as stream: + parent_hash = hashlib.file_digest(stream, "sha256").hexdigest() + if parent_hash != args.parent_sha256: + parser.error("Parent population hash mismatch") + parent = load_legacy_calibrated_us_h5(args.parent_h5) + stored = load_frame_checkpoint(args.candidate_checkpoint) + frame = stored.frame + candidate = Frame( + {e: frame.table(e) for e in frame.entities}, + frame.schema, + {e: frame.weights_for(e) for e in frame.weighted_entities}, + metadata=stored.metadata.get("frame_metadata", {}), + ) + for entity in parent.entities: + pd.testing.assert_frame_equal( + parent.table(entity), candidate.table(entity)[parent.table(entity).columns] + ) + for entity in parent.weighted_entities: + np.testing.assert_array_equal( + parent.weights_for(entity).values, candidate.weights_for(entity).values + ) + p = candidate.table("person") + attendance = p[list(US_CHILDCARE_ATTENDANCE_COLUMNS)].to_numpy(dtype=float) + resolved = np.isfinite(attendance).all(axis=1) + young = p.age.between(0, 12).to_numpy() + if not resolved[young].all(): + raise ValueError("Candidate leaves under-13 attendance unresolved") + hh = parent.table("household").copy() + hh["household_weight"] = parent.weights_for("household").values + person_weights = p.person_household_id.map( + hh.set_index("household_id").household_weight + ).to_numpy() + days = attendance[:, 1] + report = { + "parent_sha256": parent_hash, + "candidate_checkpoint_sha256": _sha256(args.candidate_checkpoint), + "validation_code_sha256": _sha256(Path(__file__)), + "engine_version": version("policyengine-us"), + "policy_year": args.year, + "population": "fixed BuildP source ages/incomes; no aging or uprating", + "people": len(p), + "households": len(hh), + "under13_children": int(young.sum()), + "outside_source_domain_people": int((~young).sum()), + "outside_source_domain_age13_17_with_disability": int( + (p.age.between(13, 17) & p.is_disabled).sum() + ), + "outside_domain_baseline_receipt": stored.metadata.get( + "frame_metadata", {} + ).get("childcare_outside_domain_baseline", {}), + "unresolved_people_retaining_baseline": int((~resolved).sum()), + "unresolved_age13_17_with_disability": int( + (~resolved & p.age.between(13, 17) & p.is_disabled).sum() + ), + "weighted_under13_attendance_share": float( + np.average(days[young] > 0, weights=person_weights[young]) + ), + "weighted_under13_days_per_week": float( + np.average(days[young], weights=person_weights[young]) + ), + "weighted_under13_hours_per_week": float( + np.average( + days[young] * attendance[young, 2], weights=person_weights[young] + ) + ), + "candidate_receipt": childcare_attendance_public_metadata(candidate), + "states": [], + "production_ready": False, + "interpretation": "attendance-only counterfactual; provider, activity, expenses and take-up inputs remain as in parent", + } + if "childcare_attendance_match_level" in p: + report["matching_levels"] = ( + p.loc[young, "childcare_attendance_match_level"].value_counts().to_dict() + ) + report["population_attendance_by_group"] = [] + for grouping in ("age", "region", "parent_work_status", "income_band"): + for label, indices in p.loc[young].groupby(grouping).groups.items(): + positions = p.index.get_indexer(indices) + w = person_weights[positions] + d = attendance[positions, 1] + report["population_attendance_by_group"].append( + { + "grouping": grouping, + "group": str(label), + "children": len(indices), + "weighted_children": float(w.sum()), + "attendance_share": float(np.average(d > 0, weights=w)), + "days_per_week": float(np.average(d, weights=w)), + "hours_per_week": float( + np.average(d * attendance[positions, 2], weights=w) + ), + } + ) + try: + for result in compare_childcare_scenarios( + parent, {"candidate": attendance}, year=args.year + ): + state = result["state"] + report["states"].append(result) + print( + f"{state}: {result['baseline']['positive_sample_units']} -> {result['candidate']['positive_sample_units']} positive units", + flush=True, + ) + report["summary"] = { + "states_evaluated": len(report["states"]), + "all_zero_states": { + arm: [ + row["state"] + for row in report["states"] + if row[arm]["positive_sample_units"] == 0 + ] + for arm in ("baseline", "candidate") + }, + "annual_potential_modeled_benefits": { + arm: sum( + row[arm]["annual_modeled_benefits"] for row in report["states"] + ) + for arm in ("baseline", "candidate") + }, + } + except Exception as exc: + report["error"] = f"{type(exc).__name__}: {exc}" + raise + finally: + args.report.parent.mkdir(parents=True, exist_ok=True) + args.report.write_text( + json.dumps(report, indent=2, allow_nan=False, default=dict) + "\n" + ) + + +if __name__ == "__main__": + main() diff --git a/tools/validate_us_childcare_qrf.py b/tools/validate_us_childcare_qrf.py new file mode 100644 index 000000000..5398fe837 --- /dev/null +++ b/tools/validate_us_childcare_qrf.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python3 +"""Run the declared canonical-QRF marginal diagnostic on licensed local data.""" + +from __future__ import annotations + +import argparse +import hashlib +import json +from pathlib import Path + +import numpy as np +import pandas as pd + +from microcosm.build.us_runtime import nsece_childcare_qrf +from microcosm.build.us_runtime.childcare_attendance_receipt import ( + attendance_recipe_identity, +) +from microcosm.build.us_runtime.nsece_childcare import load_nsece_childcare +from microcosm.build.us_runtime.nsece_childcare_pooling import ( + with_childcare_household_size, +) +from microcosm.build.us_runtime.nsece_childcare_qrf import ( + QRF_CHILDCARE_PREDICTORS, + QRFChildcareSchedules, +) +from microcosm.build.us_runtime.nsece_childcare_sibling_validation import ( + _household_splits, + _observed_child_summary, +) + + +def load_source_children(household_tsv, calendar_tsv): + """Verify source pins and add the declared common household predictors.""" + source = load_nsece_childcare(household_tsv, calendar_tsv) + raw = pd.read_csv( + household_tsv, + sep="\t", + usecols=["HH4_METH_CASEID", "HH4_HHCOMP_MEMBERS", "HH4_HHCOMP_NUMPARENTS"], + ) + raw.index = raw.HH4_METH_CASEID.astype(str) + children = with_childcare_household_size( + source.children.loc[source.children.age.between(0, 12)] + ) + children["household_members"] = children.source_household_id.map( + raw.HH4_HHCOMP_MEMBERS + ) + children["resident_parent_count"] = children.source_household_id.map( + raw.HH4_HHCOMP_NUMPARENTS + ) + return source, children + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--household-tsv", type=Path, required=True) + parser.add_argument("--calendar-tsv", type=Path, required=True) + parser.add_argument("--report", type=Path, required=True) + args = parser.parse_args() + if args.report.exists(): + parser.error("Report path must be new") + source, children = load_source_children(args.household_tsv, args.calendar_tsv) + records, folds, movements = [], [], [] + for fold, (train_mask, target_mask) in enumerate( + _household_splits(children, seed=271828, validation_seed=None, partition="all") + ): + training, target = children.loc[train_mask], children.loc[target_mask] + complete = target.groupby("source_household_id").attendance_status.agg( + lambda x: x.eq("complete").all() + ) + target = target.loc[target.attendance_status.eq("complete")] + model = QRFChildcareSchedules(training) + model.prepare(target) + for _, child in target.iterrows(): + values, _, probability = model.distribution(child) + actual = np.array( + [ + float(child.childcare_days_per_week > 0), + child.childcare_days_per_week, + child.ece_hours_per_week, + ] + ) + records.append( + ( + float(child.child_weight), + min(int(child.childcare_household_size), 3), + bool(complete.loc[child.source_household_id]), + actual, + np.average(values, axis=0, weights=probability), + np.average(values**2, axis=0, weights=probability), + ) + ) + folds.append( + { + "fold": fold, + "training_households": int(training.source_household_id.nunique()), + "evaluation_households": int(target.source_household_id.nunique()), + "household_overlap": 0, + "evaluated_children": len(target), + "profiles": len(model.cache), + } + ) + movements.extend(model.decoder_movements) + print("completed fold", fold, flush=True) + plan = ( + Path(__file__).resolve().parents[1] + / "experiments/us-childcare-attendance/qrf-calendar-plan.txt" + ) + report = { + "source": source.source_receipt, + "recipe": attendance_recipe_identity(), + "plan_sha256": hashlib.sha256(plan.read_bytes()).hexdigest(), + "diagnostic_code_sha256": { + p.name: hashlib.sha256(p.read_bytes()).hexdigest() + for p in [Path(__file__), Path(nsece_childcare_qrf.__file__)] + }, + "model": { + "name": "canonical_weighted_QRF_joint_schedule_decoder", + "predictors": QRF_CHILDCARE_PREDICTORS, + "trees": 100, + "seed": 915, + "integration_points": 128, + "mean_positive_decoder_code_movement": float(np.mean(movements)), + "max_positive_decoder_code_movement": float(np.max(movements)), + }, + "splits": folds, + "observed_child_validation": _observed_child_summary(records), + "production_ready": False, + "interpretation": "marginal development diagnostic only; no dependence fit, no source-selection correction, no population integration or independent validation", + } + args.report.write_text(json.dumps(report, indent=2, allow_nan=False) + "\n") + print( + "child failures", + sum( + not c["passed"] + for c in report["observed_child_validation"]["screen"]["checks"] + ), + flush=True, + ) + + +if __name__ == "__main__": + main() diff --git a/tools/validate_us_childcare_sensitivity.py b/tools/validate_us_childcare_sensitivity.py new file mode 100644 index 000000000..3a69e8aff --- /dev/null +++ b/tools/validate_us_childcare_sensitivity.py @@ -0,0 +1,228 @@ +#!/usr/bin/env python3 +"""Stress-test unidentified noncalendar days/irregular hours on a fixed parent. + +Outputs aggregate evidence only. This does not identify the missing schedule, +certify a dataset, or authorize publication. All output paths must be new. +""" + +from __future__ import annotations + +import argparse +import hashlib +import json +from importlib.metadata import version +from pathlib import Path + +import numpy as np +import pandas as pd + +from microcosm.build.frame_checkpoint import load_frame_checkpoint +from microcosm.build.us_runtime.childcare_attendance_receipt import ( + assert_bound_childcare_attendance, + attendance_recipe_identity, +) +from microcosm.build.us_runtime.childcare_population import ( + harmonize_asec_childcare_predictors, +) +from microcosm.build.us_runtime.childcare_sensitivity import ( + compare_childcare_scenarios, + noncalendar_sensitivity_source, + paired_noncalendar_attendance, +) +from microcosm.build.us_runtime.h5_io import load_legacy_calibrated_us_h5 +from microcosm.build.us_runtime.nsece_childcare import ( + NSECE_CHILDCARE_FALLBACK_COLUMNS, + NSECE_CHILDCARE_MATCH_COLUMNS, + load_nsece_childcare, + with_us_nsece_childcare_attendance, +) +from microcosm.build.us_runtime.nsece_childcare_bridge import ( + bridge_nsece_noncalendar_attendance, +) +from microcosm.build.us_runtime.nsece_childcare_dependence import ( + fit_nsece_sibling_dependence, +) +from microcosm.frame import Frame + + +def _sha256(path): + with Path(path).open("rb") as stream: + return hashlib.file_digest(stream, "sha256").hexdigest() + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--parent-h5", type=Path, required=True) + parser.add_argument("--parent-sha256", required=True) + parser.add_argument("--household-tsv", type=Path, required=True) + parser.add_argument("--calendar-tsv", type=Path, required=True) + parser.add_argument("--asec-source-cache", type=Path, required=True) + parser.add_argument("--seed", type=int, default=915) + parser.add_argument("--year", type=int, default=2026) + parser.add_argument("--report", type=Path, required=True) + parser.add_argument( + "--candidate-checkpoint", + type=Path, + help="Reuse a bound candidate from this parent/seed; retain its donor assignments", + ) + args = parser.parse_args() + if args.report.exists(): + parser.error("The report path must be new") + if _sha256(args.parent_h5) != args.parent_sha256: + parser.error("Parent population hash mismatch") + parent = load_legacy_calibrated_us_h5(args.parent_h5) + if args.candidate_checkpoint: + stored = load_frame_checkpoint(args.candidate_checkpoint) + if stored.metadata["parent_checkpoint_sha256"] != args.parent_sha256: + parser.error("Candidate checkpoint belongs to another parent") + frame = stored.frame + transferred = Frame( + {e: frame.table(e) for e in frame.entities}, + frame.schema, + {e: frame.weights_for(e) for e in frame.weighted_entities}, + frame.strata, + mass_log=frame.mass_log, + metadata=stored.metadata["frame_metadata"], + ) + assert_bound_childcare_attendance(transferred) + if transferred.metadata["childcare_attendance_stage"]["seed"] != args.seed: + parser.error("Candidate checkpoint uses another seed") + for entity in parent.entities: + # Check values, missingness and IDs; the dedicated artifact verifier + # additionally checks dtypes after normalizing string storage. + pd.testing.assert_frame_equal( + parent.table(entity), + transferred.table(entity).reindex(columns=parent.table(entity).columns), + check_dtype=False, + check_exact=True, + ) + for entity in parent.weighted_entities: + np.testing.assert_array_equal( + parent.weights_for(entity).values, + transferred.weights_for(entity).values, + ) + else: + normalized = harmonize_asec_childcare_predictors( + parent, source_cache=args.asec_source_cache + ) + source = load_nsece_childcare(args.household_tsv, args.calendar_tsv) + dependence = fit_nsece_sibling_dependence(source.children) + bridged = bridge_nsece_noncalendar_attendance(source, seed=args.seed) + arms = { + "candidate": bridged, + "no_modeled_irregular_hours": noncalendar_sensitivity_source( + bridged, irregular_hours=False + ), + "one_fewer_day": noncalendar_sensitivity_source(bridged, day_shift=-1), + "one_more_day": noncalendar_sensitivity_source(bridged, day_shift=1), + } + if not args.candidate_checkpoint: + transferred = with_us_nsece_childcare_attendance( + normalized, + bridged, + seed=args.seed, + match_columns=NSECE_CHILDCARE_MATCH_COLUMNS, + fallback_match_columns=NSECE_CHILDCARE_FALLBACK_COLUMNS, + sibling_dependence=dependence["rho"], + ) + scenarios, assignment_checks = {}, {} + for name, donors in arms.items(): + scenarios[name], assignment_checks[name] = paired_noncalendar_attendance( + transferred.table("person"), bridged, donors + ) + print(f"Prepared {name}", flush=True) + people = transferred.table("person") + young = people.age.between(0, 12).to_numpy() + report = { + "parent_sha256": args.parent_sha256, + "source": source.source_receipt, + "recipe": attendance_recipe_identity(), + "seed": args.seed, + "candidate_checkpoint_sha256": _sha256(args.candidate_checkpoint) + if args.candidate_checkpoint + else None, + "assignment_checks": assignment_checks, + "coupling": "same donor identities across scenarios; no care-rank reassignment", + "engine_version": version("policyengine-us"), + "policy_year": args.year, + "code_sha256": { + str(p.name): _sha256(p) + for p in ( + Path(__file__), + Path(__file__).parents[1] + / "packages/microcosm-build/src/microcosm/build/us_runtime/childcare_sensitivity.py", + ) + }, + "population": "fixed BuildP source ages/incomes; no aging or uprating", + "assumptions": { + name: donors.source_receipt.get("transport_sensitivity", {}) + for name, donors in arms.items() + }, + "changed_children": { + name: int( + np.any(values[young] != scenarios["candidate"][young], axis=1).sum() + ) + for name, values in scenarios.items() + }, + "screens": {"national_relative_change": 0.10, "state_relative_change": 0.20}, + "states": [], + "production_ready": False, + "interpretation": "assumption stress tests, not confidence intervals; potential modeled benefits, not calibrated spending", + } + try: + for result in compare_childcare_scenarios(parent, scenarios, year=args.year): + report["states"].append(result) + print(result["state"], flush=True) + totals = { + name: sum(row[name]["annual_modeled_benefits"] for row in report["states"]) + for name in ("baseline", *arms) + } + flags = [] + comparisons = [] + for name in arms: + if name == "candidate": + continue + for label, original, changed, limit in ( + ("US", totals["candidate"], totals[name], 0.10), + *( + ( + r["state"], + r["candidate"]["annual_modeled_benefits"], + r[name]["annual_modeled_benefits"], + 0.20, + ) + for r in report["states"] + ), + ): + relative = (changed - original) / original if original else None + flagged = ( + abs(relative) > limit if relative is not None else changed != 0 + ) + comparison = { + "scenario": name, + "state": label, + "relative_change": relative, + "absolute_change": changed - original, + "flagged": flagged, + } + comparisons.append(comparison) + if flagged: + flags.append(comparison) + report["summary"] = { + "states_evaluated": len(report["states"]), + "annual_potential_modeled_benefits": totals, + "sensitivity_flags": flags, + "comparisons": comparisons, + } + except Exception as exc: + report["error"] = f"{type(exc).__name__}: {exc}" + raise + finally: + args.report.parent.mkdir(parents=True, exist_ok=True) + args.report.write_text( + json.dumps(report, indent=2, allow_nan=False, default=dict) + "\n" + ) + + +if __name__ == "__main__": + main() diff --git a/tools/verify_us_childcare_candidate.py b/tools/verify_us_childcare_candidate.py new file mode 100644 index 000000000..969e6fff5 --- /dev/null +++ b/tools/verify_us_childcare_candidate.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python3 +"""Verify a saved attendance candidate through both native population loaders. + +This checks artifact integrity and preservation, not statistical validity. The +report contains hashes and aggregate counts only; source records stay local. +""" + +from __future__ import annotations + +import argparse +import hashlib +import json +from importlib.metadata import version +from pathlib import Path + +import numpy as np +import pandas as pd + +from microcosm.build.frame_checkpoint import load_frame_checkpoint +from microcosm.build.us_runtime.childcare_attendance import ( + US_CHILDCARE_ATTENDANCE_COLUMNS, +) +from microcosm.build.us_runtime.childcare_attendance_receipt import ( + assert_bound_childcare_attendance, +) +from microcosm.build.us_runtime.h5_io import load_legacy_calibrated_us_h5 +from microcosm.build.us_runtime.l0_refit_export import load_us_frame +from microcosm.frame import Frame + + +def _sha256(path): + with path.open("rb") as stream: + return hashlib.file_digest(stream, "sha256").hexdigest() + + +def _assert_table_equal(expected, actual): + # HDF may restore strings in Python rather than Arrow storage. Normalize + # that backend only; retain null semantics, values and all other dtypes. + tables = [] + for original in (expected, actual): + table = original.copy() + for column in table: + dtype = table[column].dtype + if isinstance(dtype, pd.StringDtype): + table[column] = table[column].astype( + pd.StringDtype(storage="python", na_value=dtype.na_value) + ) + tables.append(table) + pd.testing.assert_frame_equal(*tables, check_exact=True) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--parent-h5", type=Path, required=True) + parser.add_argument("--parent-sha256", required=True) + parser.add_argument("--candidate-checkpoint", type=Path, required=True) + parser.add_argument("--candidate-native-h5", type=Path, required=True) + parser.add_argument("--source-stage-report", type=Path, required=True) + parser.add_argument("--report", type=Path, required=True) + args = parser.parse_args() + if args.report.exists(): + parser.error("Report path must be new") + if _sha256(args.parent_h5) != args.parent_sha256: + parser.error("Parent population hash mismatch") + source = json.loads(args.source_stage_report.read_text()) + checkpoint_hash = _sha256(args.candidate_checkpoint) + native_hash = _sha256(args.candidate_native_h5) + for key, actual in ( + ("parent_population_sha256", args.parent_sha256), + ("candidate_checkpoint_sha256", checkpoint_hash), + ("native_candidate_sha256", native_hash), + ): + if source[key] != actual: + raise ValueError(f"Source-stage report does not bind {key}.") + if ( + not source["production_stage_executed"] + or not source["native_candidate_written"] + ): + raise ValueError("Source-stage report does not attest a native stage export.") + parent = load_legacy_calibrated_us_h5(args.parent_h5) + stored = load_frame_checkpoint(args.candidate_checkpoint) + frame = stored.frame + candidate = Frame( + {entity: frame.table(entity) for entity in frame.entities}, + frame.schema, + {entity: frame.weights_for(entity) for entity in frame.weighted_entities}, + frame.strata, + mass_log=frame.mass_log, + metadata=stored.metadata["frame_metadata"], + ) + binding = assert_bound_childcare_attendance(candidate) + columns = list(US_CHILDCARE_ATTENDANCE_COLUMNS) + verified_loaders = [] + for loader in (load_legacy_calibrated_us_h5, load_us_frame): + loaded = loader(args.candidate_native_h5) + restored = assert_bound_childcare_attendance(loaded) + if restored["binding_sha256"] != binding["binding_sha256"]: + raise ValueError("Native reload changed the attendance binding.") + _assert_table_equal( + loaded.table("person")[columns], candidate.table("person")[columns] + ) + for entity in parent.entities: + original = parent.table(entity) + _assert_table_equal(original, candidate.table(entity)[original.columns]) + _assert_table_equal(original, loaded.table(entity)[original.columns]) + for entity in parent.weighted_entities: + original_weights = parent.weights_for(entity) + for restored_frame in (candidate, loaded): + actual_weights = restored_frame.weights_for(entity) + if actual_weights.kind != original_weights.kind: + raise ValueError("Candidate changed the original weight kind.") + np.testing.assert_array_equal( + original_weights.values, actual_weights.values + ) + verified_loaders.append(loader.__module__ + "." + loader.__name__) + people = candidate.table("person") + result = { + "parent_sha256": args.parent_sha256, + "checkpoint_sha256": checkpoint_hash, + "native_sha256": native_hash, + "source_stage_report_sha256": _sha256(args.source_stage_report), + "verification_code_sha256": _sha256(Path(__file__)), + "attendance_recipe": binding["execution"]["recipe"], + "content_binding_sha256": binding["binding_sha256"], + "engine_version": version("policyengine-us"), + "core_version": version("policyengine-core"), + "people": len(people), + "households": len(candidate.table("household")), + "under13_children": int(people.age.between(0, 12).sum()), + "verified_native_loaders": verified_loaders, + "all_original_columns_and_weights_preserved": True, + "all_attendance_values_preserved_on_native_reload": True, + "comparison": "exact values and dtypes, normalizing only pandas string storage backend", + "interpretation": "artifact integrity and preservation only; no statistical certification or publication", + "production_ready": False, + } + args.report.write_text(json.dumps(result, indent=2, allow_nan=False) + "\n") + print(json.dumps(result, indent=2)) + + +if __name__ == "__main__": + main()