diff --git a/docs/design/open_population.md b/docs/design/open_population.md new file mode 100644 index 000000000..d10e4b615 --- /dev/null +++ b/docs/design/open_population.md @@ -0,0 +1,649 @@ +# Open population design, revision 13: births, migration, alignment and the long horizon + +**Status:** approved. Max authorized this lane on 21 October 2026 (decision d1802) and approved this design on 23 October 2026 (ruling d1925, "Approve as recommended"), at revision 11 (file SHA-256 `b5496c13a7f768b504226ff374d8c23ded3daa26b39aa16d89c0fe750988e8f7` as approved). The branch history was rewritten on 24 October 2026; its revision-11 commit `a18a2919` differs from the approved text only in four data-access lines. The demographic phase is authorized now. The economic phase is priced here and is approved once a B2 successor passes and Track B's B0.2 freezes J's record. §10 records each ruling. Nothing is registered: every registration this design names goes to issue #42 only through the coordinator, on Max's go. + +**Every effort figure in this document is an estimate.** The figures are engineering judgments under the staffing assumptions in §9, not demonstrated throughput. "d" means engineer-days and "lw" means agent-lane weeks at 4 engineer-days per week; in every effort cell, lw = d ÷ 4 exactly. + +**Pinned tree.** Repository citations are to `origin/master` at `1e739d32`, read for revisions 1 to 6. Package paths are under `src/populace_dynamics/` unless stated. Track B citations are to *Track B design, revision 3* (28 September 2026, approved by ruling d515), kept outside the repository at `~/microcosm-launch-evidence/dynasim-parity-20260909/trackb-design-20260928.md`. + +**Revision log.** +- *Revisions 1 to 5* (21 October 2026; commits `d0082afc` to `80605c67`) built the design and answered four coordinator notes: entrant initialization as its own row (OP8), whose price Track B's B0.2 audit cites; Track B's rules lane as owner of the insured-status rule, with a per-year provenance interface; and a shared holdout registry with J's years first. Reviews of revisions 1 to 4 were queued and cancelled before they ran. +- *Revision 6* (23 October 2026) answers the independent review of revision 5 (Subfleet job `20261021-103508-openpop-review-r5`, verdict REVISE, nine major and three minor findings). §12 maps each finding to its resolution. The main changes: the fertility mechanism and OP2's differential test are corrected; `gate_birth` is regression evidence by default because the repository already holds NCHS's 2016–2024 rates; OP3 adds the timing and exposure bridge that #218 required; the insured-status interface names the facts other than quarters of coverage that the statute needs; the EPUF arm of `gate_young_earn` needs explicit person fences; OP12 now gates unaligned totals, so no gate scores the aligned run unless Max makes an exception; ledger closure claims are narrowed; OP5 and OP7 gain date and link conventions; §5.3 sets tolerance classes by kind of source. The total rises from 133–205 d to 140–216 d (estimate). +- *Revision 7* (23 October 2026) was reverted by revision 8; its commit is not on this branch, and no estimate changed. +- *Revision 8* (23 October 2026) reverts revision 7 and adds §2.10's data-access line. No estimate changes. +- *Revision 9* (23 October 2026) answers the independent review of revision 6 (Subfleet job `20261023-062751-openpop-review-r6`, GPT-6.1 Sol, verdict REVISE): ten of revision 5's twelve findings resolved, two partly, and four major and five minor new findings. §12 maps each new finding to its resolution. The main changes: §214(c)'s requirements apply only to noncitizens whose first Social Security number was assigned on or after 1 January 2004, or who have none yet (POMS RS 00301.102, checked), and that date becomes an input with provenance; candidate-side uncertainty is set per gate rather than by resampling OP5's start; `gate_young_earn` admits earnings at 18–24 only, leaving the hand-off at 25 open; OP12 and OP11b respect the Microcosm start's hold on spouse and survivor results; OP9 waits for OP8. No estimate changes. +- *Revision 10* (23 October 2026) answers review r7 (Subfleet job `20261023-064644-openpop-review-r7`, verdict REVISE, one major and four minor findings; it found r6's findings 2–9 resolved and 1 partly resolved). The original Social Security number assignment date stays `UNKNOWN` under both pre-entry conventions; the POMS citation covers B.1–B.5 and workers not yet assigned a number; the summary and §8 state OP0's dependence on J's reservation and OP0.2's earlier finish; the widowhood invariant is qualified to surviving spouses; and OP11b's withheld outputs are limited to spouse and survivor types. No estimate changes. +- *Revision 11* (23 October 2026) adds, verbatim, the two clarifications that review r8 (Subfleet job `20261023-071323-openpop-review-r8`) asked for when it returned **APPROVE** on revision 10: §3.4's economic schedule assumes Track B's I and any required observational timing gate are ready; OP11b's estimate covers beneficiaries, benefits and Social Security income only. Nothing else changes. +- *Revision 12* (24 October 2026) records Max's ruling d1925 and, in §10, the coordinator's rulings on decision 6 and on death alignment, the latter under Max's ruling d1922 on the mortality lane's design. The mortality lane's SM owns death alignment, so OP6 no longer selects deaths: §3.1 (OP1, OP6), §3.3, §4, §5.4, §6.4 and §7 state that boundary. §3.6 and §6.4 list the entrant attributes the mortality lane asks for as unpriced. No estimate changes. OP6 drops death selection and the widowhood updates for aligned deaths, and adds a reported deaths margin and one §7 property; this revision does not re-estimate OP6, whose 8–12 d may now carry some slack. +- *Revision 13* (24 October 2026) applies the two delta reviews of revisions 11 and 12: Subfleet job `20261024-075934-openpop-review-r9c` (GPT-6.1 Sol, APPROVE, three minor findings) and an Opus 5.5 review (REVISE on one finding, which the coordinator ruled minor, and seven minor findings). §12 maps each finding to its resolution. No estimate changes. + +## In brief + +This lane owns four rows of the parity ledger (`docs/parity-ledger.md`): births, immigration and emigration, alignment and a representative population, and projections beyond 2030. The only price on record for any of it is design B's B8 (2032/2050 horizons plus population extension, income and wealth gates included): 40–70 d, an estimate made before the limits in §2.4 were written down. + +The design splits the work in two: + +- **A demographic phase that can start now.** Newborns with both parent links, immigrant cohorts sized to the Trustees' gross inflow, an emigration law, an alignment layer that keeps the unaligned path as the scored object, a 2013→2020 retrodiction of the population's composition, and the demographic projection to 2100. The demographic phase needs no forward earnings. OP0.1 freezes its gate picks only after J reserves its candidate years in the shared registry. Ten items (OP0.1, OP1 to OP7, OP10a, OP11a), **76–113 d** of effort (estimate), about 46–69 engineer-day equivalents elapsed on two lanes. +- **An economic phase that waits on Track B.** Entrant initialization (OP8: entrants' starting states, earnings state, covered-work histories and insured status, and newborns' earnings at 16–24 with the hand-off to Track B's earnings law at 25); alignment to labor targets; the economic long horizon; matched 2050, 2065 and 2070 comparisons; and a gate on SSA benefit and payment totals. Six items (OP0.2, OP8, OP9, OP10b, OP11b, OP12), **64–103 d** (estimate). They depend on Track B's H, B3, B4 and J, so none but OP0.2 can start until a successor to B2 passes (ruling d1659). The modeled path to OP11b ends about 68–109 engineer-day equivalents after that day, if Track B's B0.2 (draft PR #554) has frozen by then and Track B keeps its own estimates. OP12 has no finite date while the Microcosm start's gate 3, which it needs, waits on parked decision d947 (§3.4). + +**All 15 milestone rows (OP0 counts once): 140–216 d, or 35–54 lw (estimate).** **Entrant initialization, which Track B §3.3 left unpriced, is its own row, OP8: 26–41 d, or 6.5–10.25 lw (estimate).** It builds on demographic packets that OP2 and OP3 already pay for (9–13 d), so its full price is 35–54 d (§3.5). Insured status itself comes from Track B's insured-status rule, which OP8 consumes through the interface in §6.1 and does not price. + +Three findings shape the design: + +1. The certified M6 assembly builds its marital, disability and household panels from native PSID sources over a predeclared anchor universe, ignoring the live projection frame, and simulates each once per draw; each year it redraws a whole-window fertility history over the cached marital panel; and its native panel support is pinned through 2022 and supplies no admitted forward support afterward (§2.4). A synthetic entrant absent from that support, a newborn or an immigrant, cannot marry, give birth, become disabled or join a household through it. Open-population processes therefore run through forward-mode adapters, which Track B's B4 owns for incumbents. +2. Scheduled entrants make a projection's early years depend on its end year: on invented data, runs to 2035 and to 2045 differ from 2026 on, while the same runs without entrants are identical (§2.9). Production runs therefore use one registered horizon and read shorter horizons as prefixes. +3. Two earlier designs, for immigration (#218) and alignment (#217), closed unmerged on 25 September 2026. This design keeps their core rulings, prices them and adds what they left out: newborns' links and states, an emigration law, a population-composition gate and the horizon (§2.8). + +### Terms + +- **ACS, CPS ASEC, PUMS.** The Census Bureau's American Community Survey; the Current Population Survey's Annual Social and Economic Supplement; and the public-use microdata files of each. +- **ASFR, TFR.** Age-specific fertility rate (births per woman at an age) and total fertility rate (the sum of a year's ASFRs). +- **AWI.** SSA's national average wage index. +- **EPUF.** SSA's 2006 Earnings Public-Use File: covered earnings for 1951–2006 for a 1 percent sample of Social Security numbers. +- **OACT, V.A1 to V.A4, IV.B4, V.B1.** SSA's Office of the Chief Actuary and tables of the 2026 Trustees Report. +- **Quarters of coverage.** SSA's units of covered work, up to four a year, from which insured status is decided. +- **`u_w`.** The forward earnings law's estimate of a person's long-run earnings rank, fitted from the normalized ranks of their positive earnings (`engine/forward_earnings.py:697–712`) and blended into the law's draws (`:1528–1533`). +- **Gate, report-only, floor.** A gate is a pass-or-fail test registered before it runs; a report-only check is published the same way with no pass or fail; a floor is the spread between two disjoint samples of real data, from which a tolerance is priced. + +## 1. Purpose + +Each ledger row states the test that would show parity. This design plans the milestones that would meet each test, with a gate or an explicit report-only label at every step. + +| Ledger row | The row's test (from `docs/parity-ledger.md`) | +|---|---| +| Births | Projected births against vital statistics; newborns' links to both parents, households and starting states; their entry into later earnings, disability and benefit processes | +| Immigration and emigration | Arrivals and departures sized to OACT's assumptions; entrants' covered-work histories and insured status; their benefit receipt against SSA statistics | +| Alignment and a representative population | An alignment step to the actuaries' demographic and labor targets that keeps households consistent, with its displacement from the unaligned path published; gated SSA benefit and payment totals | +| Projections beyond 2030 | Near-term gates first (gate 3); then matched 2050, 2065 and 2070 comparisons and 75-year sensitivity surfaces on named assumption paths, each registered before it runs | + +Track B's rules carry over unchanged (Track B §1, §5.1): each mechanism, population and horizon is admitted separately, through a registered gate against independent observations; no DYNASIM comparison may select structure, parameters, denominators or rows; DYNASIM agreement never rescues a failed gate. + +One rule specific to this lane comes from M6's decision 9, which the closed alignment design quotes ("Alignment layer report-only; gate the un-aligned drift", PR #217 §1.2): **the unaligned projection is the scientific object that every gate scores; the aligned projection is a labeled production companion whose displacement is published.** This design applies the rule to every gate, OP12 included. Gating an aligned scenario would need an explicit exception from Max (§10, decision 10). + +## 2. What exists now + +I read every source cited in this section at `1e739d32`. + +### 2.1 The loop and its seams + +- **Eight adapters in a fixed order.** `engine/loop.py:117–129` defines `PeriodModules`: mortality, aging, marital core, fertility, disability, earnings, claiming and household composition, plus an optional initializer. The loop calls them in that order each year (`loop.py:297–350`). +- **No emigration or alignment step.** None of the eight adapters removes a living person or reconciles to an external target. +- **One entry seam.** Scheduled entrants arrive through `metadata["m6_scheduled_entries_by_year"]` (`loop.py:27`). The loop validates each frame (`:226–240`), rejects IDs that appear twice (`:242–250`), and appends the year's entrants before that year's mortality draw (`:271–286`). +- **Identifiers and random streams.** A projection-wide `SyntheticPersonIdAllocator` hands out new IDs and refuses reserved real ones (`loop.py:43–64`; created at `:251–262` unless the caller supplies one). Each person's stream is keyed by an ordinal: initial and scheduled IDs get ordinals in sorted order before the first year (`:263–266`); anyone else, such as a newborn, gets the next ordinal at the end of the year they appear (`:358–360`). The stream for a period and module does not depend on the projection's length: `rng.py:61–67` takes the `period`-th child of a fresh root sequence. +- **Sealed files.** `engine/loop.py` and `engine/steps.py` sit inside the source identity that the first-estimates birth-evidence reducer seals: every file under the package outside `POST_REVIEW_SOURCE_EXCLUSIONS` must equal reviewed commit `1c7f3540` (`ss/statutory_aime.py:137–141`; the exclusion tuple starts at `scripts/first_estimates_birth_evidence.py:135`, and `entrant_schedule.py` and `entrant_domains.py` are on it at `:176–178`). Track B §5.1 also forbids edits to `engine/loop.py`, `engine/steps.py`, `gates.yaml` and committed `runs/*.json`. Every new module this lane adds must join the exclusion tuple, which `tests/estimates/test_birth_evidence_artifact.py:68` pins exactly, and pass its transitive reachability test (`:367`) and the initializer-coverage test (`:336`). + +### 2.2 Births + +- **The closed projections draw none.** The registered Track A and FRA-68 projections are closed cohorts whose fertility slot draws no births (`baselines/fertility.py:8–11`). +- **Gate m6's engine materializes them, report-only.** Its reference draw added 316 newborns (`runs/gate_m6_candidate3_v1.json`, `family_b.entrants.family_b_open_additions.synthetic_births`), and the gate names entrants, births and open-panel margins as report-only (`gates.yaml:5416–5420`). +- **What a newborn gets.** `steps.materialize_maternal_births` (`steps.py:451–507`) gives each child a new ID from the projection's allocator, age 0, its birth year, a sex drawn 50/50 from the fertility module's stream (`:494–496`), a link to the mother (`:497`), `synthetic_entry = True` (`:498`), and the mother's `household_id`, `weight` and `start_weight` (`:499–503`). Every other roster column is missing, because the child rows are built on the roster's columns and only these are filled (`:485–487`). There is no second-parent link; the paternal "shadow" births are household conditioning draws and are deliberately not materialized (`:459–461`). +- **Timing.** Births are appended in step 4, after step 1's deaths, so no newborn can die in its birth year; its first mortality draw comes the next year at age 0 (`loop.py:297–323`; `steps.py:113–134`). +- **The gated fertility kernel.** Candidate 16's maternal-birth kernel draws each woman-year from her age, parity and birth decade (`engine/marital.py:376–382`), with parity starting at zero when the simulation starts (`:363`). In the M6 assembly, each projected period redraws a whole-window fertility history over the cached marital panel using that period's RNG, resets parity to zero for that invocation, and materializes only the current year's maternal births (`engine/assembly.py:301–329`; `steps.py:538–561`; `marital.py:363–391`). +- **The opt-in ASFR step.** `baselines/fertility.py` draws one Bernoulli birth per exposed woman-year at a baseline's single-age rate, at most one birth a year (`:14–22`), from a person-keyed tagged stream (`:24–28`), and materializes children through the same function (`:181`). It is labeled "not gated, report-only" (`:59`), and no registered test uses it (`:8–12`). + +### 2.3 Scheduled entrants + +- **A report-only cohort builder.** `engine/entrant_schedule.py` turns a donor frame and annual controls in thousands into seam-ready frames (`:185–396`). It sizes cohorts to the Trustees' gross positive inflow (LPR inflow plus temporary-or-unlawfully-present inflow) and excludes outflow, adjustment of status and total net change (`:37–42`, `:359–364`). It reweights donors rather than resampling them, so it consumes no random draws (`:44–48`). Its provenance says `gated: False`, `report_only: True` (`:387–388`). +- **Its timing convention is the seam's.** An entrant for year Y carries `year = Y − 1` and `age = entry_age`, faces a mortality draw at the entry age, then ages (`:14–22`; `docs/entrant-seam.md`, "Existing loop timing"). +- **That timing double-filters one control.** The temporary-or-unlawfully-present inflow counts only people who remain to year-end (`entrant_schedule.py:365–371`), so a full-year mortality draw at the seam, and any emigration in the entry year, would filter that component's survival a second time. PR #218 blocks production until a component-aware timing and exposure bridge exists (its design at head `152d087e`, lines 389–414 and 1235–1246). OP3 prices that bridge. +- **What it lacks.** The readers for controls and donors were not carried over (`entrant_schedule.py:41–42`; `docs/entrant-seam.md:1–7`), so no committed run has added an immigrant; gate m6 records `immigrant_cohorts: 0`, a value its runner writes as a constant (`harness/m6_runner.py:1027`, `:1212`). +- **Entrant support restrictions are declared.** `engine/entrant_domains.py:49–74` lists four exclusions and why: fertility risk (no parity seed), claiming (no insured-status test), the disability panel (entrants are not PSID panel members) and the earnings domain (no fitted 2014 state). Benefit outputs for entrants are blanked to missing, never zero (`:210–228`); a claiming wrapper runs the claiming step on incumbents only (`:312–380`); and the exclusion report says `execution_verified: False` (`:244–262`). These inventories do not demonstrate that every restriction executes in a projection (`:1–12`; `docs/entrant-seam.md:59–65`); only the claiming wrapper enforces its own contract. +- **ID reuse is checked outside the loop.** `validate_projection_allocator` refuses metadata whose allocator could reuse a known ID (`entrant_schedule.py:457–507`). The loop does not check it, because changing `loop.py` needs a re-pin of the reducer seal (`:472–476`). + +### 2.4 What the M6 assembly can and cannot carry for people who enter later + +`engine/assembly.py:234–447` wires the certified fitted objects into the eight slots: + +- **Marital core:** the panel builder ignores the live frame and builds candidate 16's seed panel from native sources over the full anchor universe (`engine/panel_builders.py:150–167`; the household builder likewise, `:257–274`); the assembly simulates it once per draw for the whole window and caches it (`assembly.py:282–299`). Realized PSID openers who enter in 2017 and 2019 are predeclared in that support (`harness/m6_population.py:339–350`). +- **Fertility:** each period, a whole-window redraw over the cached marital panel for the cached marital IDs, materializing that period's births (§2.2; `assembly.py:301–329`). +- **Disability:** a reproduction over realized PSID support rows for the window, simulated once (`:340–379`). +- **Household composition:** built and simulated once (`:403–422`). +- **Earnings:** the forward law behind the earnings-domain wrapper (`:243`, `:390–391`); people without the fitted 2014 state get the pinned non-scored zero (`engine/earnings_domain.py:1–7`). +- **Claiming:** `apply_claiming`, which draws a claim age for everyone 50 or older with no insured-status test (`steps.py:390–448`, `:411–413`). + +The cached updates join the live roster by a left merge on `person_id` (`_merge_period_columns`, `assembly.py:174–192`), so a person absent from a nonempty update gets missing marital, disability and household values. The panel builders accept only inputs whose declared projection end year is 2022 (`engine/panel_builders.py:27`, `:128–131`), so the native panel support is pinned through 2022 and supplies no admitted forward support afterward; for a year with no cached update, the merge returns the frame unchanged (`assembly.py:181–183`). + +**Consequence.** A synthetic entrant absent from the predeclared support, a newborn or an immigrant, cannot marry, give birth, become disabled or join a household through the certified assembly, and its native support ends in 2022. Open-population processes need forward-mode, live-roster adapters. Track B's B4 owns that successor for incumbents: forward support, redrawn initial states, and M6's marriage and divorce composed with death-triggered widowhood (Track B §3.1). B4 also declares closed-population versus entrant coverage (Track B §3.4). The forward support contract already exists and refuses realized holdout inputs (`engine/support.py:236–252`). + +### 2.5 Emigration and alignment + +- **Emigration.** The US engine has none (§2.1); `entrant_schedule.py:361` records "the engine has no emigration law". The experimental accountant has an `EMIGRATION` event kind (`engine/accounting.py:87–95`) but generates no events (`:1–8`). The UK engine has a net-migration step that adds or removes people by an age-indexed net rate (`uk/household_transitions.py:779–851`); nothing in the US engine uses it. +- **Alignment.** The engine has no alignment step. Gate m6 records its alignment displacement as `not_computed` with reason `alignment_layer_output_not_collected` (`runs/gate_m6_candidate3_v1.json`, `family_b.alignment_displacement`; the runner calls `build_alignment_displacement(None, None)` at `harness/m6_runner.py:1249`). That function computes per-year displacement between an unaligned and an aligned frame on caller-chosen keys (`harness/m6_reporting.py:321–327`) and refuses unequal keys, so a missing row cannot pass as zero displacement (`:365–374`). + +### 2.6 Horizon + +- The loop accepts any end year (`loop.py:170–201`). +- The 2026 Trustees baseline runs to 2100 (`baselines/tr2026_intermediate.py:75`) and CBO's to 2099 (`baselines/cbo2026_long_term.py:1–36`). Both are for invented-data projections only: `build_track_a_inputs` refuses a real-data run under them (`baselines/__init__.py:21–29`; `baselines/track_a.py:18–41`). +- Gate m6 certifies its 2015–2022 temporal holdout only; the 2100 extrapolation is "a decision-5 successor gate, not certified here" (`gates.yaml:5426–5430`). Gate 3 is unlocked and has no cells (`gates.yaml:2898–2905`). + +### 2.7 Inputs already pinned, and what is missing + +- **Trustees Report 2026.** The repository transcribes Tables V.C1, V.B1, VI.G1, V.A1 and V.A4 and OACT's period death probabilities (`data/tr2026.py:3–4`). Its single-age fertility is a fixed shape scaled each year to V.A1's TFR, because the public single-year tables publish no age schedule (`baselines/tr2026_intermediate.py:21–27`). It transcribes neither the immigration table nor the population table. +- **The immigration and population tables.** I fetched both on 21 October 2026 and read only their titles and column headers. Table V.A2, *Immigration Assumptions, Calendar Years 1940–2100* (in thousands), gives LPR and temporary-or-unlawfully-present inflow, outflow, adjustments of status and net change, and total net change, for history and the intermediate, low-cost and high-cost alternatives. Table V.A3, *Social Security Area Population on July 1 and Dependency Ratios, Calendar Years 1941–2100*, gives population in three age groups (under 20, 20–64, 65 and over) and dependency ratios. Neither is single-age, and V.A3 has no nativity. +- **Access.** On 21 October 2026 SSA's site returned a 404-byte body to a request with a browser user agent and HTTP 403 to a fetch tool, and served both pages to the `Wget/1.21.4` user agent that the TR2026 capture lane used (`data/external/tr2026/provenance.md:10–17`). That file records that HTML hashes change between live fetches, so captures pin the captured bytes. +- **CBO 2026.** The repository pins CBO's single-age fertility for all, native-born and foreign-born women, 2021–2099; death rates by age and sex; and covered workers by sex and covered earnings, 2026–2100 (`data/external/cbo2026/provenance.md:29–56`). CBO's January 2026 demographic workbook is pinned by hash with only TFR and life-expectancy rows transcribed (same file, `:36–38`). +- **NCHS.** `data/external/nchs_asfr_2024.json` holds NCHS age-group birth rates for 2023 and 2024 and an annual series for 2016–2024 (`fetch_nchs_asfr.py:57–62`). Gate 2's floor builder compares PSID fertility with that annual series year by year (`scripts/build_gate2_floors.py:627–674`, `:693–695`) and labels the ratios "REPORTED, not tuned" (`:743`). The series is exposure for any later births test (§4). + +### 2.8 Two closed designs and one open issue + +- **Immigration, PR #218** (docs only, closed unmerged 25 September 2026). Its rulings, which this design keeps: entrants are built before the projection and enter only through the existing seam; the size control is the Trustees' positive inflow, never total net change, and emigration is a separate exit law; donors supply state only through entry, never a cloned future; a component-aware timing and exposure bridge comes before production; a proposed `gate_imm` fits on the 2010–2013 annual ACS 1-year PUMS files and scores the separately weighted 2014 file on recent arrivals' characteristics, floors first; and the Social Security area is not the resident population, so a named universe bridge is required. Its §4.8 lists the entry-state packet each downstream module needs. +- **Alignment, PR #217** (docs only, closed unmerged 25 September 2026). Its rulings, kept: certification runs are unaligned and gate verdicts belong to the unaligned output (its §1.2 and §4.1); the aligned run is a separate replay with fresh state that never overwrites the unaligned one; discrete events are reconciled by deterministic whole-unit selection with fixed person weights; covered wages, a continuous value, by one disclosed scalar; displacement goes through `build_alignment_displacement` with per-margin, per-year attribution; and a target that a summary table cannot supply (V.A1's TFR is not an age schedule) stays `not_available` rather than invented. +- **Issue #412** (open) records what Microcosm's node graph means for dynamics: per-year alignment would become a REWEIGHT node, and immigrant entry needs an interface amendment because Microcosm's EXPAND requires every new row to name a source. It names #218's seam as the consumer of that amendment. + +Both closed designs cite file and line numbers in older trees. I re-verified at `1e739d32` every mechanism this design takes from them. + +### 2.9 A finding: with scheduled entrants, early years depend on the end year + +`docs/design/open_population_evidence/horizon_dependence.py` runs the existing loop on an invented 400-person roster to 2035 and to 2045, once with births only and once with immigrant cohorts scheduled for every year through the end year. Its committed output (`horizon_dependence.txt`) shows the closed runs' slices identical in every shared year, 2026–2035, and the open runs' slices different in every shared year, with row counts diverging from 2027. + +The mechanism follows from §2.1: every scheduled entrant through the end year gets an ordinal before the first year, so a later end year moves every newborn's ordinal, and with it the newborn's random stream; the allocator's starting ID moves too. Without entrants, ordinals do not depend on the end year. + +**Consequence for this design.** A production projection uses one registered horizon (the baseline's last year, 2100 for TR2026) and reads shorter horizons as prefixes of that run. OP1 enforces this, and §7 makes it a property test. Gate runs have their own fixed horizons and are never compared across horizons. Stable ID namespaces with adapter-owned ordinals are a possible later alternative; nothing shows it is cheaper. + +### 2.10 Constraints on every milestone + +- No edits to the sealed files of §2.1, to `gates.yaml` or to committed runs; new modules join the reducer's exclusion tuple and pass its reachability tests. +- No edits to `src/populace_dynamics/track_b/`. This lane consumes Track B's outputs through declared interfaces (§6.1). +- Builds and tests use invented data. Real-data steps are registered steps; no real PSID statistic is computed outside one, and no small-cell PSID count goes to GitHub. +- `~/microcosm-launch-evidence/dynasim-parity-20260909/RESTRICTED-FILES.md` governs every lane. The entries that bind this lane are in §6.4. +- PSID use follows the project's data-access record. + +## 3. Staged milestones + +### 3.1 Milestone table + +Milestones OP0.1 to OP7, OP10a and OP11a form the demographic phase; OP0.2, OP8, OP9, OP10b, OP11b and OP12 form the economic phase. Gate names are proposals; each registers on #42 through the coordinator. + +| Id | Deliverable | Verification or gate | Effort estimate (d / lw) | Depends on | Unlocks | +|---|---|---|---|---|---| +| **OP0** | Source, exposure, access and power audit for every open-population gate and target manifest. OP0.1 covers the demographic phase: `gate_birth`, `gate_imm`, the emigration check, the demographic target manifest, `gate_pop` and the demographic horizon record. OP0.2 covers the economic phase: `gate_entrant_earn`, `gate_young_earn`, the labor target manifest, the long-horizon backtest, OP11b's comparators and `gate_ssa_totals`. Each record includes the source-specific tolerance class and the gate-specific candidate uncertainty procedure of §5.3, and OP0.1 audits the scored estimands and selection history behind the NCHS series of §2.7 | One frozen record per gate with the elements of §5.2 and a named power procedure; a blinded review of feasibility and power before any of those gates registers. Every held-out year goes through the shared holdout registry of §5.2, cited by path, commit and SHA-256: OP0.2 takes `gate_ssa_totals`' SSA Annual Statistical Supplement years only from those left after Track B's J has recorded its candidates, registers its picks there before freezing them, and discloses by name, in both registrations, any year it must share with J | 10–14 / 2.5–3.5 (OP0.1: 6–8 / 1.5–2; OP0.2: 4–6 / 1–1.5) | Track B's frozen audit protocol (Track B §5.2), reused; OP0.2 also Track B's B0.2 record (draft PR #554); OP0.1 and OP0.2 both wait for J's candidate years in the shared registry (§5.2) before freezing their picks | Registration of every OP gate | +| **OP1** | Open-population harness around the sealed loop: an exit adapter in the mortality slot (deaths drawn exactly as the wrapped mortality adapter draws them; emigration drawn among survivors from its own tagged stream); a birth-entry adapter in the fertility slot; the scheduled-entry seam with the projection's own allocator and `validate_projection_allocator`; one registered horizon per production run (§2.9); per-year `reconcile_period` and run-level `reconcile_history` with declared birth, entry, death and emigration events; an unaligned-only facade for gate runs; reducer-seal exclusions and reachability tests | Accounting conformance: count identities exact and weight identities within the reported summation residual every year; with emigration switched off, survivors equal the closed run's exactly; the §7 properties on invented data | 6–9 / 1.5–2.25 | None (invented data) | OP2, OP3, OP4, OP6 | +| **OP2** | Births v2. (a) The newborn entry packet: mother link; second-parent link (the mother's spouse or partner in the authoritative marital state in the birth year, otherwise an explicit unlinked reason); sex from a person-keyed stream at a pinned NCHS sex ratio; household, weight and birth order; out-of-domain markers for adult processes; the fields a declared assembly adapter maps into Track B's G for child benefits. (b) Live-roster fertility with persistent projected parity: candidate 16's age, parity and birth-decade probabilities applied year by year to the live roster, with parity carried forward from registered seeds (candidates: own children in the household, or the CPS June Fertility Supplement's children ever born) and a declared rule for birth decades outside its fit. (c) `gate_birth` | (a): conformance. (b): a differential test against one invocation of the maternal kernel (`marital.py:338–404`) with identical support, initial parity and random draws; separately, persistent-parity properties (§7). (c) `gate_birth`: births by mother's five-year age group and the share male, against NCHS natality for registered years, on the unaligned path from OP5's start with OP3's and OP4's flows, floors first. It is retrospective regression by default, because NCHS's 2016–2024 age-group rates are already in the repository (§2.7); it is held-out prediction only for observations or estimands OP0.1 shows unused. The share of births to married mothers is report-only until B4 draws marriages in the projection | 11–17 / 2.75–4.25 ((a) 4–6, (b) 4–6, (c) 3–5) | OP0.1, OP1; (c) also OP3, OP4 and OP5; second-parent links for marriages formed after the start need B4's forward marital state | OP6, OP7, OP8 | +| **OP3** | Immigrant entry. A reader for V.A2's components, 1940–2100; a registered bridge from the Social Security area to the resident roster; a component-specific timing and exposure bridge that reconciles each inflow control with the seam's mortality draw and with emigration under OP4's exit-timing convention as frozen at OP0.1, so that no component's survival is filtered twice (§2.3); an ACS 1-year PUMS reader for 2010–2014 with replicate weights and per-year concept maps; the immigrant demographic packet (age, sex, nativity, citizenship, reported entry year, arrival unit and its links, marital state, a parity seed for women by the same registered imputation as OP2(b), disability proxy) under #218's rules; schedules through `build_entrant_schedule`; `gate_imm`. Production schedules remain blocked until a registered component-specific timing and exposure bridge reconciles each inflow control with mortality and emigration at the seam | `gate_imm`: recent-arrival characteristics and named joints, fitted on ACS 2010–2013 and scored once on the separately weighted 2014 file, floors first (#218 §5). Admits a stock proxy, not arrival-time truth. The timing bridge: conformance and the §7 property that detects duplicate survival filtering | 16–23 / 4–5.75 (controls, universe and timing bridges 5–7; ACS reader 3–4; packet 5–7; gate 3–5) | OP0.1, OP1 | OP2(c), OP5, OP6, OP7, OP8 | +| **OP4** | Emigration. An exit law by age, sex, nativity and years since entry, with family or individual exit per a registered rule, sized to V.A2's outflow columns; relational updates (a spouse who emigrates leaves the marriage as "abroad", never as a death); emigrants' exits recorded so that OP12 can count those insured | Accounting conformance and alignment to the outflow controls. Composition is report-only unless OP0.1 finds an admissible holdout; the candidate check is the decline of ACS arrival cohorts between 2015 and 2019 net of mortality | 8–12 / 2–3 (law and controls 3–4; relational updates 2–3; exit records 1–2; check 2–3) | OP0.1, OP1 | OP2(c), OP6, OP7 | +| **OP5** | A national demographic start for the retrodiction gates, from the ACS 2013 1-year PUMS (which keeps `gate_imm`'s 2014 holdout unread), weighted, with: a registered reference date and a mapping from ACS's calendar-year collection and its ages to that date; a registered group-quarters treatment; nativity, citizenship and reported entry year; and spouse and parent-child links reconstructed only where the relationship-to-reference-person item determines them, with every other link marked unknown rather than guessed. Link coverage is reported, not promised | Conformance: the start reproduces its own weighted ACS tabulations exactly; reported against Census's 2013 population estimates, with the link-coverage report | 5–8 / 1.25–2 (reader and weights 2–3; date and group-quarters mappings 1–2; link reconstruction and coverage 2–3) | OP0.1, OP3's ACS reader | OP2(c), OP7 | +| **OP6** | Demographic alignment: the aligned production replay with fresh state; whole-unit selection for births by mother's age and emigration by category, each against the target manifest; immigration aligned by construction; no selection of deaths, which the mortality lane's SM owns (ruling d1922, §6.4), so both replays use the same mortality adapter; households kept consistent (an aligned emigration never widows the spouse who stays); displacement reported on a margin, year and stratum representation (§5.4), with deaths reported as a margin OP6 does not select; displacement corridors set before release | Production integrity, not a scientific gate: each margin OP6 selects is within its selection-resolution floor plus a pinned numeric tolerance (#217 §6.2), and death totals are report-only; the unaligned artifact is byte-identical whether the aligned producer is importable or not | 8–12 / 2–3 | OP2(a)(b), OP3, OP4 | OP9, OP10a, OP12 | +| **OP7** | `gate_pop`: project OP5's start to 2020 on the unaligned path with births, deaths, immigration and emigration, and score population by sex and five-year age group against the 2020 Census at its 1 April 2020 reference date, and the foreign-born by period of entry against the ACS 2019 1-year file using a projection slice matched to that file's calendar-year collection; each mapping is registered | `gate_pop`, floors first, under §5.3's tolerance classes. Its arms (fitted laws with 2013-vintage assumptions, or realized aggregate controls) are frozen at OP0.1 | 6–9 / 1.5–2.25 | OP2, OP3, OP4, OP5 | OP10a | +| **OP8** | **Entrant initialization**, the item Track B §3.3 left unpriced, for immigrants and newborns, delivered to Track B as one atomic bundle per entrant (§3.5 lists what goes to each Track B milestone). (a) Starting states in Track B's schemas: marital state and duration, spouse and household links, parity seed, a disability state at entry by a registered mapping or an explicit out-of-domain marker, and the year the entrant joins each risk set. (b) Immigrants' earnings anchors and latent state: earnings and employment at entry from the donor packet, and the forward law's state (`u_w` and its lags) mapped into the law's rank space by a declared rule. (c) Covered-work histories: pre-entry US covered years under the convention Max picks (§10, decision 4), never silently zero; post-entry accrual through H; quarters of coverage by year, each year with its provenance. (d) Insured status: the facts other than quarters that the statute needs, each with its provenance (§6.1), and the status from Track B's insured-status rule through the §6.1 interface: a status, or the rule's named refusal, with `entrant_domains.py`'s claiming and DI exclusions lifted only where the rule returns a status. (e) Newborns' economic entry: participation and earnings at 16–24 (the same module serves incumbents under 25) and the hand-off state at 25 in Track B's rank space. (f) Two gates | (a), (c), (d): conformance and the §7 properties. (f) `gate_entrant_earn`: earnings and employment of the 2010–2014 arrival cohorts in the ACS 2019 1-year file, by years since arrival, age and sex, projected from their entry bundles through Track B's admitted law; it admits only that combined initialization-and-projection result. `gate_young_earn`: CPS ASEC earnings at 18–24 in unused years, plus an EPUF arm with explicit person fences (§4); the EPUF arm is regression evidence unless OP0.2 demonstrates an independent partition. `gate_young_earn` admits the observed earnings outcomes at 18–24 only; the age-25 transition stays unadmitted until independent evidence on the implied joint histories and the transition, covering these entrants, comes from a separately priced test or from J (§3.6). Each gate lifts Track B's `ENTRANT_INIT_UNADMITTED` only for the states and populations it covers | 26–41 / 6.5–10.25 ((a) 3–5; (b) 5–8; (c) 2–4; (d) 3–5; (e) 6–9; (f) 7–10, of which `gate_entrant_earn` 3–4 and `gate_young_earn` 4–6) | OP0.2; OP2 and OP3 (the demographic packets); Track B's H and B3 for (c) and (e), and B4 for (a), (b) and `gate_entrant_earn`; Track B's agreement to the hand-off interface for (e); Track B's insured-status rule (rules lane, a separate PR after #530) for (d) | OP9, OP10b, OP12; Track B's B4 open coverage, B5, B6a, J and B7 targets that need open coverage | +| **OP9** | Labor alignment on the aligned replay: covered workers selected to Table IV.B4's concept (workers with covered earnings at any time in the year), average covered wage by one scalar to V.B1's growth, with chain-state updates coherent with Track B's law | Production integrity, as OP6; displacement and corridors published | 8–12 / 2–3 | OP0.2, OP6, Track B's B4; OP8, for the final open-population replay (a preliminary build on invented data needs only OP6) | OP12 | +| **OP10a** | The demographic horizon to 2100: declared rules for every demographic component outside its fitted support (fertility birth decades, marital decades, migration controls); a Leslie-matrix differential test; demographic sensitivity surfaces on the TR2026 intermediate, low-cost and high-cost paths and CBO's | Mechanics and sensitivity only. The horizon record (§5.2) labels every year past 2030 "conditional on named assumptions" | 6–9 / 1.5–2.25 | OP6, OP7 | OP11a | +| **OP10b** | The economic horizon and its license record: declared rules for every economic component past its fitted support (the earnings law's wage normalization to the baseline AWI, DI rates, the claim table); an open-population sibling of Track B's B3L backtest; economic sensitivity surfaces | Retrospective regression evidence and sensitivity. The license record admits a year past 2030 only as a conditional projection, never a validated one | 8–12 / 2–3 | OP8, OP9, Track B's J | OP11b | +| **OP11a** | Registered, report-only comparisons of the projected population in 2050, 2065 and 2070, each on the dimensions its publisher releases: OACT's V.A3 by its three age groups (it has no nativity); CBO's and the Census Bureau's 2023 projections by age, and by nativity where they publish it (confirmed at OP0.1) | Registered cross-model comparison; agreement or disagreement only | 4–6 / 1–1.5 | OP10a | None | +| **OP11b** | Registered comparisons in 2050, 2065 and 2070 of beneficiaries, benefits and the income measures DYNASIM and MINT publish, with OACT and CBO first and DYNASIM one of several (d660); DYNASIM comparisons follow Track B's B7 blind protocol. This estimate covers beneficiaries, benefits and Social Security income. Comparisons requiring other income measures need separately priced inputs | Registered comparison with a sealed comparator where DYNASIM or MINT is involved; not a validation gate. When a comparison uses the Microcosm start, its spouse and survivor outputs remain subject to that start's T2 marital-makeup publication condition, as for OP12 | 10–20 / 2.5–5, only after target-specific prerequisites pass | OP10b, Track B's J | None | +| **OP12** | `gate_ssa_totals`: unaligned SSA beneficiary counts and benefit and payment totals by type, on the open population started from Microcosm, through the unaligned-only facade; the aligned totals are published beside them, report-only | `gate_ssa_totals` on held-out years of SSA's Annual Statistical Supplement chosen at OP0.2 from the shared registry (§4, §5.2), under §5.3's administrative tolerance class. Admits aggregate totals by type only; it does not establish entrants' benefit receipt separately. OP12's spouse and survivor outputs, including report-only companions, remain subject to the Microcosm start's T2 marital-makeup publication condition (`microcosm-start.md:452`); until that condition is cleared, OP12's published scope excludes those types | 8–12 / 2–3 | OP0.2, OP8, Track B's J, I and G (v2 and part 2), the Microcosm start's gate 3, Track B's insured-status rule; OP6 and OP9 for the aligned companion; the Microcosm start's T2 marital-makeup publication condition for spouse and survivor types | M7; Track B's B7 targets that need open coverage, for aggregate totals only | + +### 3.2 Verification class and admitted scope per milestone + +The classes are Track B's (Track B §3.2), with "production integrity" added for alignment, which admits nothing scientific. + +| Id | Verification class | Admitted scope on success | +|---|---|---| +| OP0 | Source audit | Nothing scientific. It authorizes registration of the named gates on their frozen records | +| OP1 | Accounting conformance | Stock-flow identities and seam mechanics only | +| OP2 (a), (b) | Accounting conformance; differential conformance for the live-roster kernel | The newborn packet's structure; agreement with one kernel invocation given identical support, initial parity and draws; persistent-parity properties. No new fertility claim | +| OP2 (c) | Retrospective regression by default; held-out prediction only for observations or estimands OP0.1 shows unused | Births by mother's age group and the share male, for OP5's population with OP3's and OP4's flows, in the registered years | +| OP3 | Held-out prediction on the ACS 2014 recent-arrival stock proxy; conformance for the bridges | Entrants' demographic composition as a stock proxy, conditional on the control. Not gross flows, arrival-time state, legal status or anything after entry | +| OP4 | Accounting conformance; alignment to controls | Exit totals by category. Composition stays report-only unless the check becomes a gate at OP0.1 | +| OP5 | Accounting conformance | A weighted start that reproduces its source, with its reported link coverage | +| OP6, OP9 | Production integrity | That the disclosed reconciler produced the pinned scenario. Nothing about the transition laws it corrects | +| OP7 | Held-out prediction (retrodiction) | The unaligned demographic machinery's 2013→2020 composition by age, sex and nativity for OP5's population, under the registered date mappings | +| OP8 (a), (c), (d) | Accounting and statutory conformance | Entrants' starting states, covered-work histories and insured status (or refusals) as constructed objects that obey the §7 properties. No population claim | +| OP8 (b), (f): `gate_entrant_earn` | Held-out prediction | The combined result of entry initialization and projection under Track B's law for the registered arrival cohorts at the ACS 2019 cross-section. It does not separately identify the entry state or its evolution | +| OP8 (e), (f): `gate_young_earn` | Held-out prediction on unused CPS observations; the EPUF arm is retrospective regression unless OP0.2 demonstrates an independent partition | The observed earnings outcomes at 18–24, for the registered cohorts and only for the arm that is independent. Not the hand-off at 25, the joint generated histories or the latent state, which no cross-section observes | +| OP10a, OP10b | Mechanics, retrospective regression and sensitivity | A year past 2030 as a conditional projection under named assumptions, with drift diagnostics. Never a validated forecast; `HORIZON_NOT_LICENSED` (Track B §7) stays in force for any claim framed as validated | +| OP11a, OP11b | Registered cross-model comparison | Agreement or disagreement on the frozen targets only | +| OP12 | Held-out prediction | Unaligned aggregate beneficiary counts and totals by type for the registered years. Not entrant-specific receipt | + +**Downstream consequence**, as in Track B §3.2: if `gate_pop`, `gate_entrant_earn` or `gate_young_earn` passes only on exposed data, later admissions cannot cite it as independent predictive evidence. + +### 3.3 Ledger rows each milestone closes + +| Ledger row | Part of the row's test | Closed by | Status after those milestones | +|---|---|---|---| +| Births | Projected births against vital statistics | OP2(c) | Regression evidence for births if `gate_birth` passes on exposed years; *Gate passed* only on observations OP0.1 shows unused | +| | Newborns' links to both parents, households and starting states | OP2(a); B4 for marriages formed after the start | Built and conformance-tested once OP2 lands, for mothers whose partnership exists in the projection's marital state; complete once B4 draws marriages in the projection | +| | Their entry into later earnings, disability and benefit processes | OP8(e) and `gate_young_earn` for earnings; an entrant forward disability model, not yet priced (§3.6) | Earnings coverage at 18–24 completes only after `gate_young_earn` passes; the transition at 25 stays open until a separately priced test or J admits it. Disability and related benefit coverage remain incomplete until an entrant forward disability model and its gate are separately priced and passed | +| Immigration and emigration | Arrivals and departures sized to OACT's assumptions | OP3, OP4, OP6 | Arrivals: *Gate passed* for composition as a stock proxy, aligned for totals once the timing bridge is registered. Departures: aligned for totals, report-only for composition | +| | Entrants' covered-work histories and insured status | OP8(c) and (d), with H and Track B's insured-status rule; `gate_entrant_earn` | Built and conformance-tested once OP8 lands, with refusals counted; *Gate passed* for the combined initialization-and-projection result of the registered arrival cohorts once `gate_entrant_earn` passes | +| | Their benefit receipt against SSA statistics | Not closed by this design | Open. OP12's aggregate totals cannot separate entrants' receipt from incumbents', whose errors can offset; an entrant-specific test (for example on the ACS's Social Security income by year of entry) is unpriced (§3.6) | +| Alignment and a representative population | Alignment to demographic and labor targets that keeps households consistent, with displacement published | OP6, OP9; deaths by the mortality adapter the mortality lane chooses (SM once admitted; ruling d1922) | *Report-only* by design: alignment is production integrity, with published displacement | +| | Gated SSA benefit and payment totals | OP12 | *Gate passed* for unaligned aggregate totals by type once OP12 passes; aligned totals report-only | +| | A representative population | The Microcosm start (`docs/plans/microcosm-start.md`, d947), not this lane | Unchanged by this lane | +| Projections beyond 2030 | Near-term gates first (gate 3) | The Microcosm start's gate 3, not this lane | Unchanged by this lane | +| | Matched 2050, 2065 and 2070 comparisons | OP11a, OP11b | *Report-only*: registered comparisons | +| | 75-year sensitivity surfaces on named assumption paths, each registered | OP10a, OP10b | *Report-only*, conditional projections | + +### 3.4 Totals and critical path (all estimates) + +**Totals.** All rows: **140–216 d, or 35–54 lw**. The demographic phase (OP0.1, OP1 to OP7, OP10a, OP11a) is 76–113 d (19–28.25 lw); the economic phase (OP0.2, OP8, OP9, OP10b, OP11b, OP12) is 64–103 d (16–25.75 lw). + +The arithmetic, from the §3.1 cells: +- Demographic: OP0.1 (6–8) + OP1 (6–9) + OP2 (11–17) + OP3 (16–23) + OP4 (8–12) + OP5 (5–8) + OP6 (8–12) + OP7 (6–9) + OP10a (6–9) + OP11a (4–6) = 76–113. +- Economic: OP0.2 (4–6) + OP8 (26–41) + OP9 (8–12) + OP10b (8–12) + OP11b (10–20) + OP12 (8–12) = 64–103. +- OP8's sub-parts: (a) 3–5 + (b) 5–8 + (c) 2–4 + (d) 3–5 + (e) 6–9 + (f) 7–10 = 26–41. + +**Demographic phase on two lanes (D1, D2), from approval.** It assumes J's candidate years are already in the shared registry when OP0.1 freezes its picks; otherwise OP0.1's freeze waits for them. +- OP0.1 on D1 and OP1 on D2 run together and both finish after 6–9 d. +- D1: OP3, finishing after 22–32 d; then OP5, 27–40; then OP6, which needs OP2(a)(b), OP3 and OP4 and so starts when OP5 frees D1, finishing after 35–52. +- D2: OP2(a)(b), finishing after 14–21; OP4, 22–33; then OP2(c), which needs OP3, OP4 and OP5, starting at 27–40 and finishing after 30–45; then OP7, finishing after 36–54. +- OP10a starts when OP6 and OP7 are both done (36–54) and finishes after 42–63; OP11a finishes after **46–69 engineer-day equivalents**. + +**Economic phase, measured from T, the day a B2 successor passes its registered gate.** T itself is unknown: ruling d1659 requires the successor's design to come to Max first. Track B's B0.2 is already under way (draft PR #554), so this schedule assumes its record, and J's candidate years in the shared registry, are frozen by T. It also assumes the demographic phase's OP2, OP3 and OP6 are done by T; otherwise each start below is the later of its OP and Track B prerequisites. Track B's chain after T, from its §3.1 cells and ignoring queues, is then: H (done at T+6–9), B3 (T+14–21), B3L (T+19–29), B4 (T+31–47), B5 (T+36–55), B6a (T+42–65) and J (T+50–77). + +These dates also assume I's mechanics and any required observational timing gate are ready before the corresponding B5, B6a or J admission. Track B leaves the timing gate's data work unpriced; any delay there moves this path and is outside these estimates. +- OP0.2 follows Track B's B0.2 record, so it can finish before T and is off the path. +- E1: OP8(c), covered-work histories, follows H: T+6–9 to T+8–13. OP8(e) and `gate_young_earn` follow B3: T+14–21 to T+24–36. +- E2: OP8(a), starting states in B4's schemas, runs once B4 starts (after B3L): T+19–29 to T+22–34, so B4 can prepare its open-coverage interface; it cannot claim open coverage until the required entrant initialization is admitted. +- E1: OP8(b), (d) and `gate_entrant_earn` follow B4: T+31–47 to T+42–64. OP8 is then complete, if Track B's insured-status rule has merged. +- E2: OP9's final replay follows OP8 and so runs T+42–64 to T+50–76; J still dominates, so OP10b's start does not move. +- OP10b (E2) follows J, OP8 and OP9: T+50–77 to T+58–89. OP11b follows it: T+58–89 to **T+68–109**. That is the modeled path to OP11b, conditional on its prerequisites. +- OP12 (E1) completes 8–12 d after all its listed dependencies are ready: J, OP8, Track B's I, G v2 and G part 2 and insured-status rule, and the Microcosm start's gate 3. Gate 3 waits on parked decision d947, so OP12 has no finite completion date yet. The economic phase finishes at the later of OP11b and OP12. + +If B0.2 instead freezes after T, as Track B §3.3's sequence had it, add B0.2's 5–7 d to every T-relative figure above: the modeled path to OP11b ends at T+73–116. Either way, the economic phase's elapsed time is set by Track B's chain to J and by OP12's external prerequisites, not by this lane's effort. + +### 3.5 Entrant initialization: the price Track B §3.3 left open + +Track B §3.4 says entrants "require admitted initialization of earnings anchors, latent state, covered histories, insured status and demographic state", and §3.3 lists entrant initialization as unpriced. **This design prices it as one milestone row, OP8: 26–41 d, or 6.5–10.25 lw (estimate).** Track B's B0.2 audit (draft PR #554) can cite that row; it records what B3 to J need from entrants and does not price this work itself. + +**What OP8 delivers to Track B.** One atomic bundle per entrant (the shape #218 §4.8 calls an `EntrantStateBundle`), keyed by person ID, with `entry_kind` (`maternal_birth` or `immigrant_cohort`) and entry year, built from invented data until each real-data step is registered: + +| Track B milestone | What it receives from OP8 | OP8 sub-part | +|---|---|---| +| H (history recorder) | A history opened at entry: pre-entry US covered years under the registered convention, kept distinct from zero; quarters of coverage by year with provenance; exits by death and by emigration kept apart | (c) | +| B3 and its successor law | For immigrants, the law's state at entry (`u_w` and its lags) in the law's rank space; for newborns, the hand-off state at 25 | (b), (e) | +| B4 (forward projection) | Starting states in B4's schemas: marital state and duration, spouse and household links, parity seed, disability state or out-of-domain marker, and the year each entrant joins each risk set; with OP3's entrant weights by kind and year for B4's coverage declaration | (a) | +| B5, B6a and I | Insured status from Track B's rule, or its named refusal, and eligibility-domain flags that keep an entrant out of claiming and DI unless the rule returns a status | (d) | +| J and B7 | Whether `ENTRANT_INIT_UNADMITTED` is lifted, and for which states and populations, from `gate_entrant_earn` and `gate_young_earn` (the latter for earnings at 18–24 only; the hand-off at 25 stays unadmitted unless J or a separate test admits it); entrant weights by kind and year for coverage declarations | (f) | + +**Data sources for OP8** (detail and exposure in §4): +- ACS 1-year PUMS: 2010–2014 (OP3's donors) for entry earnings, employment, citizenship, marital and household state and disability items; 2019 for `gate_entrant_earn`. +- CPS ASEC for earnings at 16–24 and the independent arm of `gate_young_earn`; SSA's 2006 EPUF, staged locally outside the repository with committed provenance and hashes (`data/epuf.py:36–43`), for its fenced arm. +- The CPS June Fertility Supplement for parity seeds, if OP0.1 picks it (OP2(b)). +- SSA's quarter-of-coverage amounts by year and the crediting rules Track M already implements, for (c); Track B's insured-status rule, through the §6.1 interface, for (d). +- Track B's law and H, through their declared interfaces only. + +**The full price of entrant initialization** adds the demographic packets OP8 builds on, which the demographic phase already pays for because its own gates need them: + +| Component | Where | Estimate | +|---|---|---| +| Newborns' demographic packet: parent links, sex, household, weight, birth order, out-of-domain markers | OP2(a) | 4–6 d | +| Immigrants' demographic packet: age, sex, nativity, citizenship, reported entry year, arrival unit and links, marital state, parity seed, disability proxy | OP3 (packet) | 5–7 d | +| Entrant initialization proper | OP8 | 26–41 d | +| **Total** | | **35–54 d (estimate)** | +| Insured-status rule: quarters of coverage; fully, currently and disability insured, including the special rules before 31 and for blindness; the date last insured | Track B's rules lane under d1802, a separate PR once #530 merges; OP8(d) consumes it through the §6.1 interface | Track B's estimate, 5–10 d (as the coordinator relayed it on 21 October 2026); outside every total here | + +**Is it on Track B's path to B7?** Only if B7's frozen target needs open coverage. A target defined on people alive at the start and aged 62 or older at a 2030 horizon contains no newborns; post-start immigrants enter it only if they arrive in their late fifties or older, and OP3's schedule reports their weight, so B7 can declare closed coverage under Track B §3.4 and state what it excludes. National totals, payroll and any horizon past the mid-2030s need open coverage. + +### 3.6 Still unpriced + +These must be priced before a complete budget is approved: +- an entrant forward disability model and its gate (Track B's B4 limits DI outcomes; nothing priced here gives entrants a forward disability hazard); +- a test of the age-25 transition for entrants' generated histories (their joint earnings histories and the hand-off into Track B's law), unless J's frozen estimands cover these entrants; +- an entrant-specific test of benefit receipt (for example against the ACS's Social Security income by nativity and year of entry); +- a bridge for §214(c)'s criterion for noncitizens: when the person's first Social Security number was assigned (before 1 January 2004 exempts them), and otherwise whether a number for work purposes was issued at any time since or the person was ever admitted as a business visitor or crewman (POMS RS 00301.102). No public survey records these, so until a bridge exists the insured-status rule may refuse many noncitizen entrants' statuses by name (§6.1); +- citizenship changes after entry (naturalization), which this design holds fixed at the entry state; +- totalization agreements, under which some immigrants count foreign coverage toward insured status; +- a covered-earnings bridge for temporary or unlawfully present entrants, whose covered share the ACS does not observe; +- an "abroad" ledger that keeps insured emigrants' benefits in national totals (OP4 records exits and OP12 counts insured emigrants; paying them is a separate deliverable); +- the entrant attributes the mortality lane asks for (§6.4): newborns' race and Hispanic origin, and immigrants' education and lifetime-earnings rank; +- moving the engine into Microcosm as an operator (#412), which the Microcosm start also leaves out; +- data-access time for any source OP0 finds restricted (OACT single-age fertility or population, if they must be requested); +- review and registration queues. + +## 4. Data sources and access per gate + +| Gate or record | Sources | Access | Exposure on record | Holdout | +|---|---|---|---|---| +| `gate_birth` (OP2) | NCHS natality (NVSS birth data, CDC WONDER): births by mother's age, child's sex, mother's marital status, birth order and nativity; Census population estimates for denominators; for parity seeds, the CPS June Fertility Supplement (children ever born) | Public downloads | `data/external/nchs_asfr_2024.json` holds NCHS age-group rates for 2023 and 2024 and an annual series for 2016–2024 (`scripts/fetch_nchs_asfr.py:57–62`). Gate 2's floor builder consumes the annual series for period-matched PSID/NCHS ratios (`scripts/build_gate2_floors.py:627–674`, `:693–695`, `:728`), reported and not tuned (`:743`); the TR2026 baseline's default shape uses the 2024 rates. That is exposure, not proof of fitting | Age-group rates for 2016–2024 are exposed, so `gate_birth` on them is regression evidence. OP0.1 audits the scored estimands and selection history and may admit independent prediction only on demonstrably unused observations or estimands (candidates: 2015, outside the committed series; the share male; births by mother's nativity or single year of age); 2020–2022 stay diagnostic, as in gate m6's shock window (`gates.yaml:5411–5415`) | +| `gate_imm` (OP3) | ACS 1-year PUMS 2010–2014 (person, household, replicate weights); TR2026 V.A2; the Trustees' glossary and the 2026 long-range model documentation (pinned in `docs/baselines.md`) for the universe bridge | Public Census downloads; SSA pages need the `Wget` user agent (§2.7) | A text search finds ACS tables named as anchors in the gate 2b and 2c floor builders and in U2's source registry; OP0.1 establishes whether any ACS PUMS year was read | 2014 annual file (#218 §5.2) | +| Emigration check (OP4) | V.A2 outflow columns; the Census Bureau's 2023 national projections methodology, for its emigration assumptions (to be confirmed at OP0.1); ACS arrival cohorts across 2015–2019 | Public | None known | Report-only unless OP0.1 admits a holdout | +| Demographic target manifest (OP6) | V.A1 (TFR), V.A2, CBO's single-age fertility by nativity (pinned); V.A3 and V.A4 as validation only. OP0.1 lists OACT's death probabilities (pinned) in the manifest as `validation_only`: under ruling d1922 they are the mortality lane's target, and OP6 selects nothing against them | Public; pinned files in `data/external/` | V.A1 and V.A4 transcribed (`data/tr2026.py`) | Not a gate | +| OP5 start, `gate_pop` (OP7) | ACS 2013 1-year PUMS (start); the 2020 Census by single year of age and sex, at its 1 April 2020 reference date; the ACS 2019 1-year file for the foreign-born by period of entry, a calendar-year collection; Census population estimates (report-only) | Public | None known | 2020 Census; ACS 2019; each compared with a projection slice by a registered date mapping | +| OP8 (a)–(d), entrant initialization (not gates) | ACS 1-year PUMS 2010–2014 donor items (earnings, employment, citizenship, disability items, marital status and relationships); the CPS June Fertility Supplement for parity seeds if OP0.1 picks it; SSA's quarter-of-coverage amounts by year and the crediting rules Track M already implements for years of coverage (`min_benefit_track_m/coverage.py:1–30`); Social Security Act §§214 and 223(c) and POMS RS 00301.102, read 23 October 2026, for the facts the insured-status rule needs | Public; Track M's code in the repository | ACS 2010–2014 also fit OP3 | Not a gate: conformance and the §7 properties | +| `gate_entrant_earn` (OP8) | ACS 2019 1-year PUMS for the 2010–2014 arrival cohorts; the immigrant earnings work in *Social Security Bulletin* 68(1), 2008, by Duleep and Dowhan, as cited by #218 §2.1, as a report-only benchmark | Public | ACS 2010–2014 used to fit OP3 | ACS 2019 | +| `gate_young_earn` (OP8) | CPS ASEC earnings at 18–24 in years OP0.2 shows unused; SSA's 2006 EPUF for an early-career arm | CPS public; EPUF staged locally outside the repository with committed provenance and hashes (`data/epuf.py:36–43`; `data/external/epuf_2006/provenance.md`) | EPUF is heavily exposed. `gate_epuf_fill` split it 60/20/20 into training, development and test people by a salted hash (`harness/epuf_fill_gate.py:15–18`, `:134–139`); the Microcosm start's H1 draft records that a different salt leaves most of its test people inside that gate's training and development parts (`docs/plans/microcosm-start-registration-draft.md:105–109`). A new salt therefore does not make people disjoint | The EPUF arm uses explicit person exclusions and fitting fences covering every previous training, development, selection and evaluation use; if OP0.2 cannot demonstrate an independent partition, it is regression evidence, and independent admission rests on the unused CPS observations alone | +| Labor target manifest (OP9) | TR2026 IV.B4 (covered workers) and V.B1 (average covered wage growth); CBO's covered workers by sex, 2026–2100 (pinned) | Public | IV.B4 is named in RESTRICTED-FILES for A-COLA builders (§6.4) | Not a gate | +| Long-horizon backtest (OP10b) | PSID 2006→2022, as Track B's B3L; ACS 2005→2022 for composition | PSID local; ACS public | PSID fully exposed (B3L's label applies: regression evidence) | None independent | +| OP11a, OP11b comparisons | V.A3; CBO's January 2026 demographic projections (pinned zip); Census 2023 national projections; OACT and CBO beneficiary projections; MINT8 and DYNASIM output tables | Public; DYNASIM and MINT tables only through a validation-only comparator lane | DYNASIM output and MINT option tables are restricted (§6.4) | Sealed comparators | +| `gate_ssa_totals` (OP12) | SSA Annual Statistical Supplement beneficiaries and benefits by type | Public | Track B participants opened the 2023, 2024 and 2025 supplements' §4.B, §6.B and §6.E (Track B §5.2); the Microcosm start's W2 reads the 2023 edition's 5.B1, 5.D1 and 5.G1; and the registry's prior use H005 (gate w1) used the 2023 supplement's §6.B tables (6.B5.1, 6.B4 and 6.B3) and DI ASR 2023 Table 19, as issue #151 also records, with Census HH-4 and AD-3 for 2023; and review r6 of this design opened the 2025 supplement's §5.J, including its 2024 tables. All of these are exposure, not unused holdouts | Years and tables chosen at OP0.2 after that record, from the years left after J's candidates in the shared registry (§5.2); exposed ones are regression evidence, and any year shared with J is disclosed by name in both registrations | + +## 5. Admission criteria and registration discipline + +### 5.1 General rules + +These apply to every OP milestone, in addition to Track B §5.1: +- Each milestone adds new modules and a new registered version; it edits no sealed file, no `track_b/` file, no `gates.yaml` cell and no committed run. +- Every gate, OP12 included, runs through an unaligned-only facade whose request cannot carry a target bundle; the aligned producer is outside the gate runner's import closure (#217 §4.1). Only Max can make an exception (§10, decision 10). +- Sources, module versions, seeds, populations, estimands, tolerances and alternatives are frozen before any real-data outcome is computed. Output paths are exclusive, and abort records are published. +- Every production run uses one registered horizon (§2.9). +- Every milestone reports its verification class and admitted scope (§3.2). + +### 5.2 What OP0 freezes + +OP0 produces one frozen record per gate, with Track B §5.2's elements: source release, variables, population, exposure history, holdout partition, critical cells, numerical tolerances, uncertainty treatment, pass conjunction and the named power procedure. It adds four elements this lane needs: +- **the universe** of each source and its bridge to the projection's roster (Social Security area, resident population, civilian noninstitutional population, group quarters); +- **the date mapping** from each source's reference date or collection period (a calendar-year survey, a 1 April census, a July 1 estimate) to the projection's annual slices; +- **the target manifest**: for each external target, its table, row, column, vintage, captured-byte hash and status (`available`, `not_available` or `validation_only`), as #217 §7.1 specifies; +- **the horizon record**: for each fitted component, its fitted support and the declared rule outside it. + +**The shared holdout registry.** Track B's holdout registry is the single registry of held-out years for every lane. It is `docs/design/track_b_holdout_registry.json` (schema `track_b_holdout_registry.v1`), started by Track B's B0.2 audit (draft PR #554) on branch `trackb-b0-2-20261021` at `e1c3c1e6`, file SHA-256 `aa5ce9bbb127fdd1f0729bb8af2cdc66aefe74ec897010f9e80bababfeaa002c`, and moving to its own pull request on master. Every OP record cites it by path, commit and SHA-256 together, because the hash changes with each appended entry. Its order is fixed: +1. J's candidate years are recorded first. +2. OP0.1 and OP0.2 register each of their picks there before freezing them, and choose from the years that remain. +3. Any year an OP gate must share with J or another lane is disclosed by name in both registrations. + +This matters most for `gate_ssa_totals` (OP12), whose SSA Annual Statistical Supplement years are the kind J needs for its independent holdout. + +OP0.1 must also establish whether OACT publishes single-age fertility and single-age population projections; the public single-year tables do not (§2.7). Where it does not, the margin uses a registered bridge (the TR2026 baseline's derived shape, or CBO's single-age rates) or stays `not_available`. + +### 5.3 Proposed numerical limits and tolerance classes + +**Proposals only, subject to OP0's prospective feasibility and power review**, which may rescope before any candidate result and may never loosen a limit after one. + +Each gated cell's tolerance comes from the class of its reference source, plus the uncertainty of the candidate that is compared with it. OP0 assigns every cell a reference class and a candidate procedure before its gate is approved; no class borrows another's procedure. + +| Class | Sources | Reference-side uncertainty | +|---|---|---| +| Survey microdata | ACS and CPS ASEC files | The survey design: replicate weights where the file publishes them, otherwise household-disjoint half-splits of the file itself, under the repository's floor convention (statistic \|ln(candidate / reference)\|, tolerance round(mean + 4·sd, 3), at least 20 events on the weaker half, stabilized tolerance at most T_max = ln(1.5); `gates.yaml:1336`, `:1001–1006`) | +| Administrative and vital-statistics aggregates | NCHS natality counts and rates; SSA supplement tables | No sampling floor: a named allowance for measurement, concept, coverage and vintage, such as the dispersion of revisions to the same target year across published vintages plus half the published rounding unit, after the approach issue #151 proposed for gate w1's administrative anchors. Changes between outcome years, such as annual demographic or benefit growth, are not measurement uncertainty. Household half-splits are never manufactured from aggregate tables | +| Census counts | The 2020 Census | A named coverage allowance, from the Census Bureau's published coverage measurement for 2020 (pinned at OP0.1) | + +**Candidate-side uncertainty is gate-specific.** Each gate specifies uncertainty for its actual start, donor and fitted-law inputs, respecting survey design and family clusters, plus simulation uncertainty. OP5 household resampling applies only to candidates projected from OP5's start (`gate_birth`, `gate_pop`); `gate_imm` resamples OP3's ACS donor files by their replicate design; `gate_entrant_earn` resamples OP3's entry bundles and carries Track B's law's estimation uncertainty; `gate_young_earn` resamples its own CPS and EPUF constructions; OP12 resamples the Microcosm frame by its own design. OP0 writes each gate's procedure into its frozen record. + +For every class: simultaneous 95 percent bounds with Bonferroni over each registered cell family; Monte Carlo error below one-tenth of each tolerance; insufficient precision is inconclusive, never a pass (Track B §5.2). Cells that fail eligibility are report-only by a machine partition fixed before any candidate runs. + +- **Alignment fidelity** (OP6, OP9): each margin OP6 or OP9 selects or scales is within its selection-resolution floor plus a numeric tolerance pinned in target units (#217 §6.1–6.2); death totals are report-only here. Displacement corridors are authored before release; until a corridor artifact exists, each run publishes raw displacement with `corridor_status: not_available`. No target or corridor is fitted to OP12's held-out SSA outcomes. +- **Horizon drift** (OP10b): none proposed. OP0.2 freezes limits on drift growth for the backtest. + +### 5.4 Stage-specific rules + +- **OP1.** Emigration draws come from a tagged child stream of the mortality module (as `baselines/fertility.py:24–28` does for births), so turning emigration off leaves every death draw unchanged. A person can die or emigrate in a year, never both: death is drawn first, as now, and emigration only among survivors. +- **OP2.** The second parent is the mother's spouse or partner in the authoritative marital state, of any sex; an unlinked newborn carries one of a registered list of reasons (unpartnered mother, partner outside the roster, partner unknown). The sex ratio is pinned from NCHS before any gate. Parity carries forward from its registered seed; it never resets during a projection. No newborn reads an adult process until a later milestone admits it. +- **OP3.** As #218 §3.2 and §4–§5: no cloned future; a pre-entry state is a stock proxy until a registered stock-to-arrival bridge exists; the 2014 file is read only for scoring after lock; the five-year pooled ACS file is never used. A real-data schedule needs both the universe bridge and the timing and exposure bridge; donor rows never carry a Trustees stock or legal-status label. +- **OP4.** No death is relabeled as emigration or the reverse; a spouse who emigrates never widows the partner who stays (§7). Whether a person who entered this year can also emigrate this year is frozen at OP0.1 (#217 §8, decision 2, left it open), together with the exit-timing convention OP3's bridge uses. +- **OP5.** Links are reconstructed only where the relationship-to-reference-person item determines them (for example the reference person's spouse and own children); others are unknown, never inferred from age or sex alone. +- **OP6, OP9.** As #217 §4: two immutable projections from the same inputs; whole-unit selection for events other than deaths, a scalar for covered wages; deaths are never selected or reweighted here, because the mortality lane's SM owns death alignment (ruling d1922, §6.4); no person weight changes; the gate verdicts of the unaligned run cannot move. Displacement is reported on a complete representation of each margin: one row per margin, year and stratum (for example deaths by sex and single year of age), with the unaligned and aligned totals as values and separate markers for a known zero and an unavailable cell. `build_alignment_displacement` takes those keys (it accepts caller-chosen keys, `harness/m6_reporting.py:321–327`), so the comparison never runs on the intersection of surviving person rows. The persons whose events alignment changed are published separately as the displaced set. +- **OP7.** Its arms, its 2013-vintage inputs and its date mappings are frozen at OP0.1; any arm fed realized aggregate controls is labeled as such and admits composition only. +- **OP8.** Sub-parts (b) and (e) build on Track B's admitted law and may not change it. The builder of (e) satisfies ruling d1659's independence requirement (§8, "Governance risks"). Sub-part (a) follows B4's schemas as B4 declares them; where B4 has not declared a schema, (a) delivers the #218 §4.8 packet and B4 maps it. +- **OP10a, OP10b.** The horizon record lists every component's fitted support and its declared rule outside it; a run that queries a component outside its support without a rule is refused. +- **OP11b.** As Track B §5.4 for B7: a sealed comparator with two transcriptions, a blind builder under an updated RESTRICTED-FILES, a hashed forecast before the run, and a one-shot at a registered commit. +- **OP12.** It scores the unaligned totals through the unaligned-only facade, like every other gate. The aligned totals are computed by the separate production replay and published beside it, report-only. If Max makes the exception of decision 10, an aligned-scenario evaluation runs in a separate production-scenario runner, never in the gate runner, and the unaligned gate stays as registered. Spouse and survivor types are published, gated or report-only, only once the Microcosm start's T2 marital-makeup condition is cleared. + +## 6. Interfaces + +### 6.1 Track B: H, B4, J, and also I, B7, G and the insured-status rule + +This lane edits nothing in `track_b/`; it asks Track B for the interfaces below and supplies the ones Track B §3.4 says it needs. §3.5 lists what OP8 delivers to each Track B milestone. Where a request lands inside a Track B milestone not yet built, Track B decides; nothing here changes Track B's prices. + +**H, the history recorder (Track B §3.1: 2010–2030; entry and death; labor, covered and RET-countable earnings separate; zero and missing distinct).** +- *This lane needs from H:* a history opened at entry for any entrant, with pre-entry years carried as the convention Max picks (§10, decision 4) and never silently zero; emigration recorded as its own exit, distinct from death, so that an insured emigrant's record survives; a horizon end year that is a parameter rather than a fixed 2030, so that OP10b does not need an H v3. +- *This lane supplies to H:* every entrant's `entry_kind`, entry year and exit records (OP1), and the opened history and quarters of coverage of OP8(c). + +**B4, the forward projection successor (Track B §3.1, §3.4).** +- *This lane needs from B4:* forward marital and household adapters that admit people who join the risk set after the start (newborns ageing into marriage, immigrants entering married or single), so that a second-parent link can come from a marriage formed after the start (OP2); widowhood that ignores exits by emigration; and B4's coverage declaration naming which entry kinds it covers. +- *This lane supplies to B4:* OP8(a)'s starting states in B4's schemas, built from OP2's and OP3's packets, while B4 is built, so that B4 can prepare its open-coverage interface; and, once OP8's gates pass, the admitted entrant initialization B4 needs before it claims that coverage. + +**J, joint validation (Track B §3.4; estimands frozen at B0.2 and ratified before B3 registers).** +- *This lane asks:* that J's B0.2 record declare closed or open coverage and, if closed, report the weight of entrants it excludes from each denominator. If OP8 is not admitted by then, J is closed-coverage, and any B7 target needing open coverage is blocked by `ENTRANT_INIT_UNADMITTED` (Track B §7) until OP8 passes. + +**I, the monthly calendar (Track B §3.4).** I's event journal records entry and death; this lane asks that it also record emigration as a dated exit, and adopt the seam's entry-year convention (§2.3) or register its own. + +**B7 (Track B §3.4's scope matrix).** "Population" in the scope matrix includes open or closed coverage; §3.5 says when B7 can declare closed coverage. + +**G (`track_b/gross_benefits.py`).** G consumes assembled worker and beneficiary records for a month (for example its `Beneficiary` record, `track_b/gross_benefits.py:1079–1095`); it does not resolve parentage. A declared assembly adapter maps OP2(a)'s parent links into those inputs for child benefits. + +**The insured-status rule (Track B's rules lane, under d1802; a separate PR once #530 merges).** Its scope, as the coordinator relayed it on 21 October 2026: quarters of coverage; fully, currently and disability insured, including the special rules before 31 and for blindness; and the date last insured, designed for B6a's person-month risk set. Its interface, as relayed the same day: each year of a person's record carries a provenance, `OBSERVED`, `CONVENTION_FILLED` with a convention id, or `UNKNOWN`; the rule bounds `UNKNOWN` years at zero and at the maximum quarters of coverage; where both bounds give the same status it returns that status flagged "decided despite unknowns", with the unknown years listed; where they disagree it refuses by name (for example `unknown_earnings_years_decide_status`) and keeps the row in the denominator. The flag and refusal names are as the coordinator relayed them; OP8 checks this section against the rules lane's interface section when it lands. OP8(d) consumes the rule and does not change it. What OP8 supplies to it, and needs from it: + +1. **Per-year provenance for quarters of coverage, from OP8(c).** Years whose covered earnings the entrant's history holds, reported in a source or projected after entry, go to the rule as `OBSERVED`; OP8 also records each year's origin (reported, or generated by the projection), so projected years stay labeled as model-generated even though the rule treats their values as known within the simulated scenario. Pre-entry years follow Max's decision 4 (§10): under the **zero convention** (a first-entry assumption) they go as `CONVENTION_FILLED` with zero quarters and a registered convention id; under the **censored convention** they go as `UNKNOWN`. OP8 supplies annual quarters, never monthly earnings. From 1978 on, quarters are credited from a year's covered earnings, up to four (`min_benefit_track_m/coverage.py:16–19`). The rule assigns them to calendar quarters under SSA's flexible assignment, which may place a quarter wherever it is most advantageous to the worker (POMS RS 00301.230), within the limits of RS 00301.240: a quarter counts once, none after the quarter of death, none inside a period of disability except its first and last quarters, and none in the future. +2. **The facts other than quarters that the statute needs, each with the same provenance.** Fully and currently insured status carry an additional criterion for anyone not a US citizen or national (Social Security Act §214(c)). For noncitizens and nonnationals, the rule first determines whether the additional requirements apply. Workers originally assigned an SSN before 1 January 2004 are exempt. Workers originally assigned an SSN on or after that date, and workers not yet assigned one, are subject to them. For those the rule applies POMS RS 00301.102: a Social Security number issued for work purposes at any time since then, or admission at any time as a business visitor or crewman, after which all covered earnings count (RS 00301.102 B.1–B.5, read 23 October 2026). Unknown applicability receives the same bounding or named-refusal treatment as other unavailable statutory facts. Elapsed years exclude years in a period of disability (§214(a)), and disability-insured status has a special rule for a prior period of disability that began before 31 and an exception for statutory blindness (§223(c)(1)). For entrants: + - citizenship or national status comes from the donor's ACS citizenship item, `OBSERVED` as of the donor's interview and fixed thereafter (§3.6); + - for noncitizens, the original Social Security number assignment date, or the rule's applicability determination, remains `UNKNOWN` under both pre-entry earnings conventions unless independently supported. First entry and zero pre-entry covered earnings do not establish an SSN assignment date. A sensitivity that dates assignment would need its own registered assumption and Max's decision. Where the requirements apply, whether a work-purpose number was issued or a business-visitor or crewman admission occurred is `UNKNOWN`, because no public survey records it and this design models no legal status (#218 §1.3); + - statutory blindness is `UNKNOWN`: survey vision items are not the statutory definition; + - prior periods of disability are `UNKNOWN` for immigrants under both conventions unless independently supported, because neither convention speaks to disability history, and none for newborns. + + OP8 asks the rule to bound an `UNKNOWN` fact as it bounds an `UNKNOWN` year: return a status only where every admissible value gives the same one, and otherwise refuse by name. **The zero convention resolves uncertainty about pre-entry quarters of coverage only. Where another fact required by the applicable statutory test is unavailable, OP8 preserves the rule's named refusal and the entrant's denominator weight.** +3. **Elapsed years from the birth date, not the entry date.** The fully-insured test counts one quarter for each year elapsed after 1950 or, if later, after the year the person turned 21, and before the year of death or of turning 62, with at least 6 quarters, or 40 quarters in all (§214(a)), wherever the person lived. An immigrant who arrives at 45 therefore faces the same count as a native-born worker of the same age. OP8 supplies the birth date, and the rule evaluates at a stated month, as B6a needs. For disability-insured status the fully-insured count instead runs to the evaluation month, as if the person had turned 62 and applied on its first day (§223(c)(1)(A)). +4. **Monotone in quarters, given the other facts.** With the facts of point 2 and the disability-period history held fixed, adding a quarter of coverage in any year never takes away any insured status and never makes the date last insured earlier. The rule's bounding relies on this, so OP8 asks that the rule's tests state it as a property. +5. **Each output bounded separately.** Fully insured, currently insured, disability insured and the date last insured are each decided or refused on their own: two agreeing current statuses can coexist with different historical dates last insured, and the date is then refused even when the status is returned. +6. **An optional input for credits from outside US coverage,** empty by default, so that a later treatment of totalization agreements (§3.6) can add credits without changing the rule. +7. **Refusals stay refusals.** OP8(d) passes the rule's result through unchanged: a status, with its flag where unknowns were bounded, or the rule's named refusal. A refused entrant stays outside claiming and DI, as `entrant_domains.py` keeps entrants now, stays in every denominator and is counted by refusal reason; no refusal becomes "not insured". +8. **Newborns and emigrants.** A newborn has no pre-entry years; its quarters come from its own earnings under OP8(e), and a newborn citizen meets §214(c) by citizenship. An emigrant's quarters stop accruing at exit; the rule can still evaluate the emigrant's status and date last insured at later months, which OP12 needs to count insured emigrants. + +### 6.2 The Microcosm start (`docs/plans/microcosm-start.md`; d947 parked) + +- **Start-agnostic machinery.** OP1 to OP6 run on any start: a closed PSID cohort, OP5's ACS start, or Microcosm's frame. National claims (OP12) need a representative start; that is the Microcosm start's job, and d947 decides whether its registration posts. +- **What d947 being parked blocks.** Nothing in the demographic phase: its gates use OP5's ACS start. In the economic phase, OP12 needs the Microcosm start's gate 3 to have passed, so OP12 has no finite date while d947 is parked (§3.4). +- **Weights.** The Microcosm start holds each person's start-year weight fixed and notes that the projected population closes until births and immigrants enter (`microcosm-start.md:453–456`). This lane keeps fixed trajectory weights: newborns take the mother's weight (§2.2), immigrants take the control-scaled donor weight (§2.3), and alignment selects people rather than reweighting them. +- **Gate 3.** Its cells score the first projected year's growth in retired- and disabled-worker counts and average benefits (`microcosm-start.md:351`). OP1's harness keeps entrants out of claiming with `EntrantClaimingAdapter` until OP8 lifts the exclusion, so entrants do not touch those cells. This lane recommends that gate 3 run closed, as drafted, with an open-population variant published report-only beside it. Gate 3's cells concern retired and disabled workers only, so passing it does not clear the start's separate condition on spouse and survivor results. +- **Spouse and survivor results.** The Microcosm start withholds every spouse or survivor result until Microcosm explains or fixes its frame's marital makeup, which its task T2 asks for (`microcosm-start.md:452`). OP12's spouse and survivor types, aligned companion included, and OP11b's spouse and survivor outputs from that start stay unpublished until the condition is cleared; completion of G, I or J does not clear it. +- **One convention to reconcile.** For immigrants already in the frame, the Microcosm start begins a history no earlier than a year drawn within the person's entry-year group (`microcosm-start.md:492`; the registration draft cuts histories at entry, `microcosm-start-registration-draft.md:81`). For scheduled entrants, `entrant_domains.py:210–228` treats pre-entry US covered earnings as censored and blanks benefits to missing. The two treatments differ. One registered convention should cover both populations (§10, decision 4). +- **Frame immigrants as donors.** The frame carries year of entry, nativity and citizenship (`microcosm-start.md:117`), so its recent arrivals are a candidate second donor pool; OP0.1 compares it with the ACS's. + +### 6.3 Moving the engine into Microcosm (#412) + +Issue #412 maps alignment onto per-year REWEIGHT nodes, which would change weights, while this design and #217 select whole people at fixed weights. Both can coexist: selection now, on the existing engine; a REWEIGHT implementation later must reproduce the same aligned margins and publish the same displacement. #412's "entry without lineage" amendment should take this lane's `entry_kind` and donor-provenance columns as its row markers. + +### 6.4 Other lanes and governance + +- **Insured status.** The ledger row is *None* today. Under d1802, Track B's rules lane builds the rule as a separate PR once #530 merges; OP8(d) and OP12 consume it through the §6.1 interface, as Track B's B6a does. +- **Death alignment (the coordinator's ruling, relayed 24 October 2026, under Max's ruling d1922).** The mortality lane's SM owns death alignment: its relative risks are normalized within each cell so that OACT's total deaths hold in expectation. This lane's alignment layer (OP6, OP9) covers the other demographic and labor targets and consumes SM's mortality as given. It never selects or reweights deaths, because aligning deaths a second time would double-count (the mortality lane's design, PR #558, `docs/design/mortality_groups_financing.md` §7.2, as Max approved it under ruling d1922 at file SHA-256 `26e53d0849088307c1fa22631216cbbfb9745a05646425aa0a6174055646130d`; §7.2 was unchanged at #558's head on 24 October 2026). Which mortality adapter fills the slot, the baseline's or SM once the mortality lane admits it, is that lane's decision; OP1's exit adapter wraps whichever it is and leaves its death draws unchanged. The TR2026 baseline's own adapter already draws at OACT's period q by single age and sex (`baselines/tr2026_intermediate.py:18`, `:135–159`, read at `origin/master` `4fc2b9f4` for revision 12). +- **The mortality lane's other requests.** The same section of #558 asks this lane for newborns' race and Hispanic origin under a registered inheritance rule, and for immigrants' nativity, education and a lifetime-earnings rank. OP3's packet already carries nativity; neither OP2(a)'s nor OP3's packet carries the others, and adding them is unpriced (§3.6). OP8(b) maps immigrants' `u_w`, the forward law's long-run earnings rank, only in the economic phase; whether it can serve as that rank is the mortality lane's call. #558's other requests are met elsewhere: emigration kept apart from death (OP1 and OP4, and requested of Track B's H, §6.1), and the horizon to 2100 (OP10a, OP10b), admitted only as a conditional projection (§10, decision 5). The frame columns it asks for are the Microcosm start's. +- **RESTRICTED-FILES.** These entries bind this lane: + - *A-COLA (Registration 18):* its builders read no Trustees Report table of cost, income or balance rates and, from the committed IV.B4 snapshot, only one beneficiary count. OP9's builders read IV.B4's covered-worker rows, so under that rule they cannot also be A-COLA builders. + - *NASI follow-ups:* Urban's published DYNASIM output and MINT option tables for the five reforms are restricted to validation-only comparator lanes. OP11b's builders never open them. + - *B2 outcome files (2026-10-18 entry, enforced in code by #549):* successor designs blind to B2's outcome exclude them. OP8(e) builds an earnings component whose hand-off state feeds Track B's law, so §8 sets who may build it. OP8(b) maps entrants into the unchanged law, which does not by itself make it a B2 successor. + - *B0.2 and the B2 successor design (2026-10-21 entry):* B0.2's lanes and the successor-design lanes may not open each other's folders, lane clones or (for successor roles) draft PR #554 beyond its title. OP8(e)'s builder takes one of those roles or neither, never both. This lane has opened neither side's folders, and hashed the holdout registry file from git without opening it. + - *U2 step-4 run 2 outputs (2026-10-21 entry):* restricted for everyone except their `MANIFEST.md`. Nothing in this lane reads them. + - *Transcripts, scratchpads and `~/.subfleet/` folders* other than a lane's own stay closed to every lane. + +## 7. Invariants and property-based tests per component + +Each invariant becomes a Hypothesis property test on invented data beside the example tests, as the repository's rule for load-bearing logic requires. Two are differential tests between independent implementations. + +- **Stock-flow (OP1).** For every year: people at the end = people at the start − deaths − emigrants + births + scheduled entrants, exactly in counts; and the same in weights, within the summation residual `reconcile_period` reports. Every addition carries a known `entry_kind`; every exit carries one exit kind; no person exits twice; no ID is reused (`validate_projection_allocator` on the exact metadata). +- **Emigration coupling (OP1, OP4).** With emigration off, the survivors equal the closed run's exactly. No person both dies and emigrates in one year. For a fixed post-mortality risk set, fixed exit units and coupled draws, increasing emigration probabilities cannot remove a same-year exit selected under the lower probabilities. This is a property of one year's transition only: across a projection, more exits in early years shrink later risk sets, so later-year emigrant weight can fall. +- **Horizon prefix (OP1).** Under the registered-horizon convention, the slice for year t is identical across runs that differ only in the horizon read; a production request with any other end year is refused. The committed evidence (§2.9) is the failing case this property guards. +- **Determinism and order invariance (all).** The same inputs and seeds give byte-identical output; shuffling roster rows changes nothing. +- **Newborn packet (OP2).** Each newborn has exactly one mother on the roster in its birth year; a linked second parent is on the roster, is not the mother and is her spouse or partner in that year's authoritative state; age 0 and birth year equal the year; weight equals the mother's; adult-domain markers are out of domain. +- **Live-roster fertility (OP2, differential).** Given identical support, initial parity and per-woman-year random draws, the live-roster kernel's births equal those of one invocation of `simulate_maternal_births`. Persistent parity: it starts at the registered seed, rises by exactly one with each birth, never falls, and never resets within a projection; no birth falls outside the kernel's fertile ages. +- **Entrant schedule and timing bridge (OP3).** Scaling every control by k scales every entrant weight by k; a zero control adds no rows and consumes no IDs (already true of `build_entrant_schedule`, `entrant_schedule.py:282–294`); the donor composition is reproduced exactly; no entrant's pre-entry covered earnings are zero unless the registered convention says so. **No duplicate survival filtering:** on invented data, for a component the bridge marks as year-end stayers, the expected year-end entrant weight after the seam's mortality and emigration equals that component's control; a schedule that feeds the raw stayer control into full-year mortality fails this test. +- **Relational consistency (OP4, OP6).** Each surviving married person whose linked spouse dies receives exactly one widowhood transition; every such transition traces to that spouse's death. No emigration, drawn or selected by alignment, produces widowhood. OP6 selects no deaths (ruling d1922), so every death, in either replay, comes from the mortality adapter. (When both spouses die in the same year, the loop removes both before the marital step, `engine/loop.py:297–315`, and no widowhood occurs; Track B §6 states the same qualified form.) +- **Alignment (OP6, OP9).** The unaligned artifact is byte-identical whether the aligned producer is importable or not; each margin OP6 or OP9 selects or scales is within its selection-resolution floor plus tolerance, and death totals are report-only; the margin, year and stratum representation is complete, with known zeros and unavailable cells distinct, and its keys are identical on both sides; no person weight changes; an empty target bundle reproduces the unaligned run. Both replays use the same mortality adapter specification (version, parameters and seed); in every year, the aligned replay's deaths equal that adapter's draws on the aligned replay's own start-of-year roster, and alignment selects, removes or relabels no death. Deaths can therefore differ between the replays only through the rosters the adapter receives. +- **Stable population (OP10a, differential).** With constant single-age fertility and mortality and no migration, the expected age-sex distribution in each year (the mean over seeds) agrees, within Monte Carlo error, with a two-sex Leslie projection from the same start and rates under the engine's timing conventions (§2.2); and the long-run growth rate approaches the logarithm of the Leslie matrix's dominant eigenvalue. The micro engine and the matrix are the two implementations compared. +- **Extrapolation (OP10a, OP10b).** No component is queried outside its fitted support without a declared rule; the refusal is tested. +- **Insured-status provenance (OP8(c), (d)).** Every year and every non-quarter fact of an entrant's record carries exactly one provenance; under the zero convention no pre-entry year is `UNKNOWN`. Unknown years and facts remain disclosed. Each output is returned only when all admissible completions give the same result; otherwise the rule returns its named refusal. OP8 never substitutes an invented value for an unavailable input; OP8(d) never turns a refusal into a status; a refused entrant stays in every denominator; each of the four outputs is decided or refused on its own. +- **Entrant economics (OP8).** Earnings are finite and nonnegative; pre-entry years are never filled with zero unless the registered convention says so; the hand-off at 25 lands inside the forward law's support (a support check, not an admission of the transition); no unavailable year or fact is replaced by an invented value. + +Counterexamples are executed and minimized before anyone calls them bugs. + +## 8. Risks and kill criteria + +### Blocking rule + +Track B's rule applies unchanged (Track B §7): required-source unavailability, unresolved exposure, inadequate precision, unsupported critical configurations, or a failed gate or required regression test block the corresponding admission and the milestones that depend on it. Fallbacks register before candidate outcomes. Failed or unsupported cells stay reported, and removing them cannot manufacture a pass. + +### Named conditions and what each stops + +| Condition | Trigger | Stops | +|---|---|---| +| `ACCOUNTING_IDENTITY_FAIL` | A stock-flow identity fails in any year | Every OP run until fixed | +| `ID_OR_STREAM_COLLISION` | An allocator could reuse an ID, or a production run's end year differs from its registered horizon | That run | +| `CONTROL_SOURCE_UNAVAILABLE` | A target or control (OACT single-age fertility or population, V.A2 rows) cannot be pinned | That margin stays `not_available`; no "aligned to OACT" claim for it | +| `UNIVERSE_BRIDGE_UNRESOLVED` | No registered bridge from the Social Security area to the roster | Real-data immigrant schedules and every stock claim | +| `TIMING_BRIDGE_UNRESOLVED` | No registered component-specific timing and exposure bridge | Every production immigrant schedule | +| `DONOR_SUPPORT_THIN` | `gate_imm`'s cells fail support floors after the registered pooling ladder | Gated composition claims for those cells; they stay report-only | +| `EMIGRATION_UNIDENTIFIED` | OP0.1 finds no admissible holdout for exits | Composition claims by nativity and duration; totals stay aligned | +| `HOLDOUT_EXPOSED` | OP0 cannot show a gate's observations or estimands unused (as for NCHS's 2016–2024 rates and the EPUF arm) | Independent-prediction admission for that gate; it reports as regression evidence | +| `ALIGNMENT_DISPLACEMENT_EXCESSIVE` | Displacement above its corridor in a registered number of consecutive years, or growing through the horizon | Release of that aligned margin pending model review; a second registered review that finds the same blocks any claim past 2030 that depends on the margin until its law is refit | +| `ENTRANT_INIT_UNADMITTED` (Track B §7) | OP8's `gate_entrant_earn` or `gate_young_earn` fails or is inconclusive | Targets requiring open-population coverage for the states that gate covers | +| `INSURED_STATUS_ABSENT` | Track B's insured-status rule is not merged, or does not meet the §6.1 interface | OP8(d) and its lifting of entrant exclusions; OP12 | +| `HORIZON_NOT_LICENSED` (Track B §7) | The horizon record or the long backtest fails its registered limits | Any claim past 2030 beyond a conditional projection | +| `EXTRAPOLATION_UNDECLARED` | A component is queried outside its fitted support with no declared rule | That run | +| `SUCCESSOR_EXHAUSTED` (Track B §7) | Two independently justified B2 successors fail | The economic phase pauses; the demographic phase continues | +| `GATE_FAIL_OR_REGRESSION_FAIL` | Any registered OP gate fails | That admission and its dependants; the failure is published with no seed selection or tolerance relief | + +### Attempt ledger + +Track B's cumulative attempt ledger applies by mechanism and gate family: open-population fertility, immigrant composition, emigration, demographic composition, entrant earnings and young-adult earnings each count separately. Renaming a module does not reset a counter; two failed successors pause a mechanism pending new evidence. + +### Risks most likely to slip + +- **Track B's B2 successor.** The economic build milestones wait on the B2 successor; OP0.2 may finish earlier (§3.4). Two failures pause the earnings mechanism. +- **OP12's external prerequisites.** Gate 3 waits on parked d947; G part 2, I and the insured-status rule are not yet built; and spouse and survivor types wait on the Microcosm start's T2 marital-makeup condition. +- **Holdout competition with J.** `gate_ssa_totals` and Track B's J may want the same SSA supplement years. The shared registry (§5.2) gives J first choice; if too few unexposed years remain, OP12 registers on shared years with disclosure, or as regression evidence. +- **Exposed demographic holdouts.** NCHS's 2016–2024 rates are already in the repository (§2.7); `gate_birth` may end as regression evidence. +- **Insured status for noncitizen entrants.** Without a bridge for §214(c)'s facts (§3.6), the rule may refuse many noncitizen entrants' statuses, so their benefit outputs may stay largely missing. +- **Granular demographic targets.** If OACT's single-age fertility and population are neither public nor obtainable, alignment uses registered bridges or stays partial. +- **The universe and timing bridges and V.A2's semantics.** The temporary-or-unlawfully-present inflow counts people who remain to year-end (`entrant_schedule.py:365–371`), and adjustments of status move people between categories without moving them in or out. +- **ACS stock proxies.** Recent arrivals in the ACS are survivors and stayers observed after entry, not arrivals (#218 §2.2). +- **Weight concentration and run size.** Seventy-five years of an open population on a Microcosm-sized frame is a larger run than any so far; OP1 measures memory and runtime on invented data at full size before OP10a. + +### Governance risks + +- **B2 outcome exposure.** This design's author read the parity ledger, which states B2's result, so the author is outcome-aware. Ruling d1659 requires a B2 successor's change to rest on evidence independent of that result. OP8's sub-parts (b) and (e) do not alter Track B's law, but (e)'s hand-off state would feed it. OP8(e) is built inside Track B's successor lane under its d1659 blinding, as the coordinator ruled (§10, decision 6). +- **Methodology principles are Max's.** §10 records his rulings. + +## 9. Staffing and scope assumptions behind every estimate + +- **Unit of effort.** One engineer-day is one day of reviewed output; one agent lane delivers about 4 engineer-days a week. Every lane-week figure is the engineer-day figure divided by 4. +- **Two OP lanes** in each phase, D1 and D2 in the demographic phase and E1 and E2 in the economic one, separate from Track B's two lanes. Elapsed figures assume both run at once. +- **Every range is an engineering judgment,** not demonstrated throughput. The sub-splits inside OP2, OP3, OP4, OP5 and OP8 are mine. Track B's figures in §3.4 are Track B's. Revision 6 raised OP0, OP2(b), OP3's bridges, OP5, OP7 and OP8(d) for the work the revision-5 review found missing. +- **Comparison with design B's B8.** B8's 40–70 d covered "2032/2050 and population extension" with income and wealth gates. This design prices more (births v2, emigration, demographic and labor alignment, six gates, the timing and exposure bridge, the horizon record and long-horizon comparisons) and excludes income and wealth. The difference is scope and the M6 assembly finding (§2.4), not a re-estimate of B8's items. +- **Excluded:** review and registration queues; Max's, the coordinator's and referees' time; data-access time for any restricted or requested source; Track B's insured-status rule; the items of §3.6; Track B's milestones; the Microcosm start's tasks; comparator-lane work for sealed comparisons; research after a failed gate. +- **Data.** ACS, NCHS and Census sources are public and assumed downloadable; SSA pages need the capture user agent. PSID inputs are assumed available locally for registered steps only. This was not verified for ACS and NCHS in this run. + +## 10. Decisions for Max + +1. **Approve the two-phase structure and the demographic phase now (76–113 d, estimate)?** Recommended: yes. Price the economic phase now, as here, but approve it when a B2 successor passes and Track B's B0.2 freezes J's record. +2. **Size immigration by the Trustees' gross positive inflow, with emigration as a separate exit law, rather than by net change?** Recommended: gross plus exits (#218's ruling; `entrant_schedule.py:37–42`). Net change has no person-level composition. +3. **Align by selecting whole people at fixed weights, keeping the unaligned run as the scored object?** Recommended: yes, as M6's decision 9 and #217 rule. Per-year reweighting (#412's REWEIGHT nodes) can come with the move into Microcosm if it reproduces the same margins and displacement. +4. **One convention for immigrants' pre-entry US covered earnings, applied to frame immigrants and to entrants alike:** zero under a first-entry assumption with a registered return-migration sensitivity, or censored (missing) with benefits suppressed until a bridge exists? Recommended: censored for gates and published benefits, with the zero convention as a labeled sensitivity, because a reported year of entry does not identify first entry (`entrant_domains.py:56–62`, `:215–219`). Under the censored convention, pre-entry years go to Track B's insured-status rule as `UNKNOWN`; under the zero convention they go as `CONVENTION_FILLED`. Either way, the zero convention resolves only pre-entry quarters: an entrant whose other statutory facts are unknown keeps the rule's named refusal (§6.1). +5. **Horizon admission past 2030:** every projected year past 2030 is published as conditional on named assumptions, with drift diagnostics, and never as a validated forecast; DYNASIM comparisons at 2050, 2065 and 2070 are registered, report-only, and blind. Recommended: yes. This is a methodology principle. +6. **Who builds OP8(e) (earnings at 16–24 and the hand-off to Track B's law)?** Recommended: Track B's successor lane, under its d1659 blinding, priced here; otherwise a lane d1659's terms clear. +7. **Include `gate_pop` (OP7, 6–9 d)?** Recommended: yes. It is the only scientific test of the population's composition over time; the rest of the demographic phase is conformance or alignment. +8. **Emigrants and benefits paid abroad:** in v1 emigrants leave the roster and OP12 reports insured emigrants as a named gap. Recommended: yes for v1; price an abroad ledger before any national-cost claim (M7). +9. **The registered-horizon convention (§2.9):** every production run projects to the baseline's last year, and shorter horizons are read as prefixes. Recommended: yes; it costs compute, not engineering. +10. **Gate an aligned scenario as an exception to M6's decision 9?** The ledger's alignment row asks for "gated SSA benefit and payment totals". This design meets it by gating the unaligned totals (OP12) and publishing the aligned totals report-only, so no gate scores an aligned run. An exception would gate the aligned totals too, in a separate production-scenario runner, with the unaligned gates kept as registered and no alignment target or corridor fitted to OP12's held-out SSA outcomes. Recommended: no exception; gate the unaligned totals only. + +### Rulings + +Max ruled d1925 on 23 October 2026, at revision 11: "Approve as recommended". The coordinator relayed his answers on 24 October 2026: + +| Decision | Ruling | +|---|---| +| 1, 7, 8, 9 | Start the demographic phase (76–113 d, estimate), including `gate_pop` and the 2013→2020 retrodiction. In v1, emigrants leave the roster, and OP12 reports insured emigrants as a named gap. Every production run projects to the registered horizon. The economic phase is priced now and approved once a B2 successor passes and B0.2 freezes J's record | +| 2 | Gross inflow, plus a separate emigration law | +| 3 | Select whole people at fixed weights, with the unaligned run as the scored object | +| 4 | Censored, with the zero convention as a labeled sensitivity | +| 5 | Years past 2030 are conditional, never validated. Max adopted this as a principle for every lane | +| 10 | No exception: OP12 gates the unaligned totals | + +The coordinator ruled the rest: +- **Decision 6.** Track B's successor lane builds OP8(e), under d1659's blinding. +- **Death alignment.** Under Max's ruling d1922 (23 October 2026), which approved the mortality lane's design (#558) with its mortality methodology, the coordinator ruled that the mortality lane's SM owns death alignment; this lane's alignment layer covers the other demographic and labor targets and consumes SM's (§6.4). + +## 11. Files read, commands run and exposure + +**Restricted-files list.** I read `~/microcosm-launch-evidence/dynasim-parity-20260909/RESTRICTED-FILES.md` first, in full, and opened nothing it lists. For revision 2 I reread its two entries dated 21 October 2026 (the B0.2 and B2-successor separation, and the U2 step-4 run 2 outputs); I have opened none of the folders they name, and I read only the title of draft PR #554. For revision 5 I hashed the holdout registry file from git without opening it. + +**Read for revisions 1 to 5.** +- *Instructions and plans:* `CLAUDE.md` (repository and parent); `docs/parity-ledger.md`; `docs/plans/microcosm-start.md`; `docs/plans/microcosm-start-registration-draft.md` (search matches only); Track B design revision 3 (§1–§10); design B's milestone table (`phase2-20260927/out/trackb-b.md`, lines 85–110); `docs/entrant-seam.md`; `docs/baselines.md` (lines 470–530). +- *Source:* `engine/loop.py`, `engine/entrant_schedule.py`, `engine/entrant_domains.py` and `baselines/fertility.py` in full; `engine/steps.py` (lines 100–209, 380–561); `engine/marital.py` (lines 338–404 and a search); `engine/assembly.py` (lines 1–30, 170–447); `engine/panel_builders.py` (lines 1–40 and a search); `engine/support.py` (lines 1–40, 215–260); `engine/rng.py` (lines 1–180); `engine/accounting.py` (lines 1–140); `engine/accounting_history.py` (lines 1–60); `engine/earnings_domain.py` (lines 1–25 and a search); `harness/m6_reporting.py` (lines 300–415); `baselines/base.py` (lines 1–80); `baselines/tr2026_intermediate.py` (lines 1–134); `baselines/cbo2026_long_term.py` (lines 1–45); `baselines/track_a.py` (lines 15–60); `baselines/__init__.py` (lines 15–40); `data/tr2026.py` (lines 1–60 and a search); `ss/statutory_aime.py` (lines 130–150); `scripts/first_estimates_birth_evidence.py` (lines 126–200 and a search); `scripts/fetch_nchs_asfr.py` (lines 1–25); `tests/baselines/test_invented_smoke.py` (lines 223–300); `min_benefit_track_m/coverage.py` (lines 1–30) and a search of `min_benefit_track_m/policy.py`; search matches only in `uk/household_transitions.py` (lines 747–851), `harness/m6_runner.py` (lines 1027, 1212, 1249), `tests/estimates/test_birth_evidence_artifact.py` (line 68) and `tests/track_u2/test_u2_isolation.py` (line 242). +- *Contracts and records:* `gates.yaml` (lines 995–1010, 1330–1340, 2895–2925, 5370–5450 and searches); `runs/gate_m6_candidate3_v1.json` (fields whose keys mention entrants, alignment, births or immigration); `data/external/tr2026/provenance.md` (lines 1–36 and a search); `data/external/cbo2026/provenance.md` (lines 25–60) and the top-level keys of the two CBO JSON files. +- *GitHub:* issues #412 and #151; PRs #217 and #218 (bodies, and their design documents fetched from the PR heads: #218 lines 1–315, 458–520 and 824–1124; #217 lines 1–330 and 652–857). +- *Web:* TR2026 Tables V.A2 and V.A3 (titles and column headers only, fetched 21 October 2026 with the `Wget/1.21.4` user agent). + +**Read for revision 6** (to check the revision-5 review's evidence before restating it): +- *Source and tests:* `engine/assembly.py` (lines 301–335); `engine/steps.py` (lines 528–561); `engine/panel_builders.py` (lines 150–167); `harness/m6_population.py` (lines 214–224, 339–350); `harness/m6_reporting.py` (lines 321–327); `harness/epuf_fill_gate.py` (lines 15–18, 134–139); `data/epuf.py` (lines 36–43); `engine/forward_earnings.py` (lines 697–712, 1528–1536); `track_b/gross_benefits.py` (lines 1079–1095); `tests/estimates/test_birth_evidence_artifact.py` (lines 330–372); `min_benefit_track_m/coverage.py` (lines 14–20). +- *Scripts and data:* `data/external/nchs_asfr_2024.json` (keys and the annual series' years); `scripts/fetch_nchs_asfr.py` (lines 55–63); `scripts/build_gate2_floors.py` (lines 625–632, 690–697, 740–745). +- *Plans and closed designs:* `docs/plans/microcosm-start-registration-draft.md` (lines 105–109); PR #218's design (lines 389–414, 1235–1247). +- *Web:* Social Security Act §§214 and 223 (fetched 23 October 2026 with the `Wget/1.21.4` user agent; text of §214(a)–(c) and §223(c)(1) read); POMS RS 00301.230 and RS 00301.240 (read by a fetch subagent on 23 October 2026). + +**Read for revision 9** (to check review r6's evidence): `engine/assembly.py` (lines 181–183); `docs/entrant-seam.md` (lines 59–65); `docs/plans/microcosm-start.md` (line 452, read for revision 1); POMS RS 00301.102 (read by a fetch subagent on 23 October 2026, sections A–D verbatim and the rest summarized; this design relies only on the verbatim sections, B.1–B.5). + +**Read for revision 12** (24 October 2026): the mortality lane's design (PR #558, `docs/design/mortality_groups_financing.md`, the file Max approved under d1922, SHA-256 `26e53d08…`): a keyword search that printed its first 50 lines naming SM, alignment, OACT, relative risks or normalization, and lines 1–12, 590–615, 728–775 and 905–925; a keyword search of `baselines/tr2026_intermediate.py` at `origin/master` `4fc2b9f4` for mortality, deaths and probabilities, which printed 18 matching lines from line 5 to line 214; the records of d1922 and d1925 in the local decision log. For revision 13: lines 130–160 of the same baseline file, and #558's §7.2 at its head on 24 October 2026, compared by `diff` with the approved file and found identical. + +**Commands run.** `docs/design/open_population_evidence/horizon_dependence.py` on invented data (output committed beside it); text searches of `src/`, `scripts/`, `tests/`, `docs/` and `data/external/` for migration, alignment, natality and ACS terms; a SHA-256 of the holdout registry file computed from git without printing it. + +**Exposure.** +- No real-data outcome was computed. No restricted file, Urban document, DYNASIM output, MINT table, Trustees cost table or B2 outcome file was opened. +- The parity ledger states B2's scored result, so this design's author is outcome-aware for B2 (§8). +- Printing `runs/gate_m6_candidate3_v1.json`'s entrant fields showed per-draw newborn counts and the person IDs of mothers whose scheduled births were dropped. They are committed artifact values; nothing from them but the ledger's 316 appears here. +- The closed PRs' design documents quote the 2026 V.A2 values and describe DYNASIM, MINT and PENSIM methods from public documents. This design uses none of those values. +- Reading `data/external/nchs_asfr_2024.json`'s keys printed the years of its annual series, not its rates. + +## 12. Review findings and where they are resolved + +### Delta reviews of revisions 11 and 12 + +Subfleet job `20261024-075934-openpop-review-r9c` (GPT-6.1 Sol), at `~/reviews/open-population-20261021/review-r9/review.md`, returned **APPROVE** with three minor findings. An Opus 5.5 reviewer in the main session, at `review-r9/review-opus.md` in the same folder, returned REVISE on its finding 1, which the coordinator ruled minor, plus seven minor findings. Revision 13 applies both. + +| Finding | Severity | Resolution in revision 13 | +|---|---|---| +| Sol 1. §6.4 attributes race and Hispanic origin to all entrants | Minor | §6.4 takes the review's sentence, extended as for Opus 5 | +| Sol 2. §8 keeps preapproval wording | Minor | §8 takes the review's sentences on OP8(e)'s builder and on methodology principles | +| Sol 3. Fidelity scope is implicit for deaths | Minor | OP6's row, §5.3 and §7 limit fidelity to the margins OP6 or OP9 selects or scales; death totals are report-only | +| Opus 1. Pointers into rewritten history | Major; ruled minor by the coordinator | §6.4 cites #558 by path, section and the file hash Max approved, not by commit; PR #557's description no longer reads as work in progress | +| Opus 2. Who ruled death alignment | Minor | §10, §6.4's heading and the revision log separate Max's ruling d1922 from the coordinator's boundary; the row for decisions 1, 7, 8 and 9 uses decision 8's recommended text, which d1925 approved | +| Opus 3. The §7 death property is ambiguous across years | Minor | §7 states it per year, on each replay's own roster | +| Opus 4. OP6's price rationale is unsupported | Minor | The revision log takes the review's sentence | +| Opus 5. §6.4 misstates #558's request and omits its other rows | Minor | §6.4 names newborns' and immigrants' attributes separately, notes OP8(b)'s `u_w`, and says where #558's other requests are met | +| Opus 6. Passive wording in §4; a premature claim about SM in §3.3 | Minor | §4 and §3.3 take the review's text | +| Opus 7. No reading record for revision 12 | Minor | §11 adds one; the baseline citation runs to line 159 | +| Opus 8. The revision log after the rewrite | Minor | The revision 7, 8 and 12 entries are amended | +| Opus 9. GitHub still serves the old commits | Minor, outside the design | No change: the coordinator reports that Max's choice keeps the old text in the PR's commits | + +### Review of revision 10 (r8) + +Subfleet job `20261023-071323-openpop-review-r8` (GPT-6.1 Sol), at `~/reviews/open-population-20261021/review-r8/review.md`, returned **APPROVE**: no blocking or major finding remained, and all five r7 findings were resolved. It asked for two minor clarifications, which revision 11 adds in its words. + +| Finding | Severity | Resolution in revision 11 | +|---|---|---| +| 1. The economic schedule omits a readiness assumption for monthly timing validation | Minor | §3.4 adds the review's sentence on I's mechanics and the observational timing gate | +| 2. OP11b's income scope is ambiguous | Minor | OP11b's row adds the review's sentence limiting the estimate to beneficiaries, benefits and Social Security income | + +### Review of revision 9 (r7) + +Subfleet job `20261023-064644-openpop-review-r7` (GPT-6.1 Sol), at `~/reviews/open-population-20261021/review-r7/review.md`, returned REVISE. It found r6's findings 2–9 resolved and finding 1 partly resolved, which its new finding 1 completes. + +| Finding | Severity | Resolution in revision 10 | +|---|---|---| +| 1. The zero convention invented a Social Security number assignment date | Major | §6.1 point 2 takes the review's sentences: the original assignment date, or the applicability determination, stays `UNKNOWN` under both conventions unless independently supported, and a dating sensitivity would need its own assumption and Max's decision; the r6 row below is corrected | +| 2. The POMS citation excluded the subsection behind its sentence | Minor | §6.1 cites RS 00301.102 B.1–B.5 and names workers not yet assigned a number; §11's reading record and the revision log say the same | +| 3. Two summaries contradicted the corrected dependencies | Minor | The summary and §8 take the review's sentences | +| 4. The widowhood invariant omitted the surviving-spouse condition | Minor | §7 takes the review's sentence and notes the same-year double death | +| 5. The publication condition withheld all OP11b comparisons | Minor | §6.2 limits it to OP11b's spouse and survivor outputs | + +### Review of revision 6 (r6) + +Subfleet job `20261023-062751-openpop-review-r6` (GPT-6.1 Sol), at `~/reviews/open-population-20261021/review-r6/review.md`, returned REVISE. It found revision 5's findings 1–3, 5–8, 10–12 resolved and 4 and 9 partly resolved, which its new findings 1 and 2 complete. I checked each new finding's evidence before acting on it (§11). + +| Finding | Severity | Resolution in revision 9 | +|---|---|---| +| 1. §214(c)'s requirements omit the exemption for numbers assigned before 2004 | Major | §6.1 point 2 takes the review's sentences: the rule first decides whether the requirements apply, exempting workers whose first Social Security number was assigned before 1 January 2004, then applies POMS RS 00301.102, checked on 23 October 2026; the assignment date is an input with provenance, `UNKNOWN` under both conventions unless independently supported (revision 10 removed revision 9's `CONVENTION_FILLED` date under the zero convention, after review r7); prior disability periods are `UNKNOWN` under both conventions; point 3 adds §223(c)(1)(A)'s elapsed-year endpoint for disability-insured status; §3.6, §4 and §8 updated | +| 2. The tolerance classes use the wrong candidate population for several gates | Major | §5.3 keeps the reference classes and makes candidate uncertainty gate-specific, with OP5 resampling only for candidates projected from OP5; OP0's records carry each gate's procedure; the administrative class distinguishes revisions to the same target year from changes between years; §4 records the review's exposure to the 2025 supplement's §5.J | +| 3. The CPS fallback does not admit the hand-off at 25 | Major | `gate_young_earn` admits earnings outcomes at 18–24 only (OP8, §3.2, §3.3, §3.5); the transition at 25 stays open, with a test of it listed in §3.6 unless J covers these entrants; §7 calls the support check a check, not an admission | +| 4. OP12 omits the Microcosm start's spouse and survivor condition | Major | OP12's row, dependency cell and §5.4 rule take the review's sentence; OP11b and §6.2 propagate it; §8's risk list adds it | +| 5. Dependencies and schedules omit prerequisites | Minor | OP0 waits for J's candidate years; OP9's final replay depends on OP8 and moves to T+50–76, with OP11b's T+68–109 unchanged; §3.4 states the schedules' assumptions; B4 prepares rather than declares open coverage (§3.4, §6.1) | +| 6. The emigration monotonicity property fails across a projection | Minor | §7 takes the review's one-year property and says it does not hold across years | +| 7. Two insured-status invariants contradict the interface | Minor | §7 takes the review's replacement; §6.1 point 1 records each year's origin so projected years stay labeled as model-generated | +| 8. Three mechanism descriptions overstate their code | Minor | §2.2 adds `synthetic_entry`; §2.3 says the entrant restrictions are declared and not shown to execute; the summary and §2.4 say the native panel support is pinned through 2022 rather than that every longer run refuses | +| 9. The d1659 cross-reference covers OP8(b) as well as (e) | Minor | §6.4 narrows it to OP8(e) and says OP8(b) is not by itself a B2 successor | + +### Review of revision 5 (r5) + +The independent review of revision 5 (Subfleet job `20261021-103508-openpop-review-r5`, at `~/reviews/open-population-20261021/review-r5/review.md`) returned REVISE. I checked each finding's evidence before acting on it (§11). + +| Finding | Severity | Resolution in revision 6 | +|---|---|---| +| 1. The fertility mechanism and OP2's differential test are wrong | Major | §2.2 takes the review's sentence on per-period redraws; §2.4 and finding 1 of the summary follow it; OP2(b) becomes live-roster fertility with persistent parity, tested against one kernel invocation with identical inputs and draws, plus persistent-parity properties (§7); OP2(b) re-priced from 3–5 to 4–6 d | +| 2. The birth gate's exposure inventory omits NCHS's 2016–2019 rates | Major | §2.7 and §4 disclose the 2016–2024 annual series, its consumer and its "reported, not tuned" standing; `gate_birth` is regression evidence by default, with independent admission only for observations or estimands OP0.1 shows unused (OP2, §3.2, §3.3); new condition `HOLDOUT_EXPOSED` (§8) | +| 3. Production immigration lacks the timing and exposure bridge | Major | §2.3 states the double filter; OP3 adds the component-specific bridge, the review's blocking sentence and a 2–3 d increase (controls, universe and timing bridges 5–7 d); §7 adds a property that detects duplicate survival filtering; new condition `TIMING_BRIDGE_UNRESOLVED` | +| 4. Annual quarters do not supply every fact insured status needs | Major | §6.1 point 2 names the non-quarter facts of §214(a), §214(c) and §223(c)(1), checked against the statute, with their provenance for entrants and refusal by name; the review's zero-convention sentence replaces the universal promise (§6.1, §10 decision 4); monotonicity is conditioned on fixed non-quarter facts and disability history (point 4); each output, the date last insured included, is bounded separately (point 5); quarter assignment follows POMS RS 00301.230 and RS 00301.240, checked (point 1); OP8(d) re-priced from 2–3 to 3–5 d; §3.6 adds a §214(c) bridge and citizenship changes | +| 5. A new EPUF salt is not an independent holdout | Major | §4 records `gate_epuf_fill`'s partition and H1's overlap; the EPUF arm needs explicit person fences or is regression evidence, and independent admission rests on unused CPS observations (OP8, §3.2) | +| 6. OP12 contradicts the gate-isolation rule | Major | OP12 now gates unaligned totals through the unaligned-only facade, with aligned totals report-only, so §1's and §5.1's rule holds for every gate; an aligned-scenario gate needs Max's exception (§10 decision 10), which would use a separate production-scenario runner and keep the unaligned gates; no target or corridor is fitted to OP12's held-out outcomes (§5.3, §5.4) | +| 7. Ledger closure exceeds what is tested | Major | §3.3 takes the review's sentence on earnings and disability coverage; entrants' benefit receipt stays open, with an entrant-specific test listed in §3.6; OP12 admits aggregate totals only; `gate_entrant_earn` admits only the combined initialization-and-projection result (§3.2) | +| 8. OP5 and OP7 lack date and relationship conventions | Major | OP5 freezes a reference date and mapping, group-quarters treatment and link reconstruction from the relationship item, with unknown links marked and coverage reported, re-priced to 5–8 d; OP7 compares with the 1 April 2020 census and a slice matched to ACS 2019's calendar-year collection, re-priced to 6–9 d; §5.2 adds the date mapping to every OP0 record | +| 9. One floor procedure cannot serve every reference | Major | §5.3 replaces it with three tolerance classes (survey microdata, administrative and vital-statistics aggregates, census counts), each with its own reference-side uncertainty, plus candidate sampling and Monte Carlo uncertainty; OP0 re-priced from 8–12 to 10–14 d | +| 10. The economic completion date omits prerequisites | Minor | §3.4 calls T+68–109 the modeled path to OP11b, states that OP12 completes 8–12 d after all its dependencies are ready and has no finite date while d947 is parked, and that the phase ends at the later of the two; the summary follows | +| 11. Further citation corrections | Minor | §2.4 cites the panel builders' native sources and the predeclared openers, and limits the exclusion to synthetic entrants absent from that support; §2.1 cites the reducer's transitive test (`:367`) and initializer test (`:336`); EPUF is described as staged outside the repository with committed provenance (§3.5, §4); §6.1 says G consumes assembled records through a declared adapter; OP11a restricts each comparison to the publisher's dimensions and marks V.A3's nativity unavailable | +| 12. The alignment report's representation is unspecified | Minor | §5.4 (OP6, OP9) specifies a complete margin, year and stratum representation with known zeros and unavailable cells distinct, passed to `build_alignment_displacement` on those keys, and the displaced set published separately; §7 updated; a terms list after the summary defines ASFR, TFR, AWI, EPUF and `u_w` | diff --git a/docs/design/open_population_evidence/horizon_dependence.py b/docs/design/open_population_evidence/horizon_dependence.py new file mode 100644 index 000000000..6315e3519 --- /dev/null +++ b/docs/design/open_population_evidence/horizon_dependence.py @@ -0,0 +1,155 @@ +"""Does a projection's early years depend on its end year? + +INVENTED DATA ONLY. No PSID, frame or survey record is read. + +``docs/design/open_population.md`` section 2.9 cites this script. It runs +the existing engine loop (``engine/loop.py``) twice on the same invented +roster, once to ``SHORT_END`` and once to ``LONG_END``, and compares the +person-year slices the two runs share. It does this twice: + +* closed: births only (``baselines/fertility.py``'s ASFR step); +* open: the same, plus immigrant cohorts scheduled for every year through + the run's end year with ``engine/entrant_schedule.py``. + +Run from the repository root with the package importable:: + + python docs/design/open_population_evidence/horizon_dependence.py + +The output this script printed for the design is committed beside it as +``horizon_dependence.txt``. +""" + +from __future__ import annotations + +import numpy as np +import pandas as pd + +from populace_dynamics.baselines.fertility import AsfrFertilityStep +from populace_dynamics.engine.entrant_schedule import build_entrant_schedule +from populace_dynamics.engine.loop import ( + SCHEDULED_ENTRIES_KEY, + MaritalStepResult, + PeriodModules, + ProjectionEngine, + SyntheticPersonIdAllocator, +) +from populace_dynamics.engine.rng import ProjectionModule +from populace_dynamics.engine.steps import advance_age + +START = 2025 +SHORT_END = 2035 +LONG_END = 2045 +N_PEOPLE = 400 +#: Invented constant hazards: 5 percent die each year; women 18-44 give +#: birth with probability 0.15 a year. +DEATH_PROBABILITY = 0.05 +BIRTH_RATE = 0.15 +#: Invented immigrant control, in thousands of weighted persons a year. +INFLOW_THOUSANDS = 0.003 + + +def mortality(frame, context, rng): + """Person-keyed deaths, as ``steps.apply_mortality`` draws them.""" + del rng + uniform = np.array( + [ + context.person_generator( + ProjectionModule.MORTALITY, person_id + ).random() + for person_id in frame["person_id"] + ] + ) + return frame.loc[uniform >= DEATH_PROBABILITY].reset_index(drop=True) + + +def unchanged(frame, context, rng): + return frame + + +def no_marriages(frame, context, rng): + return MaritalStepResult(sim_years=frame.iloc[0:0], births=pd.DataFrame()) + + +def no_composition(frame, context, marital, rng): + return frame + + +MODULES = PeriodModules( + mortality=mortality, + aging=advance_age, + marital_core=no_marriages, + fertility=AsfrFertilityStep( + asfr=lambda year: {age: BIRTH_RATE for age in range(18, 45)} + ), + disability=unchanged, + earnings=unchanged, + claiming=unchanged, + household_composition=no_composition, +) + +INITIAL = pd.DataFrame( + { + "person_id": np.arange(1, N_PEOPLE + 1), + "year": START, + "age": np.random.default_rng(1).integers(18, 40, N_PEOPLE), + "sex": np.where(np.arange(N_PEOPLE) % 2 == 0, "female", "male"), + "weight": 1.0, + "start_weight": 1.0, + } +) + +DONOR = pd.DataFrame( + { + "person_id": [9001, 9002, 9003], + "weight": [1.0, 2.0, 1.0], + "entry_age": [25, 30, 5], + "is_female": [True, False, True], + "source_year": 2024, + "peinusyr": 1, + "prcitshp": 4, + "penatvty": 100, + "foreign_born": [True, True, True], + } +) + + +def project(end_year: int, *, with_entrants: bool): + allocator = SyntheticPersonIdAllocator( + N_PEOPLE + 1, reserved_real_ids=frozenset(range(1, N_PEOPLE + 1)) + ) + metadata = {"synthetic_id_allocator": allocator} + if with_entrants: + schedule = build_entrant_schedule( + DONOR, + { + year: INFLOW_THOUSANDS + for year in range(START + 1, end_year + 1) + }, + allocator=allocator, + roster_columns=list(INITIAL.columns), + ) + metadata[SCHEDULED_ENTRIES_KEY] = schedule.as_metadata() + return ProjectionEngine(MODULES).project( + INITIAL, end_year=end_year, draw_index=0, metadata=metadata + ) + + +def compare(with_entrants: bool) -> None: + short = project(SHORT_END, with_entrants=with_entrants) + long = project(LONG_END, with_entrants=with_entrants) + label = ( + "open (births and scheduled entrants)" + if with_entrants + else ("closed (births only)") + ) + print(f"== {label}: end year {SHORT_END} against {LONG_END}") + for offset, year in enumerate(range(START + 1, SHORT_END + 1), start=1): + a = short.slices[offset][["person_id", "age"]].reset_index(drop=True) + b = long.slices[offset][["person_id", "age"]].reset_index(drop=True) + verdict = "identical" if a.equals(b) else "different" + print(f"{year}: rows {len(a)} and {len(b)}; slices {verdict}") + + +if __name__ == "__main__": + compare(with_entrants=False) + compare(with_entrants=True) diff --git a/docs/design/open_population_evidence/horizon_dependence.txt b/docs/design/open_population_evidence/horizon_dependence.txt new file mode 100644 index 000000000..ce9f21b40 --- /dev/null +++ b/docs/design/open_population_evidence/horizon_dependence.txt @@ -0,0 +1,22 @@ +== closed (births only): end year 2035 against 2045 +2026: rows 414 and 414; slices identical +2027: rows 412 and 412; slices identical +2028: rows 413 and 413; slices identical +2029: rows 419 and 419; slices identical +2030: rows 430 and 430; slices identical +2031: rows 432 and 432; slices identical +2032: rows 438 and 438; slices identical +2033: rows 434 and 434; slices identical +2034: rows 430 and 430; slices identical +2035: rows 422 and 422; slices identical +== open (births and scheduled entrants): end year 2035 against 2045 +2026: rows 417 and 417; slices different +2027: rows 419 and 420; slices different +2028: rows 420 and 420; slices different +2029: rows 429 and 430; slices different +2030: rows 443 and 445; slices different +2031: rows 447 and 445; slices different +2032: rows 452 and 454; slices different +2033: rows 448 and 448; slices different +2034: rows 446 and 448; slices different +2035: rows 442 and 444; slices different