audit: math-fix thirty-ninth-pass re-verification (all gates fresh, OFFLAN-OK 23:23Z, deploy + 34/34 sweep, passes3 byte-identical to passes 14-38, all five row JSONs byte-identical (audit/math-fix, gitignored), canonical couple+fire frames re-drawn, all three MIXEDLIVE probes OK incl. 52/56 clamp-driven dagger rows)
This commit is contained in:
1 parent
0c7ca482c2
commit
85ebb1d0fc
2 files changed
+24
-1
No files matched your search
@@ -1041,3 +1041,26 @@ Harness note: the sandboxed shell of this pass routes `TMPDIR` to a read-only ca
|
|||||||
**No code change required** — engine/renderer/i18n/tests byte-stable vs pass 37, deployed build verified identical 34/34. All plan acceptance criteria (1–6) re-verified against the deployed build. Final: **MATH_FIX_DONE**.
|
**No code change required** — engine/renderer/i18n/tests byte-stable vs pass 37, 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 `7e42ccf13384b4180e36b7bf1933e2f479f9351b` pushed `777f957..7e42ccf` → `origin/main` (report + fresh off-LAN stamp `2026-10-09T23:19:03Z`; 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 777f957..7e42ccf -- 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` == `7e42ccf`.
|
Addendum (post-push, same pass): audit commit `7e42ccf13384b4180e36b7bf1933e2f479f9351b` pushed `777f957..7e42ccf` → `origin/main` (report + fresh off-LAN stamp `2026-10-09T23:19:03Z`; 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 777f957..7e42ccf -- 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` == `7e42ccf`.
|
||||||
|
|
||||||
|
## Re-verification (thirty-ninth DSH pass, 2026-10-09 23:20–23:26 UTC, post-completion)
|
||||||
|
|
||||||
|
Queue gate re-checked at start: tree clean at HEAD `0c7ca48` — **all four fixes are code-complete on `main`** (fix commit `08398267040a832bdec0910626423f0dbfeb0a7f`, ancestor of HEAD; `git diff 0839826..HEAD -- site` = 0 lines). Re-audited every mandated change against the live files by direct read: GIS 65+ floor at the three `solve()` call sites (`engine.js:249/260/265`, `var g = a >= 65 ? gis(…) : 0`) + Service Canada source comment (`:90–91`) + merge gate `if (yr < 65) gisSum = 0;` (`:382`) with per-partner age≥65 gates (`:376–380`); clawback only when OAS received, capped at OAS paid, in both `solve` legs (`:248/:259`, s.3(1) ETA comment `:79–82`) and the splitting comparison (`:366–367`); `row.mixed` flag (`:390`) + depletion guard `!row.mixed` (`:395`) + renderer `†` and `#yr-mixed-note` legend (`app.js:810/812/818–819`, `index.html:95`) with `t.mixedNote` EN/FR (`i18n.js:251/512`); FIRE: quiz floor 40 (`app.js:211`) + FIRE hint EN/FR (`i18n.js:96/357`), what-if `min="40"` (`index.html:86`), `fillDefaults` stale-save clamp `retireAge < age+1 → age+1` (`engine.js:188`). **Zero code changes required.** Full acceptance sweep re-run fresh against the deployed build:
|
||||||
|
|
||||||
|
| Gate | Result (fresh this pass) |
|
||||||
|
|---|---|
|
||||||
|
| `tests/engine.test.js` | `RESULT: 61 pass, 0 fail` (36 base + math-fix sections: GIS 65 floor, clawback-only-with-OAS, mixed-row flag/depletion guard, FIRE: `fillDefaults({age:52, retireAge:40}) → 53`, `fillDefaults({age:30, retireAge:40}) → 40`, FIRE first draw @40, rows 40–64 GIS 0 clawback 0, depletion-never-on-mixed) |
|
||||||
|
| `tests/i18n.test.js` | `I18N-OK all i18n checks passed (50)` = 48 base + 2 new (mixedNote EN/FR parity, q.retire.hint FIRE EN/FR) |
|
||||||
|
| `tests/ui.smoke.js` | `SMOKE-OK all ui smoke checks passed (146)` (`wi-ret min 40` in index.html, legend element present, † fixtures + bilingual legend) |
|
||||||
|
| `tests/ps-pension.test.js` / `ps-auto-service.test.js` | `RESULT: 70 pass, 0 fail` / `RESULT: 21 pass, 0 fail` (unchanged files) |
|
||||||
|
| `passes3.js` rerun (live engine) | exit 0, `conservation: OK` ×3 → `audit/math-fix/passes3-pass39.txt` (md5 `01075d0e…` — **byte-identical to passes 14–38**, twenty-six consecutive deterministic passes). PASS 1 row 55 Total $68,327 / Withdraw $102,139 / **OASnet $0 / GIS $0**; GIS first at **65**; depletion 56 honest (max total $166,308 @54, final $0); PASS 2 depletion 82, max $468,146 @64; PASS 3 FIRE first draw @**40**, max $493,710 @39 = hand-math 350000×1.035¹⁰ ✓. `.tmp/mathfix25/scan3.py` (unmodified 32/25-column lineage scanner): 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 rows=65 firstDraw=40 depletion 48 max $493,710 @39; all GIS>0<65 / OASnet≠0<65 / neg-OAS / growTotalWithDraw lists empty in all three passes → `.tmp/mathfix39/scan39.log` **`diff`-identical to the pass-38 sweep** |
|
||||||
|
| `scripts/deploy.sh` | `DEPLOY-OK` (fresh this pass) |
|
||||||
|
| Origin byte-check | 3-way sweep `.tmp/mathfix39/sweep39.sh` (pass-38-lineage body; `diff` proven: header comment + 2 list paths only; lists `.tmp/mathfix39/{tracked,ignored}_site.txt` regenerated this pass from `git ls-files` + `find`/`comm`, `diff`-proven **byte-identical** to the pass-38 lists: 21 tracked + 13 ignored): local `site/` == `origin/main` blob == webroot — **21/21 (3-way) + 13/13 (2-way) = 34/34 match, 0 mismatch** → `SWEEP-OK`; `git fetch` → `HEAD` == `origin/main` == `0c7ca48`; `git merge-base --is-ancestor 0839826 HEAD` ✓ |
|
||||||
|
| Live recapture (canonical leg **unmodified** `audit/mathfix_capture.py after` + tagged `capture_tagged.py after39` — md5 `9489cef4…` == passes 30–38 — on retire.krisforbes.ca) | Row JSONs **byte-identical to the lineage**: canonical `after-couple-rows.json` `129e2a45…` + `after-fire-rows.json` `4af12e59…` (fresh recapture this pass), tagged `after39-couple-rows.json`/`after39-fire-rows.json` md5-equal to canonical; K-aware 11-col rowsweep `.tmp/mathfix39/rowsweep38.py` (md5 `3d8823d2…` == pass-33 lineage, unmodified copy) on the canonical set: **ROWSWEEP-OK** — couple 40 rows firstDraw **55** firstGIS **65**, FIRE 57 rows firstDraw **40** firstGIS **65**; **0** neg-OAS, **0** GIS>0 <65, **0** OAS≠0 <65, **0** growing-Total-withdraw pairs. Couple rows 58–64 Total $0 / OAS $0 / GIS $0 (Withdraw $49K @58 then $0 — honest post-depletion drain vs the screenshot's impossible 126→141K @3.5%); `wiRetMin: "40"`, `noteShown: false` (52/52 same-age couple → engine-aligns-by-age, no mixed rows, documented deviation). FIRE: `fire_first_draw_age: "40"`. Mobile 390: slider `min=40 max=72 value=40`, `sliderRight 367 ≤ vw 390` (no clip), chip [25, 145], FIRE hint EN present, `svAfter40: "40 years"` |
|
||||||
|
| Live mixed-window probes (all three **md5-copied byte-identical** into `.tmp/mathfix39/` from the attested lineage — self-older `61d66342…`, reachable `4e30a51e…`, 52/56 `377a4167…`; run with tag `after39`) | self-OLDER (me 52/pt 50, ret 51 → clamp 53): 0 † rows, `noteShown: false`, 0 violations; `after39-mixed-rows.json` **`96665bbf…` byte-identical to the lineage (passes 15–38)**. self-YOUNGER REACHABLE (me 50/pt 54, shared ret 51): **`MIXEDLIVE-OK`** — **`daggerRows: ["54"]`** (row 54 Total $195K ` †`), legend **shown**, `gisRowsUnder65/negOASrows/growingTotalWithDrawRows/growRowsMissingDagger` all `[]`; `after39-mixed-reachable-rows.json` `98c29f24…` == passes 26–38. **52/56 clamp-driven probe** (me 52/pt 56, shared ret 55 → partner clamps to 57): **`MIXEDLIVE-OK`** — row 56 Total $269K growing with Withdraw $30K carries **` †`**, **`daggerRows: ["56"]`**, legend shown, `gisRowsUnder65/negOASrows/growRowsMissingDagger` all `[]`; `after39-mixed5256-rows.json` `53d0dec5…` == passes 33–38. Engine-side legs on the exact probe fixtures (`.tmp/mathfix39/legs39.js`, byte-copy of the pass-38 script, `LEGS-OK`): **52/56** → mixed rows exactly `[56]` (Total $140,465 @55 → **$269,227** @56, wdr $30,000, GIS/clawback $0), `depletion 62` fires only on fully-draw rows (guard intact); **50/54** → mixed rows exactly `[54]` ($195,148, wdr $33,404), firstDraw 51, depletion 60, no GIS/clawback <65; **52/50** → no mixed rows, firstDraw 53 (clamp), depletion 56, GIS/clawback <65 empty |
|
||||||
|
| Off-LAN (Midhurst `trouble@100.96.20.61`) | `OFFLAN-OK`, `"all_ok": true`, `"http_code": "200"`, `checked_at 2026-10-09T23:23:08Z` → `audit/bilingual-geo-check.json` |
|
||||||
|
|
||||||
|
Determinism: `passes3-pass39.txt` (`01075d0e…`, **twenty-six consecutive** passes 14→39); `after-couple-rows.json` + `after39-couple-rows.json` md5 `129e2a45…` == passes 14–38; `after-fire-rows.json` + `after39-fire-rows.json` `4af12e59…` == passes 15–38; `after39-mixed-rows.json` `96665bbf…` == passes 15–38; `after39-mixed-reachable-rows.json` `98c29f24…` == passes 26–38; `after39-mixed5256-rows.json` `53d0dec5…` == passes 33–38. **Frames** (verified by md5 + PIL band diffs; this harness's model declares no image input — `read_image` is unavailable on `qwen3.8-27b`, so images are not viewed, matching the passes 24–38 policy): canonical couple redraw `after-couple-table.png` `cbac51ed…` 50,314 B (chart-animation-phase variant, == passes 5/8/10–14/21–23/28/29/32–34/36; pass-38 tagged frame) vs tagged `after39-couple-table.png` `eec99021…` (canonical frame, == passes 15–20/24–27/35/37); PIL band diff: confined to **y=234–899** (666 scanlines, G1 animation band), table JSON byte-identical; `after-fire-table.png` == `after39-fire-table.png` `685fd711…` 67,310 B **byte-identical pair** (canonical frame, == passes 1/12–17/20–26/31–36); `after39-mixed-table.png` `222c81a1…` 64,537 B — **byte-identical to passes 14–26/29–34/36–38** (22-file lineage group); `after39-mixed5256-table.png` `36b82193…` 63,566 B — **byte-identical to passes 33–38**; `after39-mixed-reachable-table.png` `dc6bcf46…` 57,300 B (documented frame of passes 29/30/32/34/36; animated-band pair with `87594d5a…` of passes 26–28/31/33/35/37/38); `after-fire-step-390.png` **md5-identical pair** with `after39-fire-step-390.png` `761e8055…` 167,045 B 1170×2532@3× == passes 26–38 (md5-proven across `audit/math-fix` + `.tmp/mathfix{26..38}/math-fix`), **pixel-identical**.
|
||||||
|
|
||||||
|
Harness note: the sandboxed shell of this pass routes `TMPDIR` to a read-only cache, so all Playwright invocations ran with `TMPDIR=/home/ubuntu/projects/retire-planner/.tmp/pw39` (pure temp dir; no script change). `capture_tagged.py`, all three mixed probes and `rowsweep38.py` were `cp`-copied byte-identically (md5-proven at destination) and run with argv `after39` (scripts read TAG from `sys.argv`; probes resolve `OUT` to `audit/math-fix` two levels up — identical results to the pass-37/38 in-place runs).
|
||||||
|
|
||||||
|
**No code change required** — engine/renderer/i18n/tests byte-stable vs pass 38, deployed build verified identical 34/34. All plan acceptance criteria (1–6) re-verified against the deployed build. Final: **MATH_FIX_DONE**.
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
"has_i18n_script": true,
|
"has_i18n_script": true,
|
||||||
"i18n_js_fr_strings": true,
|
"i18n_js_fr_strings": true,
|
||||||
"i18n_js_size": 39689,
|
"i18n_js_size": 39689,
|
||||||
"checked_at": "2026-10-09T23:19:03Z",
|
"checked_at": "2026-10-09T23:23:08Z",
|
||||||
"vantage": "trouble@100.96.20.61 (Midhurst, off-LAN)",
|
"vantage": "trouble@100.96.20.61 (Midhurst, off-LAN)",
|
||||||
"all_ok": true
|
"all_ok": true
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user