Web built-but-unreachable surfaces — findings + cleanup plan
- Status: Draft for PO/Alfredo ruling
- Date: 2026-09-12
- Author: web verification lane (fell out of the #164 e2e fixme audit)
- Method: static analysis of
terminales-web@main— route inventory (79src/app/**/page.tsx), inbound-link greps, and a scan of all 110 playground-registry components for a shipped-route mount.
The pattern. A component or page can be built, pass its own tests, and have a playground entry — yet be reachable by no user, because nothing mounts it or links to it. Every measure reads “done” except the only one that counts. This cycle surfaced it repeatedly; this doc gives the honest list and a fix scoped as three separate workstreams, not one “wire everything” list — most of a flat list would be wrong work.
The honest list — 6 genuine instances
Section titled “The honest list — 6 genuine instances”Corrected from the “five” figure previously circulated: VAS web is NOT one — it turned out reachable and merely mis-documented (the kind of wrong entry a flat count produces). The real six, in two sub-types:
Route-level (a built page with no way in):
- Clientes —
/admin/customers(+/[id]) built, but no drawer entry; the list is reachable only circularly. PDR-0001 puts Clientes IN MVP. (See mvp-completeness-web.md T2.) - Merchant wallet —
/admin/walletbuilt and live-verified (US-BAL-1), but no owner-facing entry point. PDR-0003 names wallet visibility. (T3.) - Stock-movements reception —
/admin/pos/stock-movements/receivebuilt, but its parent list never links it; receive/transfer/adjust run as dialogs.
Component-level (a built component mounted in no route):
4. StockTransferDialog — built + tested, but not mounted in /admin/pos/stock-movements (only the playground). Found in the #164 audit; kept as an honest test.fixme (web PR #914). W28 was retired from the registry, so it is not among the 110.
5. CommandPalette (⌘K global search) — built organism, rendered nowhere (not in AdminShell/AppShell).
6. ImpersonationBanner (platform-admin impersonation, US-PLAT-2) — built organism, rendered nowhere.
The registry scan also found 3 superseded twins and 13 parity scaffolds (below) — those are not “features a user needs” but they are the noise that hides instances like #4–#6, which is why the process fix (Workstream C) matters most.
Workstream A — wire-or-cut the 2 unreachable features (Alfredo’s call)
Section titled “Workstream A — wire-or-cut the 2 unreachable features (Alfredo’s call)”Both are built, so the question is wire-or-cut, not build-or-defer — decide against the real (small) cost, not an imagined one.
| Feature | What it is | My read on cost-to-wire |
|---|---|---|
| CommandPalette (⌘K) | Global search palette (US-SEARCH-1). | UI wiring is small — mount the palette in AdminShell behind a global ⌘K handler. BUT making it return results needs the search backend endpoint, which is unticketed (draft web-parity-global-search-backend.md). So: cheap to surface, not cheap to make useful. Recommend cut from MVP unless search is a launch requirement. |
| ImpersonationBanner | Banner shown while a platform-admin impersonates a merchant (US-PLAT-2). | Small if the impersonation session state exists to read (US-PLAT-2 is PARTIAL/live-tested, so the plumbing is likely present) — mount the banner in the shell keyed on that state. Verify the state is actually populated before committing. Recommend wire if impersonation ships in MVP; else cut. |
☐ Ruling — CommandPalette: wire (shell only / shell+backend) or cut? ☐ Ruling — ImpersonationBanner: wire or cut?
(Note: the two are estimates, not certainties. Each wiring PR would ship with the test that proves reachability — the exact assertion these components currently lack.)
Workstream B — delete the 3 superseded twins (done, at PO gate)
Section titled “Workstream B — delete the 3 superseded twins (done, at PO gate)”TenderPicker, CashTender, SplitPayment (src/ui/organisms/pos/) are DS organisms superseded by the terminal’s bespoke TenderMethodDialog / CashTenderDialog / SplitTenderDialog. Mounted in no route; only consumers were the registry, the barrel, and their own tests. Absence proven mechanically (grep imports + JSX; the terminal’s TenderMethod type is local; suggestQuickAmounts has zero consumers). Removed with their showcases + registry entries so nothing points at a deleted component. tsc/eslint clean.
→ web PR #916 (to PO gate; not merged). This is dead-code removal, not a product decision.
Workstream C — the process fix (the root cause, most valuable)
Section titled “Workstream C — the process fix (the root cause, most valuable)”The registry scan found 13 parity scaffolds — Cuenta (w59–62 + CuentaFlow), Reportes (w55–58 + ReportesFlow), Ventas (w30 + VentasFlow), Dashboard (w07) — each a mock design-parity twin of a shipped screen, kept in the playground after the live route shipped. Thirteen scaffolds = the parity pipeline creates a mock twin per screen and never retires it, leaving two trees per screen permanently. That “which one is real?” ambiguity is exactly what made the VAS specs point at a dead route and a cuenta test assert against a showcase instead of the shipped component (both fixed in the #164 audit, PRs #913/#914).
Proposed rule (concrete, with owner and trigger):
A parity scaffold — its playground showcase, its parity screen component, and its registry entry — is retired in the same PR that ships (or marks live-green) its real route.
- Owner: the developer who ships the live route (they alone know the mock twin is now redundant).
- Trigger: the PR that mounts the live route or turns its live e2e spec green. Retiring the twin is a line in that PR’s Definition of Done.
- Backstop: the registry scan in this doc, run each verification sweep, catches stragglers — the cheapest way to find the next instance before a customer does. (Not a substitute for the DoD trigger; a wish with no owner is not a rule.)
✅ ADOPTED (PO, 2026-09-12). Canonical statement (with the why) in design-parity-playbook.md §10; one-line DoD reference in ticket-content-template so it reaches the doer. Backstop: this registry scan, re-run each verification sweep.
Not findings (for completeness, so they aren’t re-litigated)
Section titled “Not findings (for completeness, so they aren’t re-litigated)”- 3 UNSURE registry entries (w31 refund/void showcases) paint the unmounted parity backdrop but demo components that ARE mounted (
ApprovalModal,RefundCaptureDialog). - 8 inline parity-composition showcases (w25/w26/w37/w38/w39/w48/w33/w34) have no extractable product component; their live route siblings exist and are mounted.
- DS primitives (Button, Chip, Avatar, DataTable, …) are mounted transitively across the app.