From d8d153d36c028e1a52ae0615946f2d6c5e35f8be Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Jul 2026 13:12:01 -0400 Subject: [PATCH 01/18] M7 design doc: title, metadata, revision log (incremental) Co-Authored-By: Claude Fable 5 --- docs/design/m7_trust_fund_accounting.md | 58 +++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 docs/design/m7_trust_fund_accounting.md diff --git a/docs/design/m7_trust_fund_accounting.md b/docs/design/m7_trust_fund_accounting.md new file mode 100644 index 00000000..599b5a46 --- /dev/null +++ b/docs/design/m7_trust_fund_accounting.md @@ -0,0 +1,58 @@ +# M7 trust-fund accounting — design and the M2-reproduction / balance-identity gate proposal (draft for referee) + +- **Design id**: `2026-07-14-m7-trust-fund-accounting` +- **Roadmap**: [#113](https://github.com/PolicyEngine/populace-dynamics/issues/113) + M7 (full revenue + trust-fund accounting), the milestone after #113 M6 (the + projection engine) and before #113 M8 (integrated scoring). Program-design + anchors: #74 (the anchor catalogue, the "Rosetta stone" anchor 2), #100 + (W1/W2/W3 seams), #106 (external review). Depends on M6 exposing the §6 levels + (`docs/design/m6_projection_engine.md` §6) on the projected panel. +- **Status**: DESIGN (draft, revision 1) — **for the adversarial fable referee + round, which follows the in-flight `gate_m6` verdict** (this document does not + trigger it). **This document edits no `gates.yaml` cell, moves no threshold, + builds no floor, writes no test, and runs no scored anything.** The proposed + `gate_m7` in §6 is a *proposal for the referee*, not a lock. +- **What M7 is, in one sentence**: a **deterministic accounting layer** that + takes M6's already-realized person-period panel plus vintage-pinned SSA + parameters and emits, per projection year, taxable payroll, payroll-tax + revenue, benefit outlays by beneficiary class, and a trust-fund balance + ledger — reproducing M2's committed pseudo-projection numbers exactly on the + M2 frame, and lifting the same arithmetic onto M6's open panel as report-only + levels. +- **What M7 certifies (proposed)**: two **internal** identities — (1) the + **M2-reproduction identity** (M7's accounting on the M2 setup reproduces + `runs/m2_pseudo_projection_v1.json`'s committed numbers, or names every + delta) and (2) **exact balance-identity closure** (`start + revenue + + interest − outlays = end`, residual `== 0` to floating point, on every + projection year). It **explicitly does not gate against external SSA/Trustees + aggregates** — those enter as **report-only** anchors under a level-vs- + composition caveat (§5). This is the M2 precedent ("levels are frame-relative; + signs and orderings are the transportable content") carried into M7. +- **The one caveat the referee must weigh first**: the roadmap #113 M7 row asks + to *"[r]eproduce the corresponding TR baseline deficit within a pre-registered + tolerance; per-provision balance vs the Five-Approaches A-tables in LEVELS, + not just ordinally."* That is an **external-level** gate. M2 established — and + this design argues (§5.3, §8 decision 1) — that a **1,549-career PSID survey + panel is not the covered-worker universe**, so external *levels* are not + honestly gradable on this frame; only internal identities and normalized + shapes are. §6 therefore proposes an internal gate and §8 decision 1 surfaces + the contradiction with the roadmap wording for the referee to adjudicate, + rather than silently resolving it. +- **Evidence base cited by path+field**: the roadmap (#113 M7 row, verbatim in + §1); the committed M2 pseudo-projection (`runs/m2_pseudo_projection_v1.json`, + `scripts/m2_pseudo_projection.py`, commit `747966cd`, `pe_us_revision + bf71be3b`); the SSA parameter/benefit oracle (`ss/params.py`, `ss/benefits.py`); + the M6 handoff (`docs/design/m6_projection_engine.md` §6, §2.8.10); the M4 + disability gate (`gates.gate_m4`, `disability_hazard_sim.py`, + `disability_conversion.py`); the Mermin/Smith anchors + (`scripts/replication_cost_ordering.py`, `scripts/replication_mermin_rows.py`); + the external-vintage guards (`engine/refit.py:825-838`, + `harness/m6_inputs.py:198-250`). + +## Revision log (finding → section) + +- Revision 1 seeds the document for the referee round. No findings yet; the + referee's verdict and any ten-decision adjudication will be mapped here in + revision 2, exactly as the M6 doc maps PR #170's round. + + From 08b17ec538594e05aba220189916f518146abbc7 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Jul 2026 13:13:19 -0400 Subject: [PATCH 02/18] =?UTF-8?q?M7=20design=20doc:=20=C2=A71=20summary=20?= =?UTF-8?q?+=20=C2=A72.1=20M6=20handoff=20inputs=20(incremental)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- docs/design/m7_trust_fund_accounting.md | 89 +++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/docs/design/m7_trust_fund_accounting.md b/docs/design/m7_trust_fund_accounting.md index 599b5a46..c1951caf 100644 --- a/docs/design/m7_trust_fund_accounting.md +++ b/docs/design/m7_trust_fund_accounting.md @@ -55,4 +55,93 @@ referee's verdict and any ten-decision adjudication will be mapped here in revision 2, exactly as the M6 doc maps PR #170's round. +## 1. Summary + +M7 is the **trust-fund accounting layer** of the roadmap. The #113 M7 row reads, +verbatim: + +> **Full revenue + trust-fund accounting**: OASDI cost/income rates, trust-fund +> ratio path, 75-yr actuarial balance in % of taxable payroll | *gate:* Reproduce +> the corresponding TR baseline deficit within a pre-registered tolerance; +> per-provision balance vs the Five-Approaches A-tables in LEVELS, not just +> ordinally | *unlocks:* The Rosetta stone (#74 anchor 2) graded in its own units + +M2 already built this accounting **once**, on a *closed* observed cohort: the +`scripts/m2_pseudo_projection.py` pseudo-projection added "taxable payroll, +combined-OASDI revenue, claiming × survival outlays on a calendar ledger, a PV +balance analogue, and a calibrated-reserve exhaustion year" to the #115 common +frame of 1,549 real PSID careers born 1943–1957 (`runs/m2_pseudo_projection_v1.json`). +M2 named its own limits precisely: *levels are frame-relative by construction and +are NOT graded; the transportable content is signs, orderings, and delta- +orderings.* M7 is the same accounting, generalized two ways: (a) it runs on M6's +**open** projected panel (immigration entrants, forward earnings, DI, forward +couple formation), and (b) it adds the beneficiary classes M2 excluded (DI +disabled-worker, 402(b)/(c)/(e)/(f) auxiliary), each **bounded by what its gate +actually certified** (§2.6). + +**The layer is deterministic (§3).** All stochastic content — every earnings +draw, mortality draw, marital transition, claiming draw — is realized *upstream* +in M6's wave loop. M7 consumes a fixed panel and computes sums, caps, products, +and a recursion. Given the same panel and the same pinned parameters, M7's +accounts are **byte-identical**. There is no RNG at the accounting layer. + +**M7 runs in two modes**, and the distinction is load-bearing for the gate: + +1. **The M2-reproduction run** (the internal anchor, §5.1): feed M7's accounting + engine the *exact M2 setup* — the closed #115 frame, OASI-only, wage-indexed + real dollars, the calibrated reserve, no DI / no auxiliary / no immigration — + and it must emit `runs/m2_pseudo_projection_v1.json`'s committed numbers, or + name every delta. This isolates the **arithmetic** from the projection. +2. **The M6-panel run** (the deliverable levels): the same arithmetic on M6's + open panel, producing the OASDI cost/income-rate and balance path — carried + **report-only** against external Trustees corridors under the level-vs- + composition caveat (§5.3). + +**What M7 proposes to gate (§6)** is neither an external-level match nor an +ordering: it is **two internal identities** — the M2-reproduction and the +exact balance-identity closure (`residual == 0`). The choice not to gate the +external TR deficit *in levels* — despite the roadmap row's wording — is the +central design judgment, argued in §5.3 and surfaced for the referee in §8 +decision 1. It follows M2's discipline directly: on a survey panel, the honest +certifiable content is arithmetic self-consistency and reproduction, not a +levels-match to a universe the panel does not represent. + +## 2. Scope — the per-projection-year accounting on the projected panel + +The accounting is defined per projection year `y` over M6's panel, aggregable by +cohort. Everything below is a pure function of (the panel, the pinned SSA +parameters); §3 states the determinism law that makes that precise. + +### 2.1 The inputs M7 consumes from M6 (the §6 handoff) + +M6 §6 ("M7 interface sketch — levels the engine must expose") already pins the +handoff. M7 **binds to exactly those exposed levels** and computes no dynamics of +its own. Quoting the M6 contract, M7 consumes, keyed by `(year)`: + +- **covered / taxable earnings aggregate by year** — `Σ w · min(earnings_y, + taxable_max_y)`, with **both capped and uncapped** person earnings exposed so + cap-reform provisions (`cap_150k`, `elimination`) recompute without re- + simulation (M6 §6; M2 `revenue_side.cap_150k`, `payroll_increments`); +- **the taxable-maximum interaction** — each person's year-`y` earnings and the + year-`y` wage base; +- **benefit outlays by type by year** — OASI retired-worker, DI disabled-worker, + 402(b)/(c)/(e)/(f) auxiliary, survival-weighted on the calendar (M4 DI + + auxiliaries; FRA conversions per `disability_conversion.py`); +- **immigration entries by year** — the synthetic entrant cohorts M2 structurally + lacks (M2's frame is *closed*, `n_common_frame 1549`, `weight_sum 33696344.0`); +- **the per-year alignment-layer adjustments** — the versioned interventions M6 + applies each year (M6 §4.8), so M7 reports scheduled-vs-payable on an *audited* + alignment (#113 named-hard-part 2); +- **the OASDI rate constants and Trustees vintage assumptions** — the pe-us rate + nodes where they exist (M2 `revenue_side.oasdi_combined_rate.combined 0.124`) + and the discount / interest / CPI assumptions M2 carries as TR-cited constants + (M2 `balance_analogue.discount_rate 0.029`, `tr_vintage_cite`), which become + M7's versioned alignment inputs (§4). + +**Boundary discipline.** M6 "stops at exposing these levels"; M7 "lifts it onto +the open panel." M7 therefore introduces **no new stochastic law and reads no +gate M6 did not already certify** — it is arithmetic over M6's output plus §4's +parameter bindings. If a level M7 needs is *not* in M6's exposed surface, that is +an M6 gap to be raised against M6 §6, not silently synthesized here (§8 decision 7). + From 31eb76198766d23926bb5ecea2d63936209e0f76 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Jul 2026 13:14:46 -0400 Subject: [PATCH 03/18] =?UTF-8?q?M7=20design=20doc:=20=C2=A72.2=20taxable?= =?UTF-8?q?=20payroll/revenue=20+=20=C2=A72.3=20outlays=20by=20class=20(in?= =?UTF-8?q?cremental)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- docs/design/m7_trust_fund_accounting.md | 94 +++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/docs/design/m7_trust_fund_accounting.md b/docs/design/m7_trust_fund_accounting.md index c1951caf..0be2b86b 100644 --- a/docs/design/m7_trust_fund_accounting.md +++ b/docs/design/m7_trust_fund_accounting.md @@ -144,4 +144,98 @@ gate M6 did not already certify** — it is arithmetic over M6's output plus §4 parameter bindings. If a level M7 needs is *not* in M6's exposed surface, that is an M6 gap to be raised against M6 §6, not silently synthesized here (§8 decision 7). +### 2.2 Taxable payroll and payroll-tax revenue (employer + employee, wage-base cap) + +**Taxable payroll.** For each person `i` and covered year `y`, + +``` +taxable_earnings[i,y] = min( earnings[i,y] , wage_base(y) ) +taxable_payroll[y] = Σ_i w[i,y] · taxable_earnings[i,y] +``` + +where `w[i,y]` is M6's per-year calibrated weight and `wage_base(y)` is the +contribution-and-benefit base. The cap is the committed `creditable_history` +convention (`ss/benefits.py:68-75`, "cap each year's earnings at that year's wage +base") applied over **all** working years — M2's `taxable_payroll_convention` +notes it reuses the AIME-convention per-year capping *"but over ALL working +years (every covered year pays tax), not the highest-35 selection."* `wage_base(y)` +is a step function read from pe-us (`ss/params.py:151-160`, `wage_base_for`). + +**Revenue.** Payroll-tax income is the combined OASDI rate on taxable payroll: + +``` +revenue[y] = rate_combined · taxable_payroll[y] + = ( rate_employee + rate_employer ) · taxable_payroll[y] +``` + +The employer and employee halves are **both** counted (the task's employer + +employee requirement): `rate_employee = rate_employer = 0.062`, summing to the +`rate_combined = 0.124` M2 loaded from `gov/irs/payroll/social_security/rate/ +{employee,employer}` (26 USC 3101(a) employee + 3111(a) employer). This is the +**scheduled-rate** convention a Trustees projection uses, applied to all taxable +payroll — not the historical rate ramp (M2 `named_deltas`: "combined OASDI rate +from the pe-us statute series (12.4%) … as the current-law scheduled rate"). + +**Cap-reform recomputation.** Because M6 exposes **uncapped** person earnings +(§2.1), the two revenue-side provisions recompute without re-simulation: +`cap_150k` raises the base to $150k stated in 2016 dollars, wage-indexed by NAWI +to each earnings year (42 USC 430; M2 `revenue_side.cap_150k`); `elimination` +removes the cap (`min(earnings, ∞) = earnings`); `payroll_plus_{1,2}pp` add +`0.01`/`0.02` to `rate_combined`. Each is a pure recomputation on the exposed +levels. + +**The OASI-vs-DI rate split is an open decision (§8 decision 4).** Statute splits +the 12.4% into OASI (10.6%) and DI (1.8%). M2 applied the *combined* 12.4% against +*OASI-only* outlays — a deliberate asymmetry that drives its positive baseline +balance (§2.4, §5.3). M7's "OASI(+DI)" scope must state, per run, whether revenue +is allocated to a combined OASDI fund or split across two funds; the M2-repro run +(§5.1) must reproduce M2's combined-rate / OASI-outlay convention exactly. + +### 2.3 Benefit outlays by beneficiary class + +The outlay convention is M2's, generalized. For a retired worker, M2 places at +calendar year `birth_year + a`: + +``` +outlay[i, a] = 12 · PIA[i] · Σ_{claim c ≤ a} pmf_c(i) · benefit_factor(c) · S(62→a | i) +``` + +where `pmf_c` is the B2 claim-age distribution, `benefit_factor(c)` the 402(q)/(w) +early-reduction / delayed-credit factor (`ss/benefits.py:134-164`), and `S` the +B1 NCHS-2023 × PSID-band survival weight (M2 `outlay_side.convention`). `PIA[i]` +is `pia(aime(history), eligibility_year)` (`ss/benefits.py:100-131`). M7 sums +`Σ_i w[i,y] · outlay[i,y]` by class: + +- **OASI retired-worker** — the M2 class, unchanged. Own AIME→PIA→claim-factor, + survival-weighted. +- **DI disabled-worker** — the M4 addition. **Bounded by `gate_m4`**: the M4 gate + is *anchor-based* and certifies the work-limitation **incidence/recovery + hazards**, the disabled-occupancy **prevalence stock** (`prevalence.50-59`), + and the near-FRA **exit composition** (retirement-vs-return, Table 50 + dominance) — but its `covers` field states plainly *"no SSA DI LEVEL is + gated."* So the disabled **headcount trajectory** feeding DI outlays rides + certified shape/dominance, while the **DI benefit dollar level** is + report-only (the disability PIA, like every PIA, is never gated; M6 §2.8.3a). + The **DI→retirement conversion at FRA** (`disability_conversion.py`) moves the + disabled worker onto the retired-worker rolls at FRA — the "conversion column" + of Table 6.B5.1. +- **402(b)/(c) spouse and 402(e)/(f) survivor auxiliary** — the M3/household + addition. `spousal_benefit` (`ss/benefits.py:205-236`) and `widow_benefit` + (`ss/benefits.py:266-328`) encode the excess-spouse and widow(er) amounts + including dual entitlement, the RIB-LIM, and the 71.5% survivor floor. These + require M3 couple/household structure (who is married to whom, who survives + whom) — **bounded by `gate_2` (2b household composition, 2c couple formation) + and mortality**. Their rate constants have **no pe-us node** and are carried as + statute-cited constants (§4.3, the LOUD gap). + +**The unifying certification rule.** Across all three classes, **every benefit +dollar level is report-only** (AIME/PIA/claiming/auxiliary are never gated). What +*is* certified is the **population composition** that determines *who* draws +*which* class in *which* year — marital state (gate_2), disability state +(gate_m4), survival (mortality), earnings (gate_1, gate_m6). M7 outlays are thus +"certified-composition × report-only-level" products. This is the exact meaning +of the scope phrase "OASI(+DI, bounded by what M4/gate-2 actually certified)": +M7 does not manufacture certified benefit levels the underlying gates declined to +certify. §2.6 makes the boundary explicit per class. + From 695bbd16d0a320fe99a29f67be5b267c2d3fd466 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Jul 2026 13:16:22 -0400 Subject: [PATCH 04/18] =?UTF-8?q?M7=20design=20doc:=20=C2=A72.4=20balance?= =?UTF-8?q?=20identity=20+=20=C2=A72.5=20COLA/indexation=20+=20=C2=A72.6?= =?UTF-8?q?=20DI/OASI=20boundary=20(incremental)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- docs/design/m7_trust_fund_accounting.md | 94 +++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/docs/design/m7_trust_fund_accounting.md b/docs/design/m7_trust_fund_accounting.md index 0be2b86b..6d9d01b7 100644 --- a/docs/design/m7_trust_fund_accounting.md +++ b/docs/design/m7_trust_fund_accounting.md @@ -238,4 +238,98 @@ of the scope phrase "OASI(+DI, bounded by what M4/gate-2 actually certified)": M7 does not manufacture certified benefit levels the underlying gates declined to certify. §2.6 makes the boundary explicit per class. +### 2.4 The trust-fund balance identity + +The per-year ledger is the OASDI fund recursion: + +``` +TF[y] = TF[y-1] + revenue[y] + interest[y] − outlays[y] (I) +interest[y] = interest_rate(y) · TF[y-1] (start-of-year-balance convention) +``` + +with `TF[y_0-1] = reserve_0` the opening reserve. From it derive the two headline +Trustees objects the #113 M7 row names: + +- **the trust-fund ratio path** — `ratio[y] = TF[y-1] / outlays[y]`, start-of-year + assets as a percent of that year's cost (the standard SSA definition); +- **the 75-year actuarial balance in % of taxable payroll** — + `balance = [ PV(revenue) + reserve_0 − PV(outlays) − PV(target_ending_reserve) ] + / PV(taxable_payroll)` in the summarized-rate form, or M2's flow-only analogue + `[PV(revenue) − PV(outlays)] / PV(taxable_payroll)` (M2 `balance_analogue`, + discount `0.029`). + +**Two accounting views, which M7 must carry and reconcile.** M2 deliberately ran +two: a **discounted** PV balance analogue and an **undiscounted, reserve- +calibrated** exhaustion ledger (M2 `named_deltas`: "two accounting views, both +frame-relative"). The exhaustion year is the first `y` with `TF[y] < 0` +(fractional, linearly interpolated; M2 `exhaustion_analogue`). Identity (I) is an +**accounting identity** — it must close to floating-point zero by construction if +the components are materialized consistently. That closure is one half of the +proposed gate (§6): for every year `y`, the artifact carries `TF[y-1]`, +`revenue[y]`, `interest[y]`, `outlays[y]`, `TF[y]` independently, and a referee +can recompute (I) and confirm the residual is `0`. It is **non-vacuous** because a +dropped beneficiary class, a double-counted employer half, or a mis-discounted PV +breaks it — the same reconcile-to-`0.0` discipline M6 applied to its recombination +identity (M6 candidate-16 residual `1.7e-18`, "reconciled to 0.0"). + +**Interest and the opening reserve are LOUD input gaps (§4.3).** `interest_rate(y)` +(the trust-fund's special-issue yield) has **no pe-us node** — M2 confirms "no +policyengine-us rate node" for the TR rate and carried `discount_rate 0.029` as a +TR-cited constant. The opening reserve M2 did not source at all: it **calibrated** +`reserve_0 = 7,889,236,006,574.16` so the baseline exhausts in Smith's 2034 year +(M2 `calibration_disclosure`). Whether M7 keeps the calibrated-reserve convention +or binds an actual SSA Trustees opening-balance series is §8 decision 3. + +### 2.5 COLA and awards indexation + +Two distinct indexation channels feed the accounts, and only one is sourced today. + +- **Awards indexation (present in pe-us).** Bend points and the wage base are + NAWI-indexed at *eligibility* (415(a): `bend_points(year)` uses `NAWI(year−2) / + NAWI(1977)`, `ss/params.py:138-149`; the wage base is its own NAWI-driven step + series). This is fully sourced from pe-us and **vintage-pinned exactly as M6 + §2.8.10.2 pins it**: realized NAWI ≤2014, `I_proj` beyond — never realized + post-`T*` NAWI on any scored path. For a forward projection to 2100, future + eligibility years read projected NAWI; M7 inherits M6's wage-index surface + rather than re-deriving it (§8 decision 6). +- **Benefits-in-payment indexation / COLA (the LOUD gap, §4.3).** After a worker + claims, the benefit is uprated annually by the COLA (CPI-W, 215(i)). **pe-us's + `ss/` machinery applies no COLA** and binds no CPI-W series — `ss/benefits.py` + computes the claim-year benefit only. M2 sidestepped this by working in + **wage-indexed real (2048 age-60-indexing) dollars**, in which a benefit is + carried at constant real PIA across ages — COLA and NAWI-deflation net out of + the *level* convention, so no explicit CPI-W series is needed. The Mermin + `reduced_cola` provision (COLA − 0.4pp) is then a **benefit-side encoding** + reused verbatim (M2 `outlay_side`), not a nominal-series perturbation. + +**The consequence for M7 is a nominal-vs-real fork (§8 decision 2).** If M7 keeps +M2's **real** convention, no CPI-W series is required and interest is a *real* +rate (2.9%); the accounts stay comparable to M2. If M7 goes **nominal** (the units +a Trustees report actually prints), it must bind a CPI-W / COLA series *and* a +nominal special-issue interest series — **neither has a pe-us node** — and every +benefit-in-payment path grows by COLA. The two are a coherent pair (real flows ↔ +real interest; nominal flows ↔ nominal interest + COLA); mixing them breaks +identity (I). M7 must declare the convention per run; the M2-repro run (§5.1) is +real by construction. + +### 2.6 The DI / OASI certification boundary (what M4 and gate-2 actually certified) + +Making the scope phrase "bounded by what M4/gate-2 actually certified" operational, +per class: + +| Class | Composition certified by | Level status | +|---|---|---| +| OASI retired-worker | earnings (gate_1/gate_m6), claiming mix, survival | **report-only** (PIA never gated) | +| DI disabled-worker | gate_m4 hazards + `prevalence.50-59` stock + Table-50 exit **dominance** (all shape/dominance) | **report-only** (M4: "no SSA DI LEVEL is gated") | +| DI→retirement conversion at FRA | gate_m4 exit composition; `disability_conversion.py` | **report-only** level | +| 402(b)/(c) spouse | gate_2b/2c household + couple formation | **report-only** (aux rate = statute constant) | +| 402(e)/(f) survivor | gate_2b + mortality (who survives whom) | **report-only** (aux rate = statute constant) | + +Every level is report-only; only composition is certified. M7 must **not** present +any beneficiary-class dollar aggregate as a certified level, and must **not** claim +a certified DI trust-fund balance — the DI fund is a report-only lift of a class +whose levels no gate certified. The auxiliary classes additionally depend on M3 +tranches (2b/2c) whose own lock status bounds them; if a tranche M7 leans on is not +locked at run time, that class is disclosed report-only with its tranche gap named. + From a6b496e563a8d9affd4fb478013a0b4578aef2b7 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Jul 2026 13:18:43 -0400 Subject: [PATCH 05/18] =?UTF-8?q?M7=20design=20doc:=20=C2=A73=20determinis?= =?UTF-8?q?m=20law=20+=20=C2=A74.1=20binding=20table=20(incremental)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- docs/design/m7_trust_fund_accounting.md | 67 +++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/docs/design/m7_trust_fund_accounting.md b/docs/design/m7_trust_fund_accounting.md index 6d9d01b7..11f25c31 100644 --- a/docs/design/m7_trust_fund_accounting.md +++ b/docs/design/m7_trust_fund_accounting.md @@ -332,4 +332,71 @@ whose levels no gate certified. The auxiliary classes additionally depend on M3 tranches (2b/2c) whose own lock status bounds them; if a tranche M7 leans on is not locked at run time, that class is disclosed report-only with its tranche gap named. +## 3. The determinism law + +**Law.** *Given the same M6 panel and the same pinned parameter bundle (§4), the +M7 accounts are byte-identical across runs, processes, and platforms. There is no +stochastic element at the accounting layer.* + +This is stronger than M6's discipline and simpler to guarantee, because M7 +consumes no randomness. Every stochastic draw — earnings, mortality, marital +transitions, claiming age, disability incidence, immigrant entry — is realized +**upstream** in M6's wave loop and is already a fixed column of the panel M7 +reads. M6 owns a projection RNG stream registry (M6 §3, the `(draw × module × +period × person)` spawn tree); **M7 owns no RNG stream and spawns none.** The +accounting is a pure function + +``` +accounts = A( panel , params ) with no rng argument +``` + +built from caps (`min`), products, weighted sums (`Σ w·x`), a discount, and the +recursion (I). Determinism therefore reduces to two mechanical obligations: + +1. **Pinned reduction order.** Floating-point addition is non-associative, so + every aggregate `Σ_i w[i,y]·x[i,y]` fixes a canonical iteration order (sort by + `(person_id, year)`) and a fixed dtype, so the summed bytes do not depend on + row order, thread count, or grouping. This is the M7 analogue of M6's + draw-by-draw byte-identity (M6 candidate-16 "RNG-neutral … byte-identical + draw-by-draw"); here it is reduction-order neutrality. +2. **Pinned parameter bytes.** The parameter side is fully determined by the + pe-us 1.752.2 pin plus the statute/TR constants (§4), each vintage-asserted and + hash-gated (§4.4). No parameter is read from the environment beyond the pinned + pe-us directory. + +**Verification is trivial and belongs in the gate's determinism check:** run M7 +twice on the same panel and byte-diff the artifact (modulo the wall-clock +`elapsed_seconds` field, as M2 already excludes). Any difference is a defect — +an unpinned reduction, a dict-ordering leak, or a stray RNG call — not noise. The +determinism law is what makes the M2-reproduction identity (§5.1) a *byte* claim +rather than an approximate one. + +## 4. Input bindings — the SSA series, vintage-pinned with tamper gates + +M7's parameter side must be pinned to the same bar M6 §2.8.10 set for its external +references: fixed source, fixed vintage, tamper-evident, and **loudly flagged** +where the series does not exist in policyengine-us and would need a 3d-style +amendment. The deployment pin is **policyengine-us 1.752.2** (the frame pin, +`data/deployment_frame.py`, shared with every `gate_w1` artifact and adopted by M6 +§2.8.10.2). The vintage boundary `T* = 2014` is inherited: realized values ≤2014, +`I_proj` projections beyond, never realized post-`T*` NAWI on a scored path +(`engine/refit.py:825-838` `validate_external_vintage` raises on `vintage > 2014`). + +### 4.1 The binding table + +| Series | Source | pe-us node (1.752.2) | Status | +|---|---|---|---| +| Payroll tax rate (employee 6.2% / employer 6.2%) | 26 USC 3101(a)/3111(a) | `gov/irs/payroll/social_security/rate/{employee,employer}` | **present** | +| Wage base (taxable max) | 42 USC 430 | `gov/ssa/social_security/wage_base.yaml` | **present** (realized ≤2014, Trustees/`I_proj` beyond) | +| NAWI (average-wage index) | SSA determinations | `gov/ssa/nawi.yaml` | **present** (realized ≤2014, projections beyond) | +| PIA formula factors (90/32/15) | 42 USC 415(a) | `gov/ssa/social_security/pia/formula_factors.yaml` | **present** | +| FRA schedule | 42 USC 416(l) | `gov/ssa/.../full_retirement_age_by_birth_year.yaml` | **present** | +| Early-reduction & delayed-credit rates | 42 USC 402(q)/(w) | `gov/ssa/.../retirement_age_adjustment/...` | **present** | +| 1978-base bend constants ($180 / $1,085) | 42 USC 415(a)(1)(B) | — (statute constant, cross-checked to pe-us thresholds, `ss/params.py:60-62,340-354`) | **statute constant** | +| Auxiliary 402(b)/(c)/(e)/(f) rate constants | 42 USC 402(b)/(c)/(e)/(f)/(k)/(q) | **NONE** | **GAP → §4.3** | +| COLA / CPI-W (benefits-in-payment) | 42 USC 415(i) | **NONE in `ss/`** | **GAP → §4.3** (nominal runs only) | +| Trust-fund interest rate (special-issue yield) | TR intermediate | **NONE** | **GAP → §4.3** | +| TR ultimate assumptions (real int 2.9%, CPI 2.7%, real-wage diff 1.13%) | 2014 OASDI TR Table V.B1 | **NONE** | **GAP → §4.3** | +| Trust-fund opening reserve | SSA TR historical | **NONE** | **GAP → §4.3** (M2 *calibrated* it) | + From 3c5ee1089a94fb6182da8ce14659debd9ec985ea Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Jul 2026 13:20:04 -0400 Subject: [PATCH 06/18] =?UTF-8?q?M7=20design=20doc:=20=C2=A74.2=20exposed?= =?UTF-8?q?=20+=20=C2=A74.3=20LOUD=20gaps=20+=20=C2=A74.4=20tamper-gate=20?= =?UTF-8?q?factory=20(incremental)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- docs/design/m7_trust_fund_accounting.md | 94 +++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/docs/design/m7_trust_fund_accounting.md b/docs/design/m7_trust_fund_accounting.md index 11f25c31..22e7d1c1 100644 --- a/docs/design/m7_trust_fund_accounting.md +++ b/docs/design/m7_trust_fund_accounting.md @@ -399,4 +399,98 @@ amendment. The deployment pin is **policyengine-us 1.752.2** (the frame pin, | TR ultimate assumptions (real int 2.9%, CPI 2.7%, real-wage diff 1.13%) | 2014 OASDI TR Table V.B1 | **NONE** | **GAP → §4.3** | | Trust-fund opening reserve | SSA TR historical | **NONE** | **GAP → §4.3** (M2 *calibrated* it) | +### 4.2 What pe-us 1.752.2 exposes (the revenue and own-benefit side) + +The entire **own-benefit** formula and the **revenue** rate/base are sourced from +the pinned pe-us tree with no hand-typing beyond the two statutory 1978-base bend +constants (`ss/params.py` docstring; `load_ssa_parameters` reads `nawi.yaml`, +`wage_base.yaml`, `pia/formula_factors.yaml`, `full_retirement_age_by_birth_year +.yaml`, the early/delayed adjustment rates, and cross-checks derived bend points +against pe-us's stored thresholds and `NAWI(1977) = 9,779.44`, `ss/params.py:334`). +These carry the M6 §2.8.10.2 vintage rule unchanged. So the **income side** and +the **OASI retired-worker level** are fully pe-us-sourced; the gaps are all on the +**auxiliary, DI-fund, indexation, and reserve/interest** perimeter. + +### 4.3 What pe-us 1.752.2 LACKS — flagged loudly (each needs a 3d-style amendment) + +**These are the series a faithful M7 needs that policyengine-us 1.752.2 does not +provide. Each is a design STOP, exactly like M6's second designed stop +(`gate_m6` §2.8.10): it must be pinned by a reviewed amendment before any scored +M7 run, not silently filled.** + +1. **Auxiliary 402(b)/(c)/(e)/(f) rate constants — NO pe-us node anywhere.** Per + `ss/params.py` (docstring lines 18-38): pe-us "carries `social_security_ + retirement`, `social_security_survivors` and `social_security_dependents` as + uprated survey **inputs** (no formula)," computing only the worker's own PIA + and 402(q)/(w) adjustment. The spousal share (0.5), survivor share (1.0), + RIB-LIM (0.825), 71.5% survivor floor, and protected-remarriage ages are + therefore carried as **statute-cited constants** validated against SSA worked + examples (`tests/ss/test_aux_benefits.py`, `runs/aux_benefit_examples_v1.json`), + not pe-us. Any auxiliary outlay M7 reports rides these constants — the same + "constant of the statute itself" exception pe-us's own tree forces. +2. **Trust-fund interest rate (special-issue yield) — NO pe-us node.** M2 states + it directly: "no policyengine-us rate node" for the TR rate. Required for + `interest[y]` in identity (I). Bind as a TR-cited constant / versioned + alignment input. +3. **TR ultimate assumptions (real interest 2.9%, CPI 2.7%, real-wage + differential 1.13%) — NO pe-us node.** M2 carried the 2014 TR Table V.B1 + bundle as a "TR-cited constant (no TR PDF staged; no policyengine-us rate + node)." These parameterize discounting and (in a nominal run) COLA/wage growth. +4. **COLA / CPI-W benefits-in-payment series — NO pe-us node in `ss/`.** Needed + only for a **nominal** M7 (§2.5); a real-dollar M7 nets it out. If M7 goes + nominal, this is a hard binding, not an option. +5. **Trust-fund opening reserve — NO pe-us node; M2 did not source it at all.** + M2 **calibrated** `reserve_0` to hit Smith's 2034 exhaustion year + (`calibration_disclosure`). A levels-honest M7 either keeps the calibrated + convention (disclosed, frame-relative) or binds an SSA TR historical + opening-balance series (§8 decision 3). + +Gaps 2–5 share a root cause: **policyengine-us models the benefit/​tax *formula*, +not the *trust fund*.** The trust-fund perimeter (interest, reserve, the +macro/CPI assumption set) is Trustees-Report territory with no upstream node. M7's +amendment must pin these to staged TR sources at a fixed vintage with the §4.4 +tamper gate — or, absent a staged TR artifact, carry them as explicitly TR-cited +frame-relative constants that feed only report-only levels, never a gated cell. + +### 4.4 The tamper-gate factory (mirroring M6 §2.8.10.4) + +M7's inputs are supplied by a **zero-argument factory** on the M6 pattern — a new +module `scripts/registered_m7_inputs.py` exposing `build_inputs() -> +M7AccountingInputs`, resolved the way `run_gate_m6_candidate1.py` resolves +`registered_m6_inputs:build_inputs`. Every binding is **hardcoded**; there is no +argument and no environment-derived vintage selection beyond +`POPULACE_DYNAMICS_PE_US_DIR` → the pinned 1.752.2 install. Deterministic steps, +in order: + +1. **Version + directory assert (M6 §2.8.10.2/.5, F2).** Assert + `importlib.metadata.version("policyengine-us") == CERTIFIED_PIN["model_version"] + == "1.752.2"` **and** assert the resolved parameter directory is the + metadata-versioned install — the metadata assert alone does not bind the + *directory* `POPULACE_DYNAMICS_PE_US_DIR` loads from (the F2 finding M6 §2.8.10.5 + closes). Then `params_full = load_ssa_parameters()` runs its own load-time + cross-check (derived bend points vs pe-us thresholds; `NAWI(1977)`). +2. **Content-hash tamper gate on every staged external artifact.** For each staged + file under a repo-root-anchored `data/external/` (`DATA = Path(__file__) + .resolve().parents[1] / "data" / "external"`, never CWD-relative, mirroring + `claiming._ROOT`) — the TR-constants JSON (gaps 2–4), the auxiliary-constant + provenance record (gap 1), and any staged reserve series (gap 5) — **assert the + JSON file's own sha256 equals a constant hardcoded in the factory.** The raw + source's hash (a TR PDF, an SSA table page) lives separately in + `provenance.source_sha256` as **build-time** provenance, **not** the tamper + gate (M6 §2.8.10.4's exact split: "the factory instead asserts the JSON file's + own hash"). +3. **Vintage refusal.** Route every staged series through + `validate_external_vintage` (`engine/refit.py:825-838`) so any `vintage > T*` + raises **before any accounting, artifact write, or gate evaluation** — the same + fence M6's `_validate_external_inputs` (`harness/m6_inputs.py:198-250`) puts in + front of fit/score/write. + +The point of the hash gate on **report-only** frame-relative constants (gaps 2–5 +feed no gated cell) is the same as M6's on its report-only claiming reference: +tamper-evidence. A constant that silently drifts would move the reported levels +and the M2-reproduction check without a diff anywhere; the sha256 gate makes the +one thing that could silently change — the staged TR/aux numbers — impossible to +change unnoticed. The factory is the single pinned entry point, candidate-blind +(no binding is tuned to any observable), exactly as M6 §2.8.10 requires of its own. + From 218866f0a9f01544cc7e9377ea22460691c1bac4 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Jul 2026 13:21:13 -0400 Subject: [PATCH 07/18] =?UTF-8?q?M7=20design=20doc:=20=C2=A75=20anchors=20?= =?UTF-8?q?intro=20+=20=C2=A75.1=20M2-reproduction=20target=20table=20(inc?= =?UTF-8?q?remental)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- docs/design/m7_trust_fund_accounting.md | 43 +++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/docs/design/m7_trust_fund_accounting.md b/docs/design/m7_trust_fund_accounting.md index 22e7d1c1..75239eb7 100644 --- a/docs/design/m7_trust_fund_accounting.md +++ b/docs/design/m7_trust_fund_accounting.md @@ -493,4 +493,47 @@ one thing that could silently change — the staged TR/aux numbers — impossibl change unnoticed. The factory is the single pinned entry point, candidate-blind (no binding is tuned to any observable), exactly as M6 §2.8.10 requires of its own. +## 5. Anchors — all REPORT-ONLY + +M7 carries three anchor families. **None gates** (§6 gates only internal +identities). They are reported alongside the levels so a reader can see agreement +and named disagreement, exactly as M2 reported its forecasts without grading them +("the orchestrator grades … this artifact reports outcomes vs forecasts and does +not grade"). + +### 5.1 The M2-reproduction anchor (the internal one, feeds the gate) + +Unlike the two external families below, M2-reproduction is an **internal** anchor: +M7's accounting engine, restricted to the exact M2 setup, must reproduce +`runs/m2_pseudo_projection_v1.json` (commit `747966cd`, `pe_us_revision bf71be3b`) +**to floating point, or name every delta.** The committed targets: + +| Quantity | Committed M2 value | +|---|---| +| common frame | `n_common_frame 1549`, `weight_sum 33696344.0`, born 1943–1957, earnings 1968–2018, benefits 2005–2057 | +| combined OASDI rate | `0.124` (employee `0.062` + employer `0.062`) | +| calibrated reserve | `7889236006574.162` | +| baseline exhaustion year | `2034.0` | +| baseline balance analogue | `0.04689166331354922` | +| cap_150k | balance `0.053154118080107754`, Δbalance `0.0062624547665585326`, exhaustion `2035.1188537982976`, Δyears `1.1188537982975504` | +| elimination | balance `0.06118610701057222`, Δbalance `0.014294443697022999`, exhaustion `2037.2048065597855`, Δyears `3.2048065597855384` | +| payroll +1pp | balance `0.05689166331354923`, Δbalance `0.010000000000000009`, exhaustion `2035.950472894025`, Δyears `1.950472894025097` | +| payroll +2pp | balance `0.06689166331354923`, Δbalance `0.02000000000000001`, exhaustion `2038.2313708228655`, Δyears `4.231370822865529` | +| FRA→72 | balance `0.072506643421113`, Δbalance `0.02561498010756378`, exhaustion `null` (never exhausts on-frame), Δyears `41.0` (censored) | +| PI outlay Δ | `-0.3326593963115843` (`-33.266%`) | +| PPI outlay Δ | `-0.11000744343246105` (`-11.001%`) | +| NRA→70 outlay Δ | `-0.20234306477534883` (`-20.234%`) | +| reduced-COLA outlay Δ | `-0.007987803755968265` (`-0.799%`) | +| forecast outcomes | F1 met (100%, 14/14); **F2 NOT met** (Kendall τ `0.667`, our order +2pp > elim > +1pp > cap vs Smith elim > +2pp > +1pp > cap); F3 met; F4 met | + +**Why reproduction is the expectation, not a hope.** M7 generalizes M2 by *adding* +classes (DI, auxiliary) and *opening* the frame (immigration, forward dynamics). +On the M2 setup those additions are switched **off** (OASI-only, closed 1943–1957 +cohort, real dollars, calibrated reserve), so a faithful generalization must +collapse to M2 exactly. A non-zero delta is therefore diagnostic: either a bug, or +a documented arithmetic change M7 must name and justify cell-by-cell (the M6 +"reproduce M2's committed numbers or explain every delta" discipline). The F2 +"NOT met" outcome is part of the committed record and must reproduce as-is — +reproduction means matching M2's *result*, including its registered forecast miss. + From 4f76ab80dca70003f601d5247a4691f9afad4a54 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Jul 2026 13:22:10 -0400 Subject: [PATCH 08/18] =?UTF-8?q?M7=20design=20doc:=20=C2=A75.2=20Mermin?= =?UTF-8?q?=20cost-ordering=20+=20=C2=A75.3=20Trustees=20corridors=20+=20l?= =?UTF-8?q?evel-vs-composition=20caveat=20(incremental)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- docs/design/m7_trust_fund_accounting.md | 59 +++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/docs/design/m7_trust_fund_accounting.md b/docs/design/m7_trust_fund_accounting.md index 75239eb7..87997108 100644 --- a/docs/design/m7_trust_fund_accounting.md +++ b/docs/design/m7_trust_fund_accounting.md @@ -536,4 +536,63 @@ a documented arithmetic change M7 must name and justify cell-by-cell (the M6 "NOT met" outcome is part of the committed record and must reproduce as-is — reproduction means matching M2's *result*, including its registered forecast miss. +### 5.2 The Mermin cost-ordering anchor + +Mermin (2005), Urban Institute 411260, DYNASIM3 Runid 432, Table 1 +(`@mermin2005benefitreductions`; transcription re-verified against the PDF on +2026-07-09 per #74 protocol note 3, `scripts/replication_cost_ordering.py:197-227`). +The "75-year deficit/surplus (percent of taxable payroll)" row: + +| Provision | Mermin Table 1 (% taxable payroll) | Mermin % of scheduled, 2050 | +|---|---|---| +| price indexing (PI) | `+0.68` | `69.3` | +| progressive price indexing (PPI) | `-0.14` | `81.8` | +| NRA raised to 70 | `-0.5` | `85.2` | +| reduced COLA (−0.4pp) | `-1.12` | `98.3` | +| scheduled deficit | `-1.69` | `100.0` (payable `78.4`) | + +M7 reports its own per-provision % of taxable payroll and the induced **ordering** +against this row — a sign/rank check, **never a level match.** The transportable +content is the ordering by savings (PI > PPI > NRA > COLA by Mermin's 75-yr +payroll effect) and, on the observed frame, the **PPI↔NRA swap** M2 already found +(its F4 outlay order `PI > NRA > PPI > COLA`, the compressed-careers swap that +persists "because the support is unchanged"). M7 must reproduce that swap on the +M2 frame (§5.1) and may report whether opening the frame (M6 entrants, forward +careers) unwinds it — as a reported observation, not a graded one. + +### 5.3 SSA Trustees historical corridors — with the level-vs-composition caveat + +M7 on the M6 panel produces objects that *look* like Trustees series: an OASDI +**cost rate** (`outlays / taxable_payroll`), an **income rate** (`revenue / +taxable_payroll`), a **balance** in % of taxable payroll, and a **trust-fund ratio +path**. It is tempting to grade these against the Trustees Report's historical +corridor. **This is exactly the temptation M2 was built to refuse, and the caveat +must be stated in the artifact, loudly.** + +**The survey panel is not the covered-worker universe.** M2's frame is 1,549 PSID +careers, `weight_sum 33,696,344` — and M6's panel, while larger, is a +CPS-anchored transported frame, not the ~180M-worker / ~68M-beneficiary OASDI +universe. So **aggregate dollar levels are not comparable to SSA aggregates**: +wrong universe size, a closed 1943–1957 cohort in M2 / an open transported panel +in M6, real (wage-indexed) rather than nominal dollars, and — the decisive one — +a **composition** that omits classes. M2's baseline balance analogue is +`+0.04689` — *positive*, the arithmetic opposite of the real OASDI 75-year +deficit — for one reason it states plainly: it "is POSITIVE because revenue is the +full combined-OASDI rate on all taxable payroll while outlays are OASI +retired-worker benefits only (no DI, no auxiliary) and fall later on the calendar." +That single number is the proof that these levels are frame-relative. + +**What normalization is honest.** Dividing by taxable payroll (the cost/income +rate, the balance-as-%-of-payroll) or by beneficiary count (per-capita benefit) +divides out the **universe-size** mismatch, so those normalized *shapes* — the +cost-rate trajectory, the trust-fund-ratio decline, the balance sign — are the +honest objects to lay beside the Trustees corridor, **report-only, with named +composition deltas** (OASI-only vs OASDI; no immigration in M2; PSID/CPS vs the +covered universe; real vs nominal). What is **not** honest, and what M7 must never +present as agreement: a levels-match of aggregate dollars, or a normalized rate +gated against the external corridor as if the composition deltas were noise. They +are not noise; they are the reason #113's roadmap "in LEVELS" gate is not +attainable here (§8 decision 1), and the reason §6 gates internal identities +instead. + From 2ba927c2aac05bc4f6e30528c1616379c32f2a54 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Jul 2026 13:22:55 -0400 Subject: [PATCH 09/18] =?UTF-8?q?M7=20design=20doc:=20=C2=A76=20proposed-n?= =?UTF-8?q?ot-locked=20gate=5Fm7=20(internal-identity)=20block=20(incremen?= =?UTF-8?q?tal)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- docs/design/m7_trust_fund_accounting.md | 69 +++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/docs/design/m7_trust_fund_accounting.md b/docs/design/m7_trust_fund_accounting.md index 87997108..ccf782e0 100644 --- a/docs/design/m7_trust_fund_accounting.md +++ b/docs/design/m7_trust_fund_accounting.md @@ -595,4 +595,73 @@ are not noise; they are the reason #113's roadmap "in LEVELS" gate is not attainable here (§8 decision 1), and the reason §6 gates internal identities instead. +## 6. Proposed `gate_m7` (proposal for the referee — NOT locked) + +`gate_m7` is proposed as an **internal-identity** gate: it certifies that M7's +accounting is arithmetically self-consistent and reproduces the committed M2 +result, and it certifies **nothing external.** This is a deliberate departure +from the roadmap #113 M7 row's "reproduce the TR baseline deficit … in LEVELS" +wording, argued in §5.3 and surfaced as §8 decision 1. The block below is a +**sketch for the referee**, `locked: false`, editing no `gates.yaml` cell and +built on no floor; it becomes real only in a future lock ceremony (design review → +referee → verification → ratify-by-merge → lock), which this document does not +begin. + +```yaml gate_m7-proposed-not-locked +gates: + gate_m7: + id: m7_trust_fund_accounting_internal_identity + status: design_proposal_for_referee # NOT draft_cleared, NOT locked + locked: false + kind: internal_identity # cf. gate_m6 temporal_holdout, gate_m4 anchor_based + design: docs/design/m7_trust_fund_accounting.md + covers: >- + the TRUST-FUND ACCOUNTING layer (roadmap #113 M7): per-projection-year + taxable payroll, payroll-tax revenue, benefit outlays by beneficiary class, + and the trust-fund balance ledger, computed deterministically over the M6 + panel. The gate certifies TWO INTERNAL IDENTITIES ONLY: (1) M2-REPRODUCTION + -- M7's accounting restricted to the M2 setup reproduces + runs/m2_pseudo_projection_v1.json's committed numbers to floating point, or + names every delta; (2) BALANCE-IDENTITY CLOSURE -- for every projection year + the ledger (start + revenue + interest - outlays = end) closes with residual + == 0 to floating point, and the PV balance analogue computed two ways (from + the annual ledger vs from the flow PVs) agrees to residual == 0. No external + SSA/Trustees aggregate is gated; all external anchors (Mermin ordering, TR + corridors, per-provision A-table levels) are REPORT-ONLY. + thresholds: + m2_reproduction: + rule: >- + exact byte reproduction of the committed cells (baseline balance + 0.04689166331354922; baseline exhaustion 2034.0; the five Smith + balance/exhaustion deltas; the four Mermin outlay deltas; F1-F4 + outcomes incl. F2 NOT met) OR a named, justified per-cell delta ledger. + tolerance: 0.0 # exact; deltas are named, not tolerated + locked: false + balance_identity_closure: + rule: >- + max_y |TF[y] - (TF[y-1] + revenue[y] + interest[y] - outlays[y])| == 0 + AND |PV_balance_from_ledger - PV_balance_from_flows| == 0, both to a + fixed relative floating-point tolerance (~1e-12), on every scored run. + tolerance: 1.0e-12 # floating-point closure, not an empirical band + locked: false + determinism: + rule: byte-identical artifact on re-run (modulo elapsed_seconds), per §3. + locked: false + not_certified: >- + external OASDI level match; TR baseline deficit in levels; per-provision + A-table LEVELS; DI trust-fund balance as a certified level; any beneficiary + -class dollar aggregate as a certified level; the 2100 path beyond M6's + gated window; behavioral response. + publishes_regardless: true # one-shot, published regardless of verdict +``` + +**Why these two and not an external match.** The M2-reproduction identity pins the +arithmetic to a committed, adversarially-reviewed reference. The balance-identity +closure pins internal consistency — it is non-vacuous (a dropped class or a +mis-discount breaks it) yet fully attainable (it is an accounting identity, not an +empirical fit). Together they certify "the accounting is correct and reproduces +what we already published," which is the honest ceiling on a frame whose levels +§5.3 shows are not externally gradable. The determinism sub-check (§3) makes both +identities byte-claims. + From 545ebb0c5e2dfb36f9b0b1011459bc65a2996f25 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Jul 2026 13:23:50 -0400 Subject: [PATCH 10/18] =?UTF-8?q?M7=20design=20doc:=20=C2=A77=20what=20M7?= =?UTF-8?q?=20does=20NOT=20certify=20(certification-scope=20voice)=20(incr?= =?UTF-8?q?emental)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- docs/design/m7_trust_fund_accounting.md | 34 +++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/docs/design/m7_trust_fund_accounting.md b/docs/design/m7_trust_fund_accounting.md index ccf782e0..3ba50124 100644 --- a/docs/design/m7_trust_fund_accounting.md +++ b/docs/design/m7_trust_fund_accounting.md @@ -664,4 +664,38 @@ what we already published," which is the honest ceiling on a frame whose levels §5.3 shows are not externally gradable. The determinism sub-check (§3) makes both identities byte-claims. +## 7. What M7 does NOT certify (certification-scope voice) + +A `gate_m7` pass certifies that the accounting **arithmetic** is self-consistent +and reproduces M2 (§6). It supports **no** claim beyond that. In the campaign's +`certification_scope` voice, the following are explicitly **outside** the scope a +`gate_m7` pass supports: + +- **No external level accuracy.** A pass says nothing about whether M7's OASDI + cost rate, income rate, balance, or trust-fund-ratio path matches the SSA + Trustees Report in levels. Those are frame-relative (§5.3); the corridors are + report-only. +- **No certified benefit levels.** Every AIME, PIA, claiming-adjusted, and + auxiliary benefit dollar is report-only (M6 §2.8.3a). A pass certifies the + *composition* that routes people to classes, never a class's dollar level. +- **No certified DI trust-fund balance.** The DI fund is a report-only lift of a + class (`gate_m4`) whose levels no gate certified ("no SSA DI LEVEL is gated"). +- **No behavioral response.** Claiming is drawn mechanically from Table 6.B5.1; no + labor-supply, claim-timing, or savings response to the rate, cap, or FRA + changes (M2: "no benefit feedback from cap changes"; #113 named-hard-part 4). +- **No macro feedback.** Wages, prices, the trust-fund interest rate, and the wage + base are exogenous Trustees inputs; no general-equilibrium loop. +- **No benefit feedback from cap reforms.** Raising or eliminating the taxable + maximum is scored revenue-side only; the higher covered earnings do not raise + the PIA (M2's stated convention — "Smith nets a modest benefit feedback"). +- **No validated projection beyond M6's gated window.** The 2100 path is + report-only extrapolation; M7 certifies accounting *over* M6's output, not the + projection's forward validity, which is M6's (conditional) claim, not M7's. +- **No new spec estimation.** M7 estimates nothing; it composes M1–M6 certified + specs and adds only arithmetic plus the §4 parameter bindings. The TR interest / + CPI / reserve constants (§4.3) are **cited, not certified** — they parameterize + report-only levels and feed no gated cell. +- **No whole-panel simultaneous rules scoring.** Executing rulespec/pe-us rules + per projected year across the panel is M8 (W2/W3), not M7. + From f81ce3ec3250a71c77b5f421ff79df34fd11d3e4 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Jul 2026 13:25:01 -0400 Subject: [PATCH 11/18] =?UTF-8?q?M7=20design=20doc:=20=C2=A78=20open=20dec?= =?UTF-8?q?isions=20for=20the=20referee=20(12=20under-determined=20choices?= =?UTF-8?q?)=20(incremental)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- docs/design/m7_trust_fund_accounting.md | 83 +++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/docs/design/m7_trust_fund_accounting.md b/docs/design/m7_trust_fund_accounting.md index 3ba50124..318a1c63 100644 --- a/docs/design/m7_trust_fund_accounting.md +++ b/docs/design/m7_trust_fund_accounting.md @@ -698,4 +698,87 @@ and reproduces M2 (§6). It supports **no** claim beyond that. In the campaign's - **No whole-panel simultaneous rules scoring.** Executing rulespec/pe-us rules per projected year across the panel is M8 (W2/W3), not M7. +## 8. Open decisions for the referee + +These are under-determined and are **listed, not silently resolved.** Each states +the choice, the options, and this design's lean — the referee decides. + +1. **Internal gate vs the roadmap's external-level gate (the central one).** #113 + M7 says gate on "the TR baseline deficit … in LEVELS" and "per-provision balance + vs the Five-Approaches A-tables in LEVELS." §5.3 argues those levels are not + honestly gradable on a survey panel. *Options:* (a) internal-identity gate + (§6); (b) the roadmap's external-level gate with a pre-registered tolerance; (c) + a normalized-shape gate on % of taxable payroll with composition deltas held + fixed. **Lean: (a)** — it matches the M2 precedent and the campaign's "levels + are frame-relative" discipline; (b) would gate the composition mismatch as if + it were model error. This lean directly contradicts the roadmap wording, which + is why it is decision 1 and not a silent choice. +2. **Nominal vs real accounting (§2.5).** *Options:* (a) M2's wage-indexed real + dollars (no CPI-W needed, real interest 2.9%); (b) nominal (Trustees' printed + units, requires the CPI-W and nominal special-issue series — both §4.3 gaps). + **Lean: (a) for the gated M2-repro run** (mandatory — M2 is real); the M6-panel + report-only run may additionally present (b) if the CPI-W/interest bindings are + staged. Mixing the two within one ledger breaks identity (I). +3. **Calibrated reserve vs sourced opening balance (§2.4, §4.3 gap 5).** *Options:* + (a) keep M2's calibrated `reserve_0` (disclosed, frame-relative, reproduces + M2); (b) bind an SSA TR historical opening-balance series. **Lean: (a) on the + M2-repro run** (required for reproduction); (b) is only meaningful if the + external-level path (decision 1b) is adopted, and even then the universe + mismatch makes a real opening balance incommensurable with panel-scale flows. +4. **OASI-vs-DI rate/fund split (§2.2).** *Options:* (a) one combined OASDI fund at + 12.4% (M2's convention, OASI-only outlays); (b) two funds, revenue split + 10.6%/1.8%, DI outlays from `gate_m4` composition. **Lean: (a) for M2-repro**; + (b) as an additional report-only view once DI outlays are wired, clearly marked + report-only (DI levels are ungated, §2.6). +5. **Scheduled vs payable baseline (#74 protocol note 1).** M7 should produce both + (scheduled = full statutory benefits; payable = benefits scaled to available + revenue after exhaustion). *Open:* which is primary, and the exact + post-exhaustion payable rule (uniform proportional reduction to the income rate, + vs the statutory sequence). **Lean:** report both; gate neither's *level*; + the payable rule is a named convention, disclosed, not certified. + +6. **Wage-index surface: inherit M6's vs re-derive (§2.5).** M6 already pins a + realized-≤2014 / `I_proj`-beyond NAWI surface (M6 §2.8.10.2). *Options:* (a) M7 + reads M6's surface verbatim; (b) M7 re-derives it. **Lean: (a)** — re-deriving + risks a second, divergent wage-index vintage and re-opens the leakage + prohibition M6 already closed. +7. **A level M7 needs that M6 §6 does not expose.** *Options:* (a) raise it as an + M6 §6 gap and block M7 until M6 exposes it; (b) synthesize it in M7. **Lean: + (a)** — M7 introduces no dynamics (§2.1); anything M6 does not expose is an M6 + boundary question, not an M7 shortcut. +8. **Interest timing convention (§2.4).** `interest[y] = rate · TF[y-1]` + (start-of-year) vs a mid-year / average-balance convention (closer to SSA's). + **Lean:** start-of-year for identity-closure simplicity; the choice is a named + convention, immaterial to the closure gate but material to the reported ratio + path — so it is disclosed, not hidden. +9. **"Reproduce M2" exactness vs floating-point reduction order (§3, §5.1).** If M7 + re-implements the aggregations in a different summation order than + `scripts/m2_pseudo_projection.py`, byte-exact reproduction of M2's committed + floats may not hold even with correct arithmetic. *Options:* (a) M7 reuses M2's + exact reduction path on the M2 frame (true byte reproduction); (b) + reproduction is defined to a fixed relative tolerance (~1e-12) with any residual + named. **Lean: (a) where feasible**, falling back to (b) with a disclosed + reduction-order note — the §6 `m2_reproduction.tolerance: 0.0` presumes (a). +10. **TR vintage for the report-only corridors.** The Mermin/Smith anchors and + M2's TR constants are **2014-TR-vintage** (DYNASIM's vintage). A 2026 projection + could instead lay its corridors beside the current Trustees Report + (`@ssa2025trustees`). *Options:* (a) hold 2014 vintage for commensurability + with M2/Mermin/Smith; (b) add the current TR as a second report-only corridor. + **Lean:** (a) for the reproduction anchor; (b) additionally, clearly + vintage-labeled, for the M6-panel report. +11. **Immigrant-entrant partial careers.** Entrants (§2.1) lack pre-entry covered + earnings; their taxable payroll and AIME see only post-entry years. *Open:* the + coverage-year treatment for AIME's 35-year divisor and for the taxable-payroll + aggregate. **Lean:** treat pre-entry years as non-covered zeros (the AIME + convention in `ss/benefits.py:100-117` already zero-fills unselected years) and + disclose the entrant share of each year's payroll — a reported composition + delta, never a gated cell. +12. **Per-capita denominator for §5.3 normalization.** Which head is a + "beneficiary" (dual-entitled counted once or by class; auxiliary-only + recipients). *Open;* affects only the report-only per-capita corridor. **Lean:** + unique-person beneficiary count with a class-breakout table, disclosed. + +The referee is invited to add decisions this draft missed; the revision-2 log will +map the round's verdict to these entries, as M6's did. + From 16782dbd3d66b576173ce0629f48e16209681ccb Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Jul 2026 13:26:11 -0400 Subject: [PATCH 12/18] =?UTF-8?q?M7=20design=20doc:=20=C2=A79=20design-par?= =?UTF-8?q?ameters=20JSON=20provenance=20block;=20doc=20complete?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- docs/design/m7_trust_fund_accounting.md | 47 ++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/docs/design/m7_trust_fund_accounting.md b/docs/design/m7_trust_fund_accounting.md index 318a1c63..f3d273fc 100644 --- a/docs/design/m7_trust_fund_accounting.md +++ b/docs/design/m7_trust_fund_accounting.md @@ -781,4 +781,49 @@ the choice, the options, and this design's lean — the referee decides. The referee is invited to add decisions this draft missed; the revision-2 log will map the round's verdict to these entries, as M6's did. - +## 9. Design-parameters summary (design proposal — not a test-bound ledger) + +This block summarizes the proposed design and the artifact/code fields it derives +from. Unlike a ratified amendment's consistency ledger, it is **not** bound to +committed artifacts by a test — this is a docs-only design draft that builds no +floor and writes no test. The numbers become test-bound only when the `gate_m7` +block and its floor are authored in a future lock ceremony (§6). + +```json m7-design-parameters +{ + "design_id": "2026-07-14-m7-trust-fund-accounting", + "revision": 1, + "status": "design_draft_for_referee", + "referee_round": "follows the in-flight gate_m6 verdict; NOT triggered by this document", + "gates_yaml_untouched_by_this_document": true, + "builds_no_floor_writes_no_test_runs_nothing_scored": true, + "roadmap_m7_row_verbatim": "Full revenue + trust-fund accounting: OASDI cost/income rates, trust-fund ratio path, 75-yr actuarial balance in % of taxable payroll | gate: Reproduce the corresponding TR baseline deficit within a pre-registered tolerance; per-provision balance vs the Five-Approaches A-tables in LEVELS, not just ordinally | unlocks: The Rosetta stone (#74 anchor 2) graded in its own units", + "certifies_proposed": { + "m2_reproduction": "M7 accounting on the M2 setup reproduces runs/m2_pseudo_projection_v1.json to floating point, or names every delta", + "balance_identity_closure": "start + revenue + interest - outlays = end, residual == 0 every year; PV balance two ways agrees to residual == 0", + "determinism": "byte-identical accounts on re-run; no RNG at the accounting layer (all draws realized upstream in M6)" + }, + "explicitly_not_gated": "external SSA/Trustees aggregates; TR baseline deficit in LEVELS; per-provision A-table LEVELS; DI trust-fund balance as a certified level; any beneficiary-class dollar level", + "central_open_decision": "roadmap asks to gate in LEVELS (#113 M7 row); this design argues the 1549-career PSID survey panel is not the covered-worker universe (M2 baseline balance +0.04689 is positive because revenue is combined-OASDI on all payroll while outlays are OASI-only), so external levels are frame-relative and not honestly gradable -> proposes an internal-identity gate instead (§8 decision 1, for the referee)", + "m2_reproduction_targets": { + "commit": "747966cd", "pe_us_revision": "bf71be3b", + "baseline_balance": 0.04689166331354922, + "baseline_exhaustion_year": 2034.0, + "calibrated_reserve": 7889236006574.162, + "smith_balance_deltas": {"cap_150k": 0.0062624547665585326, "elimination": 0.014294443697022999, "payroll_plus_1pp": 0.010000000000000009, "payroll_plus_2pp": 0.02000000000000001, "fra_to_72": 0.02561498010756378}, + "smith_exhaustion_delta_years": {"cap_150k": 1.1188537982975504, "elimination": 3.2048065597855384, "payroll_plus_1pp": 1.950472894025097, "payroll_plus_2pp": 4.231370822865529, "fra_to_72": 41.0}, + "mermin_outlay_deltas": {"price_indexing": -0.3326593963115843, "progressive_price_indexing": -0.11000744343246105, "nra_raised_to_70": -0.20234306477534883, "reduced_cola": -0.007987803755968265}, + "forecasts": {"F1": "met 100% 14/14", "F2": "NOT met, kendall 0.667", "F3": "met", "F4": "met"} + }, + "input_bindings": { + "pe_us_pin": "1.752.2", "vintage_boundary_T_star": 2014, + "present_in_pe_us": ["payroll_rate_employee_employer", "wage_base", "nawi", "pia_formula_factors", "fra_schedule", "early_delayed_adjustment_rates"], + "LOUD_GAPS_need_3d_style_amendment": ["auxiliary_402bcef_rate_constants", "trust_fund_interest_rate", "tr_ultimate_assumptions_2014", "cola_cpiw_benefits_in_payment", "trust_fund_opening_reserve"], + "tamper_gate": "scripts/registered_m7_inputs.py build_inputs() zero-arg; version+dir assert (M6 2.8.10.5 F2); sha256 on staged JSON (M6 2.8.10.4); validate_external_vintage refuses vintage>2014 (refit.py:825-838)" + }, + "anchors_all_report_only": ["m2_reproduction (internal, feeds gate)", "mermin_2005_table1_411260", "smith_2015_solvency_72196", "ssa_trustees_historical_corridors (level-vs-composition caveat)"], + "open_decisions_for_referee": ["1 internal-gate vs roadmap external-level gate", "2 nominal vs real accounting", "3 calibrated reserve vs sourced opening balance", "4 OASI-vs-DI rate/fund split", "5 scheduled vs payable baseline + post-exhaustion rule", "6 inherit M6 wage-index surface vs re-derive", "7 M6-unexposed level: raise vs synthesize", "8 interest timing convention", "9 M2-reproduction byte-exact vs 1e-12 tolerance", "10 TR vintage for corridors 2014 vs current", "11 immigrant-entrant partial-career treatment", "12 per-capita beneficiary denominator"], + "evidence_base": ["runs/m2_pseudo_projection_v1.json", "scripts/m2_pseudo_projection.py", "ss/params.py", "ss/benefits.py", "docs/design/m6_projection_engine.md#6", "gates.gate_m4", "disability_conversion.py", "scripts/replication_cost_ordering.py", "engine/refit.py:825-838", "harness/m6_inputs.py:198-250"] +} +``` + From 75c7073c7b5734f96a99ea698f47ce40adb5da3d Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Jul 2026 13:59:06 -0400 Subject: [PATCH 13/18] =?UTF-8?q?M7=20fixes:=20S1=20CPI-W/COLA=20is=20a=20?= =?UTF-8?q?present=20pe-us=20node=20(gov/ssa/uprating.yaml);=20=C2=A74.3?= =?UTF-8?q?=20A/B/C=20reclassification=20(S1,N1);=20bend-constant=20label?= =?UTF-8?q?=20(N2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- docs/design/m7_trust_fund_accounting.md | 142 ++++++++++++++---------- 1 file changed, 81 insertions(+), 61 deletions(-) diff --git a/docs/design/m7_trust_fund_accounting.md b/docs/design/m7_trust_fund_accounting.md index f3d273fc..b0b9d9a6 100644 --- a/docs/design/m7_trust_fund_accounting.md +++ b/docs/design/m7_trust_fund_accounting.md @@ -392,65 +392,82 @@ amendment. The deployment pin is **policyengine-us 1.752.2** (the frame pin, | PIA formula factors (90/32/15) | 42 USC 415(a) | `gov/ssa/social_security/pia/formula_factors.yaml` | **present** | | FRA schedule | 42 USC 416(l) | `gov/ssa/.../full_retirement_age_by_birth_year.yaml` | **present** | | Early-reduction & delayed-credit rates | 42 USC 402(q)/(w) | `gov/ssa/.../retirement_age_adjustment/...` | **present** | -| 1978-base bend constants ($180 / $1,085) | 42 USC 415(a)(1)(B) | — (statute constant, cross-checked to pe-us thresholds, `ss/params.py:60-62,340-354`) | **statute constant** | -| Auxiliary 402(b)/(c)/(e)/(f) rate constants | 42 USC 402(b)/(c)/(e)/(f)/(k)/(q) | **NONE** | **GAP → §4.3** | -| COLA / CPI-W (benefits-in-payment) | 42 USC 415(i) | **NONE in `ss/`** | **GAP → §4.3** (nominal runs only) | -| Trust-fund interest rate (special-issue yield) | TR intermediate | **NONE** | **GAP → §4.3** | -| TR ultimate assumptions (real int 2.9%, CPI 2.7%, real-wage diff 1.13%) | 2014 OASDI TR Table V.B1 | **NONE** | **GAP → §4.3** | -| Trust-fund opening reserve | SSA TR historical | **NONE** | **GAP → §4.3** (M2 *calibrated* it) | +| Bend constants $180 / $1,085 (1979-cohort amounts, indexed off 1977 NAWI) | 42 USC 415(a)(1)(B) | — (statute constant, cross-checked to pe-us thresholds, `ss/params.py:60-62,340-354`) | **statute constant** | +| Auxiliary 402(b)/(c)/(e)/(f) rate constants | 42 USC 402(b)/(c)/(e)/(f)/(k)/(q) | — (statute constants in `ss/params.py`, tested) | **already bound in-repo (§4.3 A)** | +| CPI-W / COLA (benefits-in-payment) | 42 USC 415(i) | `gov/ssa/uprating.yaml`, `gov/bls/cpi/cpi_w.yaml` | **present, not yet wired in `ss/` (§4.3 B)** | +| Trust-fund interest rate (special-issue yield) | TR intermediate | **NONE** | **GAP → §4.3 C** | +| TR ultimate assumptions (real int 2.9%, CPI 2.7%, real-wage diff 1.13%) | 2014 OASDI TR Table V.B1 | **NONE** | **GAP → §4.3 C** | +| Trust-fund opening reserve | SSA TR historical | **NONE** | **GAP → §4.3 C** (M2 *calibrated* it) | ### 4.2 What pe-us 1.752.2 exposes (the revenue and own-benefit side) The entire **own-benefit** formula and the **revenue** rate/base are sourced from -the pinned pe-us tree with no hand-typing beyond the two statutory 1978-base bend -constants (`ss/params.py` docstring; `load_ssa_parameters` reads `nawi.yaml`, +the pinned pe-us tree with no hand-typing beyond the two statutory bend constants +(the 1979-cohort $180/$1,085 amounts, indexed off 1977 NAWI; `ss/params.py` +docstring; `load_ssa_parameters` reads `nawi.yaml`, `wage_base.yaml`, `pia/formula_factors.yaml`, `full_retirement_age_by_birth_year .yaml`, the early/delayed adjustment rates, and cross-checks derived bend points against pe-us's stored thresholds and `NAWI(1977) = 9,779.44`, `ss/params.py:334`). These carry the M6 §2.8.10.2 vintage rule unchanged. So the **income side** and -the **OASI retired-worker level** are fully pe-us-sourced; the gaps are all on the -**auxiliary, DI-fund, indexation, and reserve/interest** perimeter. - -### 4.3 What pe-us 1.752.2 LACKS — flagged loudly (each needs a 3d-style amendment) - -**These are the series a faithful M7 needs that policyengine-us 1.752.2 does not -provide. Each is a design STOP, exactly like M6's second designed stop -(`gate_m6` §2.8.10): it must be pinned by a reviewed amendment before any scored -M7 run, not silently filled.** - -1. **Auxiliary 402(b)/(c)/(e)/(f) rate constants — NO pe-us node anywhere.** Per - `ss/params.py` (docstring lines 18-38): pe-us "carries `social_security_ - retirement`, `social_security_survivors` and `social_security_dependents` as - uprated survey **inputs** (no formula)," computing only the worker's own PIA - and 402(q)/(w) adjustment. The spousal share (0.5), survivor share (1.0), - RIB-LIM (0.825), 71.5% survivor floor, and protected-remarriage ages are - therefore carried as **statute-cited constants** validated against SSA worked - examples (`tests/ss/test_aux_benefits.py`, `runs/aux_benefit_examples_v1.json`), - not pe-us. Any auxiliary outlay M7 reports rides these constants — the same - "constant of the statute itself" exception pe-us's own tree forces. -2. **Trust-fund interest rate (special-issue yield) — NO pe-us node.** M2 states - it directly: "no policyengine-us rate node" for the TR rate. Required for - `interest[y]` in identity (I). Bind as a TR-cited constant / versioned - alignment input. -3. **TR ultimate assumptions (real interest 2.9%, CPI 2.7%, real-wage - differential 1.13%) — NO pe-us node.** M2 carried the 2014 TR Table V.B1 - bundle as a "TR-cited constant (no TR PDF staged; no policyengine-us rate - node)." These parameterize discounting and (in a nominal run) COLA/wage growth. -4. **COLA / CPI-W benefits-in-payment series — NO pe-us node in `ss/`.** Needed - only for a **nominal** M7 (§2.5); a real-dollar M7 nets it out. If M7 goes - nominal, this is a hard binding, not an option. -5. **Trust-fund opening reserve — NO pe-us node; M2 did not source it at all.** - M2 **calibrated** `reserve_0` to hit Smith's 2034 exhaustion year - (`calibration_disclosure`). A levels-honest M7 either keeps the calibrated - convention (disclosed, frame-relative) or binds an SSA TR historical +the **OASI retired-worker level** are fully pe-us-sourced; the auxiliary constants +are already bound in-repo (§4.3 A) and CPI-W/COLA is present in pe-us but not yet +wired into `ss/` (§4.3 B), leaving the genuine gaps only on the **trust-fund +perimeter** — interest, opening reserve, and the TR macro-assumption set (§4.3 C). + +### 4.3 What M7 needs, by binding status (only category C is genuinely absent) + +**The series a faithful M7 needs, classified by how they bind. Only category C is a +design STOP — a genuinely-absent series that must be pinned by a reviewed amendment +before any scored M7 run (M6's second designed stop, `gate_m6` §2.8.10, is the +precedent). A is already bound in-repo; B is present in pe-us but not yet wired.** + +**A — already bound in-repo (statute constants; no amendment).** The auxiliary +402(b)/(c)/(e)/(f) rate constants — spousal share (0.5), survivor share (1.0), +RIB-LIM (0.825), the 71.5% survivor floor, protected-remarriage ages — are +**already bound and tested** in existing repo code (`ss/benefits.py` +`spousal_benefit` / `widow_benefit` / `survivor_reduction`; validated in +`tests/ss/test_aux_benefits.py` against `runs/aux_benefit_examples_v1.json`), +carried as statute-cited constants because pe-us "carries +`social_security_{retirement,survivors,dependents}` as uprated survey **inputs** +(no formula)" (`ss/params.py` docstring lines 18-38). This is the same "constant of +the statute itself" exception pe-us's tree forces for the 1979-cohort bend amounts +— **not** a pre-scored-run STOP. M7 reuses them as-is and stages nothing new. + +**B — present in pe-us but not yet wired into `ss/` (bind like NAWI/wage_base; not +a STOP).** The **CPI-W / COLA** series a nominal M7 (§2.5) needs is **present in +policyengine-us**: `gov/ssa/uprating.yaml` — "the US indexes Social Security +benefits (OASDI and SSI) … annually updating based on **CPI-W in the third quarter +of the prior year**," actuals through 2026, CBO-married forecasts through 2035, and +2036–2100 set programmatically — plus the raw `gov/bls/cpi/cpi_w.yaml` index (from +1913). The repo's `ss/` wrapper simply doesn't load it yet (`ss/benefits.py` +computes the claim-year benefit only). So COLA is **not** a trust-fund-perimeter +gap: M7 binds and vintage-pins `gov/ssa/uprating.yaml` **exactly as it binds +NAWI/`wage_base`** — realized ≤`T*`, projection beyond, the same leakage fence that +already handles those series' post-2014 values (never realized post-`T*` COLA on a +scored path). *Confirm-at-pin caveat:* the node was verified present in 1.532.0 and +1.690.7, not directly in the 1.752.2 pin, but `cpi_w.yaml` / `gov/ssa/uprating.yaml` +are long-standing structurally-stable nodes (no trust-fund model has ever entered +pe-us); the §4.4 factory confirms the node at the pin. + +**C — genuinely absent from pe-us (the real STOP: a reviewed amendment / TR-cited +constants before any scored run).** + +1. **Trust-fund interest rate (special-issue yield).** M2: "no policyengine-us rate + node" for the TR rate. Required for `interest[y]` in identity (I). +2. **TR ultimate assumptions (real interest 2.9%, CPI 2.7%, real-wage differential + 1.13%).** M2 carried the 2014 TR Table V.B1 bundle as a "TR-cited constant (no TR + PDF staged; no policyengine-us rate node)." +3. **Trust-fund opening reserve.** No pe-us node; M2 **calibrated** `reserve_0` to + hit Smith's 2034 exhaustion year (`calibration_disclosure`). Keep the calibrated + convention (disclosed, frame-relative) or bind an SSA TR historical opening-balance series (§8 decision 3). -Gaps 2–5 share a root cause: **policyengine-us models the benefit/​tax *formula*, -not the *trust fund*.** The trust-fund perimeter (interest, reserve, the -macro/CPI assumption set) is Trustees-Report territory with no upstream node. M7's -amendment must pin these to staged TR sources at a fixed vintage with the §4.4 -tamper gate — or, absent a staged TR artifact, carry them as explicitly TR-cited -frame-relative constants that feed only report-only levels, never a gated cell. +Category C shares a root cause: **policyengine-us models the benefit/tax *formula*, +not the *trust fund*** — the interest/reserve/macro-assumption perimeter is +Trustees-Report territory with no upstream node. M7's amendment pins these to staged +TR sources at a fixed vintage with the §4.4 tamper gate, or — absent a staged TR +artifact — carries them as explicitly TR-cited frame-relative constants that feed +only report-only levels, never a gated cell. ### 4.4 The tamper-gate factory (mirroring M6 §2.8.10.4) @@ -469,24 +486,27 @@ in order: *directory* `POPULACE_DYNAMICS_PE_US_DIR` loads from (the F2 finding M6 §2.8.10.5 closes). Then `params_full = load_ssa_parameters()` runs its own load-time cross-check (derived bend points vs pe-us thresholds; `NAWI(1977)`). -2. **Content-hash tamper gate on every staged external artifact.** For each staged - file under a repo-root-anchored `data/external/` (`DATA = Path(__file__) - .resolve().parents[1] / "data" / "external"`, never CWD-relative, mirroring - `claiming._ROOT`) — the TR-constants JSON (gaps 2–4), the auxiliary-constant - provenance record (gap 1), and any staged reserve series (gap 5) — **assert the - JSON file's own sha256 equals a constant hardcoded in the factory.** The raw - source's hash (a TR PDF, an SSA table page) lives separately in - `provenance.source_sha256` as **build-time** provenance, **not** the tamper - gate (M6 §2.8.10.4's exact split: "the factory instead asserts the JSON file's - own hash"). +2. **Content-hash tamper gate on every staged external artifact.** The only staged + external artifacts are the **category-C** constants (§4.3 C) — the TR-constants + JSON (interest rate + TR ultimate assumptions) and any staged opening-reserve + series. (Category A aux constants live in tested repo code, and category B + CPI-W/COLA loads from the pe-us node under the §2.8.10.2 version+dir assert, so + neither is a staged artifact.) For each staged file under a repo-root-anchored + `data/external/` (`DATA = Path(__file__).resolve().parents[1] / "data" / + "external"`, never CWD-relative, mirroring `claiming._ROOT`) — **assert the JSON + file's own sha256 equals a constant hardcoded in the factory.** The raw source's + hash (a TR PDF) lives separately in `provenance.source_sha256` as **build-time** + provenance, **not** the tamper gate (M6 §2.8.10.4's exact split: "the factory + instead asserts the JSON file's own hash"). 3. **Vintage refusal.** Route every staged series through `validate_external_vintage` (`engine/refit.py:825-838`) so any `vintage > T*` raises **before any accounting, artifact write, or gate evaluation** — the same fence M6's `_validate_external_inputs` (`harness/m6_inputs.py:198-250`) puts in front of fit/score/write. -The point of the hash gate on **report-only** frame-relative constants (gaps 2–5 -feed no gated cell) is the same as M6's on its report-only claiming reference: +The point of the hash gate on **report-only** frame-relative constants (the +category-C constants feed no gated cell) is the same as M6's on its report-only +claiming reference: tamper-evidence. A constant that silently drifts would move the reported levels and the M2-reproduction check without a diff anywhere; the sha256 gate makes the one thing that could silently change — the staged TR/aux numbers — impossible to From eb82e6926d9ffe0126306a6a4754fc28f326d083 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Jul 2026 14:01:24 -0400 Subject: [PATCH 14/18] =?UTF-8?q?M7=20fixes:=20=C2=A72.5=20COLA=20is=20pre?= =?UTF-8?q?sent-but-unwired=20(S1=20cross-ref);=20candidate-16=20=3D=20gat?= =?UTF-8?q?e-2=20identity=20M6=20consumes=20(N3);=20gate=5Fm4=20internal?= =?UTF-8?q?=20vs=20anchor=20cells=20(N4);=20cross-platform=20numpy=20cavea?= =?UTF-8?q?t=20(N5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- docs/design/m7_trust_fund_accounting.md | 40 +++++++++++++++---------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/docs/design/m7_trust_fund_accounting.md b/docs/design/m7_trust_fund_accounting.md index b0b9d9a6..22d7f83c 100644 --- a/docs/design/m7_trust_fund_accounting.md +++ b/docs/design/m7_trust_fund_accounting.md @@ -269,8 +269,11 @@ proposed gate (§6): for every year `y`, the artifact carries `TF[y-1]`, `revenue[y]`, `interest[y]`, `outlays[y]`, `TF[y]` independently, and a referee can recompute (I) and confirm the residual is `0`. It is **non-vacuous** because a dropped beneficiary class, a double-counted employer half, or a mis-discounted PV -breaks it — the same reconcile-to-`0.0` discipline M6 applied to its recombination -identity (M6 candidate-16 residual `1.7e-18`, "reconciled to 0.0"). +breaks it — the same reconcile-to-`0.0` discipline behind the **gate-2** +recombination identity M6 adopts as `ft.CANDIDATE_16` (its +`support_stratum_recombination` residual `1.734723475976807e-18`, +`runs/gate2_hazard_v16.json`, "reconciled to 0.0") — a gate-2 identity M6 consumes, +not an M6-native reconciliation. **Interest and the opening reserve are LOUD input gaps (§4.3).** `interest_rate(y)` (the trust-fund's special-issue yield) has **no pe-us node** — M2 confirms "no @@ -292,10 +295,13 @@ Two distinct indexation channels feed the accounts, and only one is sourced toda post-`T*` NAWI on any scored path. For a forward projection to 2100, future eligibility years read projected NAWI; M7 inherits M6's wage-index surface rather than re-deriving it (§8 decision 6). -- **Benefits-in-payment indexation / COLA (the LOUD gap, §4.3).** After a worker - claims, the benefit is uprated annually by the COLA (CPI-W, 215(i)). **pe-us's - `ss/` machinery applies no COLA** and binds no CPI-W series — `ss/benefits.py` - computes the claim-year benefit only. M2 sidestepped this by working in +- **Benefits-in-payment indexation / COLA (present in pe-us, not yet wired — §4.3 + B).** After a worker claims, the benefit is uprated annually by the COLA (CPI-W, + 215(i)). The CPI-W/COLA series **is present in pe-us** (`gov/ssa/uprating.yaml` + + `gov/bls/cpi/cpi_w.yaml`); the repo's **`ss/` wrapper simply does not load it** + yet — `ss/benefits.py` computes the claim-year benefit only. A nominal M7 wires + it like NAWI/`wage_base` (§4.3 B), no new artifact. M2 sidestepped it by working + in **wage-indexed real (2048 age-60-indexing) dollars**, in which a benefit is carried at constant real PIA across ages — COLA and NAWI-deflation net out of the *level* convention, so no explicit CPI-W series is needed. The Mermin @@ -305,9 +311,10 @@ Two distinct indexation channels feed the accounts, and only one is sourced toda **The consequence for M7 is a nominal-vs-real fork (§8 decision 2).** If M7 keeps M2's **real** convention, no CPI-W series is required and interest is a *real* rate (2.9%); the accounts stay comparable to M2. If M7 goes **nominal** (the units -a Trustees report actually prints), it must bind a CPI-W / COLA series *and* a -nominal special-issue interest series — **neither has a pe-us node** — and every -benefit-in-payment path grows by COLA. The two are a coherent pair (real flows ↔ +a Trustees report actually prints), it must **wire** the existing CPI-W/COLA node +(§4.3 B, present in pe-us) *and* **bind** a nominal special-issue interest series +(§4.3 C, genuinely absent) — and every benefit-in-payment path grows by COLA. The +two are a coherent pair (real flows ↔ real interest; nominal flows ↔ nominal interest + COLA); mixing them breaks identity (I). M7 must declare the convention per run; the M2-repro run (§5.1) is real by construction. @@ -320,7 +327,7 @@ per class: | Class | Composition certified by | Level status | |---|---|---| | OASI retired-worker | earnings (gate_1/gate_m6), claiming mix, survival | **report-only** (PIA never gated) | -| DI disabled-worker | gate_m4 hazards + `prevalence.50-59` stock + Table-50 exit **dominance** (all shape/dominance) | **report-only** (M4: "no SSA DI LEVEL is gated") | +| DI disabled-worker | gate_m4 flow hazards + `prevalence.50-59` stock (8 internal half-split **reproduction** cells) + Table-19 shape / Table-50 exit **dominance** (4 concept-bridged anchor cells) | **report-only** (M4: "no SSA DI LEVEL is gated") | | DI→retirement conversion at FRA | gate_m4 exit composition; `disability_conversion.py` | **report-only** level | | 402(b)/(c) spouse | gate_2b/2c household + couple formation | **report-only** (aux rate = statute constant) | | 402(e)/(f) survivor | gate_2b + mortality (who survives whom) | **report-only** (aux rate = statute constant) | @@ -335,8 +342,9 @@ locked at run time, that class is disclosed report-only with its tranche gap nam ## 3. The determinism law **Law.** *Given the same M6 panel and the same pinned parameter bundle (§4), the -M7 accounts are byte-identical across runs, processes, and platforms. There is no -stochastic element at the accounting layer.* +M7 accounts are byte-identical across runs and processes (and across platforms +given a pinned numpy build — the cross-platform caveat of §8 decision 9). There is +no stochastic element at the accounting layer.* This is stronger than M6's discipline and simpler to guarantee, because M7 consumes no randomness. Every stochastic draw — earnings, mortality, marital @@ -356,9 +364,11 @@ recursion (I). Determinism therefore reduces to two mechanical obligations: 1. **Pinned reduction order.** Floating-point addition is non-associative, so every aggregate `Σ_i w[i,y]·x[i,y]` fixes a canonical iteration order (sort by `(person_id, year)`) and a fixed dtype, so the summed bytes do not depend on - row order, thread count, or grouping. This is the M7 analogue of M6's - draw-by-draw byte-identity (M6 candidate-16 "RNG-neutral … byte-identical - draw-by-draw"); here it is reduction-order neutrality. + row order, thread count, or grouping. This is the M7 analogue of the + draw-by-draw byte-identity of the **gate-2** candidate-16 marital core M6 embeds + ("RNG-neutral … byte-identical draw-by-draw"); here it is reduction-order + neutrality. Cross-platform identity additionally needs a pinned numpy build + (pairwise-summation/SIMD differences otherwise perturb the low bits; §8 dec. 9). 2. **Pinned parameter bytes.** The parameter side is fully determined by the pe-us 1.752.2 pin plus the statute/TR constants (§4), each vintage-asserted and hash-gated (§4.4). No parameter is read from the environment beyond the pinned From d3a7381d29ac76a1112139f822d10fe0c009f47b Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Jul 2026 14:03:31 -0400 Subject: [PATCH 15/18] =?UTF-8?q?M7=20fixes:=20S2=20decision=201=20?= =?UTF-8?q?=E2=80=94=20roadmap=20#113=20amendment=20ratification=20path=20?= =?UTF-8?q?+=20option-(c)=20report-only=20companion=20(rebut=20c-as-gate,?= =?UTF-8?q?=20adopt=20c-as-report);=20N6=20'in=20its=20own=20units';=20thr?= =?UTF-8?q?ead=20companion=20into=20=C2=A75.3/=C2=A76?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- docs/design/m7_trust_fund_accounting.md | 67 ++++++++++++++++++------- 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/docs/design/m7_trust_fund_accounting.md b/docs/design/m7_trust_fund_accounting.md index 22d7f83c..79aad241 100644 --- a/docs/design/m7_trust_fund_accounting.md +++ b/docs/design/m7_trust_fund_accounting.md @@ -622,8 +622,10 @@ covered universe; real vs nominal). What is **not** honest, and what M7 must nev present as agreement: a levels-match of aggregate dollars, or a normalized rate gated against the external corridor as if the composition deltas were noise. They are not noise; they are the reason #113's roadmap "in LEVELS" gate is not -attainable here (§8 decision 1), and the reason §6 gates internal identities -instead. +attainable here (§8 decision 1), and the reason §6 gates internal identities while +these normalized shapes ride **report-only** as the option-(c) companion surface +(§8 decision 1) — the reading that honors "not just ordinally" without gating a +level the frame cannot support. ## 6. Proposed `gate_m7` (proposal for the referee — NOT locked) @@ -631,11 +633,17 @@ instead. accounting is arithmetically self-consistent and reproduces the committed M2 result, and it certifies **nothing external.** This is a deliberate departure from the roadmap #113 M7 row's "reproduce the TR baseline deficit … in LEVELS" -wording, argued in §5.3 and surfaced as §8 decision 1. The block below is a -**sketch for the referee**, `locked: false`, editing no `gates.yaml` cell and -built on no floor; it becomes real only in a future lock ceremony (design review → -referee → verification → ratify-by-merge → lock), which this document does not -begin. +wording, argued in §5.3 and surfaced as §8 decision 1. **The departure is not +self-ratifying:** the committed "in LEVELS" row is contract until amended, so +adopting this gate requires an explicit **roadmap #113 amendment ceremony** (§8 +decision 1) — a design doc/referee cannot retire it by argument. The gate ships +alongside the **option-(c) report-only companion surface** (the normalized % of +taxable-payroll cost/income-rate and balance shapes, composition deltas named, +§5.3), which honors "not just ordinally" without gating a frame-relative level. +The block below is a **sketch for the referee**, `locked: false`, editing no +`gates.yaml` cell and built on no floor; it becomes real only in a future lock +ceremony (design review → referee → verification → ratify-by-merge → lock), which +this document does not begin. ```yaml gate_m7-proposed-not-locked gates: @@ -733,16 +741,41 @@ and reproduces M2 (§6). It supports **no** claim beyond that. In the campaign's These are under-determined and are **listed, not silently resolved.** Each states the choice, the options, and this design's lean — the referee decides. -1. **Internal gate vs the roadmap's external-level gate (the central one).** #113 - M7 says gate on "the TR baseline deficit … in LEVELS" and "per-provision balance - vs the Five-Approaches A-tables in LEVELS." §5.3 argues those levels are not - honestly gradable on a survey panel. *Options:* (a) internal-identity gate - (§6); (b) the roadmap's external-level gate with a pre-registered tolerance; (c) - a normalized-shape gate on % of taxable payroll with composition deltas held - fixed. **Lean: (a)** — it matches the M2 precedent and the campaign's "levels - are frame-relative" discipline; (b) would gate the composition mismatch as if - it were model error. This lean directly contradicts the roadmap wording, which - is why it is decision 1 and not a silent choice. +1. **Internal-identity gate vs the roadmap's external-level gate (the central + one).** #113 M7 says gate on "the TR baseline deficit … in LEVELS" and + "per-provision balance vs the Five-Approaches A-tables in LEVELS, **not just + ordinally**." §5.3 argues those levels are not honestly gradable on a survey + panel. *Options:* (a) internal-identity gate (§6); (b) the roadmap's **raw + external-level** gate with a pre-registered tolerance; (c) a **normalized-shape** + gate on % of taxable payroll with composition deltas held fixed. + - **Rebuttal of (b):** raw levels certify the frame's composition/universe gap as + fidelity — M2's baseline balance is `+0.04689`, the arithmetic opposite of the + real deficit, purely from OASI-only outlays against full-rate revenue. + - **Option (c) taken seriously (not dismissed as (b)).** (c), not (b), is the + roadmap-faithful reading of "not just ordinally": normalizing by taxable + payroll divides out the universe-size mismatch (§5.3), so (c) is not obviously + composition-gaming. But **gating** (c) still fails: (i) "holding composition + fixed" needs a composition to hold it *to* — the covered-worker universe the + panel does not represent — so the gate re-imports an external target the frame + cannot honestly hit; (ii) M2's **F2 `τ=0.667`** shows even the weaker, + more-transportable *ordering* already misses Smith on this compressed frame, so + a tighter normalized-**level** band fails a fortiori. **Conditional adoption:** + M7 adopts (c) as a **report-only companion surface** (the normalized + cost/income-rate and balance-in-%-of-payroll shapes, composition deltas named + and held fixed, laid beside the Trustees corridor per §5.3) — which *honors* + "not just ordinally" (M7 reports normalized shapes, not merely orderings) + **without gating** a level the frame cannot support. N6: the roadmap's own + unlock says the Rosetta stone is "graded **in its own units**" (frame-relative), + in tension with the same row's "in LEVELS"; the companion resolves that tension + the way the unlock language leans. + - **Ratification path (not a referee blessing).** A design doc cannot retire the + committed "in LEVELS" gate row by argument; that row is **contract until + amended**. The honest path is an explicit **roadmap #113 amendment ceremony** + (proposal → adversarial referee → verification → ratify-by-merge) that replaces + "in LEVELS" with the §6 internal-identity gate **plus** the (c) report-only + companion. This doc *proposes* that substitution; it does not enact it. + - **Lean: (a) gated + (c) report-only companion, ratified via a #113 amendment** + — not (b), and not (c)-as-a-gate. 2. **Nominal vs real accounting (§2.5).** *Options:* (a) M2's wage-indexed real dollars (no CPI-W needed, real interest 2.9%); (b) nominal (Trustees' printed units, requires the CPI-W and nominal special-issue series — both §4.3 gaps). From 62ced18a4c0daa1701927427425ddf74ced97083 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Jul 2026 14:05:25 -0400 Subject: [PATCH 16/18] =?UTF-8?q?M7=20fixes:=20S3=20sex-dimension=20coupli?= =?UTF-8?q?ng=20to=20m6-sex-patch=20(=C2=A72.1=20+=20decision=2013);=20S4?= =?UTF-8?q?=20revision-2=20log=20+=20thirteen-decision=20count?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- docs/design/m7_trust_fund_accounting.md | 40 +++++++++++++++++++++---- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/docs/design/m7_trust_fund_accounting.md b/docs/design/m7_trust_fund_accounting.md index 79aad241..5ff1825a 100644 --- a/docs/design/m7_trust_fund_accounting.md +++ b/docs/design/m7_trust_fund_accounting.md @@ -7,9 +7,10 @@ anchors: #74 (the anchor catalogue, the "Rosetta stone" anchor 2), #100 (W1/W2/W3 seams), #106 (external review). Depends on M6 exposing the §6 levels (`docs/design/m6_projection_engine.md` §6) on the projected panel. -- **Status**: DESIGN (draft, revision 1) — **for the adversarial fable referee +- **Status**: DESIGN (draft, revision 2) — **for the adversarial fable referee round, which follows the in-flight `gate_m6` verdict** (this document does not - trigger it). **This document edits no `gates.yaml` cell, moves no threshold, + trigger it). Revision 2 applies the round-1 referee's SPEC-SOUND fixes (see the + revision log). **This document edits no `gates.yaml` cell, moves no threshold, builds no floor, writes no test, and runs no scored anything.** The proposed `gate_m7` in §6 is a *proposal for the referee*, not a lock. - **What M7 is, in one sentence**: a **deterministic accounting layer** that @@ -51,9 +52,19 @@ ## Revision log (finding → section) -- Revision 1 seeds the document for the referee round. No findings yet; the - referee's verdict and any ten-decision adjudication will be mapped here in - revision 2, exactly as the M6 doc maps PR #170's round. +- **Revision 2** applies the round-1 SPEC-SOUND referee (PR #202 comment + 4972284096; 0 BLOCKING, 4 SHOULD-FIX, 6 NOTE). **S1** (CPI-W/COLA is a *present* + pe-us node, not an absent series) → §4.1 / §4.2 / §4.3 (A/B/C reclassification) + + §2.5; **S2** (Decision 1 — roadmap #113-amendment ratification path + option-(c) + report-only companion) → §5.3, §6, §8 decision 1; **S3** (sex-dimension coupling + to `m6-sex-patch`) → §2.1, §8 decision 13; **S4** (stale count) → this log + + §8 now lists **thirteen** decisions. Notes: **N1** (aux already bound in-repo) → + §4.3 A; **N2** (bend-constant label: 1979-cohort / 1977-indexed) → §4.1 / §4.2; + **N3** (candidate-16 is a gate-2 identity M6 consumes) → §2.4, §3; **N4** (gate_m4 + internal reproduction vs concept-bridged anchor cells) → §2.6; **N5** + (cross-platform byte-identity needs a pinned numpy build) → §3; **N6** ("graded in + its own units" roadmap tension) → §8 decision 1. +- **Revision 1** seeded the document for the round-1 referee. ## 1. Summary @@ -127,6 +138,12 @@ its own. Quoting the M6 contract, M7 consumes, keyed by `(year)`: - **benefit outlays by type by year** — OASI retired-worker, DI disabled-worker, 402(b)/(c)/(e)/(f) auxiliary, survival-weighted on the calendar (M4 DI + auxiliaries; FRA conversions per `disability_conversion.py`); +- **person sex and the sex-resolved mortality/survival state** — the survivor and + spousal outlays (`widow_benefit`, 402(e)/(f), `ss/benefits.py:266-328`) and the + survival weighting `S` are sex-dependent (who-survives-whom; M2 itself carries + `n_careers_mermin_sex_resolvable`), so M7 consumes person sex from the projected + panel. The panel's **sex construction is an upstream dependency** — the in-flight + `m6-sex-patch` is changing which frame supplies it (§8 decision 13); - **immigration entries by year** — the synthetic entrant cohorts M2 structurally lacks (M2's frame is *closed*, `n_common_frame 1549`, `weight_sum 33696344.0`); - **the per-year alignment-layer adjustments** — the versioned interventions M6 @@ -840,6 +857,19 @@ the choice, the options, and this design's lean — the referee decides. "beneficiary" (dual-entitled counted once or by class; auxiliary-only recipients). *Open;* affects only the report-only per-capita corridor. **Lean:** unique-person beneficiary count with a class-breakout table, disclosed. +13. **Panel sex source — the `m6-sex-patch` coupling (§2.1).** M7's survivor/spousal + outlays and survival weighting consume person sex from the projected panel. The + real staged-PSID `demo` frame has **no `sex` column** (`(892,639 × 7)`: + `person_id, period, age, sequence, relationship, weight, interview`); the + in-flight `m6-sex-patch` (grading 4972045579) sources sex in + `build_realized_population` from where it actually lives (a sibling + `load_sources` frame). *Coupling:* because M7 "consumes a fixed panel," the + patch's **canonical sex-source choice** shifts M7's report-only M6-panel + survivor outlays. *Insulation (why not blocking):* the gated M2-repro run rides + the frozen M2 artifact (already sex-resolved) and the M6-panel survivor levels + are report-only (§2.6). **Lean:** M7 consumes whatever canonical sex column the + patched builders certify, records the frame-stack revision in provenance, and + discloses the coupling — it picks no sex source of its own. The referee is invited to add decisions this draft missed; the revision-2 log will map the round's verdict to these entries, as M6's did. From 8a95a5d3910ea2fd6f1deabe1498a3a7284fcef3 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Jul 2026 14:08:18 -0400 Subject: [PATCH 17/18] =?UTF-8?q?M7=20fixes:=20=C2=A79=20JSON=20provenance?= =?UTF-8?q?=20rev-2=20(A/B/C=20bindings,=20decision=2013,=20ratification?= =?UTF-8?q?=20path);=20reconcile=20stale=20=C2=A74.3=20gap=20cross-refs=20?= =?UTF-8?q?to=20A/B/C=20scheme=20(=C2=A72.3,=20=C2=A78=20dec=202/3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- docs/design/m7_trust_fund_accounting.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/docs/design/m7_trust_fund_accounting.md b/docs/design/m7_trust_fund_accounting.md index 5ff1825a..61d4c057 100644 --- a/docs/design/m7_trust_fund_accounting.md +++ b/docs/design/m7_trust_fund_accounting.md @@ -242,8 +242,8 @@ is `pia(aime(history), eligibility_year)` (`ss/benefits.py:100-131`). M7 sums including dual entitlement, the RIB-LIM, and the 71.5% survivor floor. These require M3 couple/household structure (who is married to whom, who survives whom) — **bounded by `gate_2` (2b household composition, 2c couple formation) - and mortality**. Their rate constants have **no pe-us node** and are carried as - statute-cited constants (§4.3, the LOUD gap). + and mortality**. Their rate constants have **no pe-us node** but are **already + bound and tested in-repo** as statute-cited constants (§4.3 A) — not a gap. **The unifying certification rule.** Across all three classes, **every benefit dollar level is report-only** (AIME/PIA/claiming/auxiliary are never gated). What @@ -795,11 +795,12 @@ the choice, the options, and this design's lean — the referee decides. — not (b), and not (c)-as-a-gate. 2. **Nominal vs real accounting (§2.5).** *Options:* (a) M2's wage-indexed real dollars (no CPI-W needed, real interest 2.9%); (b) nominal (Trustees' printed - units, requires the CPI-W and nominal special-issue series — both §4.3 gaps). + units, requires wiring the present CPI-W/COLA node (§4.3 B) and binding the + absent nominal special-issue interest series (§4.3 C)). **Lean: (a) for the gated M2-repro run** (mandatory — M2 is real); the M6-panel report-only run may additionally present (b) if the CPI-W/interest bindings are staged. Mixing the two within one ledger breaks identity (I). -3. **Calibrated reserve vs sourced opening balance (§2.4, §4.3 gap 5).** *Options:* +3. **Calibrated reserve vs sourced opening balance (§2.4, §4.3 C).** *Options:* (a) keep M2's calibrated `reserve_0` (disclosed, frame-relative, reproduces M2); (b) bind an SSA TR historical opening-balance series. **Lean: (a) on the M2-repro run** (required for reproduction); (b) is only meaningful if the @@ -885,9 +886,10 @@ block and its floor are authored in a future lock ceremony (§6). ```json m7-design-parameters { "design_id": "2026-07-14-m7-trust-fund-accounting", - "revision": 1, + "revision": 2, + "revision_2_note": "applies round-1 SPEC SOUND referee (PR #202 comment 4972284096, 0 BLOCKING / 4 SHOULD-FIX / 6 NOTE): S1 CPI-W/COLA reclassified as a PRESENT pe-us node (gov/ssa/uprating.yaml); S2 decision-1 roadmap #113-amendment ratification path + option-(c) report-only companion; S3 sex-dimension coupling to m6-sex-patch; S4 count; N1-N6", "status": "design_draft_for_referee", - "referee_round": "follows the in-flight gate_m6 verdict; NOT triggered by this document", + "referee_round": "the design referee round follows the in-flight gate_m6 verdict; NOT triggered by this document; verification referee follows the fixes", "gates_yaml_untouched_by_this_document": true, "builds_no_floor_writes_no_test_runs_nothing_scored": true, "roadmap_m7_row_verbatim": "Full revenue + trust-fund accounting: OASDI cost/income rates, trust-fund ratio path, 75-yr actuarial balance in % of taxable payroll | gate: Reproduce the corresponding TR baseline deficit within a pre-registered tolerance; per-provision balance vs the Five-Approaches A-tables in LEVELS, not just ordinally | unlocks: The Rosetta stone (#74 anchor 2) graded in its own units", @@ -897,7 +899,7 @@ block and its floor are authored in a future lock ceremony (§6). "determinism": "byte-identical accounts on re-run; no RNG at the accounting layer (all draws realized upstream in M6)" }, "explicitly_not_gated": "external SSA/Trustees aggregates; TR baseline deficit in LEVELS; per-provision A-table LEVELS; DI trust-fund balance as a certified level; any beneficiary-class dollar level", - "central_open_decision": "roadmap asks to gate in LEVELS (#113 M7 row); this design argues the 1549-career PSID survey panel is not the covered-worker universe (M2 baseline balance +0.04689 is positive because revenue is combined-OASDI on all payroll while outlays are OASI-only), so external levels are frame-relative and not honestly gradable -> proposes an internal-identity gate instead (§8 decision 1, for the referee)", + "central_open_decision": "roadmap asks to gate in LEVELS (#113 M7 row); this design argues the 1549-career PSID survey panel is not the covered-worker universe (M2 baseline balance +0.04689 is positive because revenue is combined-OASDI on all payroll while outlays are OASI-only), so external levels are frame-relative and not honestly gradable -> proposes an internal-identity gate + option-(c) normalized-shape REPORT-ONLY companion, retiring the 'in LEVELS' row via a roadmap #113 amendment ceremony (not by referee argument alone); §8 decision 1", "m2_reproduction_targets": { "commit": "747966cd", "pe_us_revision": "bf71be3b", "baseline_balance": 0.04689166331354922, @@ -911,12 +913,14 @@ block and its floor are authored in a future lock ceremony (§6). "input_bindings": { "pe_us_pin": "1.752.2", "vintage_boundary_T_star": 2014, "present_in_pe_us": ["payroll_rate_employee_employer", "wage_base", "nawi", "pia_formula_factors", "fra_schedule", "early_delayed_adjustment_rates"], - "LOUD_GAPS_need_3d_style_amendment": ["auxiliary_402bcef_rate_constants", "trust_fund_interest_rate", "tr_ultimate_assumptions_2014", "cola_cpiw_benefits_in_payment", "trust_fund_opening_reserve"], + "already_bound_in_repo_statute_constants_A": ["auxiliary_402bcef_rate_constants (ss/benefits.py, tested runs/aux_benefit_examples_v1.json)"], + "present_in_pe_us_not_yet_wired_bind_like_nawi_B": ["cpi_w_cola via gov/ssa/uprating.yaml + gov/bls/cpi/cpi_w.yaml"], + "genuinely_absent_LOUD_GAPS_need_amendment_C": ["trust_fund_interest_rate", "tr_ultimate_assumptions_2014", "trust_fund_opening_reserve"], "tamper_gate": "scripts/registered_m7_inputs.py build_inputs() zero-arg; version+dir assert (M6 2.8.10.5 F2); sha256 on staged JSON (M6 2.8.10.4); validate_external_vintage refuses vintage>2014 (refit.py:825-838)" }, "anchors_all_report_only": ["m2_reproduction (internal, feeds gate)", "mermin_2005_table1_411260", "smith_2015_solvency_72196", "ssa_trustees_historical_corridors (level-vs-composition caveat)"], - "open_decisions_for_referee": ["1 internal-gate vs roadmap external-level gate", "2 nominal vs real accounting", "3 calibrated reserve vs sourced opening balance", "4 OASI-vs-DI rate/fund split", "5 scheduled vs payable baseline + post-exhaustion rule", "6 inherit M6 wage-index surface vs re-derive", "7 M6-unexposed level: raise vs synthesize", "8 interest timing convention", "9 M2-reproduction byte-exact vs 1e-12 tolerance", "10 TR vintage for corridors 2014 vs current", "11 immigrant-entrant partial-career treatment", "12 per-capita beneficiary denominator"], - "evidence_base": ["runs/m2_pseudo_projection_v1.json", "scripts/m2_pseudo_projection.py", "ss/params.py", "ss/benefits.py", "docs/design/m6_projection_engine.md#6", "gates.gate_m4", "disability_conversion.py", "scripts/replication_cost_ordering.py", "engine/refit.py:825-838", "harness/m6_inputs.py:198-250"] + "open_decisions_for_referee": ["1 internal-gate vs roadmap external-level gate", "2 nominal vs real accounting", "3 calibrated reserve vs sourced opening balance", "4 OASI-vs-DI rate/fund split", "5 scheduled vs payable baseline + post-exhaustion rule", "6 inherit M6 wage-index surface vs re-derive", "7 M6-unexposed level: raise vs synthesize", "8 interest timing convention", "9 M2-reproduction byte-exact vs 1e-12 tolerance", "10 TR vintage for corridors 2014 vs current", "11 immigrant-entrant partial-career treatment", "12 per-capita beneficiary denominator", "13 panel sex source (m6-sex-patch coupling)"], + "evidence_base": ["runs/m2_pseudo_projection_v1.json", "scripts/m2_pseudo_projection.py", "ss/params.py", "ss/benefits.py", "gov/ssa/uprating.yaml", "gov/bls/cpi/cpi_w.yaml", "docs/design/m6_projection_engine.md#6", "gates.gate_m4", "disability_conversion.py", "scripts/replication_cost_ordering.py", "engine/refit.py:825-838", "harness/m6_inputs.py:198-250", "PR #202 referee comment 4972284096", "m6-sex-patch grading 4972045579"] } ``` From 6ed5df9be5469cd854d8504a12c25a8ac4c3adfb Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Jul 2026 14:16:03 -0400 Subject: [PATCH 18/18] =?UTF-8?q?M7=20fixes:=20=C2=A74.3=20B=20=E2=80=94?= =?UTF-8?q?=20CPI-W=20actuals=20run=20through=202025=20(2026=20is=20first?= =?UTF-8?q?=20CBO-forecast=20row);=20verification=20residual?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- docs/design/m7_trust_fund_accounting.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/design/m7_trust_fund_accounting.md b/docs/design/m7_trust_fund_accounting.md index 61d4c057..c886b57b 100644 --- a/docs/design/m7_trust_fund_accounting.md +++ b/docs/design/m7_trust_fund_accounting.md @@ -464,7 +464,8 @@ the statute itself" exception pe-us's tree forces for the 1979-cohort bend amoun a STOP).** The **CPI-W / COLA** series a nominal M7 (§2.5) needs is **present in policyengine-us**: `gov/ssa/uprating.yaml` — "the US indexes Social Security benefits (OASDI and SSI) … annually updating based on **CPI-W in the third quarter -of the prior year**," actuals through 2026, CBO-married forecasts through 2035, and +of the prior year**," actuals through 2025 (2026 is the first CBO-married forecast +row), forecasts through 2035, and 2036–2100 set programmatically — plus the raw `gov/bls/cpi/cpi_w.yaml` index (from 1913). The repo's `ss/` wrapper simply doesn't load it yet (`ss/benefits.py` computes the claim-year benefit only). So COLA is **not** a trust-fund-perimeter