בס״ד

MIS Engine — Freeze-Lift Fix List (canonical spec for the fix session)

docs/MIS_FREEZE_FIX_LIST.md · last changed (pre-VM history) · rendered from GitHub master

MIS Engine — Freeze-Lift Fix List (canonical spec for the fix session)

EXECUTED 2026-07-01 (4:54–6:25 PM ET, MIS engine-fix session). All 7 fixes applied in order (deploys @126–@132), #15A/#15B run after every change and every scale step, universe scaled 27→50→183→237, histogram gate PASSED, health GREEN 0/0 at 237. Recon: 898 GREEN (fix 4); 600/5692/5378 pending the nightly control refresh. Evidence: MIS/v2/baselines/ (7 commits on zee78900/MIS) + outputs/2026-07-01_18-22_audit_mis-freeze-fix-window-executed.html. ✅ FREEZE LIFTED — Sam signed off 2026-07-01 (independently verified: health GREEN 237/237, @132). Condition: Fidelity recon gaps >5% persisting after a fresh import = real data bug, fix before trusting portfolio dollars. Track-B stays queued. Deviations (all documented in the audit): SOXX legacy STARTER→REJECTED (real-RR correction, intended by fix 6) · SPCX proposed HOLD→EXIT (sector peer-set enrichment at scale, module-blessed explainable class, flagged to Sam) · Trend jitter ±2–4 on a few names via FlowStrength's sector z-term (queued as a Track-B calibration item with captured evidence).

Built 2026-07-01 from a 4-agent soundness audit (phantom/formula · v11-8-flaws · live-output · off-sheets). This is the exact, evidence-based work required to make the MIS scoring engine safe to scale 27 → 237 and lift the freeze. Execute this in full, in order, with the guardrails. Don't re-derive — the audits already found everything.

THE VERDICT (why this exists)

The engine's brain is SOUND — real prices (no phantoms in the verdict path), the v11 disease is cured (all 4 critical flaws + the inversion genuinely fixed), the proposed verdicts are correct & non-inverted (leaders→STARTER/ADD, losers→EXIT, coherent one-liners), and the logic is portable (zero GOOGLEFINANCE in the scoring/decision functions — the 6-min/750-col/200-tab walls are all DATA-layer, not logic). But it is NOT scale-ready — 4 audits converged on score-range compression + a few defects. Fix them, prove it with data, run the immutability tests, THEN scale. It's corrections, not a rebuild.

READ FIRST (don't skip — this is the anti-rediscovery rule)

THE FIX-LIST (exact — location · problem · fix)

  1. 🔴 RS_Sector horizon mismatch — Momentum_Engine col AT: currently =K2 − AN2 = 30D% ticker − 3D% sector mean (AN2 averages col I = 3D%). Feeds VSM→SACS→the verdict gate. Fix: make the sector mean 30D-based (average col K = 30D% within sector) so it's 30D-vs-30D, matching the (correct) RS_SPY at col AS. Add a real SectorMean30D/SectorStdev30D if needed.
  2. 🔴 Score-range compression (THE scale blocker — confirmed live) — Setup is hard-capped at ~49, SACS tops at ~70, only ONE of 27 names clears the "≥60" gate, ~14/27 sit below 25 — everything crams into 0–55. At 237 the shortlist gate becomes meaningless. Fix: apply the scale-expansion so scores use the full 0–100 range with real separation (re-weight/expand SACS = Flow*0.5 + RS_SPY*25 + RS_Sector*25 and the Setup/Composite so leaders reach 70–90); add a MIN(100) clamp on SACS (it can currently exceed 100 — the "0-100" contract is broken). Target: post-fix, the 40–60 band < ~35% and stdev materially above the old 12.1, with multiple names able to clear 60.
  3. 🔴 Absolute-score conversion (#15A — required to scale) — scores are currently percentile/set-relative (rankerFor), so embedding 20 names inside 237 shifts them by construction. Convert to ABSOLUTE (fixed input → 0-100 bands) per the calibration module ("scores ABSOLUTE, grades RELATIVE"). This is THE scale-invariance fix — without it, scaling changes existing scores.
  4. 🟠 898 / reconciliation gapmisV2PortfolioRecon_ + misV2GrossByAccount_ read HOLDINGS_CLEAN, which no longer contains 898 (the Fidelity-only import dropped it) → recon shows Schwab 898 = $0, RED. The live-Schwab override already exists in misV2BookData_extend it into the recon/gross path so 898 uses the live Schwab accounts API there too. Then reconcile the 3 conflicting equity numbers into ONE canonical (portrecon $24,792 vs snapshot $33,659 vs old $22,135). The engine correctly blocks portfolio dollars until recon is GREEN — get it GREEN.
  5. 🟡 ATR-floor guard — a stop < 0.5% of price → Shares = 0 (stops bond/treasury ETFs computing oversized share counts).
  6. 🟡 Per-name RR — RR is hardcoded 2.5 for every name (zero discriminating info). Compute real per-name reward:risk (Target%/Risk% off the ATR bracket). Confirm the FSE risk gate uses the real per-name RR, not the constant.
  7. 🟡 Wire recoscore — the forward-return self-grading loop reads "scored 0 this run"; wire it so there's an accumulating track record that the calls actually make money (1d/3d/5d forward returns on the engine's own ADD/STARTER calls).

METHOD (mandatory — this is how you don't break the 27)

  1. Shadow/copy first. Never edit the live scoring cold. Compute changes on a shadow (the misV2ComputeShadow_/FACTOR_DIAGNOSTICS tooling exists) or a Drive COPY of the sheet; verify; only then promote.
  2. After EACH fix, run #15A (score immutability) + #15B (action immutability) on the frozen 27-name baseline — the 27 verdicts must NOT move, except where a fix intentionally corrects one (document it explicitly). Baseline scores were the frozen 27/27 set (recompute the baseline first if the JSON is absent).
  3. Prove the fix with DATA, not "by design": run FACTOR_DIAGNOSTICS / shadowscores on the live ~183 → produce the distribution histogram showing the 40-60 band < 35%, stdev up, multiple names clearing 60. This is the evidence gate for fix #2.
  4. Deploy (each change): from MIS/v2/, clasp push -f then clasp deploy -i <LIVE_DEPLOYMENT_ID> (find via clasp deployments — the @NNN versioned one, currently the one titled with the latest change). Then curl-verify: ?fn=verify&token=<RUN_TOKEN> (proposed-state table), ?fn=fse&token=…, ?fn=shadowscores&token=… (RUN_TOKEN + MIS_SETUP_KEY are constants at the top of Code.gs). Exec base: https://script.google.com/macros/s/<deploy>/exec.
  5. Then scale the universe in stages: 27 → 50 → 183 → 237, running #15A/#15B at EACH step. STOP RULES: any baseline drift, formula error, stale/phantom value, distribution collapse, or #15 failure → halt + report.

GUARDRAILS (🔴 do not violate)

DONE (= the freeze is liftable)

Fix-list applied · #15A/#15B pass at every scale step · FACTOR_DIAGNOSTICS histogram proves the spread · recon GREEN ×5 · scaled to 237 with no drift · then Sam signs off and the freeze is formally lifted. Update MIS_OPERATOR.md (freeze → LIFTED, with the evidence) + CONTEXT.md.

Source trail · docs/MIS_FREEZE_FIX_LIST.md @ master · rendered 2026-07-02 7:23 PM EDT by scripts/build-docs.py · the .md in the repo is the truth; this page is the phone-readable view