11 — Legacy Retirement Plan (retire-after-replace; Đ28 gap-math removal)
title: 11 — Legacy Retirement Plan date: 2026-05-31 gate: P4 (after RG1–RG8 + P1/P2 live). NO production code changed this session. principle: retire-AFTER-replace (Đ30 — never remove the old path before the pivot-backed one is live)
11 — Legacy Retirement Plan
Four legacy artifacts violate Đ28 (count logic outside PG) or serve disagreeing truth. Each is retired only after its pivot-backed replacement (docs 03/05/09) is live and at parity.
L1. /api/registry/health — client/API gap-math (Đ28 violation)
Live evidence (2026-05-31T01:39:55Z): computes per-collection gap = noi_chua − noi_sinh,
status ORPHAN/PHANTOM/KHOP, totalGap: 986253. Defects:
- birth_registry
noi_sinh=0→ gap 985,472 "ORPHAN" — contradicts the real +1 leaf gap. - dot_tools
noi_sinh=592— a 4th DOT count (vs 309 table / 163 files / 309 pivot). - many
-1sentinels mislabeled ORPHAN; the wholetotalGapis a sum-of-|gaps| artifact. Replacement:GET /api/registries-pivot/integrity→v_count_integrityaggregate (net_gap 132, 3 drift, 5 unverified, source_model-aware). Retire when: the new endpoint is live AND the converged surface no longer callshealth.get.ts. Retire how: delete the handler's math; either remove the route or alias it to the new aggregate. (Gated P4.)
L2. /api/registry/counts — disagreeing grand total
Live: {"total":1721334} — a 5th total (vs CAT-ALL.record 1,719,958 / CAT-ALL.actual 2,003,754 /
leaf Σrecord 2,002,041 / leaf Σactual 2,001,909). Replacement: pivot_count('PIV-500') once
PIV-500 is created (P5) and its semantics defined (what is being totaled). Retire when: PIV-500
live and the surface reads it. Retire how: route returns pivot_count('PIV-500') verbatim, no math.
L3. Hardcoded phantom rows in /knowledge/registries
The page injects phantom rows (CAT-PHA/ORP/UNM/SPE/017-style) and does client gap-math (per design
doc 00: "retire its Đ28-violating client gap-math health.get.ts totalGap=Σ|gap|"). Replacement:
the converged surface renders only registered templates over the views; phantom shown as
unconfirmed until RG4. Retire when: /knowledge/registries-pivot reaches parity (L5).
L4. meta_catalog.record_count used as UI truth
The UI treats stored record_count as the count. Replacement: counts come from
pivot_count() / the views; record_count vs actual_count vs pivot_count are reconciled by
the integrity view, not shown as "the number." Retire when: the surface reads v_living_lists/
pivot_count for every count. Note: record_count stays as a stored column (scan output); it
just stops being the displayed truth.
L5. Old /knowledge/registries route
Replacement: /knowledge/registries-pivot (already serving 200, 1.73 MB — partially built).
Per design: one converged surface, no 3rd parallel page. The physical route choice (mint
/knowledge/registries-pivot + alias the other two, vs. keep /knowledge/pivot under the new name)
is GATED_BY_APPROVAL (RG6). Retire when: converged surface passes doc-09 Truth-Check 100% +
coverage 100% + 0 hardcode_violation (doc 12). Retire how: 301/alias the old routes, keep a
deprecation window, then remove.
Retirement sequence (all gated; nothing done now)
P1 commit views ─▶ P2 expose API ─▶ P5 PIV-500 ─▶ P4 build converged render-shell
─▶ parity test (doc 09/12) ─▶ retire L1 gap-math ─▶ retire L2 counts ─▶ retire L3 phantom rows
─▶ stop using L4 record_count-as-truth ─▶ alias+deprecate L5 old route ─▶ remove old route
Each "retire" is a code change in the web repo under its own PR/review — no production code is changed in this session. Retire-after-replace guarantees no surface ever loses its count source.
Acceptance for retirement (per artifact)
- New pivot-backed endpoint live and returning the same-or-better numbers (parity table logged).
- 0 references to the legacy handler in the converged surface (CI grep, doc 12).
- Rollback: legacy route kept (aliased) for one deprecation window before deletion.