From c7a670aa09aa31ce7bc126a033b7c0f3b5d9cd02 Mon Sep 17 00:00:00 2001 From: krisf Date: Fri, 9 Oct 2026 20:38:15 -0400 Subject: [PATCH] audit: math-fix pass 56 re-verification (all gates fresh, OFFLAN-OK 00:36Z, deploy + 34/34 sweep, passes3 byte-identical to passes 14-55 (43 consecutive), all five row JSONs byte-identical, probe+legs+scan+rowsweep+capture logs diff-identical to pass 55 (tag-normalized), 3x MIXEDLIVE-OK incl. 52/56 clamp-driven dagger row, FIRE draw-at-40 live, canonical-couple+tagged md5-identical pair cbac51ed, fire-step-390 triple md5-identical 761e8055, reachable byte-identical, fire/mixed/mixed5256 band-limited y234-899 diffs only) --- MATH-FIX-REPORT.md | 21 +++++++++++++++++++++ audit/bilingual-geo-check.json | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/MATH-FIX-REPORT.md b/MATH-FIX-REPORT.md index d32e9c9..a6e1ce4 100644 --- a/MATH-FIX-REPORT.md +++ b/MATH-FIX-REPORT.md @@ -1455,3 +1455,24 @@ Determinism: `passes3-pass55.txt` (`01075d0e…`, **forty-two consecutive** pass **No code change required** — engine/renderer/i18n/tests byte-stable vs pass 54, deployed build verified identical 34/34. All plan acceptance criteria (1–6) re-verified against the deployed build. Final: **MATH_FIX_DONE**. Addendum (post-push, same pass): audit commit `738753a38096fb9825d365216391c9baca239c4f` pushed `e13f5e6..738753a` → `origin/main` (report + fresh off-LAN stamp `2026-10-10T00:30:29Z`; code untouched — the plan’s mandated fix commit `08398267040a832bdec0910626423f0dbfeb0a7f` remains the code change under test, confirmed ancestor of `HEAD`). Post-push `git fetch` + full byte sweep re-run vs the new `origin/main`: `git diff e13f5e6..HEAD -- site` = **0 lines** (zero site delta, so the sweep carries over by construction), origin blob == local == webroot md5, tracked **21/21 (3-way)** + gitignored `site/vision/*.jpeg` **13/13 (2-way)** = **34/34 match, 0 mismatch** → `SWEEP-OK`; `HEAD` == `origin/main` == `738753a`. + +--- + +## Addendum — Pass 56 (re-verification of `0839826` on `2f98219`, all gates fresh) + +Start gate: `git status --porcelain` empty at HEAD `2f98219` → proceeded (not DSH_QUEUE_BUSY). All plan fixes re-confirmed in source at HEAD: GIS 65+ floor at every `gis()` call site in `solve()` (`engine.js:249/260/265`, `var g = a >= 65 ? gis(…) : 0`) + Service Canada source comment (`:89`) + merge gates — per-partner age≥65 comment (`:373`) and `if (yr < 65) gisSum = 0;` (`:382`); clawback gated `oasGross > 0` + capped at OAS paid in both `solve` legs (`:248/:259`, s.3(1) ETA comment `:80–83`), splitting comparison same rule (`:366–367`), `row.oasClawback = r.cw` (`:302`) + `row.oasClawback = clawSum` (`:371`); `row.mixed` flag (`:390`) + depletion guard excludes mixed windows (`:395`); `fillDefaults` clamp `+o.retireAge < +o.age + 1 → age+1` (`:188`); quiz slider `min: 40` (`app.js:211`) + FIRE hint EN/FR (`i18n.js:96/357`); `#wi-ret min="40" max="72"` (`index.html:86`); renderer `†` suffix + `#yr-mixed-note` legend (`app.js:810/812/817–819`, `index.html:95`) with `t.mixedNote` EN/FR (`i18n.js:251/512`); plan tests 1–4 present (`engine.test.js:119–203` — GIS/clawback pre-65, couple mixed-window invariants + `mixed` never on non-draw rows + depletion never on a mixed row, `fillDefaults({age:52, retireAge:40}) → 53` / `({age:30, retireAge:40}) → 40`, stale-state first draw 53, “FIRE: rows 40–64 have GIS 0 and clawback 0”). `git merge-base --is-ancestor 0839826 HEAD` ✓ (ANCESTOR-OK); `git diff 0839826..HEAD -- site` = **0 lines**; `git fetch` → `HEAD` == `origin/main` == `2f98219`. + +| Gate | Result (this pass) | +|---|---| +| Unit suites | engine **61/61**, i18n **50/50** (`I18N-OK`, incl. `q.retire.hint` FIRE EN+FR + `t.mixedNote` parity), ps-pension **70/70**, ps-auto-service **21/21**, UI smoke **146/146** (`SMOKE-OK`, incl. legend element under yearly table) — all fresh, 0 fail | +| Hermes 3 passes (`passes3.js`, live engine) | `audit/math-fix/passes3-pass56.txt` md5 `01075d0e…` — **byte-identical to the pass-14→55 log (43 consecutive)**; PASS 1 (screenshot repro): row 55 Total $68,327 / Withdraw $102,139 / OASnet **$0** / GIS **$0** (was −$3,501 / $12,916 phantom), first GIS **65**, depletion 56 honest, **conservation OK** ×3. `.tmp/mathfix25/scan3.py` lineage scanner (md5 `7dd74a65…`) → `.tmp/mathfix56/scan56.log` **byte-identical (`diff` empty) to the pass-55 sweep**: PASS 1 rows=43 firstDraw=55 firstGIS=65, row55 wdr=102139 oasnet=0 gis=0, depletion 56, max $166,308 @54; PASS 2 depletion 82 max $468,146 @64; PASS 3 firstDraw=**40** depletion 48 max $493,710 @39 = hand-math 350000×1.035¹⁰ ✓; GIS>0<65 / OASnet≠0<65 / negOAS / growTotalWithDraw lists empty in all three passes | +| Deploy | `scripts/deploy.sh` → **DEPLOY-OK** (retireapp live) | +| Byte sweep (post-deploy) | `sweep56.sh` sed-derived from `sweep55.sh` (`diff` after `56→55` normalization = byte-identical: header ordinal + 2 list paths only); tracked/ignored lists regenerated from `git ls-files`/`find`, **byte-identical to pass 55** (21 + 13; list md5s `91148036…`/`670089ca…`): tracked 3-way **21/21** + vision 2-way **13/13** = **34/34 match, 0 mismatch** → `SWEEP-OK`; sweep log diff-identical to pass 55 | +| Off-LAN (Midhurst `trouble@100.96.20.61`) | `OFFLAN-OK`, `"all_ok": true`, `"http_code": "200"`, `checked_at 2026-10-10T00:36:36Z` → `audit/bilingual-geo-check.json` | +| Live rows (canonical + tagged) | `rowsweep41.py` (md5 `3d8823d2…`, unmodified) over 4 files: couple rows=40 firstDraw=55 firstGIS=65 negOAS=[] GIS<65=[] OAS<65=[] growWW=[]; FIRE rows=57 firstDraw=**40** firstGIS=65 all invariant arrays empty → `ROWSWEEP-OK`, `.tmp/mathfix56/rowsweep56.log` **`diff`-identical to the pass-55 log (tag-normalized)**. Screenshot-scenario rows 58–64 (DOM read of `after56-couple-rows.json`): OAS **$0** every row (no negatives), GIS **$0** (<65), Total $0 — honest post-depletion drain (unfunded 58+: $47K → $93K; CPP $14K from 60), **no growing-Total-with-Withdraw rows** vs the screenshot's impossible 126→141K @3.5% | +| MIXEDLIVE probes (live site, tag `after56`) | 52/50 → dagger rows `[]`, legend hidden (`noteShown: false`), 0 violations; 50/54 → **`MIXEDLIVE-OK`** dagger `[54]`, EN legend shown verbatim, all violation lists `[]`; 52/56 (clamp-driven) → **`MIXEDLIVE-OK`** dagger `[56]`, legend shown, all violation lists `[]`; all three probe logs **byte-identical (`diff` empty) to pass 55**; engine-side `legs42.js` (md5 `33084975…`) → **`LEGS-OK`**, log **byte-identical to pass 55** (52/56 mixed row 56 grows with wdr $30,000 carrying ` †`) | +| FIRE acceptance | live FIRE table first draw **age 40** (`fire_first_draw_age: "40"` + rowsweep `firstDraw=40`; DOM row: age 40 Total $443K, Withdraw $63K); `#wi-ret` min **40** max **72**; 390px: slider `min=40 max=72 value=40` “40 years”, `sliderRight 367 ≤ vw 390` (**no clip**), chip [25, 145], FIRE hint EN present (“Early retirement (FIRE) supported — plan must self-fund the CPP/OAS gap years.”) — all values identical to the pass-55 capture; canonical capture log **byte-identical to pass 55**, tagged capture log **`diff`-identical** (tag/path-normalized) | + +Determinism: `passes3-pass56.txt` (`01075d0e…`, **forty-three consecutive** passes 14→56); all five row JSONs **byte-identical to pass 55 and the canonical lineage** — `after56-couple-rows.json` + canonical `after-couple-rows.json` `129e2a45…` (passes 14–55), `after56-fire-rows.json` + canonical `4af12e59…` (passes 15–55), `after56-mixed-rows.json` `96665bbf…` (passes 15–55), `after56-mixed-reachable-rows.json` `98c29f24…` (passes 26–55), `after56-mixed5256-rows.json` `53d0dec5…` (passes 33–55). **Frames** (md5 + PIL band diffs; this harness's model declares no image input — a direct image-read attempt this pass was rejected by the harness ("does not declare image input"), matching the passes 24–55 policy of not viewing images): **md5-identical pairs this pass** — canonical redraw `after-couple-table.png` == `after56-couple-table.png` both `cbac51ed…` (documented animation-phase variant, == passes 5/8/10–14/21–23/28/29/32–34/36/39/43–44/46–47/49/51–52; PIL bbox vs the pass-55 tagged canonical frame `eec99021…` confined to **y=234–899**, the G1 animation band; row JSON byte-identical); `after56-fire-table.png` `685fd711…` (documented canonical frame, == passes 15–20/24–27/35/37/41–43/45/47/49/51/54; PIL bbox vs the pass-55 frame `b4ed3a16…` **band-confined y=234–899**; canonical redraw this pass `after-fire-table.png` `b4ed3a16…` **byte-identical to the pass-55 frame**, PIL bbox canonical-vs-tagged band-confined, DOM row JSON byte-identical); `after56-fire-step-390.png` == canonical `after-fire-step-390.png` == `after55-fire-step-390.png` all `761e8055…` == passes 26–55, PIL bbox `None` **pixel-identical**; `after56-mixed-reachable-table.png` `87594d5a…` **byte-identical to the pass-55 frame** (documented lineage frame, == passes 49–50/55, PIL bbox `None`); `after56-mixed-table.png` `c1d065cc…` (documented frame, == pass 53; PIL bbox vs the pass-55 canonical-lineage frame `222c81a1…` `(0,234,1280,900)` **band-confined y=234–899**, DOM row JSON byte-identical `96665bbf…`); `after56-mixed5256-table.png` `36b82193…` (documented lineage frame, == passes 33–40/43/45/47–48/50/52/54; PIL bbox vs the pass-55 frame `6d792f12…` `(0,234,1280,900)` **band-confined y=234–899**, DOM row JSON byte-identical `53d0dec5…`). Harness: Playwright ran with `TMPDIR=.tmp/pw56` (sandbox TMPDIR read-only, as passes 39–55); probe/capture/legs/rowsweep/scan scripts `cp`-copied byte-identically (seven-script aggregate md5 `2f6ef752…` equal source↔destination; per-file `9489cef4…`/`61d66342…`/`4e30a51e…`/`377a4167…`/`33084975…`/`3d8823d2…`/`7dd74a65…` == pass-55 lineage values) into `.tmp/mathfix56/` and run with argv `after56`. + +**No code change required** — engine/renderer/i18n/tests byte-stable vs pass 55, deployed build verified identical 34/34. All plan acceptance criteria (1–6) re-verified against the deployed build. Final: **MATH_FIX_DONE**. diff --git a/audit/bilingual-geo-check.json b/audit/bilingual-geo-check.json index 9a5d95e..8019069 100644 --- a/audit/bilingual-geo-check.json +++ b/audit/bilingual-geo-check.json @@ -5,7 +5,7 @@ "has_i18n_script": true, "i18n_js_fr_strings": true, "i18n_js_size": 39689, - "checked_at": "2026-10-10T00:30:29Z", + "checked_at": "2026-10-10T00:36:36Z", "vantage": "trouble@100.96.20.61 (Midhurst, off-LAN)", "all_ok": true } \ No newline at end of file