Repository navigation
Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42
Description
Research memo for the candidate that follows the failed baseline (#40). Gate 1 stays locked; candidate 2 runs through the same protocol on the same paired splits, and its model description should be registered in this issue before the run.
1. What the locked references demand — a three-moment back-out
The committed battery autocorrelations (log earnings among positives, biennial lags 1/2/5 = 2/4/10 years) are 0.7301 / 0.6572 / 0.5389. Fitting candidate structures to exactly these three numbers:
| structure | implied 10yr autocorr | vs locked band [0.469, 0.609] |
|---|---|---|
| AR(1) chain (the baseline's linear analogue) | 0.207 | far outside |
| AR(2) — "condition on two lags" (Yule–Walker fit to lags 1–2) | 0.396 | still outside |
| permanent + AR(1) transitory + white noise | 0.539 | exact by construction |
The three-component model fits all three committed moments exactly with permanent share 0.467, transitory share 0.364 (biennial ρ = 0.722 ≈ 0.85 annualized), noise share 0.169. The long-run autocorrelation asymptote equals the permanent share — no finite-lag chain, however nonlinear, can hold a ~0.47 floor forever; the baseline run measured exactly this (1-lag QRF: 10yr autocorr 0.31–0.37 — nonlinearity buys ~+0.13 over the linear 0.207, structurally short). The noise share of 0.169 is consistent with the PSID validation literature on reporting error (Pischke 1995; Bound & Krueger's mean-reverting error), which also cautions against pushing the chain to reproduce lag-0 variance too literally.
Conclusion: candidate 2 must carry an explicit latent person-level state. Two extra lags provably cannot do it; a permanent component is not one option among several, it is what the committed moments identify.
2. Literature mapping (all verified)
- Arellano, Blundell & Bonhomme (2017, Econometrica 85:693–734) — the theoretical home for our machinery: log earnings = a general Markovian persistent component plus a transitory innovation, estimated with quantile-based methods; persistence varies with the size and sign of the current shock (nonlinear persistence, conditional skewness). A chained QRF conditioned on a latent persistent state is the simulation-native analogue of this framework.
- Guvenen, Karahan, Ozkan & Song (2021, Econometrica 89:2303–2339) — administrative data on millions of workers: earnings changes are strongly non-Gaussian (negative skewness, kurtosis far above normal, varying by age and earnings level), and persistence is asymmetric (positive changes for high earners are transitory; negative ones persistent; reversed for low earners). QRF quantile draws capture these facts natively where parametric AR components cannot — the reason to keep the QRF frame rather than switch to a parametric process.
- Sabelhaus & Song (2010, JME 57:391–403) — permanent/transitory decomposition over the life cycle on SSA administrative earnings; already load-bearing in the paper's earnings section and the right external anchor for our fitted component shares.
- Incumbent dynamic microsimulations already encode the permanent component. MINT projects earnings by splicing donor workers' observed histories onto targets and adds a person-specific fixed effect to regression projections — splicing preserves observed profile heterogeneity by construction (MINT I methods). DYNASIM carries an estimated individual-specific error term in its earnings equations. Gate 1 is demanding of us what the incumbents already build in.
3. Recommended design: latent-permanent conditioned chained QRF
Production-compatible with the backcast use case (one anchored observation per person), and implementable in populace-fit's existing chaining:
- Training (80% complement only): residualize log positive earnings on age; estimate each training person's permanent component as the empirical-Bayes-shrunk within-person mean of residuals (shrinkage handles short observed spells).
- Anchor stage: fit QRF_perm ~ P(perm | anchor-period covariates: anchor earnings, age at anchor). At generation, draw each holdout person's perm from this conditional — never estimate it from holdout data (protocol: holdout persons are excluded from all fitting; their perm is a model draw conditioned only on the anchor row the production use case also has).
- Chain stage: the existing backward one-step chain, now conditioned on the latent draw: earnings at t−2 ~ QRF(earnings at t, perm, age at t−2). Regime gate unchanged (participation conditions on perm too, which should also help zero-spell structure).
Why it passes structurally: conditioning every step on a persistent latent state puts a floor under long-horizon autocorrelation equal to the share of variance the drawn perm explains — the exact quantity the back-out says must be ≈ 0.47 — while the QRF supplies ABB-style nonlinear persistence and GKOS-style non-Gaussian shocks within each step. The honest uncertainty is that P(perm | one anchor year) is wide; that spread is real and belongs in the draws.
Alternatives considered and ranked below it:
- Two-lag conditioning only — rejected above; the linear benchmark (0.396) sits outside the locked band before nonlinearity, and the burden it must close (~0.14) exceeds what nonlinearity bought at one lag (~0.13) starting from much further away.
- Full ABB quantile-AR estimation — estimates the latent process with quantile regressions and simulates from it; theoretically cleanest but duplicates what QRF chaining does natively at higher implementation cost; better used later as a cross-check.
- GKOS-style parametric mixture process — benchmark-grade moments but abandons the nonparametric frame and its automatic covariate conditioning; useful as an external comparison line in the paper, not as the candidate.
- MINT-style splicing — preserves heterogeneity by construction and is a strong sanity baseline, but it cannot condition on arbitrary covariates or extend to the full transition system; worth reporting as a comparison row if cheap.
4. Pre-registration discipline for the run
Same locked gate, same paired splits (seeds 0–4), one shot, no tuning against holdout scores. Before the run, this issue gets a comment registering the exact candidate spec (feature list, shrinkage rule, QRF defaults); the run publishes pass or fail, as #40 did.
Activity
MaxGhenis commentedon Jul 5, 2026
Candidate-2 registration (frozen before the run). Model: latent-permanent conditioned chained QRF, per this issue's memo. Every degree of freedom below is fixed now; the run is one shot on the locked gate (same protocol, paired seeds 0-4), publishing pass or fail.
Stage 0 — residualization (train split only). For train person-periods with positive earnings: r = log(earnings) − f(age), where f is a weighted OLS quadratic in age (weights = person-period weights), fit pooled on the seed's 80% complement.
Stage 1 — person effect. perm_i = empirical-Bayes shrunk within-person mean of residuals: perm_i = n_i·mean_i / (n_i + λ), λ = σ²_within/σ²_perm from an unweighted one-way random-effects method-of-moments decomposition on train residuals (persons with n_i ≥ 2 identify σ²_within; σ²_perm = max(0, var of person means − σ²_within · mean(1/n_i))). Persons with zero positive observations get perm_i = 0 (the prior mean, n_i = 0).
Stage 2 — perm draw model. RegimeGatedQRF (populace-fit defaults), target perm_i, predictors = (anchor-period earnings level, anchor-period age), where a person's anchor is their chronologically last observed period in the filtered panel; training rows = train persons' anchor rows, sample_weight = anchor-row weight. At generation each holdout person's perm is a DRAW from this model conditioned on their anchor row (holdout perms are never estimated from holdout data), seeded from the gate seed.
Stage 3 — chain. Identical to the baseline runner (backward one-step biennial chain, anchor keeps its real value, one-step across observation gaps, regime gate for zeros), with ONE change: the transition QRF's predictors are (earnings at t, age at t−2, perm), where perm = the estimated perm_i for training pairs and the drawn perm for generation. Weights as in the baseline (earlier-period person-period weight). populace-fit defaults throughout; all RNG seeded from the gate seed.
Artifact: runs/gate1_qrf_latent_perm_v1.json, same schema as the baseline artifact, model description updated. Scored via the identical protocol runner against the locked gates.yaml thresholds.
Gate-1 candidate 2: latent-permanent conditioned chained QRF (#43)
MaxGhenis commentedon Jul 5, 2026
Candidate-3 registration (frozen before the run). One amendment to candidate 2, motivated by its published diagnosis (PR #43: drawn perm share 0.52–0.55 vs the structural 0.467; 10yr autocorr overshoot as the sole failing battery stat): the white-noise variance decomposition in stage 1 over-attributed variance to the permanent component because the transitory component is itself persistent and does not average out over a person's few biennial observations. Stage 1 is replaced by a persistence-aware decomposition, estimated on each seed's train split only (never from the committed reference artifacts). All other stages, features, defaults, seeds, and the protocol are identical to the candidate-2 registration above.
Stage 1a — within-person autocovariances (train split). From the stage-0 residuals, compute pooled unweighted within-person autocovariances γ_k for biennial lags k = 0..5: for each lag, average r_it·r_i,t+2k over all within-person pairs of observed periods exactly 2k years apart (γ_0 over all residual squares), centering residuals at the pooled mean.
Stage 1b — three-component fit. Fit γ_0 = σ²_perm + σ²_trans + σ²_noise and γ_k = σ²_perm + σ²_trans·ρᵏ (k = 1..5) by: grid ρ ∈ {0.50, 0.51, …, 0.95}; at each ρ solve the six moment equations for (σ²_perm, σ²_trans, σ²_noise) by non-negative least squares; select the ρ minimizing the sum of squared moment residuals. Deterministic; no iterative starting-point sensitivity.
Stage 1c — person effects with correlated-noise shrinkage. perm̂_i = w_i · mean_i(r), where w_i = σ²_perm / (σ²_perm + V_i) and V_i = (1/n_i²)·[σ²_trans·Σ_j Σ_l ρ^{|p_j − p_l|/2} + n_i·σ²_noise] over person i's observed periods p (biennial lag distances); persons with no positive observations get perm̂_i = 0 as before.
Stages 0, 2, 3 unchanged from the candidate-2 registration (same anchor definition, same QRF_perm predictors, same chain predictors and gap/zero rules, populace-fit defaults, all RNG from the gate seed). Artifact: runs/gate1_qrf_latent_perm_v2.json, same schema, with the stage-1 fit (γ_k, chosen ρ, component variances, per-seed perm-share diagnostics) reported-not-gated. One shot on the locked gate; publishes pass or fail.
MaxGhenis commentedon Jul 6, 2026
Candidate-4 diagnosis and registration (frozen before the run).
Diagnosis from the three published runs
Mean autocorrelation ladders (2yr / 4yr / 10yr; locked bands 0.730±0.05 / 0.657±0.06 / 0.539±0.07):
Candidates 2 and 3 have statistically identical ladders despite a 2.3× difference in drawn-perm variance, and their shared 10-year floor (~0.648) equals the raw train person-mean variance share (candidate 2's own MoM diagnostic: 0.647). This is errors-in-variables scaling: rescaling the person-effect feature makes the QRF rescale its response inversely, so generation transmits the same total person-level variance either way — the raw person-mean share (inflated by transitory bleed over few biennial observations), not the decomposed permanent share. The imputation sensitivity (#46) rules out target contamination (excluding assigned observations moves the reference only +0.012). Conclusion: no feature-side dial can fix this; the person-level variance and the observation-noise layer must be set structurally at generation.
Candidate-4 registration: structural three-component generation
Stages 0 and 1 are identical to the candidate-3 registration above (age-quadratic WLS residualization; within-person autocovariances; grid-ρ NNLS decomposition into σ̂²_perm, σ̂²_trans, ρ̂, σ̂²_noise; correlated-noise-shrunk perm̂_i) — all per seed on the train split. The generation changes:
Participation (zero vs positive): unchanged from the prior candidates' machinery — the regime gate decides zero/positive per backward step conditioned on the next period's generated level and age, trained on the 80% complement, populace-fit defaults. (This channel passed every battery and geometry check in all three runs.)
Magnitude (positive observations), log scale, assembled from components. For each holdout person, with their anchor (chronologically last observed period) kept at its real value:
All RNG seeded from the gate seed; populace-fit defaults throughout; thresholds read from gates.yaml at runtime; same paired splits; battery-reference bit-exact precheck; one shot, publishes pass or fail. Artifact: runs/gate1_qrf_structural_v1.json (same schema; model description per this comment; reported-not-gated diagnostics: per-seed σ̂ components, Var_train[μ̂(anchor)], realized cross-person var(m), realized generated-vs-train variance ratio).
Predicted mechanics, stated for the record: the 10-year floor should fall from ~0.648 toward the decomposed permanent share, the noise layer should attenuate all lags toward the data's measured ladder, and the main residual risks are the 2-year band (if the assembled short-lag correlation undershoots) and the upper tail blocks under lognormal noise. Whatever the numbers say, they publish.
MaxGhenis commentedon Jul 6, 2026
Candidate-5a registration (frozen before the run): MINT-style donor splicing. Motivated by the four-run symmetry (conditional-draw candidates cannot set person-level variance; the structural candidate broke the marginal): splicing reuses whole observed careers, inheriting marginal AND person-level dependence from real data at once — the strategy SSA's MINT uses (donor earnings records spliced onto targets). This candidate doubles as the field-standard benchmark: if it passes, the gate has its first PASS and the generative program has the bar it must beat on conditioning flexibility; its production limits (donor support, coarse covariate conditioning) are why the generative track continues.
Per seed (same locked protocol, paired splits, seeds 0-4):
Artifact: runs/gate1_splice_v1.json — same schema; spec_registration = this comment URL; reported-not-gated diagnostics: donor-match age-window widening distribution, nearest-age fallback rate, scaling-clip rate, donor reuse counts (how many holdout persons share a donor). One shot on the locked gate; publishes pass or fail. The parallel design track (candidate 5b, to be registered separately after design work): rank-space persistent dynamics with empirical quantile marginals and simulated-moment-calibrated innovations, per the ABB/GKOS synthesis in the research memo.
Gate-1 candidate 5a: MINT-style donor splicing
Gate-1 candidate 5a: MINT-style donor splicing (#50)
MaxGhenis commentedon Jul 6, 2026
Candidate-5a′ registration (frozen before the run): segment splicing. The single-donor run (PR #50) failed on three named artifacts; this variant — closer to MINT's actual practice — addresses each by construction: segments from multiple donors mix careers (against whole-career over-persistence), splices are indexed by calendar period rather than age (against the offset-age-grid signature), and level adjustment happens per segment at its boundary (against global anchor-noise conversion). Everything below is deterministic; the gate seed enters only through the locked split.
Per seed (locked protocol, paired splits, seeds 0-4), for each holdout person, walking BACKWARD from the anchor (chronologically last observed period, kept at its real value):
Artifact: runs/gate1_splice_v2.json — same schema; spec_registration = this comment URL; reported-not-gated diagnostics: segment-count and segment-length distributions, age-window widening and segment-shortening rates, scaling-clip rate, donor reuse (distinct donors per person and per holdout), boundary-value match error distribution. One shot on the locked gate; publishes pass or fail. No model fitting; runs in the plain repo venv.
Gate-1 candidate 5a': segment splicing
Gate-1 candidate 5a': segment splicing (#51)
MaxGhenis commentedon Jul 6, 2026
Candidate-5b registration (frozen before the run): rank-space generative dynamics. The design composes the field's third and fourth strategies (paper §gate-1): empirical quantile marginals (rank space — the marginal cannot break by construction, run 4's lesson), a fixed-form latent persistence model no learner can rescale away (runs 2–3's lesson), and simulated-moment calibration so iterated — not one-step — dynamics match the ladder (the baseline's lesson). Participation reuses the regime machinery that has passed in every run. Target: beat the classifier residual segment splicing left (pairs c2st 0.547, runs 0.567) while keeping its battery. Known limitations, stated up front: Gaussian-copula innovations cannot represent the asymmetric, income-level-dependent persistence documented in administrative data, and cell-discretized quantile support may itself be classifier-visible.
All stages per seed on the locked split; train = the 80% complement throughout; holdout data appears only at scoring and as each person's real anchor.
One shot on the locked gate; publishes pass or fail.
MaxGhenis commentedon Jul 6, 2026
Candidate-6 registration (frozen before the run): anchored empirical rank-transition kernel. Run 7 validated the rank-space architecture and rejected Gaussian innovations (mobility churn; classifier-readable joint). This candidate keeps the architecture — train-cell empirical quantile marginals, the proven regime gate, real anchors — and replaces the latent-Gaussian dynamics with a nonparametric transition law estimated by counting, which (a) captures nonlinear, extreme-sticky rank persistence empirically (what the mobility diagonal demands), (b) draws empirical innovations (what the classifier residual demands), and (c) carries the person-level component through anchor-rank conditioning rather than any learner-visible feature — a counting estimator has no rescaling freedom, so the errors-in-variables channel of runs 2–3 is closed by construction. No calibration stage: the kernel has zero free parameters beyond the pinned discretization; iterated dynamics are whatever the counts imply, and the run publishes them.
All stages per seed on the locked split; train = the 80% complement; holdout appears only at scoring and as each person's real anchor.
Stated risks, for the record: the anchor-bin between-person share sets the long-run autocorrelation floor and may undershoot the 10-year band (the kernel is one-step Markov within anchor bin); the twenty-bin discretization and within-bin uniform may themselves be classifier-visible. One shot on the locked gate; publishes pass or fail.
Gate-1 candidate 6: anchored empirical rank-transition kernel (#53)
MaxGhenis commentedon Jul 6, 2026
Candidate-7 registration (frozen before the run): k-nearest-neighbor conditional rank bootstrap with anchored two-step memory. The forensics (PR #54) localized candidate 6's entire classifier residual to joint-transition flattening from discretization (20 bins + within-bin uniform + Laplace), compounding along the chain, while its marginals were exact; the battery residual (4/10-year autocorrelation) is insufficient memory. This candidate replaces the discretized kernel with continuous empirical conditional draws and deepens the conditioning memory. It stays a counting-flavored estimator — no learner (the errors-in-variables channel stays closed), no calibration stage, no scaling of values (the splice-tail defect has no analogue here). All constants below are design choices fixed a priori at registration, not tuned.
Stages 1–2 (rank machinery, anchor rank u_A) and participation (regime gate) are identical to the candidate-6 registration. The transition law changes:
Registered risks: the 10-year autocorrelation floor may still undershoot (two-step-plus-anchor memory may not carry the full permanent share); k = 25 fixed a priori may under- or over-smooth the conditional; k-NN draws reuse train u_prev values whose fine-grained distribution the classifier may read. One shot on the locked gate; publishes pass or fail.
Gate-1 candidate 7: k-NN conditional rank bootstrap (fails 2/5 both b…
237 remaining items
MaxGhenis commentedon Oct 15, 2026
Track B B2: registration of the 2010→2014 transport gate
Status: registration, posted on issue #42 before B2's floor builder runs. Nothing below states a B2 outcome; none exists.
Verification class: retrospective regression (design §3.2). Admitted scope: "2010→2014 continuity on the stated surface, ages 25–64. Not a 2010-vintage forecast" (design line 150).
Headline (d781). B2's gate covers earnings levels and zero rates only: p50, p90 and the zero rate of annual earnings, by cohort. It does not cover changes, dispersion, mobility or persistence. H and B3L rely on B2 for levels only. The other ten cells are scored and published report-only. The result's headline names the cells the ladder keeps gated, since pruning may leave fewer than six.
2012 and 2014 informed earlier selection. Every evaluation row of B2 lies in years the B0.1 audit lists as exposed (audit §5). They were selection evidence for candidate 3's law, and boundary-2008 and boundary-2010 candidate results were published (PRs #255 and #273).
EXPOSURE_UNRESOLVEDtherefore fires, and this registration is the registered fallback at the §3.2 scope above (d693 Q8 (b)). H and B3L may rely on B2 only within that scope. Removing this statement after any candidate run requires a dated amendment.The frozen record
B2 registers on the B0.1 addendum and audit, as merged to
masterby PR #505 at3d23760d:3d23760ddocs/design/track_b_b0_1_addendum.mdf719edd9bdfc969c014f2bf2d7b854d2913da9b4225d64a84a78fa53c909cd12docs/design/track_b_b0_1_audit.md16b029728cfd09ef1c879bb9419cba2ec2c5dc92d6f0355498897c11c8fbb128The addendum's section 3 lists all ten §5.2 elements and the named power procedure as frozen. Elements 6 and 7 are frozen as rules, and B2's floor produces their values before any candidate run. Its blinded review (d693 Q6) was approved in rounds 7, 8, 9 and 10 (section 15).
Rulings carried.
The ruling texts are quoted in the addendum's section 2.
Inherited evidence
B1 v2 passed as a reconstructed reproduction (weaker than bit-for-bit) (d622). It returned
RECONSTRUCTED_REPRODUCTION, with zero differences on all four conditions. Its registration is #42 comment 6110674288 and its result #42 comment 6113379406. The result discloses one launcher deviation: the launcher's shell ended with the operator's session while the run went on to complete, so its exit code was not captured.Candidate 3's disclosure, in full (design lines 29–31):
Elements
1. Source release. The PSID files B2 reads are pinned by the B0.1 counts record's
b2_read_set_sha256: 80 files, the.txtand.spsof every family wave 1968–2015, plusIND2023ER.txtandIND2023ER.sps. Its canonical SHA-256 (sorted keys, compact separators) is787725e30d2273a76854e134a41b882110c76e222925ea8022ac891f413fb62c. The floor builder refuses to open any other PSID file and checks every opened file's hash against the pin.nawi.yaml, realized through 2010, with later years from the fitter's log-linear projection over 2001–2010. It is labelledpe_us_1_752_2_nawi_realized_2010_loglinear_2001_2010, notols_log_nawi_2005_2014. It is the series as later revised, not a 2011-era release.2. Variables and the codebook concept check (audit §4.2, definitions only). All six labor-income variables define the concept as labor income "Excluding Farm and Unincorporated Business Income". The concept reads the same across B2's window. The one difference is that market gardening is absent from the 2015 head entry's component list; whether the 2015 instrument dropped or moved it was not checked.
3. Population. The 2011 anchor persons with a valid 2010 row: 13,542 persons, defined from data by the floor builder and checked against the frozen count. No one is scored outside ages 25–64 at the scored waves. B2's bridge hands this domain to H (d693 Q7).
4. Exposure history. As stated above. Each gated cell carries an exposure label, and the floor artifact's headline counts them.
earn_zero_rate.oldercarries "published candidate-3-law outcomes at boundaries 2008 and 2010". The other five gated cells carry "published five-seed floor detail, no published candidate outcome".5. Holdout partition.
6. Critical cells (d781 (a), d1342 (A)). The gate family is
earn_p50.older,earn_p50.prime,earn_p90.older,earn_p90.prime,earn_zero_rate.olderandearn_zero_rate.prime. The floor builder applies eligibility and M6's ladder inside the six on B2's own floor:m6_cells.py:681), not their SD.scripts/track_b_b0_1_ruled_power.py), with the critical value t*_{m,ν}.Either of two cases makes B2
WEAK_POWER_OR_VACUITYat floor build, before any candidate run, and B2 stops there:No rescoped or amended registration is written before he rules.
7. Tolerances. tol_c = min(round(mean_c + 3 SD_c, 3), cap) over the 100 household-split floor seeds; the caps are ln 1.5 and 0.15. The floor artifact states each gated tolerance in plain units before any candidate outcome. §5.3's earnings limits do not apply to B2: no Track B gate holds ages 25–61 earnings to a fixed limit (d693 Q4).
8. Uncertainty.
se_up: 4,000 household-bootstrap replicates, × √(1 + 1/K).
se_boot: 4,000 design replicates, Rao-Wu within strata, with the law and the paths fixed. The stratum rule (addendum section 7):
The floor builder publishes the strata by cluster count, the merges, L and ν before any candidate run. A stratum of three or more clusters draws
rng.multinomial(n_h − 1, 1/n_h)over its clusters sorted by original (stratum, cluster), and strata are visited in ascending merged code, all at the commit pinned below.se_c = √(se_boot² + a_c se_up²). a_c is the cell's registered estimation-variance ratio: e_B2 from the planning record, plus the transported cross term f × c where protocol v2's rule adds it.
Bound: |g_c| + t*{m,ν} se_c ≤ tol_c, where t*{m,ν} = t_ν⁻¹(1 − 0.05/(2m)). At ν = 63 and m = 6 it would be 2.724; B2 uses its own ν.
Monte Carlo rule: the per-draw signed gap's SD / √K must be below tol_c/10.
A cell with more than 1% of its replicates undefined cannot pass.
9. Pass conjunction. A gated cell is valid on a frame when its truth is defined, none of its K draws is undefined, and the draws are not all identical. A gate seed passes when every gated cell's side-A gap lies within tol_c. The outcome is the first that applies:
INVALID and INCONCLUSIVE are non-passes with FAIL's consequences.
10. Reference dates versus collection (audit §4.3).
FAM2011ER)FAM2013ER)FAM2015ER)Age and weight are measured at the collection wave. PSID has no 2012 or 2014 interview. All staged files are retrospective releases, made 9 to 13 years after their reference years.
Seeds and streams. The scoring root is 20261002. Household replicate b uses stream [root, b, 0], design replicate b stream [root, b, 4]. Candidate 3's law is fitted with seed 5200 and projected with draws 6200–6219 (K = 20). Floor seeds are 0–99, gate seeds 0–4.
Planning values. They come from a 2006 pseudo-origin, whose truth years, 2008 and 2010, fall in a recession. Neither their transport to 2012 and 2014 nor r's is tested.
Rules the implementation adds to the addendum's text
Each was chosen in review before any run, and is stated here so nothing is decided after an outcome:
Copies past 999. The planning script's
copy_personsnumbers copiesperson × 1,000 + kand refuses 1,000 or more. Below that, B2 calls it unchanged. Above it, which only a stratum rule scale L large enough can produce, B2 runs the same construction with a wider power-of-ten identifier scale. Only the identifiers' encoding differs.Eligibility is section 5's exactly: every seed defined, at least 20 events in the weaker half, and planning values present. A cell of the six that fails it is scored report-only, and the ladder runs on the others.
An eligible cell with zero or undefined σ, se_up or τ has an uninformative tolerance or no computable power, and section 5 never drops an eligible cell. So B2 stops at floor build as
WEAK_POWER_OR_VACUITY.Replicates that raise count as undefined for every cell, with the exception class recorded. A memory or operating-system error stops the run.
An undefined truth makes the cell invalid on that frame, as in M6.
The report-only interval is g ± t_ν⁻¹(0.975) se_c.
More than 1% undefined household replicates in a gated cell is known at floor time, as
cells[c].se_up.undefined_share_okin the floor artifact, and that cell cannot pass.outcome: LADDER_CLEARED. The operator readsundefined_share_okfor every cell insurface.gatedand posts the values on Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42.WEAK_POWER_OR_VACUITY("undefined cells", design line 454), whatever the artifact'soutcomereads. B2 returns to Max with options B–D, priced on B2's real tolerances, so B2 is not spent on a run that cannot pass.The artifact's
read_set_completefield is fixed attruein the code. It means only that every opened PSID file was in the pinned read set with its pinned hash. The files actually opened are listed with their hashes inpsid_files_opened_sha256; protocol v2 opened 74 of the 80."To B2" items carried in code and tests:
anchor_multiplicitiesanddesign_multiplicities, called with root 20261002;BOOTSTRAP_ROOT_SEED;They are in
tests/test_track_b_b2_rules.py,tests/test_track_b_b2_design.pyandtests/test_track_b_b2_pipeline.py.Interruption.
runs/track_b_b2_score.attempt.jsonlexclusively. It appends each stage there, synced to disk, and refuses to start if the file exists.POPULACE_DYNAMICS_PE_US_DIR. The cause is fixed and posted on Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42, and the scorer is relaunched.22e3f82b, since it is truth-only and deterministic. Its stderr and the interruption are posted on Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42. A partly written artifact is moved outside the clone, hashed and disclosed first.runs/track_b_b2_score.attempt-1.jsonland committed in one commit, whose single parent is the floor commit and whose only change is adding that file. Its last stage is published on Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42.--expected-commit, and step 4's checks are repeated against it, with the one added file allowed.ABORTED_AFTER_GAPS, a non-pass with FAIL's consequences. The log's last stage is published on Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42, and the attempt is counted on the cumulative ledger (design line 469). Any successor needs a new registration. Section 8 forbids any rerun after a candidate outcome.Memory. The floor artifact publishes L before the scorer runs. A design replicate copies each truth and draw frame about L times, so a replicate's memory grows with L. The scorer's worker count is
4 // L(4 at L = 1, 2 at L = 2, 1 at L = 3 or 4), and the operator posts it on #42 before launch. This keeps workers × L at most 4. Protocol v2's planning run, at the same scale, ran its fixed-law arm F with 8 workers, each copying its truth and draw frames once (L = 1), and its refit arm with 6. Its record isdocs/design/track_b_b0_1_planning_values.json,bootstrap.workers.Above L = 4 the scorer is not launched. Not launching is not an attempt and not an outcome. B2 stays unadmitted, and Max is asked about memory or the host. At the 2006 pseudo-origin every stratum had two clusters, so L was 1.
Results do not depend on the worker count: a replicate is a function of its index and the payload alone, and replicates come back in index order (
b2.run_replicates).tests/test_track_b_b2_rules.pychecks design multiplicities and a toy function at 2 and 3 workers against a serial run. Scored gaps at 4 workers are not tested separately.Runtime
All paths are on the operator's host.
Code. The B2 implementation merged by PR Track B B2: floor builder, comparator and scorer (invented-data build) #526, at
22e3f82ba876526054b46f7f484db4df04c374be.22e3f82bsrc/populace_dynamics/track_b/b2.py3390a4023041eee697df174322ede3e3f7d82e65f13a815908b09ca675bce51ascripts/track_b_b2_floor.pyc92198f49aed0dd74c67a8135f12984022f45c971f94ee0caf25f81479618c44scripts/track_b_b2_compare_floor.py98aa90cf890e5d99835802cc0b0fbb8dc19ea06d8e0f3cfbe9fa63699319deb6scripts/track_b_b2_score.pyacf4fbcf5fdcda919d8303e0b2c0bcedd5fd17f73e2fc4f89229597ee112e176scripts/track_b_b0_1_planning_values.py62bd282c4a2968e388e190806d8e0ad8612fcbcbd9564f5485d3e49752ec7c27scripts/track_b_b0_1_ruled_power.py8cc64235f5157c13e99e14bd892317286a2e7f22a69dfb7443c7610c53f60af4docs/design/track_b_b0_1_planning_values.jsonf8a29eee25d721d30422c936d3e19fff60a93f817e70b76e9cb74c866a67d897docs/design/track_b_b0_1_counts.jsone93826d4c535a41ea28155b837307a1a941f9ac9d205f8e8bf60421481e54f99The addendum and audit are unchanged at
22e3f82b; their hashes are in the table above.The run clone:
/Users/maxghenis/PolicyEngine/_trackb-b2-run/microcosm-dynamics, on branchtrackb-b2-run-20261015, cut from22e3f82b. Nothing else lives in it, so the scripts' clean-worktree check sees only the repository.The runtime:
/Users/maxghenis/PolicyEngine/_trackb-b2-run/.venv-b2, outside the clone, with Python 3.14.4.Its distributions are the 164 pins in
runtime-requirements-pins.txt(SHA-25619e95ff7e9d6fc771e8a1b88285beae6ff10ad9e8e77fa24735d944caecec7f3), the same pins as.venv-gate, the environment B2's tests ran in. policyengine-us 1.752.2 is among them, installed from its wheel.populace-fit and populace-frame 0.1.0 are editable installs from
/Users/maxghenis/PolicyEngine/_trackb-b2-run/populace-pinned. That checkout sits at the selectors' pinned headaf02c917fcb3c50816bf3af9c2b64509e928889a, with fit tree5c866378fdf5906b7a61da9977b8d028d1d36e9fand frame tree7cfb9ee78beb74911963913f202a4471aae2f52b.The floor builder and the scorer refuse any Python other than 3.14.4; any version of numpy, pandas, scikit-learn, scipy, quantile-forest, populace-fit or populace-frame other than the pinned one; and any populace head, tree or unclean source other than the pins. This is the planning script's
runtime_record, called after their thread, registration, clean-worktree and output checks.The other pins are checked by the operator. Before each launch,
runtime_check.py(SHA-256348fc70c5600149140d9a3b27d2de44c9bcb52f988c36e5a73dd84a363ab7042) runs from outside the clone, with absolute paths:<evidence>is this registration's folder on the operator's host; nothing is copied into the clone.RUNTIME OK./Users/maxghenis/PolicyEngine/_trackb-b2-run/.venv-b2/bin/python;pins_sha256 19e95ff7…;check_sha256 348fc70c…;distributions 166(the 164 pins plus the two editable populace installs);listing_sha256 b774409c651ddfdd75eed26b35a1aad2e58ab1a2a07e94ff3b537350088d2986;RUNTIME OK.policyengine-us 1.752.2, for the 2010 NAWI read only.
POPULACE_DYNAMICS_PE_US_DIR=/Users/maxghenis/PolicyEngine/_trackb-b2-run/pe-us-1.752.2holdspolicyengine_us-1.752.2.dist-info/andpolicyengine_us/parameters/gov/ssa/nawi.yaml, taken from the 1.752.2 wheel. The file's hash matches the wheel's RECORD entrysha256=nbVf6eolRHoTl2fHcZsykgmC3SpliHyPwN2xKi3PfFM(SHA-256 hex9db55fe9ea25447a139767c7719b32920982dd2a65887c8fc0ddb12a2dcf7c53). The operator checked this; the code does not.e272a7bc…, mapping SHA-25626b6a049…. The read passed at registration.Threads, jobs and workers.
OMP_NUM_THREADS,OPENBLAS_NUM_THREADS,MKL_NUM_THREADS,VECLIB_MAXIMUM_THREADSandNUMEXPR_NUM_THREADSare all1. It runs withOMP_WAIT_POLICY=PASSIVEandPOPULACE_FIT_N_JOBS=4, and with the worker count set by the memory rule above. That stays within Max's 2026-10-11 cap for the shared host.POPULACE_FIT_N_JOBSoutside 1 to 4, or more than four workers. They check this first, before reading anything. The comparator has none of these guards; its only check is that the floor artifact is committed.ACTIVE. B2 refits and projects candidate 3 at one OpenMP thread instead, through the selectors'_project, as protocol v2's planning run did. That run's record showsOMP_NUM_THREADS=1andPOPULACE_FIT_N_JOBS=4..venv-gate, the environment B2's tests ran in, at~/PolicyEngine/_trackb-b2-build-r3/microcosm-dynamics/.venv-gate. Its populace is the shared checkout~/m6-sol-lanes/populace-pinned, whose fit and frame trees equal the pins. On 2026-10-15 that checkout stood at headee8f7fc; its head on 2026-10-13 was not recorded..venv-b2, the registered runtime, with the same 164 pins and populace at the pinned headaf02c917..venv-gate, probes of candidate 3's fit and projection on invented data were run with more than one OpenMP thread (2 and 4 threads, PASSIVE and ACTIVE). No logs of these probes were kept; this account is from the session record.HistGradientBoostingClassifier.predict_proba. The 60-s tracebacks were not read.22e3f82b, the same probe was run. It is_probeintests/test_track_b_b2_threads.py, called withb2.thread_settingsstubbed to allow more threads..venv-b2it completed at 1 thread in 16 s; at 2 threads, PASSIVE, in 40 s; at 4 threads, PASSIVE, in 51 s; and at 4 threads, ACTIVE, in 19 s..venv-gateit completed at 4 threads, PASSIVE, in 59 s.thread-hang-reproduction/summary.txt; each log holds the probe's output.b2.thread_settings' docstring, and the comments where the floor builder and the scorer call it, describe the stall as if it always occurs. This account supersedes them.Determinism.
tests/test_track_b_b2_threads.pywas run at22e3f82bin this runtime. Two fresh processes with different hash seeds give:_BinMapper.n_threads, the thread count HistGradientBoosting records;2 passed (
threads-determinism-22e3f82b-venv-b2.log). CI lackspopulace.fit, so it skips that test.Procedure
--registration-idis this comment's numeric GitHub comment id. Every #42 post below is a new comment. The operator is the registering session, named under "Exposure" below.Runtime check. The operator runs
runtime_check.pyas above and posts its output on Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42.The floor builder runs once, from the clean run clone at
22e3f82b:It writes
runs/track_b_b2_floor.jsonexclusively. That file alone is committed, as the only change, in one commit whose parent is22e3f82b, and pushed totrackb-b2-run-20261015. The commit id and the artifact's SHA-256 are then posted on Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42. The artifact holds:If it records
WEAK_POWER_OR_VACUITY, or rule 7 or the memory rule stops B2, B2 stops there and returns to Max. The comparator still runs, because it gates nothing.The comparator runs once, at the floor commit and before the scorer, with its default ledgers and no
--ledger. Its code is the version at22e3f82b, since the floor commit differs from22e3f82bonly by the artifact:All four booleans it prints (two fields for each of the two boundary-2010 selection ledgers) are posted on Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42 whatever they are. A mismatch or an error is published and gates nothing. The run is recorded on Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42 as the operator's ledger read.
The scorer runs once, from the clean run clone at the floor commit. The operator first checks, and posts, that:
22e3f82b(git rev-parse <floor commit>^@prints only it), and its only change isA runs/track_b_b2_floor.json;runtime_check.pystill endsRUNTIME OK.The scorer gets the same environment as the floor builder, plus
POPULACE_DYNAMICS_PE_US_DIR=/Users/maxghenis/PolicyEngine/_trackb-b2-run/pe-us-1.752.2. Its arguments are the same--registration-id,--expected-commit <the floor commit>, and the worker count set by the memory rule.--floor-artifactis not used, so the scorer reads the defaultruns/track_b_b2_floor.json.Its output
runs/track_b_b2_score.jsonand its attempt log are created exclusively, then committed and pushed totrackb-b2-run-20261015. After any candidate outcome there is no rerun, new seed, larger K, re-pruning, tolerance change or rescoping (addendum section 8).The outcome is published on Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42 whatever it is, with every gated and report-only cell scored, and the attempt goes on the cumulative ledger (design line 469). The run branch is then merged to master by a PR that adds only the run's files.
Exposure of the registering session
This registration was written by the session that drove Track B's B2 chain (Claude, Opus 5.5). In preparing it, the session read the audit's frozen support counts for 2012 and 2014. These are rows present by cohort and rows PSID assigned or edited: presence counts, published in the audit. It has met no 2012 or 2014 earnings statistic, floor value or B2 candidate output, and no selector outcome at 2008 or 2010. B1's raw output and sealed logs, which hold reference-year 2014 values, stay unopened until B2's result is published. This session is also the operator. Its comparator run (step 3) reads two fields of the boundary-2010 selection ledgers and prints only booleans; it is recorded as this session's ledger read.
Review before posting
Each round reviewed a cleaned copy of the repository at
22e3f82b, with the Q6 exclusion list removed. Subfleet routed each review job to a model: rounds 1 and 2 ran on Opus 5.5, round 3 on GPT-6.1 Sol.All three found no blinded value in what they read.
MaxGhenis commentedon Oct 15, 2026
B2, step 1: runtime check (registration: #42 comment 6199723681).
Run with the registered runtime's python, from outside the run clone. The run clone is clean at
22e3f82ba876526054b46f7f484db4df04c374be.The floor builder (step 2) starts next.
MaxGhenis commentedon Oct 15, 2026
Track B B2, steps 2 and 3: the floor stops B2 at floor build (
WEAK_POWER_OR_VACUITY). Registration: comment 6199723681.Step 2: the floor builder
How it ran. Once, at 18:49Z, from the clean run clone at
22e3f82b, using the registered command and environment: 4 workers, one BLAS/OpenMP/numexpr thread,OMP_WAIT_POLICY=PASSIVE,POPULACE_FIT_N_JOBS=4.nohupand was watched by PID, so its exit code was not captured.Commit.
7fdc8f91c11a0d251efb399f9490fbdecc5a9bc3ontrackb-b2-run-20261015, pushed.22e3f82b, and its only change isA runs/track_b_b2_floor.json.The artifact.
500f801e0cad5be0aebaaa0704e8fa21bdc6b2d7ead50f512abe2953c5f93aaf.outcome: WEAK_POWER_OR_VACUITY,candidate_runs_permitted: false,worktree_clean: true.Read set. The builder opened 78 of the 80 pinned files, each with its pinned hash and none outside the set. The two it did not open are
FAM1968.txtandFAM1968.sps.Design.
Eligibility. All six ruled cells are eligible.
Ladder. It ran inside the six, in order of descending tolerance/σ on the household-split floor (section 5):
earn_p90.primeearn_zero_rate.primeearn_zero_rate.olderearn_p50.primeearn_p90.olderearn_p50.olderearn_p50.olderandearn_zero_rate.older, at t*₂,₆₃ = 2.296.at_least_four_cells: falseandnot_every_tolerance_at_cap: true.surface.gatedis empty, and the headline counts zero gated cells.Rule 7.
cells[c].se_up.undefined_share_okistruefor all six ruled cells.surface.gatedis empty, so these are the six ruled cells.Memory rule. L = 1 would give 4 workers. It does not apply, because the scorer is not launched.
What follows. Under the registration's element 6, first case, B2 stops at floor build, before any candidate run.
Step 3: the comparator
How it ran. Once, at the floor commit
7fdc8f91, with its default ledgers and no--ledger.22e3f82b's.Output. Four booleans, all
true:docs/analysis/m6_qstar_train_only_selection_results.jsontruetruedocs/analysis/m6_rhostar_train_only_selection_results.jsontruetrueMeaning. B2's non-gating person-split floor block and seed detail for the six cells equal both boundary-2010 selection ledgers', by canonical SHA-256. This gates nothing.
This run is the operator's ledger read. It read those two fields and printed only these booleans.
Blindness: no 2012 or 2014 floor value, tolerance or truth moment is quoted here. They are in the committed artifact. No candidate outcome exists.
MaxGhenis commentedon Oct 15, 2026
Track B B2: d1342's options B-D priced on B2's real floor. This is decision input, not a registration. It follows step 2 (comment 6200099988).
B2 stopped at floor build, so under the registration the choice among d1342's B-D returns to Max, priced on B2's real tolerances. It is queued as d1606. No rescoped or amended registration is written, and no candidate is run, before he rules.
Method.
track_b_b2_floor.ladder_power): the ruled binding evaluation with B2's τ = tol/se_up, ν = 63, and the registered planning values.7fdc8f91.Power. Binding evaluation / most lenient evaluation; 0.90 is the bar.
earn_p50.olderearn_p50.olderandearn_zero_rate.olderSensitivity. This is a hypothetical stress, not a confidence interval. The design ratio d is transported from the 2006 pseudo-origin and is uncertain by roughly ±9% (addendum section 10). Scaling every retained cell's d by one common factor:
C1 stays at or above 0.90 up to d × 1.034.
Review. GPT-6.1 Sol reviewed the pricing in two rounds.
Not quoted here. No floor value, tolerance or truth moment appears in this comment; they are in the committed artifact. No candidate outcome exists.
MaxGhenis commentedon Oct 16, 2026
Erratum note: the delayed-retirement-credit window (#494), labelled diagnostic under ruling d1408. No registered artifact was rerun or replaced.
ss.benefits.delayed_creditcapped delayed credits at 48 months. For births 1917–1942, the statutory window (42 USC 402(w)(2)(A)) is 50–60 months. #532 added the statutory function beside the sealed oracle.This diagnostic rebuilt each reachable result's admitted records with the code at its recorded commit. For five results it reproduced the committed model headlines under the legacy cap, then switched only the credit window. First estimates is bounded, not reproduced. The note reports counts and changes only; cells under ten people are withheld.
No pre-1917 record was flagged. For any one supported worker, the added gross delayed credit before payment rounding is at most 6.5 percentage points of PIA (1937 births, claim at 70). Every registered result stands as registered. Later statutory work selects
DelayedCreditWindow.STATUTORY.Details:
docs/errata/2026-10-11-delayed-credit-window.mdanddocs/errata/2026-10-11-delayed-credit-window-diagnostic.json(merged in #538 as b3ba7e2).MaxGhenis commentedon Oct 18, 2026
Track B B2: rescoped registration under d1606 (option C1)
Status. This is a registration, posted on issue #42 before B2's rescoped floor build and before any candidate run. No B2 candidate outcome exists. B2's first floor build stopped B2 before any candidate run (below).
What it replaces.
Verification class: retrospective regression (design §3.2). Admitted scope: "2010→2014 continuity on the stated surface, ages 25–64. Not a 2010-vintage forecast" (design line 150).
Headline (d781 (a), d1606 C1). B2's gate covers the p90 of annual earnings and the zero-earnings rate, by cohort, only. It does not cover median earnings, changes, dispersion, mobility or persistence.
Median earnings. B2 certifies no median earnings level, so H and B3L cannot rely on B2 for one. The medians are an open item, to be settled when B3L's surface is frozen at B0.2. This is not an assignment:
Max confirmed this wording on 2026-10-16, after a correction (d1606, note of 2026-10-16).
2012 and 2014 informed earlier selection. Every evaluation row of B2 lies in years the B0.1 audit lists as exposed (audit §5). They were selection evidence for candidate 3's law, and boundary-2008 and boundary-2010 candidate results were published (PRs #255 and #273).
EXPOSURE_UNRESOLVEDtherefore fires, and this registration is the registered fallback at the §3.2 scope above (d693 Q8 (b)).How B2 got here
22e3f82b. B2 stopped at floor build, before any candidate run, asWEAK_POWER_OR_VACUITY.nohupand was watched by PID.earn_p50.olderandearn_zero_rate.older, at power 0.862.true.892040c88a6a2342d5545b8379920e077e0f4609). It addsb2.GATE_SURFACEand runs eligibility, the stop checks, the ladder and the guards inside it. It also:The first floor build is not a candidate attempt. It ran no candidate. Its artifact stays on
trackb-b2-run-20261015at7fdc8f91(SHA-256500f801e0cad5be0aebaaa0704e8fa21bdc6b2d7ead50f512abe2953c5f93aaf). Step 5 adds it tomasterasruns/track_b_b2_floor_v1_stopped.json, unchanged.The frozen record
B2 registers on the B0.1 addendum and audit, as merged to
masterby PR #505 at3d23760d:3d23760ddocs/design/track_b_b0_1_addendum.mdf719edd9bdfc969c014f2bf2d7b854d2913da9b4225d64a84a78fa53c909cd12docs/design/track_b_b0_1_audit.md16b029728cfd09ef1c879bb9419cba2ec2c5dc92d6f0355498897c11c8fbb128At
892040c8the addendum's SHA-256 is8896e8a7c183de1e6f9d8123ae6d9968f0c9d90f915472aa434c6c72b3d4f11c. PR #534 (read log v7) changed section 15 only. Section 16 starts at line 1865, and its protocol block's SHA-256, which the floor builder checks, is unchanged at2a1681cdb3b6e28f30a8c1a319895b95f25c2fb27a175c50ded8a196d8488fe9. The audit is unchanged.Rulings carried.
Inherited evidence
B1 v2 passed as a reconstructed reproduction (weaker than bit-for-bit) (d622). It returned
RECONSTRUCTED_REPRODUCTION, with zero differences on all four conditions.Candidate 3's disclosure, in full (design lines 29–31):
Elements
1. Source release. The PSID files B2 reads are pinned by the B0.1 counts record's
b2_read_set_sha256: 80 files, the.txtand.spsof every family wave 1968–2015, plusIND2023ER.txtandIND2023ER.sps.787725e30d2273a76854e134a41b882110c76e222925ea8022ac891f413fb62c.FAM1968.txtandFAM1968.sps.nawi.yaml, realized through 2010, with later years from the fitter's log-linear projection over 2001–2010.pe_us_1_752_2_nawi_realized_2010_loglinear_2001_2010, notols_log_nawi_2005_2014.2. Variables and the codebook concept check (audit §4.2, definitions only).
3. Population. The 2011 anchor persons with a valid 2010 row: 13,542 persons.
4. Exposure history. As stated above. Each gated cell carries an exposure label, and the floor artifact's headline counts them.
earn_zero_rate.oldercarries "published candidate-3-law outcomes at boundaries 2008 and 2010".5. Holdout partition.
6. Critical cells (d781 (a), d1342 (A), d1606 (C1)).
earn_p90.older,earn_p90.prime,earn_zero_rate.olderandearn_zero_rate.prime(b2.GATE_SURFACE).earn_p50.olderandearn_p50.prime, with the reason "outside the rescoped surface (d1606 option C1)", and the other ten cells, as before.m6_cells.py:681), not their SD.scripts/track_b_b0_1_ruled_power.py), with the critical value t*_{m,ν}.Either of two cases makes B2
WEAK_POWER_OR_VACUITYat floor build, before any candidate run, and B2 stops there:Either way, B2 returns to Max. No rescoped or amended registration is written before he rules.
7. Tolerances. tol_c = min(round(mean_c + 3 SD_c, 3), cap) over the 100 household-split floor seeds; the caps are ln 1.5 and 0.15.
8. Uncertainty.
se_up: 4,000 household-bootstrap replicates, × √(1 + 1/K).
se_boot: 4,000 design replicates, Rao-Wu within strata, with the law and the paths fixed. The stratum rule (addendum section 7):
rng.multinomial(n_h − 1, 1/n_h)over their clusters sorted by original (stratum, cluster). Strata are visited in ascending merged code, all at the commit pinned below;The floor builder publishes the strata by cluster count, the merges, L and ν before any candidate run. The first floor found 63 strata of two clusters, so no merges, L = 1 and ν = 63.
se_c = √(se_boot² + a_c se_up²). a_c is the cell's registered estimation-variance ratio: e_B2 from the planning record, plus the transported cross term f × c where protocol v2's rule adds it.
Bound: |g_c| + t*{m,ν} se_c ≤ tol_c, where t*{m,ν} = t_ν⁻¹(1 − 0.05/(2m)). At m = 4 and ν = 63 it would be 2.571; B2 uses its own m and ν.
Monte Carlo rule: the per-draw signed gap's SD / √K must be below tol_c/10.
Undefined replicates: a cell with more than 1% of its replicates undefined cannot pass.
9. Pass conjunction. A gated cell is valid on a frame when its truth is defined, none of its K draws is undefined, and the draws are not all identical. A gate seed passes when every gated cell's side-A gap lies within tol_c. The outcome is the first that applies:
INVALID and INCONCLUSIVE are non-passes with FAIL's consequences.
10. Reference dates versus collection (audit §4.3).
FAM2011ER)FAM2013ER)FAM2015ER)Age and weight are measured at the collection wave. PSID has no 2012 or 2014 interview. All staged files are retrospective releases, made 9 to 13 years after their reference years.
Seeds and streams.
Planning values. They come from a 2006 pseudo-origin, whose truth years, 2008 and 2010, fall in a recession. Neither their transport to 2012 and 2014 nor r's is tested. The decision aid's hypothetical stress showed C1 stays at or above 0.90 until the design ratio is about 3.4% above its registered value.
Rules the implementation adds to the addendum's text
Rules 1–9 were chosen in review before the first floor build. Rules 10 and 11 were added with this rescoping: after that build, and before any candidate run. All are stated here, so that nothing is decided after a candidate outcome:
Copies past 999. The planning script's
copy_personsnumbers copiesperson × 1,000 + kand refuses 1,000 or more.Eligibility is section 5's exactly: every seed defined, at least 20 events in the weaker half, and planning values present. A gate-family cell that fails it is scored report-only, and the ladder runs on the others.
An eligible gate-family cell with zero or undefined σ, se_up or τ has an uninformative tolerance or no computable power, and section 5 never drops an eligible cell. So B2 stops at floor build as
WEAK_POWER_OR_VACUITY. A report-only cell's undefined value stops nothing.Replicates that raise count as undefined for every cell, with the exception class recorded. A memory or operating-system error stops the run.
An undefined truth makes the cell invalid on that frame, as in M6.
The report-only interval is g ± t_ν⁻¹(0.975) se_c.
More than 1% undefined household replicates in a gated cell is known at floor time, as
cells[c].se_up.undefined_share_okin the floor artifact, and that cell cannot pass.outcome: LADDER_CLEARED. The operator readsundefined_share_okfor every cell insurface.gatedand posts the values on Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42.WEAK_POWER_OR_VACUITY("undefined cells", design line 454), whatever the artifact'soutcomereads, and B2 returns to Max.The artifact's
read_set_completefield is fixed attruein the code. It means only that every opened PSID file was in the pinned read set with its pinned hash. The files actually opened are listed with their hashes inpsid_files_opened_sha256."To B2" items carried in code and tests. They are in
tests/test_track_b_b2_rules.py,tests/test_track_b_b2_design.pyandtests/test_track_b_b2_pipeline.py:anchor_multiplicitiesanddesign_multiplicities, called with root 20261002;BOOTSTRAP_ROOT_SEED;The gate surface (PR Track B B2: gate surface C1 (d1606) #545).
b2.GATE_SURFACEis pinned to C1 by a test, and the published surface is property-tested: the floor gates onlyGATE_SURFACEcells and publishes every gateable cell exactly once.The floor rerun must reproduce the first floor's truth side. The floor builder is truth-only and deterministic. So, at this registration's commit, its rerun must produce truth-side fields equal to the first floor's, compared with
compare_floors.py(below). Those fields are:Only the schema, the surface, the ladder, the outcome, the power and provenance may differ. If any truth-side field differs, the scorer is not launched, and the difference is published and goes to Max.
Interruption.
runs/track_b_b2_score.attempt.jsonlexclusively. It appends each stage there, synced to disk, and refuses to start if the file exists.POPULACE_DYNAMICS_PE_US_DIR. The cause is fixed and posted on Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42, and the scorer is relaunched.892040c88a6a2342d5545b8379920e077e0f4609, since it is truth-only and deterministic. Its stderr and the interruption are posted on Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42. A partly written artifact is moved outside the clone, hashed and disclosed first.runs/track_b_b2_score.attempt-1.jsonland committed in one commit, whose single parent is the floor commit and whose only change is adding that file. Its last stage is published on Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42.--expected-commit, and step 4's checks are repeated against it, with the one added file allowed.ABORTED_AFTER_GAPS, a non-pass with FAIL's consequences.Memory. The floor artifact publishes L before the scorer runs. A design replicate copies each truth and draw frame about L times, so a replicate's memory grows with L.
4 // L: 4 at L = 1, 2 at L = 2, and 1 at L = 3 or 4. The operator posts it on Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42 before launch. This keeps workers × L at most 4.Results do not depend on the worker count: a replicate is a function of its index and the payload alone, and replicates come back in index order (
b2.run_replicates).tests/test_track_b_b2_rules.pychecks design multiplicities and a toy function at 2 and 3 workers against a serial run. Scored gaps at 4 workers are not tested separately.Runtime
All paths are on the operator's host.
Code. PR Track B B2: gate surface C1 (d1606) #545's merge commit,
892040c88a6a2342d5545b8379920e077e0f4609.892040c88a6a2342d5545b8379920e077e0f4609src/populace_dynamics/track_b/b2.pybdb1676d9a4a15c3ebc83d5f2c5e4643ed214012725373949fcfbca51aa587dcscripts/track_b_b2_floor.py84b52fc7697e75c72e91ba5254e617e70c6be6e33508c50f405d3b9192120c7cscripts/track_b_b2_compare_floor.py98aa90cf890e5d99835802cc0b0fbb8dc19ea06d8e0f3cfbe9fa63699319deb6scripts/track_b_b2_score.pyfce4e580c5c1cdbc39107c4ae61d1f664684cf266fe3d003196b78efdac16526scripts/track_b_b0_1_planning_values.py62bd282c4a2968e388e190806d8e0ad8612fcbcbd9564f5485d3e49752ec7c27scripts/track_b_b0_1_ruled_power.py8cc64235f5157c13e99e14bd892317286a2e7f22a69dfb7443c7610c53f60af4docs/design/track_b_b0_1_planning_values.jsonf8a29eee25d721d30422c936d3e19fff60a93f817e70b76e9cb74c866a67d897docs/design/track_b_b0_1_counts.jsone93826d4c535a41ea28155b837307a1a941f9ac9d205f8e8bf60421481e54f99Since
22e3f82b:b2.py,track_b_b2_floor.pyandtrack_b_b2_score.py.m6_cells.py,select_m6_qstar_train_only.py,track_b_b0_1_addendum_power.py, the planning script andtrack_b_b0_1_ruled_power.py.src/populace_dynamics/data/are unchanged, apart from one new module B2 does not import.The run clone:
/Users/maxghenis/PolicyEngine/_trackb-b2-run/microcosm-dynamics-c1, on branchtrackb-b2-run-c1-20261016, cut from892040c88a6a2342d5545b8379920e077e0f4609. Nothing else lives in it, so the scripts' clean-worktree check sees only the repository.The runtime:
/Users/maxghenis/PolicyEngine/_trackb-b2-run/.venv-b2, the same as the first registration's, outside the clone, with Python 3.14.4.runtime-requirements-pins.txt(SHA-25619e95ff7e9d6fc771e8a1b88285beae6ff10ad9e8e77fa24735d944caecec7f3)./Users/maxghenis/PolicyEngine/_trackb-b2-run/populace-pinned. That checkout sits at the selectors' pinned headaf02c917fcb3c50816bf3af9c2b64509e928889a, with fit tree5c866378fdf5906b7a61da9977b8d028d1d36e9fand frame tree7cfb9ee78beb74911963913f202a4471aae2f52b.The operator's runtime check. The other pins are checked by the operator. Before each launch,
runtime_check.py(SHA-256348fc70c5600149140d9a3b27d2de44c9bcb52f988c36e5a73dd84a363ab7042) runs from outside the clone, with absolute paths:<evidence>is the first registration's folder on the operator's host; nothing is copied into the clone.RUNTIME OK./Users/maxghenis/PolicyEngine/_trackb-b2-run/.venv-b2/bin/python;pins_sha256 19e95ff7…;check_sha256 348fc70c…;distributions 166;listing_sha256 b774409c651ddfdd75eed26b35a1aad2e58ab1a2a07e94ff3b537350088d2986;populace_head af02c917…;RUNTIME OK.The floor comparison.
compare_floors.py(SHA-2561af6d03cf1cfd6b1f2b95578afaec3053f0f6211b0c0c82d7429cd9a51745385) also runs from<evidence>/rescope/, underpython3 -I, with the first floor's file and the rerun's.500f801e….addendum_sha256against the addendum at its own commit:f719edd9…for the first floor and8896e8a7…for the rerun.TRUTH SIDE REPRODUCED.policyengine-us 1.752.2, for the 2010 NAWI read only.
POPULACE_DYNAMICS_PE_US_DIR=/Users/maxghenis/PolicyEngine/_trackb-b2-run/pe-us-1.752.2holdspolicyengine_us-1.752.2.dist-info/andpolicyengine_us/parameters/gov/ssa/nawi.yaml, taken from the 1.752.2 wheel.sha256=nbVf6eolRHoTl2fHcZsykgmC3SpliHyPwN2xKi3PfFM(SHA-256 hex9db55fe9ea25447a139767c7719b32920982dd2a65887c8fc0ddb12a2dcf7c53). The operator checked this; the code does not.e272a7bc…, mapping SHA-25626b6a049….Threads, jobs and workers.
OMP_NUM_THREADS,OPENBLAS_NUM_THREADS,MKL_NUM_THREADS,VECLIB_MAXIMUM_THREADSandNUMEXPR_NUM_THREADSare all1.OMP_WAIT_POLICY=PASSIVEandPOPULACE_FIT_N_JOBS=4, and with the worker count set by the memory rule above. That stays within Max's 2026-10-11 cap for the shared host.POPULACE_FIT_N_JOBSoutside 1 to 4, or more than four workers. They check this first, before reading anything. The comparator has none of these guards; its only check is that the floor artifact is committed.ACTIVE. B2 refits and projects candidate 3 at one OpenMP thread instead, through the selectors'_project, as protocol v2's planning run did. That run's record showsOMP_NUM_THREADS=1andPOPULACE_FIT_N_JOBS=4.thread-hang-reproduction/summary.txt). The cause was not identified. B2 uses one thread because it completed in every run, and its cross-process determinism is tested. PR Track B B2: gate surface C1 (d1606) #545 bringsb2.thread_settings' docstring into line with this account.Determinism.
tests/test_track_b_b2_threads.pywas run at22e3f82bin this runtime. Two fresh processes with different hash seeds gave:_BinMapper.n_threads;PR Track B B2: gate surface C1 (d1606) #545 does not change the fit or the projection. The test was rerun at
892040c8in this runtime: 2 passed (rescope/run/threads-determinism-892040c8-venv-b2.log).Procedure
--registration-idis this comment's numeric GitHub comment id. Every #42 post below is a new comment. The operator is the registering session, named under "Exposure" below.Runtime check. The operator runs
runtime_check.pyas above and posts its output on Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42.The floor builder runs once, from the clean run clone at
892040c88a6a2342d5545b8379920e077e0f4609:runs/track_b_b2_floor.jsonexclusively.892040c88a6a2342d5545b8379920e077e0f4609. The commit is pushed totrackb-b2-run-c1-20261016.compare_floors.pyagainst the first floor and posts on Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42: the commit id, the artifact's SHA-256 and the comparison's output.undefined_share_okfor each gated cell (rule 7);When B2 stops here. B2 stops and returns to Max if any of these holds:
WEAK_POWER_OR_VACUITY;TRUTH SIDE REPRODUCED;B2 then takes the floor-stop ending in step 5: no scorer is launched, and nothing is an attempt. The comparator still runs, because it gates nothing.
The comparator runs once, at the floor commit and before the scorer, with its default ledgers and no
--ledger:The comparator has no thread guard of its own, so its command sets the registered thread settings itself.
The scorer runs once, only if step 2 reached none of its stops, from the clean run clone at the floor commit. The operator first checks, and posts, that:
892040c88a6a2342d5545b8379920e077e0f4609, and its only change isA runs/track_b_b2_floor.json;runtime_check.pystill endsRUNTIME OK.The launch.
POPULACE_DYNAMICS_PE_US_DIR=/Users/maxghenis/PolicyEngine/_trackb-b2-run/pe-us-1.752.2.--registration-id,--expected-commit <the floor commit>, and the worker count set by the memory rule.--floor-artifactis not used, so the scorer reads the defaultruns/track_b_b2_floor.json.After the run.
runs/track_b_b2_score.jsonand its attempt log are created exclusively, then committed and pushed totrackb-b2-run-c1-20261016.Publication and preservation. Exactly one of three endings applies.
A scored outcome. This needs a complete score file. The scorer writes
runs/track_b_b2_score.jsononly after its attempt log records "full-support cells", and then logswrote runs/track_b_b2_score.json (sha256 …). The file is complete when all three hold:schematrack_b_b2_score.v1and anoutcomeamongINVALID,FAIL,PASSandINCONCLUSIVE;Then the outcome is published on Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42 whatever it is, with every gated and report-only cell scored, and the attempt goes on the cumulative ledger (design line 469).
A spent attempt without complete output. This covers three cases:
ABORTED_AFTER_GAPS;When there is no score file. This ending applies only if the attempt log records "full-support cells", or if the interruption is the second. Two other cases keep their paths under "Interruption" and are not terminal: a refusal before the attempt log exists, and a first interruption before "full-support cells".
masterasruns/track_b_b2_score.partial, unchanged.A floor stop. This is any stop in step 2, a floor build refused by one of its checks, or the memory rule's refusal above L = 4.
In every ending, the run branch is then merged to
masterby a PR that adds only the run's files that exist: any floor artifact, score output, partial score bytes and attempt logs. The same PR adds the first floor asruns/track_b_b2_floor_v1_stopped.json, unchanged (SHA-256500f801e…).Exposure of the registering session
This registration was written by the session that drove Track B's B2 chain (Claude, Opus 5.5). The session is also the operator.
What it has seen from 2012 and 2014 data, all truth-side and all before any candidate run.
The choice of C1. It was made with the floor in view, as d1342 provided: "the choice among B-D returns to Max on B2's real tolerances". No candidate output informed it.
What it has not seen. No B2 candidate output, and no selector outcome at 2008 or 2010.
B1's sealed output. B1's raw output and sealed logs, which hold reference-year 2014 values, stay unopened until B2's result is published.
Ledger reads.
Review before posting
Each round reviewed a cleaned copy of the repository at
892040c8, built byscripts/track_b_b0_1_review_root.pywith the Q6 exclusion list removed. Its context held this text, the first registration, the rulings (d1606 included), the decision aid and its pricing files, the step-2 and pricing posts, PR #545's body,compare_floors.py, and the runtime and determinism evidence. Subfleet ran every round on Astra.f719edd9….compare_floors.py, and found no truth-side field missing from it.No round met a blinded value.
MaxGhenis commentedon Oct 18, 2026
Track B B2 (rescoped registration, comment 6252388925), step 1: runtime check.
runtime_check.py(SHA-256348fc70c…) was run from outside the clone, as the registration states. Its output:It ends
RUNTIME OK. Every line matches the first registration's runtime check. The run clone/Users/maxghenis/PolicyEngine/_trackb-b2-run/microcosm-dynamics-c1is ontrackb-b2-run-c1-20261016at892040c88a6a2342d5545b8379920e077e0f4609, clean, with no untracked or ignored files. Step 2, the floor builder, follows.MaxGhenis commentedon Oct 18, 2026
Track B B2 (rescoped registration, comment 6252388925), step 2: the floor builder clears (
LADDER_CLEARED).892040c8, with the registered command and environment: 4 workers, one BLAS/OpenMP/numexpr thread,OMP_WAIT_POLICY=PASSIVE,POPULACE_FIT_N_JOBS=4,--registration-id 6252388925.89c0ed9d6fe643469ada338cd5a2ae17059d194eontrackb-b2-run-c1-20261016, pushed. Its single parent is892040c8, and its only change isA runs/track_b_b2_floor.json.65c5fa52d03ce20497c38faa2c9dd78f25845efefef88d9790cbbffe59ca9ccd.schema: track_b_b2_floor.v2,outcome: LADDER_CLEARED,candidate_runs_permitted: true,registration_id: 6252388925.Truth-side reproduction (rule 11).
compare_floors.py(SHA-2561af6d03c…) compared this artifact with the first floor (500f801e…). Its output:Every truth-side field equals the first floor's. Only the fields the registration allows to differ do.
Decision, inside
GATE_SURFACE.earn_p90.prime,earn_zero_rate.prime,earn_zero_rate.older,earn_p90.older. Power is 0.9226 before any pruning, so the ladder stops at once. Nothing is pruned.at_least_four_cells: trueandnot_every_tolerance_at_cap: true. No gated tolerance is at its cap.earn_p90.older,earn_p90.prime,earn_zero_rate.older,earn_zero_rate.prime. That is m = 4, with t*₄,₆₃ = 2.5714.earn_zero_rate.older) is labelled "published candidate-3-law outcomes at boundaries 2008 and 2010", and three are labelled "published five-seed floor detail, no published candidate outcome".Rule 7.
cells[c].se_up.undefined_share_okistruefor all four gated cells.Memory rule. L = 1, so the scorer runs with 4 workers.
None of step 2's stops applies. Steps 3 (the comparator) and 4 (the scorer) follow.
Blindness: no 2012 or 2014 floor value, tolerance or truth moment is quoted here. They are in the committed artifact. No candidate outcome exists.
MaxGhenis commentedon Oct 18, 2026
Track B B2 (rescoped registration, comment 6252388925), steps 3 and 4: the comparator, and the scorer's pre-launch checks.
Step 3: the comparator
89c0ed9d, with its default ledgers and no--ledger.OMP_WAIT_POLICY=PASSIVE, andPOPULACE_FIT_N_JOBS=4.true: the six-cell floor block and the seed detail, for each ofdocs/analysis/m6_qstar_train_only_selection_results.jsonanddocs/analysis/m6_rhostar_train_only_selection_results.json, in that order.Step 4: the scorer's checks before launch
89c0ed9dand clean. The floor commit's single parent is892040c8, and its only change isA runs/track_b_b2_floor.json.runtime_check.pyendsRUNTIME OK, identical to step 1.POPULACE_DYNAMICS_PE_US_DIRholds the 1.752.2nawi.yamlwith its RECORD hash9db55fe9….The scorer is launched now. It runs with the same environment as the floor builder, plus
POPULACE_DYNAMICS_PE_US_DIR=/Users/maxghenis/PolicyEngine/_trackb-b2-run/pe-us-1.752.2, and with--registration-id 6252388925 --expected-commit 89c0ed9d6fe643469ada338cd5a2ae17059d194e --workers 4, with no--floor-artifact. The memory rule gives 4 workers, since L = 1.B2 score and attempt log (registration #42 comment 6252388925)
MaxGhenis commentedon Oct 18, 2026
Track B B2 (rescoped registration, comment 6252388925), step 5: the outcome is
FAIL.The run
89c0ed9d, with the registered command and environment and--workers 4. It started at 16:41Z and exited 0 at 17:11Z, after 1,744 s.430f8883699609278ccfc425fd9563993b654888ontrackb-b2-run-c1-20261016, pushed. Its single parent is the floor commit89c0ed9d. It adds only these two files:runs/track_b_b2_score.json, SHA-256df82a102a2b4c40c34f0e36b4333dbe7b90d13bfb3658b60b3f6d3f3e2dd8489;runs/track_b_b2_score.attempt.jsonl, SHA-256bb77de73413a52252b124c64e49a230202efd8ba9502922f3b8570d555e0dab5.wrote runs/track_b_b2_score.json (sha256 df82a102…)stage records;schema: track_b_b2_score.v1andoutcome: FAIL;Why it fails
The outcome is the first rule of element 9 that applies:
earn_zero_rate.prime, |g| = 0.3034 against a tolerance of 0.202. The metric is the log ratio of the projected rate to the realized one, so the projected prime-age zero-earnings rate is about 35% above the realized rate.earn_zero_rate.prime's is within on none of the five.Three of the four gated bounds also exceed their tolerances; only
earn_p90.primepasses the bound rule.The cells
Gated cells (m = 4, t*₄,₆₃ = 2.5714; every Monte Carlo and undefined-share rule holds):
earn_p90.olderearn_p90.primeearn_zero_rate.olderearn_zero_rate.primeearn_autocorr_lag1earn_autocorr_lag2earn_dlog_mean.olderearn_dlog_mean.primeearn_dlog_sd.olderearn_dlog_sd.primeearn_mob_h1_diagearn_mob_h2_diagearn_p10.olderearn_p10.primeearn_p50.olderearn_p50.primeabs_gapcells' gaps are projected minus realized.What follows
GATE_FAIL_OR_REGRESSION_FAIL, design §7). Its admission and every dependent milestone are blocked: H and B3L cannot rely on B2.SUCCESSOR_EXHAUSTED. The first registration's floor build was not an attempt.master:runs/track_b_b2_floor_v1_stopped.json(500f801e…), unchanged;docs/design/track_b_attempt_ledger.md.Attempt ledger: count spent attempts; drop the unverified earlier-rec…
Income-and-resources design revision 3: round-3 review and source cat…
U2 §20 steps 5–6: answer review r2 (undated merge; record and test nits)
Parity ledger: the three approved designs, U2's ratification and the …