Skip to content

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 (79 src/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.

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):

  1. 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.)
  2. Merchant wallet — /admin/wallet built and live-verified (US-BAL-1), but no owner-facing entry point. PDR-0003 names wallet visibility. (T3.)
  3. Stock-movements reception — /admin/pos/stock-movements/receive built, 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.