From 2d7ec13310983f13e2c736c2eee3ce403c499c8d Mon Sep 17 00:00:00 2001 From: "Claude (Build J)" Date: Thu, 9 Jul 2026 21:48:28 -0400 Subject: [PATCH 01/17] Build J re-certification: Step 0 setup + Step 1 base rebuild launched (#368) Setup on origin/main 561c198 (all of #369/#373/#384/#385 + SNAP train). Findings: F1 base pool unchanged (assets/SNAP are release-time source stages, not base-builder changes) -> base sha expected 18833fb6; F2 target registry byte-identical to Build H (v8 facts reusable, 5533/5514 surface = clean Build I comparison); F3 SSI probe ref +$9.66B SCF-only overlay, re-solved rebuild should land lower. Runtime scripts snapshot for durability; live copies in _buildj-runtime (absolute paths). STAGING/LOCAL ONLY. Co-Authored-By: Claude Fable 5 --- PROGRESS_BUILDJ.md | 85 ++++++++++++++++++++ experiments/build_j_recert/buildj_base.sh | 95 +++++++++++++++++++++++ experiments/build_j_recert/detach.py | 34 ++++++++ 3 files changed, 214 insertions(+) create mode 100644 PROGRESS_BUILDJ.md create mode 100755 experiments/build_j_recert/buildj_base.sh create mode 100755 experiments/build_j_recert/detach.py diff --git a/PROGRESS_BUILDJ.md b/PROGRESS_BUILDJ.md new file mode 100644 index 00000000..d43c2664 --- /dev/null +++ b/PROGRESS_BUILDJ.md @@ -0,0 +1,85 @@ +# Build J — full re-certification of the whole stack under main's new gates + asset columns + +Task: PolicyEngine/populace **#368 (final phase)**. A full gated rebuild proving the whole +stack on `main`: base pool (restored columns) -> dense -> sparse (rmloss100 selection) -> +ALL gates -> verdict on #368. The point vs Build I: the SCF-wealth asset columns (#373) and +Daphne's SNAP-train inputs (#350/#352/#353) now flow, so SSI resource-limit reforms must +score **nonzero**; the #369 coverage/reform-smoke gate, #384 TANF fix + cross-register/take-up +preflights, and #385 release-native loading are all ON. + +**STAGING/LOCAL ONLY** — never prod HF / latest.json. Publication + default-flip is Max's call. +Compute discipline: every process < 30 min, chunked, detached (python start_new_session=True + +caffeinate -i + pidfile + rc + append logs), NO killing watchdog (pressure-sample only — six +jetsam kills AND healthy-run watchdog kills taught this). Commit + this log after EVERY step. +Three-strike per chunk. Verbatim numbers only. Never @-mention; --body-file for GitHub bodies. + +## Runtime + branch +- Worktree: `/Users/maxghenis/PolicyEngine/_worktrees/populace-build-j-recert` branch + **build-j-recert** off **origin/main `561c198`** (#385 release-native loading HEAD, which sits + on #384 #373 #369 + Daphne's SNAP train #350/#352/#353). +- Runtime home (durable, outside repos): `/Users/maxghenis/PolicyEngine/_buildj-runtime/` + (mirrors `_buildi-runtime` layout: inputs/logs/out/checkpoints/scratch/src). +- venv: worktree `.venv` (uv sync --all-packages --all-extras), policyengine-us **1.764.6** / + core **3.26.11** (EXACT Build I match); scf_wealth stage imports verified. + +## Build I bar (from #359 verdict = the numbers to meet/beat) +final_loss **0.030833** · within-10% **0.8888** · fed income tax (SOI) **+0.22%** · +export-mass parity **PASS 0/35** · records 57,240 · ESS 12,303 · realized_max_ratio 4.993 · +zero-support (post-excl) 0. Build I was pinned to Build H lineage and did NOT address #340/#356 +(assets absent; SSI reforms scored $0) — that hole is exactly Build J's job. + +## Frozen invariants (inherit where identical; the DELTA vs Build I is the source stages + gates) +- base **18833fb6** (expected — see finding F1), pe-us 1.764.6, period 2024, seed 0, lambda=0. +- feed v8 facts **94b7155f** (`consumer_facts_buildh_v8.jsonl`, 131 MB) — REUSED (registry + identical, finding F2). +- target registry **d71c59514e3a** / 5533 declared -> 5514 sparse after the 19-cell zero-support + exclusion (finding F2: `fiscal_target_references.json` byte-identical to Build H). +- export-mass reference = live-default 57k **c2065b64** (`populace_us_2024.h5`), +/-50% band, $1B + floor; reviewed exclusions estate_income + non_sch_d_capital_gains ONLY. +- selection = Build I **rmloss100** manifest (152baca3) carried onto the Build J base (#330 + identity join); 19-cell zero-support exclusions (abb106af) revalidated on Build J. +- SCF donor = `rscfp2022.dta` (Fed econres scfp2022s.zip), zip sha **3bb4d890** / member sha + **6b8dd2d9** — BOTH match the pinned digests in scf_wealth.py. Pre-fetched to + `_buildj-runtime/inputs/scf_cache/rscfp2022.dta`; passed via `--scf-summary-extract`. + +## Architectural findings (verified on origin/main; correct the task's mental model where needed) +- **F1 — the base pool does NOT change for assets/SNAP.** #350/#352/#353 (SNAP) and #373 (SCF + wealth) modified `packages/populace-build/src/populace/build/us_runtime/*` + `source_stages.json` + + the RELEASE tool `tools/build_us_fiscal_refresh_release.py` — NOT the base builder + `tools/build_us_puf_support_base.py` (byte-identical to Build F's; `git diff` empty). Assets + + SNAP are RELEASE-TIME source stages that enrich the frame during the release build. So a base + rebuild with the same inputs/builder/pe-us is expected to reproduce **18833fb6** (NOT a "new" + sha). The rebuild is run anyway to (a) satisfy the #368 step and (b) empirically confirm + determinism; the confirming/again sha is a deliverable. [Base rebuild in flight — Step 1.] +- **F2 — the calibration target registry is unchanged.** `fiscal_target_references.json` is + byte-identical between Build H (b42fbfe) and origin/main (both `010fbfa5…`). So v8 facts + (94b7155f) remain valid and the registry compiles to the same 5533/5514 surface -> the Build I + loss/within-10%/income-tax numbers are a like-for-like bar. +- **F3 — the SSI probe reference.** scf_wealth.py's own #368 acceptance probe (seed 0, pe-us + 1.764.6): SCF-only overlay onto the Build H dense frame makes `ssi_countable_resources` nonzero + for 40.3% of people (dense-native ref 42.5%) and the $10k/$20k reform scores **+$9.7B @ 2026** + (#374's SCF-only overlay = +$9.66B). This is ABOVE the dense-native +$1.6B/+$16.1B reference + (restored baseline 4.74M recipients vs 8.05M) for two documented #356 follow-up reasons (SIPP + blend absent — the SCF draw omits the low liquid-asset bottom mass; and the overlay is on an + already-calibrated frame). The **re-solved rebuild should land LOWER than +$9.66B** (task + expectation); the SIPP blend is a KNOWN open refinement (#356), to be stated, not fixed here. + +## TIMELINE +### 2026-07-09/10 +- **Step 0 (setup + recon — DONE).** Read #368, the #359 Build I verdict (bar above), + PROGRESS_BUILDH/I.md, and the codex architecture review §3 (release-tool failure modes: + non-transactional local construction; frame + per-reform vectors are the only restartable + products with atomic writes; source stages rerun until the frame checkpoint hits; no optimizer + checkpoint; the warm-start-into-L0 config trap; memory — the 88 GB risk is the full-pool solve, + sparse peak RSS ~3.6 GB). Created worktree `build-j-recert` @ 561c198 + runtime `_buildj-runtime`. + Verified inputs: census_cps 2024/2023/2022 + puf_2024 present; base-build aux inputs match Build + F shas (aging-v5 a5d34d4a, cdx 383a6666, bladder 7ba39b95); v8 facts 94b7155f present. Pre-fetched + + sha-verified the SCF 2022 summary extract (zip 3bb4d890, member 6b8dd2d9 — both == pinned). + Established findings F1/F2/F3 above. Wrote the detacher (`detach.py`, start_new_session=True + + caffeinate) and the base launcher (`buildj_base.sh`, integrity preflight + pressure sampler, no + killing watchdog). +- **Step 1 (base rebuild — IN FLIGHT).** Launched `buildj_base.sh` detached (wrapper pid recorded + in logs/buildj-run/base.wrapperpid). Replicates Build F's exact base command on main's + (identical) builder: 3-year ASEC pool 2024+2023+2022, 2x PUF clone, seed 0, n-estimators 32, + aging-facts a5d34d4a, CD assignment (cdx 383a6666, seed 0), block ladder 7ba39b95. Expect sha + 18833fb6 (finding F1). Build F base was 12m14s -> one chunk. [Blocking on base.rc + base.sha.] diff --git a/experiments/build_j_recert/buildj_base.sh b/experiments/build_j_recert/buildj_base.sh new file mode 100755 index 00000000..cc2ae425 --- /dev/null +++ b/experiments/build_j_recert/buildj_base.sh @@ -0,0 +1,95 @@ +#!/bin/bash +# Build J STEP 1 — base pool rebuild on main's stages (populace#368 re-certification). +# Replicates Build F's base command EXACTLY on origin/main's base builder +# (byte-identical to Build F's tools/build_us_puf_support_base.py) to (a) satisfy the +# #368 "base pool rebuild" step and (b) EMPIRICALLY confirm determinism. The SNAP +# (#350/#352/#353) and SCF-wealth (#373) enrichments are RELEASE-TIME source stages +# (us_runtime/*), NOT base-builder stages, so the base sha is expected == Build F's +# 18833fb6 (documented finding vs the task's "new base sha expected" premise). +# +# Compute discipline: ~12 min (Build F was 12m14s), one chunk (<30 min). Detached via +# setsid+caffeinate; pidfile + real rc + append log + memory-pressure sampler. +# NO killing watchdog (six jetsam kills + healthy-run kills taught this — sample only). +# STAGING/LOCAL ONLY. +set -u +RT=/Users/maxghenis/PolicyEngine/_buildj-runtime +WT=/Users/maxghenis/PolicyEngine/_worktrees/populace-build-j-recert +USD=/Users/maxghenis/PolicyEngine/policyengine-us-data/policyengine_us_data/storage +BIN=/Users/maxghenis/PolicyEngine/_buildf-runtime/inputs # canonical base inputs (Build F set) +AGING_FACTS="$BIN/consumer_facts_builde_aging_v5.jsonl" # a5d34d4a +CDX="$BIN/congressional_district_vintage_crosswalk.csv" # 383a6666 +BLADDER="$BIN/us_block_ladder_2020.npz" # 7ba39b95 +OUTDIR="$RT/out/base-j" +BASE="$OUTDIR/base_populace_us_2024_puf_support.h5" +LOGDIR="$RT/logs/buildj-run" +LOG="$LOGDIR/chain_base.log" +TS=$(date -u +%Y%m%dT%H%M%SZ) +PLOG="$LOGDIR/pressure_base_$TS.log" +mkdir -p "$LOGDIR" "$OUTDIR" +say() { echo "[$(date -u +%FT%TZ)] $1" | tee -a "$LOG"; } +rm -f "$LOGDIR/base.rc" + +cd "$WT" || { say "FATAL cannot cd $WT"; echo 2 > "$LOGDIR/base.rc"; exit 2; } +source .venv/bin/activate 2>/dev/null + +# ---- integrity preflight on inputs (reproduce Build F's exact base) ---- +chk() { local got exp; got=$(shasum -a 256 "$1" | cut -c1-16); [ "$got" = "$2" ] || { say "FATAL sha mismatch $1: $got != $2"; echo 2 > "$LOGDIR/base.rc"; exit 2; }; } +for f in "$USD/census_cps_2024.h5" "$USD/census_cps_2023.h5" "$USD/census_cps_2022.h5" "$USD/puf_2024.h5" "$AGING_FACTS" "$CDX" "$BLADDER"; do + [ -f "$f" ] || { say "FATAL missing input $f"; echo 2 > "$LOGDIR/base.rc"; exit 2; } +done +chk "$AGING_FACTS" a5d34d4aad325d8c +chk "$CDX" 383a666631aafd4f +chk "$BLADDER" 7ba39b959068181b + +SHORT=$(git rev-parse --short HEAD) +PEUS=$(.venv/bin/python -c "from importlib.metadata import version; print(version('policyengine-us'))" 2>/dev/null) +say "BUILD J BASE START commit=$SHORT pe-us=$PEUS pid=$$ pressure_log=$PLOG" +say " inputs: asec 2024/2023/2022 + puf_2024; aging-facts a5d34d4a; cdx 383a6666; bladder 7ba39b95; seed 0 n-est 32" + +if [ -f "$BASE" ]; then + say "BASE: already present at $BASE — verifying sha only (delete to force rebuild)" +else + # ---- memory-pressure sampler (self-terminates on python exit; SAMPLE ONLY, no kill) ---- + ( echo "ts_utc,free_pct,swap_used_mb,py_rss_mb,py_pid" + while :; do + fp=$(memory_pressure 2>/dev/null | awk -F': ' '/free percentage/{gsub(/%/,"",$2);print $2}') + sw=$(sysctl -n vm.swapusage 2>/dev/null | sed -E 's/.*used = ([0-9.]+)M.*/\1/') + pid=$(pgrep -f 'build_us_puf_support_base.py' | head -1) + rss=""; if [ -n "$pid" ]; then rss=$(ps -o rss= -p "$pid" 2>/dev/null | awk '{print int($1/1024)}'); fi + echo "$(date -u +%FT%TZ),${fp:-},${sw:-},${rss:-},${pid:-}" + [ -z "$pid" ] && sleep 4 && pid2=$(pgrep -f 'build_us_puf_support_base.py' | head -1) && [ -z "$pid2" ] && break + sleep 15 + done ) >> "$PLOG" 2>&1 & + SAMPLER=$! + + say "BASE: rebuilding (3-year ASEC pool 2024+2023+2022, 2x PUF clone, spec-less equal thirds)" + .venv/bin/python tools/build_us_puf_support_base.py \ + --asec-h5 2024="$USD/census_cps_2024.h5" \ + --asec-h5 2023="$USD/census_cps_2023.h5" \ + --asec-h5 2022="$USD/census_cps_2022.h5" \ + --puf-h5 "$USD/puf_2024.h5" \ + --target-year 2024 \ + --seed 0 --n-estimators 32 \ + --ledger-facts "$AGING_FACTS" \ + --assign-congressional-districts \ + --congressional-district-vintage-crosswalk "$CDX" \ + --congressional-district-seed 0 \ + --block-ladder-artifact "$BLADDER" \ + --out "$OUTDIR" \ + >> "$LOGDIR/base_j.log" 2>&1 + rc=$? + kill "$SAMPLER" 2>/dev/null + say "BASE: python exited rc=$rc" + if [ $rc -ne 0 ]; then echo "$rc" > "$LOGDIR/base.rc"; say "BASE FAILED rc=$rc — diagnose in base_j.log"; exit "$rc"; fi +fi + +BASE_SHA=$(shasum -a 256 "$BASE" | cut -d' ' -f1) +echo "$BASE_SHA" > "$LOGDIR/base.sha" +say "BASE sha: $BASE_SHA" +if [ "$BASE_SHA" = "18833fb68e60ee74461608d81a5c5ab7d52435e17026d9e3b062d9de18d6871f" ]; then + say "BASE sha CONFIRMS Build F 18833fb6 — base pool unchanged (assets/SNAP are release-time source stages, not base-builder stages)" +else + say "BASE sha DIFFERS from 18833fb6 — investigate before proceeding (base builder or deps changed the pool)" +fi +echo "0" > "$LOGDIR/base.rc" +say "BUILD J BASE DONE rc=0 sha=$BASE_SHA" diff --git a/experiments/build_j_recert/detach.py b/experiments/build_j_recert/detach.py new file mode 100755 index 00000000..a66b4284 --- /dev/null +++ b/experiments/build_j_recert/detach.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +"""Detach a Build J chunk so it survives session/terminal death. + +Usage: detach.py [args...] + +Launches `caffeinate -i bash [args...]` in its own session +(start_new_session=True -> setsid semantics; reparented to init if the +launching session dies), appends combined output to , records +the child PID in , and exits immediately. No killing watchdog: +the chunk runs to natural completion; monitoring is via the script's own +rc/append logs + a memory-pressure sampler. STAGING/LOCAL ONLY. +""" +import os +import subprocess +import sys +import time + +pidfile, wrapper_log, script, *rest = sys.argv[1:] +logf = open(wrapper_log, "a", buffering=1) +logf.write(f"[{time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())}] detach launching: " + f"caffeinate -i bash {script} {' '.join(rest)}\n") +p = subprocess.Popen( + ["caffeinate", "-i", "bash", script, *rest], + stdout=logf, + stderr=subprocess.STDOUT, + stdin=subprocess.DEVNULL, + start_new_session=True, + close_fds=True, +) +with open(pidfile, "w") as f: + f.write(str(p.pid) + "\n") +logf.write(f"[{time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())}] detached child pid={p.pid} " + f"(caffeinate wrapper; bash+python are its children)\n") +print(f"detached pid={p.pid} pidfile={pidfile} log={wrapper_log}") From ef4e4176e2404ff35a3634c55a0291fec079c730 Mon Sep 17 00:00:00 2001 From: "Claude (Build J)" Date: Thu, 9 Jul 2026 21:58:30 -0400 Subject: [PATCH 02/17] Build J: stage dense/sparse/direct-solve/carry-over launchers (#368) All arm launchers verified against origin/main APIs: release-tool internals (_load_frame, _read_target_frame_checkpoint, compile_us_fiscal_target_registry, load_ledger_consumer_artifact, calibrate) signatures match the Build H direct-solve call exactly; base_selection_mask(frozen_support) is the built-in >0-miss STOP. Dense/sparse add --scf-summary-extract (sha-pinned rscfp2022.dta) + fresh checkpoint roots; NO killing watchdogs (pressure-sample only). STAGING/LOCAL ONLY. Co-Authored-By: Claude Fable 5 --- experiments/build_j_recert/buildj_dense.sh | 87 +++++++++++ experiments/build_j_recert/buildj_sparse.sh | 92 +++++++++++ .../direct_solve_dense_buildj.py | 145 ++++++++++++++++++ .../verify_selection_carryover_buildj.py | 67 ++++++++ 4 files changed, 391 insertions(+) create mode 100644 experiments/build_j_recert/buildj_dense.sh create mode 100644 experiments/build_j_recert/buildj_sparse.sh create mode 100644 experiments/build_j_recert/direct_solve_dense_buildj.py create mode 100644 experiments/build_j_recert/verify_selection_carryover_buildj.py diff --git a/experiments/build_j_recert/buildj_dense.sh b/experiments/build_j_recert/buildj_dense.sh new file mode 100644 index 00000000..d0239ae3 --- /dev/null +++ b/experiments/build_j_recert/buildj_dense.sh @@ -0,0 +1,87 @@ +#!/bin/bash +# Build J DENSE arm — STEP D1: materialize the target-frame checkpoint (WITH the +# scf_wealth asset stage + SNAP source stages) and attempt the dense solve/gates/H5. +# Mirrors buildh_dense.sh EXACTLY; the ONLY additions vs Build H: --scf-summary-extract +# (the pre-fetched, sha-pinned rscfp2022.dta so assets flow, #368/#373) and a FRESH +# --checkpoint-root buildj-dense (the scf_wealth source stage busts the Build H frame +# checkpoint). base 18833fb6 / v8 facts 94b7155f / ref c2065b64 / registry d71c59514e3a +# all unchanged. --dense-default-dataset -> no L0, warm-start-compatible. Detached, +# pressure-sampled, NO killing watchdog. If jetsam/session kills the SOLVE, the atomic +# frame checkpoint survives -> Step D2 direct-solve loads it (bounded). STAGING/LOCAL ONLY. +set -u +RT=/Users/maxghenis/PolicyEngine/_buildj-runtime +WT=/Users/maxghenis/PolicyEngine/_worktrees/populace-build-j-recert +BASE="$RT/out/base-j/base_populace_us_2024_puf_support.h5" +REF=/Users/maxghenis/PolicyEngine/_buildg-runtime/forensics/populace_us_2024.h5 # c2065b64 +FACTS=/Users/maxghenis/PolicyEngine/_buildh-runtime/inputs/consumer_facts_buildh_v8.jsonl +SCF="$RT/inputs/scf_cache/rscfp2022.dta" +LOGDIR="$RT/logs/buildj-run" +OUT="$RT/out/buildj-run/dense" +LOG="$LOGDIR/chain_dense.log" +TS=$(date -u +%Y%m%dT%H%M%SZ) +PLOG="$LOGDIR/pressure_dense_$TS.log" +mkdir -p "$LOGDIR" "$OUT" +say() { echo "[$(date -u +%FT%TZ)] $1" | tee -a "$LOG"; } +rm -f "$LOGDIR/dense.rc" + +cd "$WT" || { say "FATAL cannot cd $WT"; echo 2 > "$LOGDIR/dense.rc"; exit 2; } +source .venv/bin/activate 2>/dev/null + +# ---- integrity preflight ---- +[ -f "$BASE" ] || { say "FATAL base missing $BASE"; echo 2 > "$LOGDIR/dense.rc"; exit 2; } +BASE_SHA=$(shasum -a 256 "$BASE" | cut -d' ' -f1) +REF_SHA12=$(shasum -a 256 "$REF" | cut -c1-12) +FACTS_SHA=$(shasum -a 256 "$FACTS" | cut -d' ' -f1) +SCF_SHA12=$(shasum -a 256 "$SCF" | cut -c1-12) +SHORT=$(git rev-parse --short HEAD) +PEUS=$(.venv/bin/python -c "from importlib.metadata import version; print(version('policyengine-us'))" 2>/dev/null) +say "BUILD J DENSE(D1) START commit=$SHORT pe-us=$PEUS pid=$$ pressure_log=$PLOG" +say " base sha: $BASE_SHA" +say " ref sha: ${REF_SHA12}…" +say " facts sha: $FACTS_SHA (v8)" +say " scf sha: ${SCF_SHA12}… (rscfp2022.dta member)" +if [ "$BASE_SHA" != "18833fb68e60ee74461608d81a5c5ab7d52435e17026d9e3b062d9de18d6871f" ]; then + say "WARN base sha != 18833fb6 (got $BASE_SHA) — Build J base differs; proceeding (finding, not fatal) but note in verdict" +fi +if [ "$REF_SHA12" != "c2065b642ab0" ]; then say "FATAL ref sha prefix mismatch: $REF_SHA12"; echo 2 > "$LOGDIR/dense.rc"; exit 2; fi +if [ "$FACTS_SHA" != "94b7155f7ca9e2de32ddb3a0add2fff2d8c66e73147fe5bd112cff3ba69b1669" ]; then + say "FATAL v8 facts sha mismatch"; echo 2 > "$LOGDIR/dense.rc"; exit 2; fi +if [ "$SCF_SHA12" != "6b8dd2d935a7" ]; then say "FATAL scf member sha mismatch: $SCF_SHA12"; echo 2 > "$LOGDIR/dense.rc"; exit 2; fi + +RID="populace-us-2024-buildj-dense-$SHORT-$TS" +say "RELEASE(dense): starting id=$RID (full base; scf_wealth ON; fresh buildj-dense checkpoint)" + +# ---- memory-pressure sampler (SAMPLE ONLY; self-terminates on python exit; NO kill) ---- +( echo "ts_utc,free_pct,swap_used_mb,py_rss_mb,py_pid" + while :; do + fp=$(memory_pressure 2>/dev/null | awk -F': ' '/free percentage/{gsub(/%/,"",$2);print $2}') + sw=$(sysctl -n vm.swapusage 2>/dev/null | sed -E 's/.*used = ([0-9.]+)M.*/\1/') + pid=$(pgrep -f 'build_us_fiscal_refresh_release.py' | head -1) + rss=""; if [ -n "$pid" ]; then rss=$(ps -o rss= -p "$pid" 2>/dev/null | awk '{print int($1/1024)}'); fi + echo "$(date -u +%FT%TZ),${fp:-},${sw:-},${rss:-},${pid:-}" + [ -z "$pid" ] && sleep 4 && pid2=$(pgrep -f 'build_us_fiscal_refresh_release.py' | head -1) && [ -z "$pid2" ] && break + sleep 15 + done ) >> "$PLOG" 2>&1 & +SAMPLER=$! + +.venv/bin/python tools/build_us_fiscal_refresh_release.py \ + --base-h5 "$BASE" \ + --ledger-facts "$FACTS" \ + --ledger-facts-sha256 "$FACTS_SHA" \ + --export-input-mass-reference-h5 "$REF" \ + --scf-summary-extract "$SCF" \ + --out "$OUT" \ + --release-id "$RID" \ + --checkpoint-root "$RT/checkpoints/buildj-dense" \ + --seed 0 \ + --dense-default-dataset \ + --no-staging \ + >> "$LOGDIR/release_dense.log" 2>&1 +rc=$? +kill "$SAMPLER" 2>/dev/null +echo "$rc" > "$LOGDIR/dense.rc" +echo "$RID" > "$LOGDIR/dense.release_id" +say "RELEASE(dense): exited rc=$rc id=$RID" +CKPT="$RT/checkpoints/buildj-dense/target_frame_checkpoint.h5" +if [ -f "$CKPT" ]; then say "frame checkpoint PRESENT ($(shasum -a256 "$CKPT"|cut -c1-12)…, $(ls -la "$CKPT"|awk '{print $5}') bytes) — D2 direct-solve can load it"; else say "frame checkpoint ABSENT — materialization did not reach checkpoint"; fi +say "BUILD J DENSE(D1) DONE rc=$rc" diff --git a/experiments/build_j_recert/buildj_sparse.sh b/experiments/build_j_recert/buildj_sparse.sh new file mode 100644 index 00000000..7f1b496a --- /dev/null +++ b/experiments/build_j_recert/buildj_sparse.sh @@ -0,0 +1,92 @@ +#!/bin/bash +# Build J SPARSE arm — the deployable 57,240 (rmloss100) dense-polish solve + ALL gates. +# Mirrors buildi_sparse_supervised.sh EXACTLY; the ONLY changes vs Build I: base -> base-j, +# ADD --scf-summary-extract (assets flow, #368/#373), fresh --checkpoint-root buildj-sparse, +# and NO killing watchdog (Build I's 75-min watchdog killed healthy runs — pressure-sample +# only). The release reduces to the rmloss100 57,240 BEFORE ACA (:5309<:5471) -> materialises +# on the 57k frame (memory-benign, RSS ~3.6 GB) then solves + runs EVERY gate in one bounded +# process. selection manifest = Build I rmloss100 (152baca3, carried onto base-j, carry-over +# verified 0 misses); zero-support exclusions = Build I 19-cell (abb106af) REVALIDATED by the +# release on the Build J frame (a stale/uncovered cell fails the gate = finding). Gates ALL +# ON: coverage manifest #369, reform-coverage smoke (SSI $10k/$20k must be nonzero), export +# mass, parity, degenerate (TANF now expected non-degenerate), take-up, register consistency, +# #384 preflights. NO bypass flags. STAGING/LOCAL ONLY. +set -u +RT=/Users/maxghenis/PolicyEngine/_buildj-runtime +WT=/Users/maxghenis/PolicyEngine/_worktrees/populace-build-j-recert +BASE="$RT/out/base-j/base_populace_us_2024_puf_support.h5" +REF=/Users/maxghenis/PolicyEngine/_buildg-runtime/forensics/populace_us_2024.h5 # c2065b64 +SEL=/Users/maxghenis/PolicyEngine/_buildi-runtime/inputs/buildi_rmloss100_selection_source.json +SPARSE_EXCL=/Users/maxghenis/PolicyEngine/_buildi-runtime/inputs/sparse_zero_support_exclusions_buildi.json +FACTS=/Users/maxghenis/PolicyEngine/_buildh-runtime/inputs/consumer_facts_buildh_v8.jsonl +SCF="$RT/inputs/scf_cache/rscfp2022.dta" +LOGDIR="$RT/logs/buildj-run" +OUT="$RT/out/buildj-run/sparse" +LOG="$LOGDIR/chain_sparse.log" +TS=$(date -u +%Y%m%dT%H%M%SZ) +PLOG="$LOGDIR/pressure_sparse_$TS.log" +mkdir -p "$LOGDIR" "$OUT" +say() { echo "[$(date -u +%FT%TZ)] $1" | tee -a "$LOG"; } +rm -f "$LOGDIR/sparse.rc" + +cd "$WT" || { say "FATAL cannot cd $WT"; echo 2 > "$LOGDIR/sparse.rc"; exit 2; } +source .venv/bin/activate 2>/dev/null + +[ -f "$BASE" ] || { say "FATAL base missing $BASE"; echo 2 > "$LOGDIR/sparse.rc"; exit 2; } +BASE_SHA=$(shasum -a 256 "$BASE" | cut -d' ' -f1) +REF_SHA12=$(shasum -a 256 "$REF" | cut -c1-12) +SEL_SHA12=$(shasum -a 256 "$SEL" | cut -c1-12) +FACTS_SHA=$(shasum -a 256 "$FACTS" | cut -d' ' -f1) +EXCL_SHA12=$(shasum -a 256 "$SPARSE_EXCL" | cut -c1-12) +SCF_SHA12=$(shasum -a 256 "$SCF" | cut -c1-12) +SHORT=$(git rev-parse --short HEAD) +PEUS=$(.venv/bin/python -c "from importlib.metadata import version; print(version('policyengine-us'))" 2>/dev/null) +say "BUILD J SPARSE START commit=$SHORT pe-us=$PEUS pid=$$ pressure_log=$PLOG" +say " base sha: $BASE_SHA" +say " sel sha: ${SEL_SHA12}… (rmloss100 manifest)" +say " ref sha: ${REF_SHA12}…" +say " facts sha: $FACTS_SHA (v8)" +say " excl sha: ${EXCL_SHA12}… (19-cell Build-I, revalidated by release)" +say " scf sha: ${SCF_SHA12}… (rscfp2022.dta member)" +if [ "$REF_SHA12" != "c2065b642ab0" ]; then say "FATAL ref sha prefix mismatch: $REF_SHA12"; echo 2 > "$LOGDIR/sparse.rc"; exit 2; fi +if [ "$FACTS_SHA" != "94b7155f7ca9e2de32ddb3a0add2fff2d8c66e73147fe5bd112cff3ba69b1669" ]; then + say "FATAL v8 facts sha mismatch"; echo 2 > "$LOGDIR/sparse.rc"; exit 2; fi +if [ "$SCF_SHA12" != "6b8dd2d935a7" ]; then say "FATAL scf member sha mismatch: $SCF_SHA12"; echo 2 > "$LOGDIR/sparse.rc"; exit 2; fi + +RID="populace-us-2024-buildj-sparse-rmloss100-$SHORT-$TS" +say "RELEASE(sparse): starting id=$RID (rmloss100 dense-polish; scf_wealth ON; ALL gates; NO bypass flags)" + +# ---- memory-pressure sampler (SAMPLE ONLY; no kill) ---- +( echo "ts_utc,free_pct,swap_used_mb,py_rss_mb,py_pid" + while :; do + fp=$(memory_pressure 2>/dev/null | awk -F': ' '/free percentage/{gsub(/%/,"",$2);print $2}') + sw=$(sysctl -n vm.swapusage 2>/dev/null | sed -E 's/.*used = ([0-9.]+)M.*/\1/') + pid=$(pgrep -f 'build_us_fiscal_refresh_release.py' | head -1) + rss=""; if [ -n "$pid" ]; then rss=$(ps -o rss= -p "$pid" 2>/dev/null | awk '{print int($1/1024)}'); fi + echo "$(date -u +%FT%TZ),${fp:-},${sw:-},${rss:-},${pid:-}" + [ -z "$pid" ] && sleep 4 && pid2=$(pgrep -f 'build_us_fiscal_refresh_release.py' | head -1) && [ -z "$pid2" ] && break + sleep 15 + done ) >> "$PLOG" 2>&1 & +SAMPLER=$! + +.venv/bin/python tools/build_us_fiscal_refresh_release.py \ + --base-h5 "$BASE" \ + --selection-source-manifest "$SEL" \ + --dense-default-dataset \ + --ledger-facts "$FACTS" \ + --ledger-facts-sha256 "$FACTS_SHA" \ + --export-input-mass-reference-h5 "$REF" \ + --zero-support-exclusions "$SPARSE_EXCL" \ + --scf-summary-extract "$SCF" \ + --out "$OUT" \ + --release-id "$RID" \ + --checkpoint-root "$RT/checkpoints/buildj-sparse" \ + --seed 0 \ + --no-staging \ + >> "$LOGDIR/release_sparse.log" 2>&1 +rc=$? +kill "$SAMPLER" 2>/dev/null +echo "$rc" > "$LOGDIR/sparse.rc" +echo "$RID" > "$LOGDIR/sparse.release_id" +say "RELEASE(sparse): exited rc=$rc id=$RID" +say "BUILD J SPARSE DONE rc=$rc" diff --git a/experiments/build_j_recert/direct_solve_dense_buildj.py b/experiments/build_j_recert/direct_solve_dense_buildj.py new file mode 100644 index 00000000..9394f8c2 --- /dev/null +++ b/experiments/build_j_recert/direct_solve_dense_buildj.py @@ -0,0 +1,145 @@ +"""Build J DENSE arm — STEP D2: direct dense CSR solve from the frame checkpoint. + +Adapted from Build H's experiments/learned_selection_prior/src/ +direct_replay_dense_weights_buildh.py (the proven ~18-min direct solve). ONLY the +runtime root (_buildh-runtime -> _buildj-runtime), checkpoint root (buildh-dense -> +buildj-dense), and the base sha (read dynamically from the Build J base) change; the +feed (v8 94b7155f), registry (d71c59514e3a), pe-us (1.764.6), and every solver +hyperparameter are IDENTICAL to Build H, so the Build J dense final_loss is directly +comparable to Build H's dense parent. + +Why this exists (codex review §3): the monolithic release path re-materialises the ACA +base frame + five JCT reform vectors, then holds a multi-tens-of-GB footprint while it +solves + exports -> macOS jetsam SIGKILLs it (rc=137). The buildj-dense frame checkpoint +(written atomically DURING the D1 release, WITH the scf_wealth asset stage) already stores +the fully materialised post-ACA/post-target frame; loading it via the tool's own +_read_target_frame_checkpoint skips ALL materialisation, leaving only the deterministic +CSR solve (~18 min, bounded footprint — the 88 GB full-pool-solve risk avoided). Saves the +dense weights AND a warm-start calibration.npz that Step D3 (the warm-start release) consumes. + +--verify-only: compile the registry + load the frame (seconds) and stop; de-risks the +identity match before the ~18-min solve. STAGING/LOCAL ONLY. +""" +from __future__ import annotations + +import argparse +import hashlib +import sys +import time +from pathlib import Path + +import numpy as np + +WT = Path("/Users/maxghenis/PolicyEngine/_worktrees/populace-build-j-recert") +sys.path.insert(0, str(WT / "tools")) +import build_us_fiscal_refresh_release as release # noqa: E402 + +from populace.calibrate import calibrate # noqa: E402 + +RT = Path("/Users/maxghenis/PolicyEngine/_buildj-runtime") +CKPT = RT / "checkpoints/buildj-dense/target_frame_checkpoint.h5" +BASE = RT / "out/base-j/base_populace_us_2024_puf_support.h5" +FACTS = Path("/Users/maxghenis/PolicyEngine/_buildh-runtime/inputs/consumer_facts_buildh_v8.jsonl") +FACTS_SHA = "94b7155f7ca9e2de32ddb3a0add2fff2d8c66e73147fe5bd112cff3ba69b1669" +PEUS = "1.764.6" +REG_VERSION_EXPECTED = "d71c59514e3a" +OUT = RT / "out/buildj-run/densewts_direct" +OUT.mkdir(parents=True, exist_ok=True) + +# Build H dense anchor (Build J registry is IDENTICAL d71c59514e3a -> comparable). +BUILDH_DENSE_FINAL_LOSS = 0.04018 +SANE_LO, SANE_HI = 0.010, 0.100 + + +def _sha256(path: Path) -> str: + h = hashlib.sha256() + with open(path, "rb") as f: + for chunk in iter(lambda: f.read(1 << 20), b""): + h.update(chunk) + return h.hexdigest() + + +def log(m): + print(f"[{time.strftime('%H:%M:%S')}] {m}", flush=True) + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--verify-only", action="store_true") + args = ap.parse_args() + t0 = time.time() + + base_sha = _sha256(BASE) + log(f"Build J base sha = {base_sha}") + + log("loading v8 feed + compiling target registry (no microsim) ...") + ledger = release.load_ledger_consumer_artifact( + FACTS, expected_facts_sha256=FACTS_SHA + ) + registry0 = release.compile_us_fiscal_target_registry( + ledger.facts, target_period=release.PERIOD, + include_congressional_district_targets=False, + congressional_district_vintage_crosswalk=None, + age_targets=True, allow_unaged_dollar_targets=False, + extra_support_exclusions=None) + target_specs = registry0.specs + active_registry = release.TargetRegistry(target_specs, country="us") + log(f"registry version = {active_registry.version} " + f"(expected {REG_VERSION_EXPECTED}) n_specs={len(target_specs)}") + if active_registry.version != REG_VERSION_EXPECTED: + log(f"FATAL registry version mismatch — got {active_registry.version}, " + f"expected {REG_VERSION_EXPECTED}. STOP.") + sys.exit(3) + + identity = release._target_frame_checkpoint_identity( + base_dataset_sha256=base_sha, policyengine_us_version=PEUS, seed=0, + target_period=release.PERIOD, target_registry_version=active_registry.version, + congressional_district_vintage_crosswalk_sha256=None) + log(f"checkpoint identity: {identity}") + + loaded = release._read_target_frame_checkpoint( + CKPT, identity=identity, target_specs=target_specs, + gate_congressional_district_targets=False) + if loaded is None: + log("CHECKPOINT MISS — identity mismatch; cannot fast-load. STOP + report.") + sys.exit(4) + frame, registry, _comp = loaded + log(f"checkpoint HIT: frame n(household)={frame.n('household')} " + f"n_targets={len(registry)}") + + tlw = release._fiscal_target_loss_weights(registry) + if args.verify_only: + log("verify-only: frame + registry loaded from checkpoint OK. stopping.") + return + + log("calibrating (adam, 1500 epochs, lr 0.02, mass=conserve, ratio 5.0, " + "l2=0, seed 0) — ~18 min ...") + result = calibrate( + frame, registry.to_target_set(), epochs=1500, learning_rate=0.02, + max_weight_ratio=5.0, seed=0, mass="conserve", l2_lambda=0.0, + target_loss_weights=tlw, target_loss_cap=release.US_FISCAL_TARGET_LOSS_CAP, + warm_start_weights=None) + w = np.asarray(result.weights, dtype=np.float64) + w0 = np.asarray(result.initial_weights, dtype=np.float64) + ess = (w.sum() ** 2) / (w ** 2).sum() + log(f"DONE. final_loss={result.final_loss:.10f} initial_loss={result.initial_loss:.6f}") + log(f" Build H dense anchor final_loss={BUILDH_DENSE_FINAL_LOSS:.6f} (same registry -> comparable)") + log(f" ESS={ess:.2f} n_nonzero={(w>0).sum()} n_households={w.shape[0]}") + + np.save(OUT / "dense_household_weight.npy", w) + np.save(OUT / "dense_initial_weight.npy", w0) + np.savez( + OUT / "populace_us_2024_calibration.npz", + household_weight=w, + initial_household_weight=w0, + ) + log(f"saved dense weights + warm-start npz to {OUT} ({time.time()-t0:.1f}s)") + + sane = np.isfinite(result.final_loss) and SANE_LO <= result.final_loss <= SANE_HI + log(f"SANITY {'PASS' if sane else 'FAIL'} (final_loss in [{SANE_LO}, {SANE_HI}])") + if not sane: + sys.exit(5) + + +if __name__ == "__main__": + main() diff --git a/experiments/build_j_recert/verify_selection_carryover_buildj.py b/experiments/build_j_recert/verify_selection_carryover_buildj.py new file mode 100644 index 00000000..36aa0637 --- /dev/null +++ b/experiments/build_j_recert/verify_selection_carryover_buildj.py @@ -0,0 +1,67 @@ +"""Build J STEP 2 — selection carry-over verification (#330 identity join). + +Re-derive the Build I rmloss100 57,240-record selection onto the NEW Build J base by +joining the manifest identities (join key: source_year, source_household_id, +household_support_channel, household_support_clone_index) onto the base frame in +"frozen_support" mode. That mode RAISES on any unmapped or ambiguous identity — the +task's STOP condition (">0 missing identities = STOP and report"). Reports n_selected +(expect 57,240), n_unmapped (expect 0), n_ambiguous (expect 0). STAGING/LOCAL ONLY. +""" +from __future__ import annotations + +import hashlib +import sys +from pathlib import Path + +WT = Path("/Users/maxghenis/PolicyEngine/_worktrees/populace-build-j-recert") +sys.path.insert(0, str(WT / "tools")) +import build_us_fiscal_refresh_release as release # noqa: E402 + +from populace.build.us_runtime.warm_start_selection import ( # noqa: E402 + load_selection_source_from_manifest, +) + +BASE = Path("/Users/maxghenis/PolicyEngine/_buildj-runtime/out/base-j/base_populace_us_2024_puf_support.h5") +MANIFEST = Path("/Users/maxghenis/PolicyEngine/_buildi-runtime/inputs/buildi_rmloss100_selection_source.json") +EXPECT_N = 57_240 + + +def _sha256(path: Path) -> str: + h = hashlib.sha256() + with open(path, "rb") as f: + for chunk in iter(lambda: f.read(1 << 20), b""): + h.update(chunk) + return h.hexdigest() + + +def main() -> int: + print(f"base sha: {_sha256(BASE)}") + print(f"manifest sha: {_sha256(MANIFEST)[:16]}…") + base_frame = release._load_frame(str(BASE)) + print(f"base frame n(household) = {base_frame.n('household')}") + source = load_selection_source_from_manifest(MANIFEST) + print(f"manifest: n_selected={source.size} join_key={source.join_key} " + f"identities_sha256={getattr(source, 'identities_sha256', 'n/a')}") + try: + mask, report = source.base_selection_mask(base_frame, mode="frozen_support") + except Exception as exc: # frozen_support raises on unmapped/ambiguous + print(f"CARRY-OVER FAIL (STOP): {type(exc).__name__}: {exc}") + return 2 + print("=== CARRY-OVER REPORT ===") + print(f" n_selected = {report.n_selected} (expect {EXPECT_N})") + print(f" n_unmapped = {report.n_unmapped} (expect 0)") + print(f" n_ambiguous = {report.n_ambiguous} (expect 0)") + print(f" mode = {report.mode}") + print(f" mask.sum() = {int(mask.sum())}") + ok = ( + report.n_selected == EXPECT_N + and report.n_unmapped == 0 + and report.n_ambiguous == 0 + and int(mask.sum()) == EXPECT_N + ) + print(f"CARRY-OVER {'PASS' if ok else 'FAIL (STOP)'}") + return 0 if ok else 2 + + +if __name__ == "__main__": + sys.exit(main()) From 5460ef0d9aaa6a377798f5d506217fdd504a80be Mon Sep 17 00:00:00 2001 From: "Claude (Build J)" Date: Thu, 9 Jul 2026 22:03:07 -0400 Subject: [PATCH 03/17] Build J: gate map + verdict-data locations; --skip-reform-validation on arms (#368) reform-VALIDATION tail (optional, post-H5, not a gate) skipped to avoid the pre-existing selection-agnostic MD-UNKNOWN crash (populace#367 / policyengine-us#8975, unfixed on pinned pe-us 1.764.6); reform-COVERAGE smoke GATE stays ON (separate flag). Recorded PERIOD=2024 for the SSI probe, the #384 register-consistency preflight, TANF exclusion removal, and per-gate verdict-data file locations. STAGING/LOCAL ONLY. Co-Authored-By: Claude Fable 5 --- PROGRESS_BUILDJ.md | 36 ++++++++++++++++++++- experiments/build_j_recert/buildj_dense.sh | 1 + experiments/build_j_recert/buildj_sparse.sh | 1 + 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/PROGRESS_BUILDJ.md b/PROGRESS_BUILDJ.md index d43c2664..9e405c59 100644 --- a/PROGRESS_BUILDJ.md +++ b/PROGRESS_BUILDJ.md @@ -82,4 +82,38 @@ zero-support (post-excl) 0. Build I was pinned to Build H lineage and did NOT ad in logs/buildj-run/base.wrapperpid). Replicates Build F's exact base command on main's (identical) builder: 3-year ASEC pool 2024+2023+2022, 2x PUF clone, seed 0, n-estimators 32, aging-facts a5d34d4a, CD assignment (cdx 383a6666, seed 0), block ladder 7ba39b95. Expect sha - 18833fb6 (finding F1). Build F base was 12m14s -> one chunk. [Blocking on base.rc + base.sha.] + 18833fb6 (finding F1). Build F base was 12m14s; this run ran ~15 min active (99% CPU, RSS ~52 GB, + free% ~86 — healthy, no jetsam risk; slower tail vs Build F is variance). [Blocking on base.rc.] + +## Gate map + verdict-data locations (verified on origin/main; for the resumed run + verdict) +Runs = worktree `.venv/bin/python tools/build_us_fiscal_refresh_release.py`; the sparse (deployable) +release dir holds every certification artifact. NO bypass flags are passed (gates ALL ON). +- **calibration_diagnostics.json** — final_loss, within-10%, ESS, realized_max_weight_ratio, key + fits (fed income tax SOI, SS, net cap gain, mortgage tax-exp). Bar = Build I 0.030833 / 0.8888 / + +0.22%. +- **input_mass_parity.json** — export-mass gate (35 cols, ±50%, $1B floor; reviewed exclusions + estate_income + non_sch_d_capital_gains ONLY). Bar = Build I PASS 0/35. +- **reform_coverage_smoke.json** — the #369 SSI probe `ssi_asset_limit_10k_20k` (binding on + bank_account_assets/stock_assets/bond_assets; individual->$10k couple->$20k; direction + reform_minus_baseline; **PERIOD = 2024**; $1B floor). Read `details.results.ssi_asset_limit_10k_20k + .effect` — VERBATIM = the SSI probe magnitude for the verdict. Gate hard-fails if <$1B (no bypass). + Note the release scores at **2024** (the scf_wealth doc's +$9.7B / #374's +$9.66B SCF-only overlay + were quoted at 2026 — state the period alongside the number). A relaxation raises SSI cost -> effect + positive. Expected: nonzero (>=$1B), LOWER than the +$9.66B overlay (re-solve vs overlay), still + above the dense-native +$1.6B (the SIPP-blend gap, #356 open — state, don't fix). +- **Structural + coverage + degenerate + take-up + register gates** — the release raises/writes a + verdict per gate; `release_gates.passed` is the aggregate. Watch surfaces: + - **#369 input-coverage manifest** (`release_input_coverage_manifest.json`: 65 required + 93 + reviewed-exclusions incl. the 3 asset leaves now REQUIRED). Hard, no `--allow-input-coverage-gaps`. + - **#369 reform-smoke** (above). + - **degenerate (#286)** — TANF exclusion REMOVED by #384 -> `takes_up_tanf_if_eligible` must now + carry signal AND be unexcused (Build I's rmloss100 made it non-degenerate). A constant-at-default + unexcused column fails; a stale exclusion fails. + - **#384 register-consistency (#377)** — cross-checks signal-side vs excused-side registers; any + column both required-to-signal AND excused (degenerate/documented-absent) fails. Cheap preflight. + - **#384 cross-register + take-up preflights**; **eCPS parity (#316)**; **export-mass**; **base + population / immigration (#266) / validation-input-coverage (#278/9)** structural gates. + A gate failure is a FINDING: diagnose precisely (three-strike per chunk), do NOT bypass. +- **release_manifest.json** + exported **populace_us_2024.h5** — written last; `--skip-reform-validation` + avoids the Build I MD-UNKNOWN tail bug (policyengine-us#8975 / populace#367) without touching the + certified dataset (gates + export-mass + H5 all complete before the optional reform-validation tail). diff --git a/experiments/build_j_recert/buildj_dense.sh b/experiments/build_j_recert/buildj_dense.sh index d0239ae3..4e6c98db 100644 --- a/experiments/build_j_recert/buildj_dense.sh +++ b/experiments/build_j_recert/buildj_dense.sh @@ -75,6 +75,7 @@ SAMPLER=$! --checkpoint-root "$RT/checkpoints/buildj-dense" \ --seed 0 \ --dense-default-dataset \ + --skip-reform-validation \ --no-staging \ >> "$LOGDIR/release_dense.log" 2>&1 rc=$? diff --git a/experiments/build_j_recert/buildj_sparse.sh b/experiments/build_j_recert/buildj_sparse.sh index 7f1b496a..34f6d7a8 100644 --- a/experiments/build_j_recert/buildj_sparse.sh +++ b/experiments/build_j_recert/buildj_sparse.sh @@ -82,6 +82,7 @@ SAMPLER=$! --release-id "$RID" \ --checkpoint-root "$RT/checkpoints/buildj-sparse" \ --seed 0 \ + --skip-reform-validation \ --no-staging \ >> "$LOGDIR/release_sparse.log" 2>&1 rc=$? From 3d88c6d56b2e8d775017325b77b2ec00b4ae5b4c Mon Sep 17 00:00:00 2001 From: "Claude (Build J)" Date: Thu, 9 Jul 2026 22:36:17 -0400 Subject: [PATCH 04/17] Build J Step 1 DONE: base rebuilt rc=0, sha 0b50660a (data == Build F 18833fb6) (#368) Base DATA identical to Build F (summary byte-identical except self-sha+path; base_household_weight_total 134690323.34024483 exact; builder 0-diff build-f vs main). h5 sha 0b50660a != 18833fb6 = HDF5 serialization non-determinism, benign (all arms read sha dynamically; Build I comparison stays like-for-like; rmloss100 join keys on data cols). F1 corrected. STAGING/LOCAL ONLY. Co-Authored-By: Claude Fable 5 --- PROGRESS_BUILDJ.md | 42 ++- .../build_j_recert/base_j.summary.json | 333 ++++++++++++++++++ 2 files changed, 361 insertions(+), 14 deletions(-) create mode 100644 experiments/build_j_recert/base_j.summary.json diff --git a/PROGRESS_BUILDJ.md b/PROGRESS_BUILDJ.md index 9e405c59..e637a2ea 100644 --- a/PROGRESS_BUILDJ.md +++ b/PROGRESS_BUILDJ.md @@ -43,14 +43,21 @@ zero-support (post-excl) 0. Build I was pinned to Build H lineage and did NOT ad `_buildj-runtime/inputs/scf_cache/rscfp2022.dta`; passed via `--scf-summary-extract`. ## Architectural findings (verified on origin/main; correct the task's mental model where needed) -- **F1 — the base pool does NOT change for assets/SNAP.** #350/#352/#353 (SNAP) and #373 (SCF - wealth) modified `packages/populace-build/src/populace/build/us_runtime/*` + `source_stages.json` - + the RELEASE tool `tools/build_us_fiscal_refresh_release.py` — NOT the base builder - `tools/build_us_puf_support_base.py` (byte-identical to Build F's; `git diff` empty). Assets + - SNAP are RELEASE-TIME source stages that enrich the frame during the release build. So a base - rebuild with the same inputs/builder/pe-us is expected to reproduce **18833fb6** (NOT a "new" - sha). The rebuild is run anyway to (a) satisfy the #368 step and (b) empirically confirm - determinism; the confirming/again sha is a deliverable. [Base rebuild in flight — Step 1.] +- **F1 — the base pool DATA does NOT change for assets/SNAP; the h5 SHA does (HDF5 + non-determinism).** #350/#352/#353 (SNAP) and #373 (SCF wealth) modified `us_runtime/*` + + `source_stages.json` + the RELEASE tool — NOT the base builder `build_us_puf_support_base.py` + (0-diff build-f vs origin/main). Assets + SNAP are RELEASE-TIME source stages. **VERIFIED after + the rebuild (Step 1):** the Build J base summary is byte-identical to Build F's `18833fb6` base + summary EXCEPT the self-referential `output_sha256` + `output_h5` path (263/265 json lines + identical); `base_household_weight_total = 134690323.34024483` matches Build F EXACTLY (a + QRF/imputation change would perturb it); puf_donor_rows 211677, seed 0, n_estimators 32 all + match. So the base DATA is unchanged. The base h5 SHA is **`0b50660a…`** (NOT 18833fb6) purely + because HDF5 serialization is non-reproducible (embedded timestamps / chunk layout), not a data + change. BENIGN: (a) the checkpoint identity + all arms read the base sha DYNAMICALLY + (self-consistent on 0b50660a); (b) the Build I comparison stays like-for-like (identical pool + data); (c) the rmloss100 identity join keys on DATA columns (source_year/household_id/channel/ + clone), not the file hash. The task's "new base sha expected" is literally true (new bytes) but + the pool is unchanged — corrects my pre-rebuild prediction that the SHA byte-value would reproduce. - **F2 — the calibration target registry is unchanged.** `fiscal_target_references.json` is byte-identical between Build H (b42fbfe) and origin/main (both `010fbfa5…`). So v8 facts (94b7155f) remain valid and the registry compiles to the same 5533/5514 surface -> the Build I @@ -78,12 +85,19 @@ zero-support (post-excl) 0. Build I was pinned to Build H lineage and did NOT ad Established findings F1/F2/F3 above. Wrote the detacher (`detach.py`, start_new_session=True + caffeinate) and the base launcher (`buildj_base.sh`, integrity preflight + pressure sampler, no killing watchdog). -- **Step 1 (base rebuild — IN FLIGHT).** Launched `buildj_base.sh` detached (wrapper pid recorded - in logs/buildj-run/base.wrapperpid). Replicates Build F's exact base command on main's - (identical) builder: 3-year ASEC pool 2024+2023+2022, 2x PUF clone, seed 0, n-estimators 32, - aging-facts a5d34d4a, CD assignment (cdx 383a6666, seed 0), block ladder 7ba39b95. Expect sha - 18833fb6 (finding F1). Build F base was 12m14s; this run ran ~15 min active (99% CPU, RSS ~52 GB, - free% ~86 — healthy, no jetsam risk; slower tail vs Build F is variance). [Blocking on base.rc.] +- **Step 1 (base rebuild — DONE, rc=0).** `buildj_base.sh` completed 02:06:03Z (~19.6 min wall; + Build F was 12m14s — the extra is CPU contention with concurrent recon, healthy throughout: 99% + CPU, RSS peaked ~53 GB, free% ~86, no jetsam). Base at + `_buildj-runtime/out/base-j/base_populace_us_2024_puf_support.h5` (1,879,908,154 bytes). **Base + sha `0b50660a21e0e138cbdcf941303240435b8cf92f4ca3824b2c062ae1085e9c51`** — differs from Build F's + 18833fb6, but the base DATA is IDENTICAL (finding F1: summary byte-identical except the self-sha + + path; base_household_weight_total 134690323.34024483 == Build F exactly; builder 0-diff build-f + vs main). The SHA delta is HDF5 serialization non-determinism, not a data change. Proceeding on + 0b50660a (read dynamically by every arm). +- **Step 2 (selection carry-over — running).** `verify_selection_carryover_buildj.py`: #330 identity + join of the Build I rmloss100 manifest onto base-j in frozen_support mode (raises on any + unmapped/ambiguous = the >0-miss STOP). Expect n_selected 57,240, n_unmapped 0, n_ambiguous 0 + (the join keys on data-identity columns, unaffected by the h5-byte delta). ## Gate map + verdict-data locations (verified on origin/main; for the resumed run + verdict) Runs = worktree `.venv/bin/python tools/build_us_fiscal_refresh_release.py`; the sparse (deployable) diff --git a/experiments/build_j_recert/base_j.summary.json b/experiments/build_j_recert/base_j.summary.json new file mode 100644 index 00000000..60bfbce4 --- /dev/null +++ b/experiments/build_j_recert/base_j.summary.json @@ -0,0 +1,333 @@ +{ + "base_h5": null, + "base_household_weight_total": 134690323.34024483, + "base_rows": { + "family": 189401, + "household": 168852, + "marital_unit": 345873, + "person": 432523, + "spm_unit": 176039, + "tax_unit": 231007 + }, + "base_sha256": null, + "base_source": { + "kind": "pooled_asec", + "metadata": { + "anchor_year": 2024, + "sources": [ + { + "raw_household_rows": 55762, + "raw_person_population": 325952369.06, + "raw_person_rows": 142125, + "relationship_recode_source": "source:A_EXPRRP", + "scale": 0.3333333333333333, + "share": 0.3333333333333333, + "source_file": "census_cps_2024.h5", + "weighted_person_population": 108650789.68666667, + "year": 2024 + }, + { + "raw_household_rows": 56251, + "raw_person_population": 320890854.43000007, + "raw_person_rows": 144265, + "relationship_recode_source": "derived:line_spouse_parent", + "scale": 0.3385911071839787, + "share": 0.3333333333333333, + "source_file": "census_cps_2023.h5", + "weighted_person_population": 108650789.68666664, + "year": 2023 + }, + { + "raw_household_rows": 56839, + "raw_person_population": 318771270.71000004, + "raw_person_rows": 146133, + "relationship_recode_source": "derived:line_spouse_parent", + "scale": 0.34084247756916264, + "share": 0.3333333333333333, + "source_file": "census_cps_2022.h5", + "weighted_person_population": 108650789.68666667, + "year": 2022 + } + ], + "target_person_population": 325952369.06, + "weighted_person_population": 325952369.05999994 + }, + "sources": [ + { + "max_households": null, + "path": "/Users/maxghenis/PolicyEngine/policyengine-us-data/policyengine_us_data/storage/census_cps_2024.h5", + "sha256": "ec36604cb735a660b51b0b2f90be27d803b5878f3464fb30d0eacead59c1260d", + "share": null, + "year": 2024 + }, + { + "max_households": null, + "path": "/Users/maxghenis/PolicyEngine/policyengine-us-data/policyengine_us_data/storage/census_cps_2023.h5", + "sha256": "cb57817327799f42b741caed5f9be94d04021c2e6809c1ad7bd0686da5428d88", + "share": null, + "year": 2023 + }, + { + "max_households": null, + "path": "/Users/maxghenis/PolicyEngine/policyengine-us-data/policyengine_us_data/storage/census_cps_2022.h5", + "sha256": "7ccca976284bb47815d84460cc4f75a0a65d26d7754ab0a0f417de351b3d474e", + "share": null, + "year": 2022 + } + ], + "support_spine_spec": null, + "target_year": 2024 + }, + "channel_output_totals": { + "asec": { + "charitable_cash_donations": 0.0, + "charitable_non_cash_donations": 0.0, + "employment_income_before_lsr": 14293206088.0, + "estate_income": 0.0, + "farm_income": 63222024.0, + "first_home_mortgage_balance": 0.0, + "first_home_mortgage_interest": 0.0, + "first_home_mortgage_origination_year": 0.0, + "health_savings_account_ald": 0.0, + "home_mortgage_interest": 0.0, + "long_term_capital_gains_before_response": 232680034.4, + "miscellaneous_income": 29767313.0, + "non_qualified_dividend_income": 138071929.46400002, + "non_sch_d_capital_gains": 0.0, + "partnership_income": 0.0, + "partnership_self_employment_net_earnings": 0.0, + "qualified_dividend_income": 112058377.53599998, + "real_estate_taxes": 0.0, + "rental_income": 284749686.0, + "s_corp_income": 0.0, + "second_home_mortgage_balance": 0.0, + "second_home_mortgage_interest": 0.0, + "second_home_mortgage_origination_year": 0.0, + "self_employed_pension_contributions_desired": 0.0, + "self_employment_income_before_lsr": 690840548.0, + "short_term_capital_gains": 31729095.599999998, + "social_security_dependents": 14907978.0, + "social_security_disability": 129518946.0, + "social_security_retirement": 1239220149.0, + "social_security_survivors": 26586427.0, + "student_loan_interest": 0.0, + "tax_exempt_interest_income": 0.0, + "taxable_interest_income": 514367888.0927237, + "taxable_ira_distributions": 123244773.0, + "taxable_private_pension_income": 389261169.46, + "traditional_ira_contributions_desired": 0.0 + }, + "puf_tax_detail": { + "charitable_cash_donations": 342688295.3525839, + "charitable_non_cash_donations": 77570376.92806828, + "employment_income_before_lsr": 14293804422.785645, + "estate_income": 73795642.36272816, + "farm_income": 31307556.17238779, + "first_home_mortgage_balance": 19289480396.62441, + "first_home_mortgage_interest": 797427068.1769809, + "first_home_mortgage_origination_year": 126020724.0, + "health_savings_account_ald": 13793535.662896382, + "home_mortgage_interest": 811476377.0874662, + "long_term_capital_gains_before_response": 232618448.50891668, + "miscellaneous_income": -54218786.68478381, + "non_qualified_dividend_income": 50460052.57471234, + "non_sch_d_capital_gains": 77359759.73723212, + "partnership_income": 2121535525.9958038, + "partnership_self_employment_net_earnings": 31650070.658615656, + "qualified_dividend_income": 193736584.97692686, + "real_estate_taxes": 442184659.1189757, + "rental_income": 222925083.61599404, + "s_corp_income": 0.0, + "second_home_mortgage_balance": 0.0, + "second_home_mortgage_interest": 0.0, + "second_home_mortgage_origination_year": 0.0, + "self_employed_pension_contributions_desired": 57817825.61378294, + "self_employment_income_before_lsr": 692610785.4284253, + "short_term_capital_gains": 31770680.093051545, + "social_security_dependents": 174872201.82958794, + "social_security_disability": 258516855.45894375, + "social_security_retirement": 1034295691.7649374, + "social_security_survivors": 182250560.93798137, + "student_loan_interest": 24355401.72528515, + "tax_exempt_interest_income": 63255778.16347217, + "taxable_interest_income": 514394536.21998626, + "taxable_ira_distributions": 726191580.246481, + "taxable_private_pension_income": 1797676388.1225595, + "traditional_ira_contributions_desired": 46450772.81113391 + } + }, + "channel_weight_totals": { + "asec": 67345161.67012241, + "puf_tax_detail": 67345161.67012241 + }, + "congressional_district_assignment": { + "applied": true, + "assigned_congressional_districts": 436, + "assigned_states": 51, + "congressional_district_vintage_crosswalk": "/Users/maxghenis/PolicyEngine/_buildf-runtime/inputs/congressional_district_vintage_crosswalk.csv", + "congressional_district_vintage_crosswalk_sha256": "383a666631aafd4f584816935ae340960fb3fc127929dccf61d223790a82140b", + "distribution_congressional_districts": 436, + "distribution_states": 51, + "household_rows": 337704, + "ledger_facts": "/Users/maxghenis/PolicyEngine/_buildf-runtime/inputs/consumer_facts_builde_aging_v5.jsonl", + "ledger_facts_sha256": "a5d34d4aad325d8c79c45ea4944c7eec3a4e51e30a9997c3efa1da4571976816", + "seed": 0, + "state_total_proxy_districts": 0 + }, + "expanded_household_weight_total": 134690323.34024483, + "expanded_rows": { + "family": 378802, + "household": 337704, + "marital_unit": 691746, + "person": 865046, + "spm_unit": 352078, + "tax_unit": 462014 + }, + "geography_ladder_assignment": { + "applied": true, + "artifact": "/Users/maxghenis/PolicyEngine/_buildf-runtime/inputs/us_block_ladder_2020.npz", + "artifact_sha256": "7ba39b959068181b56a7ce1dc8f2477b31af33f28d0a1803ff6cba84cdfab06b", + "assigned_block_geoid_values": 295559, + "assigned_cbsa_code_values": 918, + "assigned_county_fips_values": 3115, + "assigned_place_fips_values": 13757, + "assigned_sldl_values": 596, + "assigned_sldu_values": 100, + "assigned_tract_geoid_values": 76901, + "block_geoid_nonempty_weighted_share": 1.0, + "cbsa_code_nonempty_weighted_share": 0.934370818765334, + "county_fips_nonempty_weighted_share": 1.0, + "gate": { + "details": { + "cbsa_code_nonempty_weighted_share": 0.934370818765334, + "nyc_weighted_household_share": 0.02569792738318323, + "nyc_weighted_share_of_new_york": 0.435428985645774, + "place_fips_nonempty_weighted_share": 0.7501115109795187, + "sldl_nonempty_weighted_share": 0.99153514241429, + "sldu_nonempty_weighted_share": 1.0 + }, + "failures": [], + "passed": true + }, + "household_rows": 337704, + "ladder_blocks": 5769942, + "layer_vintages": { + "block": "2020_tabulation_blocks", + "cbsa": "omb_2023_delineations", + "congressional_district": "119th_congress", + "place": "2020_census", + "sldl": "2020_baf", + "sldu": "2020_baf" + }, + "nyc_weighted_household_share": 0.02569792738318323, + "place_fips_nonempty_weighted_share": 0.7501115109795187, + "sampling_basis": "population", + "seed": 0, + "sldl_nonempty_weighted_share": 0.99153514241429, + "sldu_nonempty_weighted_share": 1.0, + "tract_geoid_nonempty_weighted_share": 1.0 + }, + "immigration_composition": { + "immigration_status_str": { + "population": { + "CITIZEN": 300278565.90654266, + "CUBAN_HAITIAN_ENTRANT": 551871.8912606479, + "DACA": 422917.8040477772, + "LEGAL_PERMANENT_RESIDENT": 11549530.381346337, + "UNDOCUMENTED": 13149483.076802507 + }, + "share": { + "CITIZEN": 0.9212344943910152, + "CUBAN_HAITIAN_ENTRANT": 0.0016931059370796035, + "DACA": 0.0012974834490923066, + "LEGAL_PERMANENT_RESIDENT": 0.03543318434731287, + "UNDOCUMENTED": 0.0403417318754999 + } + }, + "person_population": 325952369.05999994, + "ssn_card_type": { + "population": { + "CITIZEN": 300278565.90654266, + "NONE": 13149483.076802507, + "NON_CITIZEN_VALID_EAD": 4068284.563125225, + "OTHER_NON_CITIZEN": 8456035.51352954 + }, + "share": { + "CITIZEN": 0.9212344943910152, + "NONE": 0.0403417318754999, + "NON_CITIZEN_VALID_EAD": 0.012481224096813827, + "OTHER_NON_CITIZEN": 0.025942549636670958 + } + } + }, + "n_estimators": 32, + "output_h5": "/Users/maxghenis/PolicyEngine/_buildj-runtime/out/base-j/base_populace_us_2024_puf_support.h5", + "output_sha256": "0b50660a21e0e138cbdcf941303240435b8cf92f4ca3824b2c062ae1085e9c51", + "puf_donor_columns": [ + "charitable_cash_donations", + "charitable_non_cash_donations", + "employment_income_before_lsr", + "estate_income", + "farm_income", + "filing_status_code", + "first_home_mortgage_balance", + "first_home_mortgage_interest", + "first_home_mortgage_origination_year", + "health_savings_account_ald", + "home_mortgage_interest", + "long_term_capital_gains_before_response", + "miscellaneous_income", + "non_qualified_dividend_income", + "non_sch_d_capital_gains", + "partnership_income", + "partnership_self_employment_net_earnings", + "puf_predictor_dividend_income", + "puf_predictor_employment_income", + "puf_predictor_filing_status_code", + "puf_predictor_long_term_capital_gains", + "puf_predictor_self_employment_income", + "puf_predictor_short_term_capital_gains", + "puf_predictor_tax_unit_person_count", + "puf_predictor_taxable_interest_income", + "qualified_dividend_income", + "real_estate_taxes", + "rental_income", + "s_corp_income", + "second_home_mortgage_balance", + "second_home_mortgage_interest", + "second_home_mortgage_origination_year", + "self_employed_pension_contributions_desired", + "self_employment_income_before_lsr", + "short_term_capital_gains", + "social_security_dependents", + "social_security_disability", + "social_security_retirement", + "social_security_survivors", + "student_loan_interest", + "tax_exempt_interest_income", + "tax_unit_id", + "tax_unit_person_count", + "taxable_interest_income", + "taxable_ira_distributions", + "taxable_private_pension_income", + "traditional_ira_contributions_desired", + "weight" + ], + "puf_donor_rows": 211677, + "puf_h5": "/Users/maxghenis/PolicyEngine/policyengine-us-data/policyengine_us_data/storage/puf_2024.h5", + "puf_sha256": "7669f5b5281f20080e77204f9bd4aabfad0aa101fa283e22caf9ba8d61d4d6df", + "seed": 0, + "weights_audit": { + "details": { + "allowed_unweighted": {}, + "fits_checked": 1, + "resolved_weight_kinds": { + "us_puf_tax_detail_support": "design" + }, + "unused_allowed_unweighted": [], + "unweighted_fits": [] + }, + "failures": [], + "passed": true + } +} \ No newline at end of file From 01aed9e15e089fc21be6344caca1b1eda37957db Mon Sep 17 00:00:00 2001 From: "Claude (Build J)" Date: Thu, 9 Jul 2026 22:38:38 -0400 Subject: [PATCH 05/17] Build J Step 2 DONE: selection carry-over PASS (0 misses, 57240) (#368) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rmloss100 (152baca3) joins onto base-j with n_unmapped=0 n_ambiguous=0 — confirms F1 (base data identical, identity cols preserved). Sparse arm runs first (certification + SSI probe) then dense diagnostic; independent + serialized. STAGING/LOCAL ONLY. Co-Authored-By: Claude Fable 5 --- PROGRESS_BUILDJ.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/PROGRESS_BUILDJ.md b/PROGRESS_BUILDJ.md index e637a2ea..ca554c16 100644 --- a/PROGRESS_BUILDJ.md +++ b/PROGRESS_BUILDJ.md @@ -94,10 +94,16 @@ zero-support (post-excl) 0. Build I was pinned to Build H lineage and did NOT ad path; base_household_weight_total 134690323.34024483 == Build F exactly; builder 0-diff build-f vs main). The SHA delta is HDF5 serialization non-determinism, not a data change. Proceeding on 0b50660a (read dynamically by every arm). -- **Step 2 (selection carry-over — running).** `verify_selection_carryover_buildj.py`: #330 identity - join of the Build I rmloss100 manifest onto base-j in frozen_support mode (raises on any - unmapped/ambiguous = the >0-miss STOP). Expect n_selected 57,240, n_unmapped 0, n_ambiguous 0 - (the join keys on data-identity columns, unaffected by the h5-byte delta). +- **Step 2 (selection carry-over — DONE, PASS).** #330 identity join of the Build I rmloss100 + manifest (identities_sha256 `152baca3`, n_identities 57,240) onto base-j (n(household) 337,704) + in frozen_support mode: **n_selected 57,240, n_unmapped 0, n_ambiguous 0, mask.sum() 57,240** — + ZERO misses. Confirms F1 (identity columns preserved; the h5-byte delta doesn't touch the join) + and the release will select exactly this 57,240 support. No STOP. Log: logs/buildj-run/carryover.log. +- **Step 3/4 ordering note.** The dense (full-frame, task step 3) and sparse (57k deployable, step + 4) arms are INDEPENDENT: the sparse reduces to the 57k BEFORE ACA (own checkpoint buildj-sparse, + self-contained dense-polish solve — no dependency on the full-frame dense weights). To de-risk the + #368 verdict against session/jetsam kills, the **certifiable sparse arm runs FIRST** (all gates + + the SSI probe = the headline), then the dense DIAGNOSTIC parent. Serialized (no memory overlap). ## Gate map + verdict-data locations (verified on origin/main; for the resumed run + verdict) Runs = worktree `.venv/bin/python tools/build_us_fiscal_refresh_release.py`; the sparse (deployable) From 8ceb876323708db73213747bfac39f5f7ed6ca0c Mon Sep 17 00:00:00 2001 From: "Claude (Build J)" Date: Thu, 9 Jul 2026 22:41:37 -0400 Subject: [PATCH 06/17] Build J: verdict gate-extractor; sparse arm materializing (57k, memory-benign) (#368) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sparse release running detached (rmloss100 dense-polish, scf_wealth ON, all gates, no bypass): past ACA + into Medicaid eligibility materialization on the reduced 57k, RSS ~15GB, free% 85 — no jetsam risk. Extractor reads calibration_diagnostics/ input_mass_parity/reform_coverage_smoke/input_coverage for the #368 table. Co-Authored-By: Claude Fable 5 --- .../build_j_recert/extract_gates_buildj.py | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 experiments/build_j_recert/extract_gates_buildj.py diff --git a/experiments/build_j_recert/extract_gates_buildj.py b/experiments/build_j_recert/extract_gates_buildj.py new file mode 100644 index 00000000..84593774 --- /dev/null +++ b/experiments/build_j_recert/extract_gates_buildj.py @@ -0,0 +1,102 @@ +"""Build J verdict extractor — reads a release dir's certification artifacts and +prints the gate table + headline diagnostics + SSI probe for the #368 verdict. + +Usage: extract_gates_buildj.py (dir containing calibration_diagnostics.json etc.) +STAGING/LOCAL ONLY — read-only. +""" +from __future__ import annotations + +import json +import sys +from pathlib import Path + + +def load(p: Path): + return json.loads(p.read_text()) if p.exists() else None + + +def find(o, *names): + """Depth-first search for the first key in `names`; returns its value or None.""" + if isinstance(o, dict): + for n in names: + if n in o: + return o[n] + for v in o.values(): + r = find(v, *names) + if r is not None: + return r + elif isinstance(o, list): + for v in o: + r = find(v, *names) + if r is not None: + return r + return None + + +def main() -> int: + rd = Path(sys.argv[1]) + diag = load(rd / "calibration_diagnostics.json") + parity = load(rd / "input_mass_parity.json") + smoke = load(rd / "reform_coverage_smoke.json") + coverage = load(rd / "input_coverage.json") + + print(f"=== RELEASE DIR: {rd}") + if diag: + print("\n--- HEADLINE DIAGNOSTICS ---") + for label, keys in [ + ("final_loss", ("final_loss",)), + ("within_10pct", ("within_10_percent", "within-10%", "within_10pct", "share_within_10_percent")), + ("ESS", ("effective_sample_size", "ess", "ESS")), + ("realized_max_weight_ratio", ("realized_max_weight_ratio", "max_weight_ratio")), + ("n_records", ("n_records", "n_households")), + ("n_nonzero", ("n_nonzero",)), + ]: + print(f" {label}: {find(diag, *keys)}") + # gate roll-up under build{} + print("\n--- STRUCTURAL / SOURCE GATES (passed) ---") + build = diag.get("build", diag) if isinstance(diag, dict) else {} + for gname in [ + "target_profile_coverage", "health_input_signal", "base_population", + "immigration", "degenerate_input", "ecps_parity", "input_mass_reference", + "hours_worked", "snap_take_up", "eligibility_inputs", "pregnancy", + "snap_discretionary_exemption", "validation_input_coverage", + ]: + g = find(build, gname) or find(build, gname + "_gate") or find(build, gname + "_signal") + if isinstance(g, dict) and "passed" in g: + fl = g.get("failures") or [] + print(f" {gname}: passed={g['passed']}" + (f" FAILURES={fl}" if fl else "")) + rg = find(diag, "release_gates") + if isinstance(rg, dict): + print(f" release_gates.passed = {rg.get('passed')} failures={rg.get('failures')}") + + if parity: + print("\n--- EXPORT-MASS PARITY ---") + pg = parity.get("input_mass_parity", parity) if isinstance(parity, dict) else parity + print(f" passed = {find(parity, 'passed')}") + fails = find(parity, "failures") + print(f" failures = {fails}") + cols = find(parity, "columns") or find(parity, "results") + if isinstance(cols, (list, dict)): + n = len(cols) + print(f" n_columns = {n}") + + if smoke: + print("\n--- REFORM-COVERAGE SMOKE (SSI probe) ---") + print(f" gate passed = {find(smoke, 'passed')}") + res = find(smoke, "results") + if isinstance(res, dict): + for pid, r in res.items(): + print(f" {pid}: effect={r.get('effect'):+,.0f} min_abs={r.get('min_abs_effect'):,.0f} " + f"passed={r.get('passed')} baseline={r.get('baseline_total')} reform={r.get('reform_total')}") + + if coverage: + print("\n--- INPUT-COVERAGE (#369) ---") + print(f" passed = {find(coverage, 'passed')}") + cf = find(coverage, "failures") + print(f" failures = {cf if cf else '[]'}") + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) From 2bbcd1c76c80aae76cdd6df77b7e750f4f160a2e Mon Sep 17 00:00:00 2001 From: "Claude (Build J)" Date: Fri, 10 Jul 2026 00:15:10 -0400 Subject: [PATCH 07/17] Build J Step 4 BLOCKED: #334 Medicaid gate fails closed on RI (CMS 202412 unreported at source) (#368) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First release-scale run of #334: RI's December 2024 CMS snapshot is footnoted 0 ('Unable to Provide Data due to System Limitations') in the pinned PI dataset — ledger package + v8 feed faithful; registry compiles 50/51 state medicaid targets (FIPS 44 absent); gate unconditionally hard, runs pre-calibration in both arms. scf_wealth signal gate PASSED before the block (assets flow). STOP per protocol — no synthesis; filed populace#386 with the option space. Registry re-verified d71c59514e3a/5533 (F2 double-confirmed under #334). Co-Authored-By: Claude Fable 5 --- PROGRESS_BUILDJ.md | 33 ++++++++++++++ .../build_j_recert/issue_ri_medicaid.md | 45 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 experiments/build_j_recert/issue_ri_medicaid.md diff --git a/PROGRESS_BUILDJ.md b/PROGRESS_BUILDJ.md index ca554c16..14d2a387 100644 --- a/PROGRESS_BUILDJ.md +++ b/PROGRESS_BUILDJ.md @@ -104,6 +104,39 @@ zero-support (post-excl) 0. Build I was pinned to Build H lineage and did NOT ad self-contained dense-polish solve — no dependency on the full-frame dense weights). To de-risk the #368 verdict against session/jetsam kills, the **certifiable sparse arm runs FIRST** (all gates + the SSI probe = the headline), then the dense DIAGNOSTIC parent. Serialized (no memory overlap). +- **Step 4 (sparse arm — BLOCKED at the #334 Medicaid take-up gate; STOP per protocol).** Run + `populace-us-2024-buildj-sparse-rmloss100-01aed9e-20260710T023838Z` exited **rc=1 at 02:42:52Z** + (~4 min in, before calibration): + `Medicaid take-up failed: states without CMS enrollment targets: ['44']`. + **A REAL fail-closed finding, not an ops failure — the first release-scale run of #334.** + Diagnosis (verified at every layer): + - CMS PI dataset (`pi-dataset-april-2026-release.csv`, the pinned ledger artifact): BOTH RI + 202412 rows (P/N and final U/Y) carry Total Medicaid Enrollment **0** with footnote + **"Unable to Provide Data due to System Limitations"** — RI did not report December 2024. + The gap is exactly ONE state-month: RI 202411 = 273,400; 202501 = 279,404 (same CSV, final + rows); CMS never backfilled (April 2026 release still 0). + - Ledger package `cms-medicaid-chip-monthly-enrollment-december-2024` (vintage + april_2026_release, extracted 2026-05-11) faithfully selects the 0 row; v8 feed faithfully + carries all five RI month2024_12 facts at value 0 + (`…state_enrollment.ri.total_medicaid_enrollment` etc.). + - Registry compile on v8 (verified live): version **d71c59514e3a / 5,533 specs — IDENTICAL to + Build H/I even under #334** (the medicaid_enrollment targets were already among the 5,533; + the STAGE is new, the targets are not — F2 double-confirmed). 50 state-level + medicaid_enrollment specs; **FIPS 44 absent** (a 0-valued count compiles to no spec). + - The gate is unconditionally hard (no --allow bypass exists, correct per #368 doctrine), has + no reviewed-exclusion mechanism, and runs BEFORE calibration in BOTH arms -> the dense arm + would fail identically (NOT launched; zero wasted compute). #334's PR designed exactly this + failure mode ("fails on … a state missing its target row"), tested on fixtures; Build J is + the first run against the real feed. The v9-feed fix path is MOOT: the CMS family is already + in v8 (475 facts); a re-export reproduces the same source 0. + - **Positive #368 signal en route to the block**: the run passed the #373 scf_wealth signal + gate (raise-point :5993 < medicaid gate :6053) — the SSI asset columns materialized WITH + signal on the 57k frame. Asset restoration works; the SSI probe (post-H5) was never reached. + - Per the STOP rule (no usable RI value exists at source; do NOT synthesize — nearest-month, + cross-source T-MSIS, or an exclusion register are #334 design decisions), Build J + certification STOPS here. Filed **populace#386** (full evidence + option space). Relaunch + after the #386 decision is mechanical: all launchers staged/committed; if the fix changes + facts, swap --ledger-facts to the re-exported feed and record the new registry version. ## Gate map + verdict-data locations (verified on origin/main; for the resumed run + verdict) Runs = worktree `.venv/bin/python tools/build_us_fiscal_refresh_release.py`; the sparse (deployable) diff --git a/experiments/build_j_recert/issue_ri_medicaid.md b/experiments/build_j_recert/issue_ri_medicaid.md new file mode 100644 index 00000000..4b919781 --- /dev/null +++ b/experiments/build_j_recert/issue_ri_medicaid.md @@ -0,0 +1,45 @@ +## The failure (Build J, first release-scale run of #334) + +The Build J re-certification sparse release (#368, run `populace-us-2024-buildj-sparse-rmloss100-01aed9e-20260710T023838Z`, commit 01aed9e on origin/main 561c198) fails closed at the #334 Medicaid take-up gate: + +``` +RuntimeError: Release gates failed: Medicaid take-up failed: states without CMS +enrollment targets: ['44'] — the feed is incomplete; those states would ship +anchored-only enrollment. +``` + +This is the gate working exactly as #334 designed it ("fails on … a state missing its target row") — its 23 tests covered the missing-target mode on fixtures, but Build J is the first full-release run against the real v8 feed, and the real feed has exactly one hole: Rhode Island. + +## Root cause: RI's December 2024 CMS snapshot is unreported at source + +- **CMS PI dataset** (`pi-dataset-april-2026-release.csv`, the pinned ledger artifact): both RI 202412 rows — preliminary (P/N) and final (U/Y) — carry `Total Medicaid Enrollment = 0` with footnote **"Unable to Provide Data due to System Limitations"**. RI did not report December 2024. Every other 202412 state row has a real count. +- **The gap is exactly one state-month.** RI's own series is otherwise continuous: 202411 = 273,400 and 202501 = 279,404 (final U/Y rows in the same pinned CSV). CMS never backfilled it — the April 2026 release, 16 months later, still carries the footnoted 0. +- **Ledger package is faithful, not defective**: `cms-medicaid-chip-monthly-enrollment-december-2024` (vintage `april_2026_release`, extracted 2026-05-11) selects RI's 202412 U/Y row per spec; the extraction correctly mirrors the source's 0. +- **v8 feed is faithful**: `consumer_facts_buildh_v8.jsonl` (94b7155f) carries all five RI cms_medicaid facts at month 2024-12 with value 0 (e.g. `cms_medicaid.month2024_12.state_enrollment.ri.total_medicaid_enrollment`). +- **Registry compile drops the zero**: `compile_us_fiscal_target_registry` on v8 yields registry `d71c59514e3a` / 5,533 specs (identical to Build H/I — the medicaid_enrollment targets were already among them) with **50 state-level `medicaid_enrollment` specs; FIPS 44 absent** (a 0-valued count compiles to no spec). `_medicaid_source_target_table` therefore has no RI row, and `us_medicaid_take_up_gate` fails closed. + +So: the stage has no RI target because no true RI December-2024 count exists anywhere in the pinned source. Re-exporting the feed cannot fix this; the hole is at CMS. + +## Why this blocks Build J (and any future certification on main) + +The gate is unconditionally hard — no `--allow-*` bypass exists for it (correct per #368's no-bypass doctrine), the stage has no reviewed-exclusion mechanism, and it runs before calibration in both dense and sparse arms. Every release build on current main fails at this gate until RI has either a target or a documented exception. + +Notably, the run got past the #373 scf_wealth signal gate before failing here — the SSI asset columns materialized with signal on the 57k frame. The #368 asset restoration itself is on track; this is a separate, newly exposed data hole. + +## Decision needed (data-design call, deliberately not made in Build J) + +Build J stopped rather than synthesize a value. Options, for whoever owns #334's design: + +1. **Nearest-reported-month anchor for unreported state-months**: target RI at 202411 (273,400) or 202501 (279,404), tagged in provenance as a substituted month. Smallest change; slightly breaks the uniform point-in-time month (#332) for one state. +2. **Reviewed-exclusion register for unreported states**: let RI ship anchored-only with an issue-linked exclusion, mirroring the #286 cannot-rot semantics. Preserves month purity; RI's enrollment then rests on the CPS anchor floor alone (undercount known). +3. **Alternative CMS source for the same month**: the T-MSIS-based monthly enrollment snapshot reports RI December 2024 independently of the PI dataset. Cross-source consistency with the other 50 states needs review before splicing. +4. Any of the above requires a feed re-export only if the chosen fix changes the facts (option 1 or 3); option 2 is stage-side only. + +## Evidence trail + +- Failed run log: `_buildj-runtime/logs/buildj-run/release_sparse.log` (rc=1, 02:42:52Z) +- CSV rows: `ledger` repo `db/data/cms_medicaid/chip_monthly_enrollment_dataset/pi-dataset-april-2026-release.csv`, RI 202412 P/N + U/Y rows +- Package: `ledger` repo `packages/cms_medicaid/chip_monthly_enrollment_december_2024/source_package.yaml` (RI selected-row spec at lines 175-178) +- Registry verification: 50/51 state specs, RI absent, version d71c59514e3a (Build J worktree, pe-us 1.764.6, seed 0) + +Refs: #334 (the stage + gate), #368 (Build J re-certification, blocked on this), #332 (point-in-time month doctrine), #321 (the CHIP analogue of a concept-level data gap). From 992ee2e825858d95a914d3fdc8ed9ae2e8858f05 Mon Sep 17 00:00:00 2001 From: "Claude (Build J)" Date: Fri, 10 Jul 2026 00:16:21 -0400 Subject: [PATCH 08/17] Build J: post blocked-run report on #368; file #386 (RI Medicaid source hole) (#368) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Report: https://github.com/PolicyEngine/populace/issues/368#issuecomment-4931930270 Finding issue: https://github.com/PolicyEngine/populace/issues/386 Verdict: NOT CERTIFIABLE this run — blocked at the #334 gate pending the #386 decision; not an artifact-quality failure. Asset stage (#373) confirmed working at release scale en route. Resume is mechanical post-decision. Co-Authored-By: Claude Fable 5 --- .../build_j_recert/issue368_comment.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 experiments/build_j_recert/issue368_comment.md diff --git a/experiments/build_j_recert/issue368_comment.md b/experiments/build_j_recert/issue368_comment.md new file mode 100644 index 00000000..7e73b008 --- /dev/null +++ b/experiments/build_j_recert/issue368_comment.md @@ -0,0 +1,37 @@ +## Build J re-certification run — BLOCKED at the #334 Medicaid take-up gate (fail-closed on a real source hole); asset stage confirmed working en route + +Ran the #368 final phase per plan: full gated rebuild on `main` @ `561c198` (#369 coverage gate + reform smoke, #373 SCF asset stage, #384 TANF fix + preflights, #385 release-native loading, SNAP train #350/#352/#353) — base pool rebuild -> rmloss100 selection carry-over -> sparse release with ALL gates on and no bypass flags. **The run stopped exactly where the gate architecture says it must**: the first release-scale execution of #334's Medicaid take-up gate failed closed because Rhode Island has no CMS December-2024 enrollment target — a genuine hole at the CMS source, not an ops failure and not a populace defect. STAGING/LOCAL ONLY throughout; nothing touched prod HF or `latest.json`. + +Environment: worktree branch `build-j-recert`, policyengine-us **1.764.6** / core **3.26.11** (exact Build I match), seed 0, period 2024, v8 facts `94b7155f`, export-mass reference `c2065b64`, SCF donor `rscfp2022.dta` (zip `3bb4d890` / member `6b8dd2d9`, both matching the #373 pinned digests). + +### What completed and passed + +| step | result | +|---|---| +| Base pool rebuild (Build F command, main's builder) | **rc=0**, sha `0b50660a21e0…` — base **data identical** to Build F/I's `18833fb6` (summary byte-identical except the self-referential sha+path; `base_household_weight_total` 134,690,323.34024483 exact; builder 0-diff). The sha delta is HDF5 serialization non-determinism, benign. | +| Selection carry-over (#330 identity join, rmloss100 `152baca3`) | **PASS**: n_selected **57,240**, n_unmapped **0**, n_ambiguous **0** — the release selects exactly the Build I support. | +| Registry compile (v8 facts) | **d71c59514e3a / 5,533 specs — identical to Build H/I**, even with #334 in the code (its `medicaid_enrollment` targets were already among the 5,533; the stage is new, the targets are not). Build I comparison stays like-for-like. | +| #373 scf_wealth signal gate | **PASSED** (the run proceeded past its raise-point into Medicaid materialization) — the three SSI countable-resource asset columns (`bank_account_assets`, `stock_assets`, `bond_assets`) materialized **with signal** on the 57k frame. The #368 asset restoration works at release scale. | +| #384 register-consistency + take-up preflights, coverage manifest load | Passed (no raise before the Medicaid stage). | + +### The block (verbatim) + +``` +RuntimeError: Release gates failed: Medicaid take-up failed: states without CMS +enrollment targets: ['44'] — the feed is incomplete; those states would ship +anchored-only enrollment. +``` + +Run `populace-us-2024-buildj-sparse-rmloss100-01aed9e-20260710T023838Z`, rc=1 at 02:42:52Z, ~4 minutes in, before calibration. + +Root cause (full evidence in #386): the CMS PI dataset itself — the pinned ledger artifact — carries **RI 202412 = 0, footnoted "Unable to Provide Data due to System Limitations"** on both the preliminary and final rows. RI did not report December 2024 and CMS never backfilled it (the April 2026 release still carries the 0). The gap is exactly one state-month (RI 202411 = 273,400; 202501 = 279,404). Ledger package and v8 feed are faithful to the source; the registry correctly compiles no spec from a zero count, so 50 of 51 states have targets and RI does not. The gate is unconditionally hard (no bypass flag exists — correct per this issue's own no-bypass doctrine), has no reviewed-exclusion register, and runs before calibration in both arms, so the dense arm would fail identically (not launched; no wasted compute). + +This is the #368 gate philosophy vindicated on its first real outing, from an unexpected direction: a merged-but-never-release-tested stage (#334) refused to ship a silently wrong state (RI would have reverted to anchored-only enrollment, invisibly) and instead stopped the release with a precise, diagnosable message. + +### Verdict: NOT CERTIFIABLE in this run — blocked, pending a #386 decision (not an artifact-quality failure) + +No calibration ran, so there are no Build J loss/within-10%/income-tax/export-mass/SSI-probe numbers to put against the Build I bar (0.030833 / 0.8888 / +0.22% / 0-of-35). The blocker is a one-state data-availability decision that belongs to #334's design owner, deliberately not made here (no synthesized value, no nearest-month splice, no cross-source splice, no invented exclusion). Options are laid out in **#386**: nearest-reported-month anchor, an issue-linked reviewed-exclusion register for unreported states, or a T-MSIS-sourced same-month value. + +Resume is mechanical once #386 is decided: all launchers, the carry-over verifier, and the gate extractor are staged and committed on `build-j-recert` (`experiments/build_j_recert/`, runtime mirrors in `_buildj-runtime/`); if the fix changes facts, the relaunch swaps `--ledger-facts` to the re-exported feed and records the new registry version — otherwise it is a stage-side change and the same v8 invariants hold. + +Cache-key so far: base `0b50660a` (data == `18833fb6`); pe-us 1.764.6 / core 3.26.11; seed 0; period 2024; feed v8 `94b7155f`; registry `d71c59514e3a` (5,533); selection `152baca3` (57,240; join 0 unmapped / 0 ambiguous); zero-support exclusions `abb106af` (revalidation not reached); export-mass ref `c2065b64`. Working log `PROGRESS_BUILDJ.md` on `build-j-recert`; runtime `~/PolicyEngine/_buildj-runtime/`. From e61b359da0ad1ad14a517fac77c562dc0bb35c1b Mon Sep 17 00:00:00 2001 From: "Claude (Build J)" Date: Fri, 10 Jul 2026 01:38:58 -0400 Subject: [PATCH 09/17] Build J Step 5: merge #387 (CMS substitution register, RI->2024-11) + relaunch sparse (#368) Registry grows 5533->5534 (injected RI spec 273,400, issue-linked #386, cannot-rot); Build I comparison caveat: like-for-like plus the substituted RI target. Run populace-us-2024-buildj-sparse-rmloss100-a7ad0c8-20260710T053754Z detached. Co-Authored-By: Claude Fable 5 --- PROGRESS_BUILDJ.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/PROGRESS_BUILDJ.md b/PROGRESS_BUILDJ.md index 14d2a387..2a351691 100644 --- a/PROGRESS_BUILDJ.md +++ b/PROGRESS_BUILDJ.md @@ -137,6 +137,24 @@ zero-support (post-excl) 0. Build I was pinned to Build H lineage and did NOT ad certification STOPS here. Filed **populace#386** (full evidence + option space). Relaunch after the #386 decision is mechanical: all launchers staged/committed; if the fix changes facts, swap --ledger-facts to the re-exported feed and record the new registry version. +- **Step 5 (#387 remedy merged; sparse RELAUNCHED).** #386's remedy landed on main as **#387 + (012742e)**: a reviewed CMS Medicaid enrollment substitution register + (`US_MEDICAID_ENROLLMENT_SUBSTITUTIONS` in medicaid_take_up.py) — RI/44 -> the ledger-verified + November 2024 fact **273,400** (`cms_medicaid.month2024_11.state_enrollment.ri.total_medicaid_ + enrollment`), issue-linked to #386, **cannot-rot** (if CMS backfills a real 2024-12 RI count the + entry goes stale and the gate FAILS, #286 doctrine), applied at release :5678 immediately + post-registry-compile so the augmented registry feeds the checkpoint identity, the target table, + AND the certification panel (substitution records go into build_manifest + gate diagnostics). + Merged origin/main into build-j-recert (a7ad0c8; zero conflicts — #387 touches only + medicaid_take_up.py, us_runtime/__init__.py, the release tool, and tests). **Registry + consequence**: the injected RI spec grows the surface 5,533 -> **5,534 specs and changes the + registry version** (was d71c59514e3a) — the Build I comparison gains the one-spec CMS-substitution + caveat (like-for-like-plus-injected-RI-target); dense/sparse Build J arms stay internally + consistent. Failed run's checkpoint dir was empty (died pre-checkpoint) -> clean rematerialization. + Relaunched sparse detached @ commit a7ad0c8: run id + `populace-us-2024-buildj-sparse-rmloss100-a7ad0c8-20260710T053754Z`. Watch: past the Medicaid + gate at the ~4-min mark (where 01aed9e died), then materialization -> solve -> gates -> H5 -> + SSI probe. ## Gate map + verdict-data locations (verified on origin/main; for the resumed run + verdict) Runs = worktree `.venv/bin/python tools/build_us_fiscal_refresh_release.py`; the sparse (deployable) From 20b94dbe977e21fd3d53b4d1df2a4a7dc52d9e78 Mon Sep 17 00:00:00 2001 From: "Claude (Build J)" Date: Fri, 10 Jul 2026 03:13:42 -0400 Subject: [PATCH 10/17] Remove five rotted eCPS parity exemptions: the candidate populates the layers now (#368) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The #337 staleness check caught these on Build J's first full-release pass — coverage growth digesting into the debt ledger, verified per-layer on the actual rmloss100 57,240 candidate frame with the gate's own us_nonzero_shares: block_geoid / tract_geoid / county_fips: candidate 1.0 == reference 1.0 (the #277/#289 geography-ladder spine, carried by the base pool) spm_unit_pre_subsidy_childcare_expenses: candidate 0.0755 vs reference 0.1022 (raw CPS childcare signal now carried; depth still tracked in #32) health_savings_account_ald: candidate 0.00936 vs reference 0.0962 (populated but thin, ~10% of the incumbent share; depth tracked in #32) All five are genuine population (not spurious writes), so removal is the mechanism's prescribed path: parity now checks them as ordinary layers (reference-populated -> candidate-populated = pass). The register shrinks 93 -> 88 entries. Parity register tests green (13 passed). Co-Authored-By: Claude Fable 5 --- .../build/us/ecps_parity_known_gaps.json | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/packages/populace-build/src/populace/build/us/ecps_parity_known_gaps.json b/packages/populace-build/src/populace/build/us/ecps_parity_known_gaps.json index 647c5253..98587b7e 100644 --- a/packages/populace-build/src/populace/build/us/ecps_parity_known_gaps.json +++ b/packages/populace-build/src/populace/build/us/ecps_parity_known_gaps.json @@ -22,10 +22,6 @@ "reason": "Vehicle-ownership / auto-loan input (populace#49 cites us-data #267/#281; see also #252 for the OBBBA auto-loan deduction); not yet on the frame.", "issue": "PolicyEngine/populace#49" }, - "block_geoid": { - "reason": "Fine-grain geography code carried by the incumbent but not on the small national candidate frame; remaining input-layer work (#38).", - "issue": "PolicyEngine/populace#38" - }, "business_is_sstb": { "reason": "Section 199A QBI / passthrough-qualification input; not yet on the candidate frame (QBI base already off vs targets, #298).", "issue": "PolicyEngine/populace#298" @@ -42,10 +38,6 @@ "reason": "HHS OCSE child-support received/paid SPM input; not yet on the frame.", "issue": "PolicyEngine/populace#32" }, - "county_fips": { - "reason": "Fine-grain geography code carried by the incumbent but not on the small national candidate frame; remaining input-layer work (#38).", - "issue": "PolicyEngine/populace#38" - }, "cps_race": { "reason": "Demographic / occupation / labor-status descriptor input carried by the incumbent but not yet on the candidate frame; remaining input-layer work (#38).", "issue": "PolicyEngine/populace#38" @@ -110,10 +102,6 @@ "reason": "Demographic / occupation / labor-status descriptor input carried by the incumbent but not yet on the candidate frame; remaining input-layer work (#38).", "issue": "PolicyEngine/populace#38" }, - "health_savings_account_ald": { - "reason": "SPM MOOP / work-expense / deduction input (childcare-MOOP-work-expense family of #32); not yet on the candidate frame.", - "issue": "PolicyEngine/populace#32" - }, "hourly_wage": { "reason": "Hours-worked / hourly-wage / labor input not yet carried through Populace US outputs (#242).", "issue": "PolicyEngine/populace#242" @@ -258,10 +246,6 @@ "reason": "SPM energy-subsidy (LIHEAP) resource input; not yet on the candidate frame.", "issue": "PolicyEngine/populace#32" }, - "spm_unit_pre_subsidy_childcare_expenses": { - "reason": "SPM childcare-expense input; not yet on the candidate frame.", - "issue": "PolicyEngine/populace#32" - }, "spm_unit_tenure_type": { "reason": "HUD housing-assistance / tenure SPM input feeding capped housing subsidy; not yet on the candidate frame.", "issue": "PolicyEngine/populace#32" @@ -334,10 +318,6 @@ "reason": "Residual US tax-input / income-source layer not yet sourced onto the candidate frame; tracked as remaining input-layer work in #38.", "issue": "PolicyEngine/populace#38" }, - "tract_geoid": { - "reason": "Fine-grain geography code carried by the incumbent but not on the small national candidate frame; remaining input-layer work (#38).", - "issue": "PolicyEngine/populace#38" - }, "treasury_tipped_occupation_code": { "reason": "Residual US tax-input / income-source layer not yet sourced onto the candidate frame; tracked as remaining input-layer work in #38.", "issue": "PolicyEngine/populace#38" From 7d6535d06bfba2673f20db37c21a89de775b5d5d Mon Sep 17 00:00:00 2001 From: "Claude (Build J)" Date: Fri, 10 Jul 2026 03:15:04 -0400 Subject: [PATCH 11/17] Build J Step 6: eCPS parity anti-rot catch diagnosed + fixed; sparse relaunched (#368) Co-Authored-By: Claude Fable 5 --- PROGRESS_BUILDJ.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/PROGRESS_BUILDJ.md b/PROGRESS_BUILDJ.md index 2a351691..c1769d41 100644 --- a/PROGRESS_BUILDJ.md +++ b/PROGRESS_BUILDJ.md @@ -155,6 +155,27 @@ zero-support (post-excl) 0. Build I was pinned to Build H lineage and did NOT ad `populace-us-2024-buildj-sparse-rmloss100-a7ad0c8-20260710T053754Z`. Watch: past the Medicaid gate at the ~4-min mark (where 01aed9e died), then materialization -> solve -> gates -> H5 -> SSI probe. +- **Step 6 (a7ad0c8 run: Medicaid gate PASSED -> NEXT anti-rot catch, eCPS parity; fixed + + relaunched).** The a7ad0c8 run cleared the #334 Medicaid gate (#387 substitution works — RI + target present) and died at the NEXT gate in sequence, rc=1 at 05:41:47Z: `eCPS parity failed: + Stale known-gap exemptions — the candidate populates the layer now, remove the exemption or + re-reason it: ['block_geoid', 'county_fips', 'health_savings_account_ald', + 'spm_unit_pre_subsidy_childcare_expenses', 'tract_geoid']`. **Gate-class #2, another anti-rot + catch (#337's staleness check), also a GOOD failure** — the week's coverage merges populate five + layers the debt ledger still exempted. Verified EACH against the actual candidate frame (the + gate's own `us_nonzero_shares` on the rmloss100-reduced 57,240): block/tract/county geo triplet + **1.0 == reference 1.0** (the #277/#289 geography-ladder spine, base-carried); + spm_unit_pre_subsidy_childcare_expenses **0.0755** vs ref 0.1022 (raw CPS childcare signal now + carried); health_savings_account_ald **0.00936** vs ref 0.0962 (populated but thin, ~10% of the + incumbent share). All five = GENUINE population (not spurious writes) -> the mechanism's + prescribed path is REMOVE (staleness keys on share>0; no reason text can satisfy it; "re-reason" + is only for spurious population). Removed the five from `ecps_parity_known_gaps.json` (93 -> 88 + entries; depth gaps for HSA/childcare stay tracked by their existing issue #32); parity register + tests green (13 passed). NOTE for wrap-up: this register edit lives on build-j-recert and needs + a main PR alongside certification. Committed 20b94db; relaunched sparse: run id + `populace-us-2024-buildj-sparse-rmloss100-20b94db-20260710T071342Z`. **Coordinator flag rule: + gate-class #1 = #334 Medicaid (fixed by #387), #2 = #337 eCPS parity staleness (fixed here); a + THIRD distinct gate class failing = flag for something systematic.** ## Gate map + verdict-data locations (verified on origin/main; for the resumed run + verdict) Runs = worktree `.venv/bin/python tools/build_us_fiscal_refresh_release.py`; the sparse (deployable) From d79815869fce0d6ef1826521d3878c45df39e2e8 Mon Sep 17 00:00:00 2001 From: "Claude (Build J)" Date: Fri, 10 Jul 2026 04:46:33 -0400 Subject: [PATCH 12/17] =?UTF-8?q?Build=20J=20Step=207:=20zero-support=20ca?= =?UTF-8?q?tch=20#3=20=E2=80=94=20five=20thin-state=20TANF=20cells=20under?= =?UTF-8?q?=20live=20take-up=20seeding=20(#368)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Third register digesting the week's coverage growth (coordinator-confirmed same root cause, not systemic): #384 made TANF take-up seeding live (13,205/59,900 spm_units True vs the old constant-True), and fl/ia/mo/ne/nj lose their few sparse-selection TANF carriers under the seeded draw. Verified on the identity-matched buildj-sparse checkpoint (registry 2496460ad8c3, 5,515 specs): exactly those five cells at 0 nonzero records; all other states 1-14 (national 156); AL = the pre-existing Build-I exclusion. New 24-cell exclusion list (19 Build-I verbatim + 5 TANF, measured justifications, sha 0be0c200); sparse now compiles 5,533-24+1 = 5,510 specs (Build I: 5,514). Selection-side remedy tracked as #346/#355-class work. Co-Authored-By: Claude Fable 5 --- PROGRESS_BUILDJ.md | 29 +++++++++++++++++++ experiments/build_j_recert/buildj_sparse.sh | 4 +-- ...sparse_zero_support_exclusions_buildj.json | 26 +++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 experiments/build_j_recert/sparse_zero_support_exclusions_buildj.json diff --git a/PROGRESS_BUILDJ.md b/PROGRESS_BUILDJ.md index c1769d41..32f17faf 100644 --- a/PROGRESS_BUILDJ.md +++ b/PROGRESS_BUILDJ.md @@ -176,6 +176,35 @@ zero-support (post-excl) 0. Build I was pinned to Build H lineage and did NOT ad `populace-us-2024-buildj-sparse-rmloss100-20b94db-20260710T071342Z`. **Coordinator flag rule: gate-class #1 = #334 Medicaid (fixed by #387), #2 = #337 eCPS parity staleness (fixed here); a THIRD distinct gate class failing = flag for something systematic.** +- **Step 7 (20b94db run: parity PASSED -> gate-class #3, zero-support; coordinator confirmed + same root cause; fixed + relaunched).** The 20b94db run cleared Medicaid AND eCPS parity, + materialized ACA + Medicaid + ALL FIVE JCT reform targets, wrote the target-frame checkpoint + (119 MB, atomic) + reform vector cache, then rc=1 at 07:37:57Z at the zero-support preflight + (:6436): `5 positive fiscal targets have zero materialized support` — the five cells VERBATIM: + `hhs_acf_tanf.fy2024.cash_assistance.{fl,ia,mo,ne,nj}.basic_assistance_excluding_relative_ + foster_care_and_adoption_guardianship.all_funds@2024`. Coordinator ran the systematic check: + same root cause as #1/#2 (coverage growth), NOT systemic breakage — proceeding per the cycle; + three-class pattern goes to Max in the morning summary. + **Mechanism + verification (on the EXACT frame the gate measured — identity-matched checkpoint + load, registry `2496460ad8c3` / 5,515 = 5,533 − 19 excl + 1 RI substitution, base 0b50660a):** + #384 removed the stale constant-True TANF exclusion and the take-up seeding is LIVE + (takes_up_tanf_if_eligible on spm_unit: **13,205 / 59,900 True** — real variation vs Build H/I's + effective constant-True world). Under the seeded draw, five thin-TANF states' few carriers all + fall out (seed-0 draws + engine eligibility): measured per-state nonzero counts on the + materialized household TANF cells — **fl 0, ia 0, mo 0, ne 0, nj 0** (ZERO SUPPORT, exactly the + gate's five) while every other non-excluded state carries 1-14 supporting records (ca 14, ny 10, + oh 10, ...; national cell 156) and AL never compiles (pre-existing exclusion). The Build-I + 19-cell exclusion list was pre-TANF-live vintage — Build I's AL-only TANF hole reflected the + constant-True world. Same class as the Build I AL precedent: per-artifact + support-expressibility; the 337,704 dense parent expresses these cells; selection-side remedy + (thin-state TANF carriers) = #346/#355-class work. + **Fix:** wrote `_buildj-runtime/inputs/sparse_zero_support_exclusions_buildj.json` — the 19 + Build-I cells VERBATIM + the 5 TANF cells with measured justifications (sha `0be0c200…`, + 24 cells); launcher now points at it. **Registry consequence:** sparse compiles + 5,533 − 24 + 1 = **5,510 specs** (Build I compiled 5,514; delta = −5 TANF thin-state cells + + 1 RI substitution — both live-coverage consequences, to be stated in the verdict). + Relaunch note: changing exclusions changes the compiled registry -> checkpoint identity MISS -> + full rematerialization (~24 min), unavoidable by design (exclusions apply at compile). ## Gate map + verdict-data locations (verified on origin/main; for the resumed run + verdict) Runs = worktree `.venv/bin/python tools/build_us_fiscal_refresh_release.py`; the sparse (deployable) diff --git a/experiments/build_j_recert/buildj_sparse.sh b/experiments/build_j_recert/buildj_sparse.sh index 34f6d7a8..f2bd62f5 100644 --- a/experiments/build_j_recert/buildj_sparse.sh +++ b/experiments/build_j_recert/buildj_sparse.sh @@ -17,7 +17,7 @@ WT=/Users/maxghenis/PolicyEngine/_worktrees/populace-build-j-recert BASE="$RT/out/base-j/base_populace_us_2024_puf_support.h5" REF=/Users/maxghenis/PolicyEngine/_buildg-runtime/forensics/populace_us_2024.h5 # c2065b64 SEL=/Users/maxghenis/PolicyEngine/_buildi-runtime/inputs/buildi_rmloss100_selection_source.json -SPARSE_EXCL=/Users/maxghenis/PolicyEngine/_buildi-runtime/inputs/sparse_zero_support_exclusions_buildi.json +SPARSE_EXCL=/Users/maxghenis/PolicyEngine/_buildj-runtime/inputs/sparse_zero_support_exclusions_buildj.json # 24-cell: Build-I 19 + 5 TANF (live take-up seeding) FACTS=/Users/maxghenis/PolicyEngine/_buildh-runtime/inputs/consumer_facts_buildh_v8.jsonl SCF="$RT/inputs/scf_cache/rscfp2022.dta" LOGDIR="$RT/logs/buildj-run" @@ -46,7 +46,7 @@ say " base sha: $BASE_SHA" say " sel sha: ${SEL_SHA12}… (rmloss100 manifest)" say " ref sha: ${REF_SHA12}…" say " facts sha: $FACTS_SHA (v8)" -say " excl sha: ${EXCL_SHA12}… (19-cell Build-I, revalidated by release)" +say " excl sha: ${EXCL_SHA12}… (24-cell Build-J: 19 Build-I + 5 TANF)" say " scf sha: ${SCF_SHA12}… (rscfp2022.dta member)" if [ "$REF_SHA12" != "c2065b642ab0" ]; then say "FATAL ref sha prefix mismatch: $REF_SHA12"; echo 2 > "$LOGDIR/sparse.rc"; exit 2; fi if [ "$FACTS_SHA" != "94b7155f7ca9e2de32ddb3a0add2fff2d8c66e73147fe5bd112cff3ba69b1669" ]; then diff --git a/experiments/build_j_recert/sparse_zero_support_exclusions_buildj.json b/experiments/build_j_recert/sparse_zero_support_exclusions_buildj.json new file mode 100644 index 00000000..92ba7a45 --- /dev/null +++ b/experiments/build_j_recert/sparse_zero_support_exclusions_buildj.json @@ -0,0 +1,26 @@ +{ + "hhs_acf_tanf.fy2024.cash_assistance.al.basic_assistance_excluding_relative_foster_care_and_adoption_guardianship.all_funds": "The Build I 57,240-record sparse selection (rmloss100) has zero positive Alabama TANF basic-assistance support under PolicyEngine-US state TANF formulas; the 337,704 dense parent expresses it (0 zero-support on the dense run). Per-artifact support-expressibility exclusion. RECOMPUTED (not reused) on the Build I rmloss100 selection via the #359 de-risk (registry d71c59514e3a, direct checkpoint solve): exactly this 19-cell set (1 AL TANF + 18 state-AGI under-$1 taxable-interest amount/returns across al/ct/in/me/ms/ne/nm/ri/wy), zero additions vs Build H frozen. rmloss100 = the certified frozen 57,240 with the 100 largest-|misc| negative 'other income' carriers swapped for high-AGI misc-zero absorbers (a misc-only swap); the AL-TANF and under-$1-AGI state-tail records are untouched by that swap, so these cells remain zero-support exactly as in the frozen/dense lineage (PolicyEngine/populace#359 Build I).", + "irs_soi.ty2022.historic_table_2.state_agi.al.under_1.taxable_interest_amount": "The Build I 57,240-record sparse selection (rmloss100) has zero AL taxable-interest amount support in the under-$1 AGI slice; this narrow offset-income tail cell needs richer state/tail support than the sparse selection carries. The 337,704 dense parent expresses it. Per-artifact support-expressibility exclusion. RECOMPUTED (not reused) on the Build I rmloss100 selection via the #359 de-risk (registry d71c59514e3a, direct checkpoint solve): exactly this 19-cell set (1 AL TANF + 18 state-AGI under-$1 taxable-interest amount/returns across al/ct/in/me/ms/ne/nm/ri/wy), zero additions vs Build H frozen. rmloss100 = the certified frozen 57,240 with the 100 largest-|misc| negative 'other income' carriers swapped for high-AGI misc-zero absorbers (a misc-only swap); the AL-TANF and under-$1-AGI state-tail records are untouched by that swap, so these cells remain zero-support exactly as in the frozen/dense lineage (PolicyEngine/populace#359 Build I).", + "irs_soi.ty2022.historic_table_2.state_agi.al.under_1.taxable_interest_returns": "The Build I 57,240-record sparse selection (rmloss100) has zero AL taxable-interest returns support in the under-$1 AGI slice; this narrow offset-income tail cell needs richer state/tail support than the sparse selection carries. The 337,704 dense parent expresses it. Per-artifact support-expressibility exclusion. RECOMPUTED (not reused) on the Build I rmloss100 selection via the #359 de-risk (registry d71c59514e3a, direct checkpoint solve): exactly this 19-cell set (1 AL TANF + 18 state-AGI under-$1 taxable-interest amount/returns across al/ct/in/me/ms/ne/nm/ri/wy), zero additions vs Build H frozen. rmloss100 = the certified frozen 57,240 with the 100 largest-|misc| negative 'other income' carriers swapped for high-AGI misc-zero absorbers (a misc-only swap); the AL-TANF and under-$1-AGI state-tail records are untouched by that swap, so these cells remain zero-support exactly as in the frozen/dense lineage (PolicyEngine/populace#359 Build I).", + "irs_soi.ty2022.historic_table_2.state_agi.ct.under_1.taxable_interest_amount": "The Build I 57,240-record sparse selection (rmloss100) has zero CT taxable-interest amount support in the under-$1 AGI slice; this narrow offset-income tail cell needs richer state/tail support than the sparse selection carries. The 337,704 dense parent expresses it. Per-artifact support-expressibility exclusion. RECOMPUTED (not reused) on the Build I rmloss100 selection via the #359 de-risk (registry d71c59514e3a, direct checkpoint solve): exactly this 19-cell set (1 AL TANF + 18 state-AGI under-$1 taxable-interest amount/returns across al/ct/in/me/ms/ne/nm/ri/wy), zero additions vs Build H frozen. rmloss100 = the certified frozen 57,240 with the 100 largest-|misc| negative 'other income' carriers swapped for high-AGI misc-zero absorbers (a misc-only swap); the AL-TANF and under-$1-AGI state-tail records are untouched by that swap, so these cells remain zero-support exactly as in the frozen/dense lineage (PolicyEngine/populace#359 Build I).", + "irs_soi.ty2022.historic_table_2.state_agi.ct.under_1.taxable_interest_returns": "The Build I 57,240-record sparse selection (rmloss100) has zero CT taxable-interest returns support in the under-$1 AGI slice; this narrow offset-income tail cell needs richer state/tail support than the sparse selection carries. The 337,704 dense parent expresses it. Per-artifact support-expressibility exclusion. RECOMPUTED (not reused) on the Build I rmloss100 selection via the #359 de-risk (registry d71c59514e3a, direct checkpoint solve): exactly this 19-cell set (1 AL TANF + 18 state-AGI under-$1 taxable-interest amount/returns across al/ct/in/me/ms/ne/nm/ri/wy), zero additions vs Build H frozen. rmloss100 = the certified frozen 57,240 with the 100 largest-|misc| negative 'other income' carriers swapped for high-AGI misc-zero absorbers (a misc-only swap); the AL-TANF and under-$1-AGI state-tail records are untouched by that swap, so these cells remain zero-support exactly as in the frozen/dense lineage (PolicyEngine/populace#359 Build I).", + "irs_soi.ty2022.historic_table_2.state_agi.in.under_1.taxable_interest_amount": "The Build I 57,240-record sparse selection (rmloss100) has zero IN taxable-interest amount support in the under-$1 AGI slice; this narrow offset-income tail cell needs richer state/tail support than the sparse selection carries. The 337,704 dense parent expresses it. Per-artifact support-expressibility exclusion. RECOMPUTED (not reused) on the Build I rmloss100 selection via the #359 de-risk (registry d71c59514e3a, direct checkpoint solve): exactly this 19-cell set (1 AL TANF + 18 state-AGI under-$1 taxable-interest amount/returns across al/ct/in/me/ms/ne/nm/ri/wy), zero additions vs Build H frozen. rmloss100 = the certified frozen 57,240 with the 100 largest-|misc| negative 'other income' carriers swapped for high-AGI misc-zero absorbers (a misc-only swap); the AL-TANF and under-$1-AGI state-tail records are untouched by that swap, so these cells remain zero-support exactly as in the frozen/dense lineage (PolicyEngine/populace#359 Build I).", + "irs_soi.ty2022.historic_table_2.state_agi.in.under_1.taxable_interest_returns": "The Build I 57,240-record sparse selection (rmloss100) has zero IN taxable-interest returns support in the under-$1 AGI slice; this narrow offset-income tail cell needs richer state/tail support than the sparse selection carries. The 337,704 dense parent expresses it. Per-artifact support-expressibility exclusion. RECOMPUTED (not reused) on the Build I rmloss100 selection via the #359 de-risk (registry d71c59514e3a, direct checkpoint solve): exactly this 19-cell set (1 AL TANF + 18 state-AGI under-$1 taxable-interest amount/returns across al/ct/in/me/ms/ne/nm/ri/wy), zero additions vs Build H frozen. rmloss100 = the certified frozen 57,240 with the 100 largest-|misc| negative 'other income' carriers swapped for high-AGI misc-zero absorbers (a misc-only swap); the AL-TANF and under-$1-AGI state-tail records are untouched by that swap, so these cells remain zero-support exactly as in the frozen/dense lineage (PolicyEngine/populace#359 Build I).", + "irs_soi.ty2022.historic_table_2.state_agi.me.under_1.taxable_interest_amount": "The Build I 57,240-record sparse selection (rmloss100) has zero ME taxable-interest amount support in the under-$1 AGI slice; this narrow offset-income tail cell needs richer state/tail support than the sparse selection carries. The 337,704 dense parent expresses it. Per-artifact support-expressibility exclusion. RECOMPUTED (not reused) on the Build I rmloss100 selection via the #359 de-risk (registry d71c59514e3a, direct checkpoint solve): exactly this 19-cell set (1 AL TANF + 18 state-AGI under-$1 taxable-interest amount/returns across al/ct/in/me/ms/ne/nm/ri/wy), zero additions vs Build H frozen. rmloss100 = the certified frozen 57,240 with the 100 largest-|misc| negative 'other income' carriers swapped for high-AGI misc-zero absorbers (a misc-only swap); the AL-TANF and under-$1-AGI state-tail records are untouched by that swap, so these cells remain zero-support exactly as in the frozen/dense lineage (PolicyEngine/populace#359 Build I).", + "irs_soi.ty2022.historic_table_2.state_agi.me.under_1.taxable_interest_returns": "The Build I 57,240-record sparse selection (rmloss100) has zero ME taxable-interest returns support in the under-$1 AGI slice; this narrow offset-income tail cell needs richer state/tail support than the sparse selection carries. The 337,704 dense parent expresses it. Per-artifact support-expressibility exclusion. RECOMPUTED (not reused) on the Build I rmloss100 selection via the #359 de-risk (registry d71c59514e3a, direct checkpoint solve): exactly this 19-cell set (1 AL TANF + 18 state-AGI under-$1 taxable-interest amount/returns across al/ct/in/me/ms/ne/nm/ri/wy), zero additions vs Build H frozen. rmloss100 = the certified frozen 57,240 with the 100 largest-|misc| negative 'other income' carriers swapped for high-AGI misc-zero absorbers (a misc-only swap); the AL-TANF and under-$1-AGI state-tail records are untouched by that swap, so these cells remain zero-support exactly as in the frozen/dense lineage (PolicyEngine/populace#359 Build I).", + "irs_soi.ty2022.historic_table_2.state_agi.ms.under_1.taxable_interest_amount": "The Build I 57,240-record sparse selection (rmloss100) has zero MS taxable-interest amount support in the under-$1 AGI slice; this narrow offset-income tail cell needs richer state/tail support than the sparse selection carries. The 337,704 dense parent expresses it. Per-artifact support-expressibility exclusion. RECOMPUTED (not reused) on the Build I rmloss100 selection via the #359 de-risk (registry d71c59514e3a, direct checkpoint solve): exactly this 19-cell set (1 AL TANF + 18 state-AGI under-$1 taxable-interest amount/returns across al/ct/in/me/ms/ne/nm/ri/wy), zero additions vs Build H frozen. rmloss100 = the certified frozen 57,240 with the 100 largest-|misc| negative 'other income' carriers swapped for high-AGI misc-zero absorbers (a misc-only swap); the AL-TANF and under-$1-AGI state-tail records are untouched by that swap, so these cells remain zero-support exactly as in the frozen/dense lineage (PolicyEngine/populace#359 Build I).", + "irs_soi.ty2022.historic_table_2.state_agi.ms.under_1.taxable_interest_returns": "The Build I 57,240-record sparse selection (rmloss100) has zero MS taxable-interest returns support in the under-$1 AGI slice; this narrow offset-income tail cell needs richer state/tail support than the sparse selection carries. The 337,704 dense parent expresses it. Per-artifact support-expressibility exclusion. RECOMPUTED (not reused) on the Build I rmloss100 selection via the #359 de-risk (registry d71c59514e3a, direct checkpoint solve): exactly this 19-cell set (1 AL TANF + 18 state-AGI under-$1 taxable-interest amount/returns across al/ct/in/me/ms/ne/nm/ri/wy), zero additions vs Build H frozen. rmloss100 = the certified frozen 57,240 with the 100 largest-|misc| negative 'other income' carriers swapped for high-AGI misc-zero absorbers (a misc-only swap); the AL-TANF and under-$1-AGI state-tail records are untouched by that swap, so these cells remain zero-support exactly as in the frozen/dense lineage (PolicyEngine/populace#359 Build I).", + "irs_soi.ty2022.historic_table_2.state_agi.ne.under_1.taxable_interest_amount": "The Build I 57,240-record sparse selection (rmloss100) has zero NE taxable-interest amount support in the under-$1 AGI slice; this narrow offset-income tail cell needs richer state/tail support than the sparse selection carries. The 337,704 dense parent expresses it. Per-artifact support-expressibility exclusion. RECOMPUTED (not reused) on the Build I rmloss100 selection via the #359 de-risk (registry d71c59514e3a, direct checkpoint solve): exactly this 19-cell set (1 AL TANF + 18 state-AGI under-$1 taxable-interest amount/returns across al/ct/in/me/ms/ne/nm/ri/wy), zero additions vs Build H frozen. rmloss100 = the certified frozen 57,240 with the 100 largest-|misc| negative 'other income' carriers swapped for high-AGI misc-zero absorbers (a misc-only swap); the AL-TANF and under-$1-AGI state-tail records are untouched by that swap, so these cells remain zero-support exactly as in the frozen/dense lineage (PolicyEngine/populace#359 Build I).", + "irs_soi.ty2022.historic_table_2.state_agi.ne.under_1.taxable_interest_returns": "The Build I 57,240-record sparse selection (rmloss100) has zero NE taxable-interest returns support in the under-$1 AGI slice; this narrow offset-income tail cell needs richer state/tail support than the sparse selection carries. The 337,704 dense parent expresses it. Per-artifact support-expressibility exclusion. RECOMPUTED (not reused) on the Build I rmloss100 selection via the #359 de-risk (registry d71c59514e3a, direct checkpoint solve): exactly this 19-cell set (1 AL TANF + 18 state-AGI under-$1 taxable-interest amount/returns across al/ct/in/me/ms/ne/nm/ri/wy), zero additions vs Build H frozen. rmloss100 = the certified frozen 57,240 with the 100 largest-|misc| negative 'other income' carriers swapped for high-AGI misc-zero absorbers (a misc-only swap); the AL-TANF and under-$1-AGI state-tail records are untouched by that swap, so these cells remain zero-support exactly as in the frozen/dense lineage (PolicyEngine/populace#359 Build I).", + "irs_soi.ty2022.historic_table_2.state_agi.nm.under_1.taxable_interest_amount": "The Build I 57,240-record sparse selection (rmloss100) has zero NM taxable-interest amount support in the under-$1 AGI slice; this narrow offset-income tail cell needs richer state/tail support than the sparse selection carries. The 337,704 dense parent expresses it. Per-artifact support-expressibility exclusion. RECOMPUTED (not reused) on the Build I rmloss100 selection via the #359 de-risk (registry d71c59514e3a, direct checkpoint solve): exactly this 19-cell set (1 AL TANF + 18 state-AGI under-$1 taxable-interest amount/returns across al/ct/in/me/ms/ne/nm/ri/wy), zero additions vs Build H frozen. rmloss100 = the certified frozen 57,240 with the 100 largest-|misc| negative 'other income' carriers swapped for high-AGI misc-zero absorbers (a misc-only swap); the AL-TANF and under-$1-AGI state-tail records are untouched by that swap, so these cells remain zero-support exactly as in the frozen/dense lineage (PolicyEngine/populace#359 Build I).", + "irs_soi.ty2022.historic_table_2.state_agi.nm.under_1.taxable_interest_returns": "The Build I 57,240-record sparse selection (rmloss100) has zero NM taxable-interest returns support in the under-$1 AGI slice; this narrow offset-income tail cell needs richer state/tail support than the sparse selection carries. The 337,704 dense parent expresses it. Per-artifact support-expressibility exclusion. RECOMPUTED (not reused) on the Build I rmloss100 selection via the #359 de-risk (registry d71c59514e3a, direct checkpoint solve): exactly this 19-cell set (1 AL TANF + 18 state-AGI under-$1 taxable-interest amount/returns across al/ct/in/me/ms/ne/nm/ri/wy), zero additions vs Build H frozen. rmloss100 = the certified frozen 57,240 with the 100 largest-|misc| negative 'other income' carriers swapped for high-AGI misc-zero absorbers (a misc-only swap); the AL-TANF and under-$1-AGI state-tail records are untouched by that swap, so these cells remain zero-support exactly as in the frozen/dense lineage (PolicyEngine/populace#359 Build I).", + "irs_soi.ty2022.historic_table_2.state_agi.ri.under_1.taxable_interest_amount": "The Build I 57,240-record sparse selection (rmloss100) has zero RI taxable-interest amount support in the under-$1 AGI slice; this narrow offset-income tail cell needs richer state/tail support than the sparse selection carries. The 337,704 dense parent expresses it. Per-artifact support-expressibility exclusion. RECOMPUTED (not reused) on the Build I rmloss100 selection via the #359 de-risk (registry d71c59514e3a, direct checkpoint solve): exactly this 19-cell set (1 AL TANF + 18 state-AGI under-$1 taxable-interest amount/returns across al/ct/in/me/ms/ne/nm/ri/wy), zero additions vs Build H frozen. rmloss100 = the certified frozen 57,240 with the 100 largest-|misc| negative 'other income' carriers swapped for high-AGI misc-zero absorbers (a misc-only swap); the AL-TANF and under-$1-AGI state-tail records are untouched by that swap, so these cells remain zero-support exactly as in the frozen/dense lineage (PolicyEngine/populace#359 Build I).", + "irs_soi.ty2022.historic_table_2.state_agi.ri.under_1.taxable_interest_returns": "The Build I 57,240-record sparse selection (rmloss100) has zero RI taxable-interest returns support in the under-$1 AGI slice; this narrow offset-income tail cell needs richer state/tail support than the sparse selection carries. The 337,704 dense parent expresses it. Per-artifact support-expressibility exclusion. RECOMPUTED (not reused) on the Build I rmloss100 selection via the #359 de-risk (registry d71c59514e3a, direct checkpoint solve): exactly this 19-cell set (1 AL TANF + 18 state-AGI under-$1 taxable-interest amount/returns across al/ct/in/me/ms/ne/nm/ri/wy), zero additions vs Build H frozen. rmloss100 = the certified frozen 57,240 with the 100 largest-|misc| negative 'other income' carriers swapped for high-AGI misc-zero absorbers (a misc-only swap); the AL-TANF and under-$1-AGI state-tail records are untouched by that swap, so these cells remain zero-support exactly as in the frozen/dense lineage (PolicyEngine/populace#359 Build I).", + "irs_soi.ty2022.historic_table_2.state_agi.wy.under_1.taxable_interest_amount": "The Build I 57,240-record sparse selection (rmloss100) has zero WY taxable-interest amount support in the under-$1 AGI slice; this narrow offset-income tail cell needs richer state/tail support than the sparse selection carries. The 337,704 dense parent expresses it. Per-artifact support-expressibility exclusion. RECOMPUTED (not reused) on the Build I rmloss100 selection via the #359 de-risk (registry d71c59514e3a, direct checkpoint solve): exactly this 19-cell set (1 AL TANF + 18 state-AGI under-$1 taxable-interest amount/returns across al/ct/in/me/ms/ne/nm/ri/wy), zero additions vs Build H frozen. rmloss100 = the certified frozen 57,240 with the 100 largest-|misc| negative 'other income' carriers swapped for high-AGI misc-zero absorbers (a misc-only swap); the AL-TANF and under-$1-AGI state-tail records are untouched by that swap, so these cells remain zero-support exactly as in the frozen/dense lineage (PolicyEngine/populace#359 Build I).", + "irs_soi.ty2022.historic_table_2.state_agi.wy.under_1.taxable_interest_returns": "The Build I 57,240-record sparse selection (rmloss100) has zero WY taxable-interest returns support in the under-$1 AGI slice; this narrow offset-income tail cell needs richer state/tail support than the sparse selection carries. The 337,704 dense parent expresses it. Per-artifact support-expressibility exclusion. RECOMPUTED (not reused) on the Build I rmloss100 selection via the #359 de-risk (registry d71c59514e3a, direct checkpoint solve): exactly this 19-cell set (1 AL TANF + 18 state-AGI under-$1 taxable-interest amount/returns across al/ct/in/me/ms/ne/nm/ri/wy), zero additions vs Build H frozen. rmloss100 = the certified frozen 57,240 with the 100 largest-|misc| negative 'other income' carriers swapped for high-AGI misc-zero absorbers (a misc-only swap); the AL-TANF and under-$1-AGI state-tail records are untouched by that swap, so these cells remain zero-support exactly as in the frozen/dense lineage (PolicyEngine/populace#359 Build I).", + "hhs_acf_tanf.fy2024.cash_assistance.fl.basic_assistance_excluding_relative_foster_care_and_adoption_guardianship.all_funds": "The Build J 57,240-record sparse selection (rmloss100) has zero positive Florida TANF basic-assistance support under LIVE seeded TANF take-up (#384 removed the stale constant-True degenerate exclusion; takes_up_tanf_if_eligible now carries real variation, 13,205/59,900 spm_units True at seed 0): the selection's few state TANF carriers all fall out under the seeded draw / engine eligibility. VERIFIED on the identity-matched buildj-sparse target-frame checkpoint (registry 2496460ad8c3, base 0b50660a, run populace-us-2024-buildj-sparse-rmloss100-20b94db-20260710T071342Z): 0 nonzero records in the materialized state cell, while every non-excluded state cell carries 1-14 supporting records (national 156) \u2014 thin-state TANF support in a sparse selection, the Build I AL precedent (the 337,704 dense parent expresses these cells). Per-artifact support-expressibility exclusion; selection-side remedy (add thin-state TANF carriers) is #346/#355-class work. Recomputed for Build J 2026-07-10.", + "hhs_acf_tanf.fy2024.cash_assistance.ia.basic_assistance_excluding_relative_foster_care_and_adoption_guardianship.all_funds": "The Build J 57,240-record sparse selection (rmloss100) has zero positive Iowa TANF basic-assistance support under LIVE seeded TANF take-up (#384 removed the stale constant-True degenerate exclusion; takes_up_tanf_if_eligible now carries real variation, 13,205/59,900 spm_units True at seed 0): the selection's few state TANF carriers all fall out under the seeded draw / engine eligibility. VERIFIED on the identity-matched buildj-sparse target-frame checkpoint (registry 2496460ad8c3, base 0b50660a, run populace-us-2024-buildj-sparse-rmloss100-20b94db-20260710T071342Z): 0 nonzero records in the materialized state cell, while every non-excluded state cell carries 1-14 supporting records (national 156) \u2014 thin-state TANF support in a sparse selection, the Build I AL precedent (the 337,704 dense parent expresses these cells). Per-artifact support-expressibility exclusion; selection-side remedy (add thin-state TANF carriers) is #346/#355-class work. Recomputed for Build J 2026-07-10.", + "hhs_acf_tanf.fy2024.cash_assistance.mo.basic_assistance_excluding_relative_foster_care_and_adoption_guardianship.all_funds": "The Build J 57,240-record sparse selection (rmloss100) has zero positive Missouri TANF basic-assistance support under LIVE seeded TANF take-up (#384 removed the stale constant-True degenerate exclusion; takes_up_tanf_if_eligible now carries real variation, 13,205/59,900 spm_units True at seed 0): the selection's few state TANF carriers all fall out under the seeded draw / engine eligibility. VERIFIED on the identity-matched buildj-sparse target-frame checkpoint (registry 2496460ad8c3, base 0b50660a, run populace-us-2024-buildj-sparse-rmloss100-20b94db-20260710T071342Z): 0 nonzero records in the materialized state cell, while every non-excluded state cell carries 1-14 supporting records (national 156) \u2014 thin-state TANF support in a sparse selection, the Build I AL precedent (the 337,704 dense parent expresses these cells). Per-artifact support-expressibility exclusion; selection-side remedy (add thin-state TANF carriers) is #346/#355-class work. Recomputed for Build J 2026-07-10.", + "hhs_acf_tanf.fy2024.cash_assistance.ne.basic_assistance_excluding_relative_foster_care_and_adoption_guardianship.all_funds": "The Build J 57,240-record sparse selection (rmloss100) has zero positive Nebraska TANF basic-assistance support under LIVE seeded TANF take-up (#384 removed the stale constant-True degenerate exclusion; takes_up_tanf_if_eligible now carries real variation, 13,205/59,900 spm_units True at seed 0): the selection's few state TANF carriers all fall out under the seeded draw / engine eligibility. VERIFIED on the identity-matched buildj-sparse target-frame checkpoint (registry 2496460ad8c3, base 0b50660a, run populace-us-2024-buildj-sparse-rmloss100-20b94db-20260710T071342Z): 0 nonzero records in the materialized state cell, while every non-excluded state cell carries 1-14 supporting records (national 156) \u2014 thin-state TANF support in a sparse selection, the Build I AL precedent (the 337,704 dense parent expresses these cells). Per-artifact support-expressibility exclusion; selection-side remedy (add thin-state TANF carriers) is #346/#355-class work. Recomputed for Build J 2026-07-10.", + "hhs_acf_tanf.fy2024.cash_assistance.nj.basic_assistance_excluding_relative_foster_care_and_adoption_guardianship.all_funds": "The Build J 57,240-record sparse selection (rmloss100) has zero positive New Jersey TANF basic-assistance support under LIVE seeded TANF take-up (#384 removed the stale constant-True degenerate exclusion; takes_up_tanf_if_eligible now carries real variation, 13,205/59,900 spm_units True at seed 0): the selection's few state TANF carriers all fall out under the seeded draw / engine eligibility. VERIFIED on the identity-matched buildj-sparse target-frame checkpoint (registry 2496460ad8c3, base 0b50660a, run populace-us-2024-buildj-sparse-rmloss100-20b94db-20260710T071342Z): 0 nonzero records in the materialized state cell, while every non-excluded state cell carries 1-14 supporting records (national 156) \u2014 thin-state TANF support in a sparse selection, the Build I AL precedent (the 337,704 dense parent expresses these cells). Per-artifact support-expressibility exclusion; selection-side remedy (add thin-state TANF carriers) is #346/#355-class work. Recomputed for Build J 2026-07-10." +} From 75d5add76b07373e026d1267e20a098d0e0f7181 Mon Sep 17 00:00:00 2001 From: "Claude (Build J)" Date: Fri, 10 Jul 2026 05:42:01 -0400 Subject: [PATCH 13/17] Promote the five now-populated columns to required in the coverage manifest (#368) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fourth stale-register catch, same root cause as the previous three (coverage growth digesting): the #369 input-coverage gate flagged its reviewed exclusions for the identical five columns from the parity catch. Regenerated via tools/build_us_release_input_coverage_manifest.py (derives from the fixed parity register): exactly five reviewed_exclusion -> required promotions (65->70 required / 93->88 exclusions, total 158, SSI probe intact), nothing else. ONE-PASS REGISTER SWEEP (to end the serial discovery): grepped every register for the five columns + takes_up_tanf-era assumptions — parity known-gaps (fixed), coverage manifest (fixed here), US_DEGENERATE_INPUT_REVIEWED_EXCLUSIONS (clean), US_DOCUMENTED_ABSENT_INPUTS (clean), take-up contract (#384-aligned, declares TANF treatment), zero-support (Build-J 24-cell, passed in-run), medicaid substitutions (RI applied), pinned parity reference + source_stages (correct non-register mentions). takes_up_tanf_if_eligible already 'required'. test_release_input_coverage 14 passed (incl. manifest==regeneration); the release's exact #384 register-consistency preflight passes with the promotions (no signal-side/excused-side collision). Co-Authored-By: Claude Fable 5 --- .../us/release_input_coverage_manifest.json | 24 ++++++------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/packages/populace-build/src/populace/build/us/release_input_coverage_manifest.json b/packages/populace-build/src/populace/build/us/release_input_coverage_manifest.json index a1052743..84d9b50f 100644 --- a/packages/populace-build/src/populace/build/us/release_input_coverage_manifest.json +++ b/packages/populace-build/src/populace/build/us/release_input_coverage_manifest.json @@ -33,9 +33,7 @@ "status": "required" }, "block_geoid": { - "issue": "PolicyEngine/populace#38", - "reason": "Fine-grain geography code carried by the incumbent but not on the small national candidate frame; remaining input-layer work (#38).", - "status": "reviewed_exclusion" + "status": "required" }, "bond_assets": { "note": "SSI countable-resource asset input; required with NO reviewed exclusion per PolicyEngine/populace#368 so the gate fails until the asset stage is restored (Deliverable 2). Currently absent — this is the intended red gate.", @@ -71,9 +69,7 @@ "status": "required" }, "county_fips": { - "issue": "PolicyEngine/populace#38", - "reason": "Fine-grain geography code carried by the incumbent but not on the small national candidate frame; remaining input-layer work (#38).", - "status": "reviewed_exclusion" + "status": "required" }, "cps_race": { "issue": "PolicyEngine/populace#38", @@ -207,9 +203,7 @@ "status": "required" }, "health_savings_account_ald": { - "issue": "PolicyEngine/populace#32", - "reason": "SPM MOOP / work-expense / deduction input (childcare-MOOP-work-expense family of #32); not yet on the candidate frame.", - "status": "reviewed_exclusion" + "status": "required" }, "home_mortgage_interest": { "status": "required" @@ -467,9 +461,7 @@ "status": "reviewed_exclusion" }, "spm_unit_pre_subsidy_childcare_expenses": { - "issue": "PolicyEngine/populace#32", - "reason": "SPM childcare-expense input; not yet on the candidate frame.", - "status": "reviewed_exclusion" + "status": "required" }, "spm_unit_tenure_type": { "issue": "PolicyEngine/populace#32", @@ -605,9 +597,7 @@ "status": "reviewed_exclusion" }, "tract_geoid": { - "issue": "PolicyEngine/populace#38", - "reason": "Fine-grain geography code carried by the incumbent but not on the small national candidate frame; remaining input-layer work (#38).", - "status": "reviewed_exclusion" + "status": "required" }, "treasury_tipped_occupation_code": { "issue": "PolicyEngine/populace#38", @@ -665,8 +655,8 @@ } }, "counts": { - "required": 65, - "reviewed_exclusion": 93, + "required": 70, + "reviewed_exclusion": 88, "total": 158 }, "derivation": "Required surface = ecps_parity_reference.json populated layers (input columns the pinned, sha-verified reference eCPS populates). status='reviewed_exclusion' for ecps_parity_known_gaps.json entries (reason+issue from that register); EXCEPT the SSI countable-resource asset inputs (bank_account_assets, stock_assets, bond_assets), which are status='required' with NO exclusion per PolicyEngine/populace#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.", From 564a2c7d3b3624e7042401d37c6b739f1bce76b3 Mon Sep 17 00:00:00 2001 From: "Claude (Build J)" Date: Fri, 10 Jul 2026 05:43:30 -0400 Subject: [PATCH 14/17] Build J Step 8: coverage-manifest promotion + one-pass register sweep logged (#368) Co-Authored-By: Claude Fable 5 --- PROGRESS_BUILDJ.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/PROGRESS_BUILDJ.md b/PROGRESS_BUILDJ.md index 32f17faf..4238090f 100644 --- a/PROGRESS_BUILDJ.md +++ b/PROGRESS_BUILDJ.md @@ -205,6 +205,33 @@ zero-support (post-excl) 0. Build I was pinned to Build H lineage and did NOT ad + 1 RI substitution — both live-coverage consequences, to be stated in the verdict). Relaunch note: changing exclusions changes the compiled registry -> checkpoint identity MISS -> full rematerialization (~24 min), unavoidable by design (exclusions apply at compile). +- **Step 8 (d798158 run: zero-support PASSED -> 4th stale-register catch, SAME five columns; + fixed + swept ALL registers + relaunched).** The d798158 run cleared zero-support (24-cell list + works) and rematerialized everything (fresh checkpoint at the FINAL Build J registry: + **5,510 specs, version `091ace02f962`** = 5,533 − 24 excl + 1 RI substitution), then rc=1 at + 08:56:41Z at the #369 input-coverage gate (:6488): `Stale reviewed exclusions — the column + carries signal now, promote it to a hard requirement:` the IDENTICAL five columns from + gate-class #2. NOT a fourth cause — the coverage manifest DERIVES from the parity known-gaps + register (my Step-6 fix), so its exclusions for the five were stale by construction. + **Fix:** regenerated via `tools/build_us_release_input_coverage_manifest.py` — diff = EXACTLY + five reviewed_exclusion -> required promotions (65->70 required / 93->88 exclusions / 158 total, + SSI probe intact), nothing else. test_release_input_coverage **14 passed** (incl. the + manifest==regeneration guard); the release's exact #384 register-consistency preflight + **passes** with the promotions (five not in degenerate/documented-absent -> no signal/excused + collision). + **ONE-PASS REGISTER SWEEP (end the serial discovery):** grepped every register for the five + columns + takes_up_tanf-era assumptions. Result: parity known-gaps FIXED (Step 6), coverage + manifest FIXED (here), `US_DEGENERATE_INPUT_REVIEWED_EXCLUSIONS` CLEAN (SSI/Medicare/DC-PTC/ + second-home entries only — none of the five, no TANF), `US_DOCUMENTED_ABSENT_INPUTS` CLEAN, + take-up contract = #384-aligned TANF treatment declaration (not an exclusion), + `takes_up_tanf_if_eligible` already "required" in the manifest, zero-support = Build-J 24-cell + (passed in-run), medicaid substitution register = RI applied (passed in-run). Remaining + failure surfaces are ARTIFACT-dependent gates (export-mass, degenerate-on-export, reform smoke, + take-up contract post-solve) — real certification surfaces, not register staleness. + Committed 75d5add; relaunched sparse: run id + `populace-us-2024-buildj-sparse-rmloss100-75d5add-20260710T094201Z`. The 091ace02f962 + checkpoint should HIT (this fix does not touch the registry compile) -> straight to solve + + gates (~6-10 min warm). ## Gate map + verdict-data locations (verified on origin/main; for the resumed run + verdict) Runs = worktree `.venv/bin/python tools/build_us_fiscal_refresh_release.py`; the sparse (deployable) From 01f4d083af018c6f52007d7b8d969ead6627cc14 Mon Sep 17 00:00:00 2001 From: "Claude (Build J)" Date: Fri, 10 Jul 2026 06:19:21 -0400 Subject: [PATCH 15/17] =?UTF-8?q?Build=20J=20Step=209:=20SPARSE=20CERTIFIE?= =?UTF-8?q?S=20=E2=80=94=20verdict=20posted=20on=20#368=20(#368)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SSI probe +$5,153,370,118 @2024 GREEN (below the +$9.66B overlay, above the ~$1.60B dense-native class; SIPP blend #374 open). final_loss 0.030843 / within-10% 0.8900 (beats Build I) / export-mass 0/35 / zero-support 0 / release_gates True. Registry 091ace02f962 (5,510 = 5,533-24+1). H5 sha 9d1e460ddbc4…; manifest 3d292c2231d9…. Verdict: https://github.com/PolicyEngine/populace/issues/368#issuecomment-4934327413 Dense diagnostic arm materializing (D2 direct-solve script updated for the 5,534-spec dense registry). STAGING/LOCAL ONLY — publication is Max's call. Co-Authored-By: Claude Fable 5 --- PROGRESS_BUILDJ.md | 39 +++++++++++ .../direct_solve_dense_buildj.py | 17 +++-- .../build_j_recert/issue368_verdict.md | 67 +++++++++++++++++++ 3 files changed, 116 insertions(+), 7 deletions(-) create mode 100644 experiments/build_j_recert/issue368_verdict.md diff --git a/PROGRESS_BUILDJ.md b/PROGRESS_BUILDJ.md index 4238090f..7e12fd61 100644 --- a/PROGRESS_BUILDJ.md +++ b/PROGRESS_BUILDJ.md @@ -232,6 +232,45 @@ zero-support (post-excl) 0. Build I was pinned to Build H lineage and did NOT ad `populace-us-2024-buildj-sparse-rmloss100-75d5add-20260710T094201Z`. The 091ace02f962 checkpoint should HIT (this fix does not touch the registry compile) -> straight to solve + gates (~6-10 min warm). +- **Step 9 (SPARSE rc=0 — CERTIFIED; verbatim numbers).** Run + `populace-us-2024-buildj-sparse-rmloss100-75d5add-20260710T094201Z` completed 09:51:35Z + (~9.5 min wall, warm checkpoint), **rc=0, release_gates.passed=True, failures=[]**, complete + release_manifest.json (sha256 `3d292c2231d918cf58b68d14bfabd0a1ea252a43ae1890cec5228bd10db21ba9`) + + exported H5 383,024,738 bytes (sha256 + `9d1e460ddbc49c9b467b936f07edd4576ae2667ef39fdea2490bc5577c038d51`) + calibration npz + (`e913bc33…`). + **Headline vs Build I:** final_loss **0.030843270944171754** (BI 0.030833, BH 0.03091516); + fraction_within_10pct **0.8900181488203267** (BI 0.8888 — BEATS; BH 0.8901); ESS **12,088.6** + (BI 12,303.4); realized_max_weight_ratio **4.994** (BI 4.993); n_records 57,240 / n_nonzero + 57,240; initial_loss 0.360592; top_1pct_weight_share 0.10568. + **Gates (ALL PASS):** target_profile_coverage, health_input_signal, degenerate_input_signal, + base_population_scale, immigration_composition, hours_worked_signal, snap_take_up_signal, + eligibility_inputs_signal, pregnancy_signal, snap_discretionary_exemption_signal, ecps_parity, + validation_input_coverage, input coverage #369 (70 required incl the 3 asset leaves + the 5 + promotions; degenerate_required=[]; 0 failures), Medicaid take-up (RI substitution + applied=True stale=False, recorded in build_manifest + us_medicaid_take_up.json), take-up + contract (passed=True), register consistency, zero-support (post-24-excl **0**), reform smoke. + **Export-mass parity: PASS 0 failures / 35 columns** (enforced; ±50%; $1B floor; reviewed + exclusions estate_income + non_sch_d_capital_gains ONLY, both used, unused=[]). Key columns: + miscellaneous_income **+11.46%** (BI +11.5%), home_mortgage_interest **+28.92%** (BI +27.9%), + first_home_mortgage_interest **+29.00%** (BI +28.0%) — all in band. candidate_only now carries + the restored surface: bank/stock/bond assets, HSA ALD, childcare, SNAP train, take-up flags. + **Marquee fits:** fed income tax liability (SOI ht2 us.all amount) **+0.5809%** (BI +0.22%); + SS benefits (ssa_supplement payment_amount) **−0.2247%** (BI −0.18%); net capital gain (CBO) + **−25.6881%** (BI −24.18%); mortgage tax-exp (JCT) **+38.5949%** (BI +36.73%). + **SSI PROBE (the #368 point):** `ssi_asset_limit_10k_20k` effect **+$5,153,370,118 @ 2024** + (baseline SSI $55,192,291,256 -> reform $60,345,661,375), **PASSED** ($1B floor; enforced). + vs #374: **below** the +$9.66B SCF-only overlay (re-solve direction confirmed), **above** the + ~+$1.60B dense-native class — the SIPP-blend refinement (#374 step 1) remains OPEN, stated. + **Registry:** `091ace02f962`, 5,510 declared/compiled = 5,533 − 24 zero-support exclusions + + 1 RI substitution (Build I: d71c59514e3a, 5,514 = 5,533 − 19). Comparison caveat: Build-I + like-for-like PLUS {RI CMS substitution #387, 5 TANF thin-state exclusions under live take-up, + the new stage columns}. + **Verdict: the sparse artifact is CERTIFIABLE.** Dense diagnostic arm launched serialized + (D1 materialization in flight, chunk-boundary watcher armed -> D2 direct solve -> D3 + warm-start release). Handoff note: the register fixes (parity known-gaps −5, coverage-manifest + promotion) live on build-j-recert and need a main PR for reproducibility-from-main. + STAGING/LOCAL ONLY — publication + default flip = Max's call. ## Gate map + verdict-data locations (verified on origin/main; for the resumed run + verdict) Runs = worktree `.venv/bin/python tools/build_us_fiscal_refresh_release.py`; the sparse (deployable) diff --git a/experiments/build_j_recert/direct_solve_dense_buildj.py b/experiments/build_j_recert/direct_solve_dense_buildj.py index 9394f8c2..4d5472a2 100644 --- a/experiments/build_j_recert/direct_solve_dense_buildj.py +++ b/experiments/build_j_recert/direct_solve_dense_buildj.py @@ -42,7 +42,8 @@ FACTS = Path("/Users/maxghenis/PolicyEngine/_buildh-runtime/inputs/consumer_facts_buildh_v8.jsonl") FACTS_SHA = "94b7155f7ca9e2de32ddb3a0add2fff2d8c66e73147fe5bd112cff3ba69b1669" PEUS = "1.764.6" -REG_VERSION_EXPECTED = "d71c59514e3a" +# Build J dense registry = compile(v8) + the #387 RI substitution (5,534 specs). +# The version is computed live and checked against the checkpoint identity. OUT = RT / "out/buildj-run/densewts_direct" OUT.mkdir(parents=True, exist_ok=True) @@ -82,13 +83,15 @@ def main(): congressional_district_vintage_crosswalk=None, age_targets=True, allow_unaged_dollar_targets=False, extra_support_exclusions=None) - target_specs = registry0.specs + from populace.build.us_runtime import apply_us_medicaid_enrollment_substitutions + registry1, sub_records = apply_us_medicaid_enrollment_substitutions(registry0) + target_specs = registry1.specs active_registry = release.TargetRegistry(target_specs, country="us") - log(f"registry version = {active_registry.version} " - f"(expected {REG_VERSION_EXPECTED}) n_specs={len(target_specs)}") - if active_registry.version != REG_VERSION_EXPECTED: - log(f"FATAL registry version mismatch — got {active_registry.version}, " - f"expected {REG_VERSION_EXPECTED}. STOP.") + log(f"registry version = {active_registry.version} n_specs={len(target_specs)} " + f"(expect 5534 = 5533 + RI substitution)") + log(f"substitutions: {[(r['state_fips'], r['applied'], r['stale']) for r in sub_records]}") + if len(target_specs) != 5534: + log("FATAL spec count != 5534. STOP.") sys.exit(3) identity = release._target_frame_checkpoint_identity( diff --git a/experiments/build_j_recert/issue368_verdict.md b/experiments/build_j_recert/issue368_verdict.md new file mode 100644 index 00000000..eb160375 --- /dev/null +++ b/experiments/build_j_recert/issue368_verdict.md @@ -0,0 +1,67 @@ +## Build J re-certification — SPARSE CERTIFIES with the SSI probe GREEN (+$5.15B); four anti-rot registers digested the week's coverage growth en route + +The full gated rebuild is done: base pool rebuild → rmloss100 selection carry-over → sparse release on `main`'s complete stack (#369 coverage gate + reform smoke, #373 SCF asset stage, #384 TANF fix + preflights, #385 release-native loading, SNAP train #350/#352/#353, #387 CMS substitution register) with **every gate on and no bypass flags**. The deployable 57,240-record sparse artifact **passes all certification gates**, and the reform-coverage smoke — the gate this issue exists for — scores the SSI $10k/$20k reform at **+$5.15B, nonzero and green**. An SSI resource-limit reform no longer silently scores $0. STAGING/LOCAL ONLY throughout; **publication and the default flip are Max's call** — nothing touched prod HF or `latest.json`. + +Certified run: `populace-us-2024-buildj-sparse-rmloss100-75d5add-20260710T094201Z` (rc=0, `release_gates.passed=True`, `failures=[]`), branch `build-j-recert`, policyengine-us **1.764.6** / core **3.26.11**, seed 0, period 2024. All numbers below verbatim from the run's `calibration_diagnostics.json` / `input_mass_parity.json` / `reform_coverage_smoke.json` / `build_manifest.json`. + +### The SSI probe (Deliverable 1's smoke, on Deliverable 2's data) + +| probe | result | +|---|---| +| `ssi_asset_limit_10k_20k` ($10k individual / $20k couple) | **effect +$5,153,370,118 @ 2024** — baseline SSI $55,192,291,256 → reform $60,345,661,375 — **PASSED** ($1B floor, enforced) | + +Against the #374 expectations: the re-solved rebuild lands **below** the +$9.66B SCF-only overlay (the predicted re-solve direction) and **above** the ~+$1.60B dense-native reference class — the gap is the **SIPP blend, the known open refinement** (#374 step 1: SCF-only understates the low-liquid-asset left tail, so restored baseline recipients run thin and the reform delta runs high). The #369 acceptance criterion (smoke green on a bound reform) is met; landing the magnitude in the dense-native class is #374's remaining work, not this certification's. + +The three SSI countable-resource columns (`bank_account_assets`, `stock_assets`, `bond_assets`) are on the exported H5 with signal — they are **hard requirements** in the coverage manifest (no exclusion), exactly as this issue demanded. + +### Headline diagnostics vs Build I (bar: 0.030833 / 0.8888 / +0.22% / 0-of-35) + +| metric | **Build J sparse** | Build I (rmloss100) | Build H frozen | +|---|---:|---:|---:| +| final loss | **0.030843** | 0.030833 | 0.030915 | +| within-10% | **0.8900** | 0.8888 | 0.8901 | +| ESS | 12,088.6 | 12,303.4 | 13,184 | +| realized max ratio | 4.994 | 4.993 | — | +| records / nonzero | 57,240 / 57,240 | 57,240 / 57,240 | 57,240 | +| fed income tax (SOI ht2 liability) | +0.58% | +0.22% | +0.45% | +| SS benefits (SSA) | −0.22% | −0.18% | −0.18% | +| net capital gain (CBO) | −25.69% | −24.18% | −26.65% | +| mortgage tax-exp (JCT) | +38.59% | +36.73% | +35.48% | +| **export-mass parity** | **PASS 0 / 35** | PASS 0 / 35 | FAIL 1 / 35 | +| zero-support (post-exclusion) | **0** | 0 | 0 | + +Export-mass detail (±50% band, $1B floor; reviewed exclusions `estate_income` + `non_sch_d_capital_gains` only, both used, none unused): `miscellaneous_income` **+11.46%** (Build I +11.5% — the Build I fix holds), `home_mortgage_interest` **+28.92%**, `first_home_mortgage_interest` **+29.00%** — all in band. The export's candidate-only set now carries the restored surface: the three asset leaves, `health_savings_account_ald`, `spm_unit_pre_subsidy_childcare_expenses`, the SNAP-train inputs (hours, pregnancy, ABAWD exemptions), and the seeded take-up flags. + +Comparison caveat, stated: the registry is **not** byte-identical to Build I's — Build J compiles **5,510** specs (`091ace02f962`) vs Build I's 5,514 (`d71c59514e3a`). Delta = the **#387 RI CMS substitution** (+1 injected spec: RI anchored at the ledger-verified November 2024 count 273,400, issue-linked to #386, cannot-rot on backfill — recorded in `build_manifest.json`) and **5 new TANF thin-state zero-support exclusions** (−5; below). Base pool data is identical to Build F/H/I (`base_household_weight_total` exact match; base h5 sha `0b50660a` differs from `18833fb6` only by HDF5 serialization non-determinism); selection is exactly Build I's rmloss100 57,240 (identity join: 0 unmapped, 0 ambiguous). + +### Gate table (all enforced, no bypass flags) + +| gate | result | +|---|---| +| structural: target_profile, health_input, base_population, immigration, hours_worked, snap_take_up, eligibility_inputs, pregnancy, snap_discretionary_exemption | **PASS** (all) | +| #384 register-consistency + take-up preflights | **PASS** | +| #334 Medicaid take-up (with #387 RI substitution applied, not stale) | **PASS** | +| #337 eCPS parity (register 93 → 88 after the five stale-exemption removals) | **PASS** | +| zero-support (24-cell reviewed list: Build I's 19 + 5 TANF; post-exclusion 0) | **PASS** | +| #369 input coverage (70 required incl. the 3 asset leaves; degenerate-required none) | **PASS** | +| degenerate input (#286; TANF unexcused and non-degenerate) | **PASS** | +| export-mass parity (35 columns) | **PASS 0/35** | +| #369 reform-coverage smoke (SSI probe) | **PASS +$5.15B** | +| take-up contract | **PASS** | + +### The four-register night (one root cause, four catches — the anti-rot machinery digesting the week's coverage gains) + +Build J is the first release-scale run of most of this week's merges, and four registers failed closed in sequence; every failure was diagnosed against the actual frame/artifact before the register moved: + +1. **#334 Medicaid take-up**: RI (FIPS 44) had no CMS enrollment target — a genuine source hole (CMS PI dataset carries RI 202412 = 0, footnoted "Unable to Provide Data due to System Limitations"; RI never reported the month). Filed **#386**; fixed by **#387**'s reviewed substitution register (nearest reported month, 2024-11 = 273,400, cannot-rot on backfill). The gate refused to ship RI silently anchored-only — correct behavior, first time out. +2. **#337 eCPS parity staleness**: five exemptions rotted because the candidate now populates the layers — verified per-layer on the rmloss100 57k with the gate's own share computation: `block_geoid`/`tract_geoid`/`county_fips` at **1.0 = reference 1.0** (the #277/#289 geography-ladder spine), `spm_unit_pre_subsidy_childcare_expenses` 0.0755 vs ref 0.1022, `health_savings_account_ald` 0.00936 vs ref 0.0962 (genuine but thin; depth stays tracked in #32). Register 93 → 88. +3. **Zero-support**: 5 TANF state cells (`fl/ia/mo/ne/nj`) lost support because **#384 made TANF take-up seeding live** (13,205/59,900 spm_units True vs the old constant-True) — verified at 0 nonzero records on the identity-matched staged frame while every other state carries 1–14 (national 156). The Build I AL precedent, five states wider under real take-up; the dense parent expresses these cells; selection-side remedy is #346/#355-class work. Exclusion list 19 → 24, each with the measured justification. +4. **#369 input-coverage staleness**: the coverage manifest (which derives from the parity register) still excluded the same five columns — regenerated with `tools/build_us_release_input_coverage_manifest.py`; diff = exactly five `reviewed_exclusion` → `required` promotions (65→70 required / 93→88 exclusions). A one-pass sweep of every remaining register (degenerate, documented-absent, take-up contract, substitutions, probes) found no other entry carrying the five columns or TANF-era assumptions. + +### Verdict: the sparse artifact is **CERTIFIABLE** + +All gates pass with everything enforced; final loss and within-10% land at the Build I bar (within-10% beats it); export-mass parity holds 0/35 with the same two reviewed exclusions; the SSI probe — the reason this issue exists — is green at +$5.15B with the asset columns as hard requirements. The dense diagnostic arm (full 337,704 pool, same stages, no zero-support exclusions) is running serialized — its numbers follow in this thread when the chunked solve completes. + +Remaining follow-ups, tracked: #374 (SIPP blend + landing the SSI magnitude in the dense-native class), #386/#387 (RI substitution retires automatically if CMS backfills), #32 (HSA/childcare depth), #346/#355-class (thin-state TANF carriers in selection). The register edits made during this run (parity −5, coverage-manifest promotion, 24-cell zero-support list) live on `build-j-recert` and need a main PR alongside any publication decision. + +Cache-key: base `0b50660a21e0…` (pool data == Build F `18833fb6`); pe-us 1.764.6 / core 3.26.11; seed 0; period 2024; feed v8 `94b7155f`; registry `091ace02f962` (5,510 compiled); selection `152baca3` (57,240; 0/0 join); zero-support exclusions `0be0c200…` (24 cells); export-mass ref `c2065b64`; SCF donor member `6b8dd2d9` (zip `3bb4d890`, both == #373 pins). Release id `populace-us-2024-buildj-sparse-rmloss100-75d5add-20260710T094201Z`: `release_manifest.json` sha256 `3d292c2231d918cf58b68d14bfabd0a1ea252a43ae1890cec5228bd10db21ba9`, exported H5 sha256 `9d1e460ddbc49c9b467b936f07edd4576ae2667ef39fdea2490bc5577c038d51`. Artifacts under `~/PolicyEngine/_buildj-runtime/out/buildj-run/sparse/`; working log `PROGRESS_BUILDJ.md` on `build-j-recert`. From ddf3ea2a80986156b7dc18daf0b36b806ab23d0f Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 10 Jul 2026 06:38:52 -0400 Subject: [PATCH 16/17] Fix ruff lint in Build J run scaffolding (unused import + dead assignment) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI runs `ruff check .`; the staged run scaffolding tripped F401 (unused `os` in detach.py) and F841 (unused `pg` in extract_gates_buildj.py). Remove both — no behavior change. (#368) Co-Authored-By: Claude Fable 5 --- experiments/build_j_recert/detach.py | 1 - experiments/build_j_recert/extract_gates_buildj.py | 1 - 2 files changed, 2 deletions(-) diff --git a/experiments/build_j_recert/detach.py b/experiments/build_j_recert/detach.py index a66b4284..e05f650f 100755 --- a/experiments/build_j_recert/detach.py +++ b/experiments/build_j_recert/detach.py @@ -10,7 +10,6 @@ the chunk runs to natural completion; monitoring is via the script's own rc/append logs + a memory-pressure sampler. STAGING/LOCAL ONLY. """ -import os import subprocess import sys import time diff --git a/experiments/build_j_recert/extract_gates_buildj.py b/experiments/build_j_recert/extract_gates_buildj.py index 84593774..febb628d 100644 --- a/experiments/build_j_recert/extract_gates_buildj.py +++ b/experiments/build_j_recert/extract_gates_buildj.py @@ -71,7 +71,6 @@ def main() -> int: if parity: print("\n--- EXPORT-MASS PARITY ---") - pg = parity.get("input_mass_parity", parity) if isinstance(parity, dict) else parity print(f" passed = {find(parity, 'passed')}") fails = find(parity, "failures") print(f" failures = {fails}") From c10f7bb480bdbd6d8aa16f0e9dbbc4e35fe1d334 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 10 Jul 2026 06:54:42 -0400 Subject: [PATCH 17/17] Scope the incumbent-reference live-tree sweep to skip experiments/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test_no_incumbent_data_package_references_in_live_tree flagged the Build J base-rebuild summary (experiments/build_j_recert/base_j.summary.json), which records the incumbent us-data checkout in local-path provenance. experiments/ is run scaffolding / staged run outputs, not shipped source (nothing there is packaged under packages/), so it belongs in the same non-shipped class as the already-skipped `out` tree — the shipped tree under packages/ is still swept. Extends the populace#363 precedent (.claude worktrees skipped). No gate on shipped-source purity is relaxed. (#368) Co-Authored-By: Claude Fable 5 --- packages/populace-build/tests/test_us_plan.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/populace-build/tests/test_us_plan.py b/packages/populace-build/tests/test_us_plan.py index 53829cda..f8fd5f50 100644 --- a/packages/populace-build/tests/test_us_plan.py +++ b/packages/populace-build/tests/test_us_plan.py @@ -409,6 +409,11 @@ def test_no_incumbent_data_package_references_in_live_tree(self) -> None: or ".venv" in path.parts or ".claude" in path.parts or "out" in path.parts + # Run scaffolding and staged run outputs (launchers, base-rebuild + # summaries) are not shipped source and may record the incumbent + # in local-path provenance; the shipped tree under packages/ is + # still swept. Same non-shipped class as ``out``. + or "experiments" in path.parts ): continue rel = str(path.relative_to(ROOT))