12 — Legacy Retirement Readiness (real file:line evidence; retire-after-replace)
title: 12 — Legacy Retirement Readiness (Branch J) date: 2026-05-31 gate: P4 / macro M11 (after M2/M8/M3 + parity). NO production code changed this session. principle: retire-AFTER-replace (Đ30)
12 — Legacy Retirement Readiness (Branch J)
Each artifact retired only after its pivot-backed replacement is live + at parity. Real source
locations confirmed this session in /opt/incomex/docker/nuxt-repo/web (read-only ssh grep).
L1 — /api/registry/health gap-math (Đ28 violation) → RETIRE
File server/api/registry/health.get.ts:
:123totalGap: collections.reduce((s, c) => s + Math.abs(c.gap), 0)— sum-of-|gaps| (the 986,253 artifact).:117collections.sort((a,b)=>Math.abs(b.gap)-Math.abs(a.gap));:101-110buildsnoi_chua/noi_sinh,-1sentinels. Replacement:GET /api/registries-pivot/integrity→v_count_integrityaggregate. Retire when the new endpoint is live and the converged surface stops callinghealth.get.ts. How: delete the math; remove/alias the route.
L2 — /api/registry/counts disagreeing total → REPLACE
File server/api/registry/counts.get.ts (live returns {"total":1721334} — a 5th total). Also
raw-counts.get.ts:58 total_records: entries.reduce(...) (API count math). Replacement:
pivot_count('PIV-500') (after M3). Retire when PIV-500 live; route returns it verbatim, no math.
L3 — hardcoded phantom rows in /knowledge/registries → RETIRE
File pages/knowledge/registries/index.vue:
:312code: 'CAT-017'(hardcoded injected row) +:595v-if="row.code === 'CAT-017' …".:271orphan_count: hd.totalGap(frontend maps gap-sum → orphan_count) +:161-162reducerecord/orphan counts. Also[entityType]/index.vue:80-81reduce totals;health/index.vuerendersnoi_chua/noi_sinhcolumns. Replacement: converged surface renders only registered templates over the views; phantom =unconfirmed(RG4).
L4 — meta_catalog.record_count as UI truth → STOP USING AS TRUTH
The pages treat stored record_count as the number. Replacement: counts from pivot_count()/the views;
record vs actual vs pivot reconciled by v_count_integrity. record_count stays a stored scan output, not displayed truth.
L5 — old /knowledge/registries route → ALIAS → DEPRECATE → REMOVE
Replacement: /knowledge/registries-pivot (serving 200, 1.73 MB — partially built). One converged surface,
no 3rd page. Physical route choice GATED (RG6). Retire when parity (doc 13 Truth-Check 100% + coverage 100% + 0 hardcode).
Sequence (all gated; nothing done now)
M2 views → M8 API → M3 PIV-500 → M10 converged render-shell → parity test (doc 13)
→ retire L1 gap-math → replace L2 counts → retire L3 phantom rows → stop L4 truth → alias+deprecate+remove L5
Each "retire" = a reviewed PR in the web repo. No production code changed in this session.
Redirect/alias + rollback + risk
- Alias old routes (301/internal) to the converged surface; keep one deprecation window before deletion.
- Rollback: legacy route kept (aliased) until parity proven; revert PR restores old behaviour.
- No-hardcode tests (doc 13) gate each retirement.
- User-visible risk: the converged surface must show the SAME-or-better numbers (parity table logged)
before the old page is removed; the health page's scary
totalGap 986,253must be replaced by the honest net_gap (~148) — communicate that the big number was a gap-math artifact, not real data loss.