Skip to content

Screen conformance ledger ​

Every approved merchant-mobile design screen, and whether it exists in the app. The machine source of truth is screen-conformance.json; this page is the narrative. The data lives in exactly one place — never restate a screen's status here, or the two will disagree the first time one moves (the QRS-249/284/287 duplicate-source-of-truth bug class).

Run it: npm run check:screens.

⚠ THIS LEDGER'S NUMBER IS PRESENCE, AND IT HAS ALREADY BEEN READ AS PARITY ONCE

check:screens answers does an implementation path exist — never does it match the design. It says so throughout this page, and on 2026-08-14 the "27 of 36 built" figure was still allowed to imply that the merchant journey matched its approved designs. It does not: six audited screens diverge, one of them structurally.

The parity question has its own page and its own count: Ganapati parity audit. Read the two numbers together or neither is meaningful.

Why this exists (QRS-626) ​

On 2026-08-13 the product owner asked why, after two days of Shift-Left design work explicitly done so that client-side implementation could proceed smoothly, the implementation still had "significant screen mismatches, incomplete features, and deviations from the approved designs" — and why the answer kept arriving as one corrective prompt at a time.

The cause was measurable, and nothing in the repo could measure it.

The Claude Design prototype project (633dc069-6df8-4408-b625-068907c60c33) carries its own screen registry at SCREENS.md. It is authoritative by construction: PrototypeHub.dc.html generates itself from that file, and the file's own instruction is "To add, rename or retire a screen on the hub, edit the table above; never the hub." It had never been opened.

Implementation instead tracked the 20-step Ganapati journey — which SCREENS.md itself introduces as "a reading order over the shared, parameterised screens". A view over the set, not the set.

Measured at introduction: 23 approved mobile-console screens + 2 onboarding rows = 25. Nine built, three behind a later design round, nine unimplemented and reachable, four deferred by the design itself. Two of the unimplemented screens, Messages and Thread, sit behind a main tab, placeheld by an EmptyState whose source comment read "Backend-gated (messaging backend absent in R1)" — a justification that had gone stale two days earlier when the chat schema shipped (CR-26.0.1-22/23/24).

The deeper failure, which is the one the gate targets ​

Every other standard in this repo is script-enforced: check:readmes, check:parity, check:naming, check:docs-impact, check:docs, check:release, check:sql, check:portal-nav. Design conformance was enforced by the product owner noticing. That is not enforcement; it is a review queue with one reviewer and no alarm — and it produced exactly the loop the owner objected to. CLAUDE.md states the lesson in its own words, from three prior incidents: a standard with no gate decays.

A second, subtler cause is worth recording because it will recur under other names: backend blockers were allowed to stop client work the owner had explicitly descoped. Payments was held on QRS-622 (daily_sales has a feature key, a plan entitlement and no table) and Analytics on QRS-576 (no cardActivity rollup) — both genuine, both backend. The stated goal was client-side first, backend after. The repo's own packages/data seam exists precisely for this, and it had already been used one screen earlier to build all of Collections and Order detail against orders/service.stub.ts. The pattern was proven and then abandoned. For Analytics the point is sharper still: the design's null path — "nothing is recorded yet", offering the counts that do exist — is exactly what renders when the rollup is absent. The blocker was the screen's designed content.

What the gate checks ​

Six rules, each bidirectional, because a ledger that can only be wrong in one direction is one people quietly stop updating.

RuleCatches
S1A status outside built / stale / missing.
S2A built/stale entry whose impl path is not on disk — the rename-and-forget direction.
S3A missing entry that is implemented, either by a recorded path or by one appearing at its conventional feature directory. This is the direction that makes the printed count a fact rather than an estimate.
S4A stale entry with no staleReason. "Needs updating" that does not say to what is how the Settings screen sat pending across two sessions.
S5reachable: false with no blocking reason, so a legitimate deferral cannot hide something merely forgotten.
S6Two entries sharing a design or impl path, which would let one screen launder another's status.

The headline number — unimplemented and reachable — prints on every run, green or red. That is the design: the number is always visible, and it can only come down through real work.

What it deliberately does not check ​

  • Fidelity. Whether a built screen matches its design. A script cannot see spacing, states or interaction feel; that stays a design pull plus a drift-ledger row (ADR-0015). Claiming more would repeat QRS-246 — a standard documented for months and implemented by nothing. This gate answers presence, the same presence-vs-freshness split check:readmes and check:docs-impact already accept, and presence is precisely what was unmeasured.
  • Whether the registry has gained a screen since transcription. That needs the network, and a gate that fails when the design project is unreachable gets switched off. source.transcribedAt is the honest marker: re-transcribe when pulling a design round, and treat the ledger as stale-by-default after one.

Scope — read this before quoting the count ​

The ledger covers the merchant mobile app only: SCREENS.md's Merchant console — Mobile section plus its Onboarding & sign-up rows. The registry holds five further approved sections that are not counted here — Public Setu Card, Consumer app, Consumer marketplace (desktop), Merchant console Desktop, and the platform Admin Panel — plus two marked SUPERSEDED, DO NOT IMPLEMENT.

So a green run means "the merchant mobile app is accounted for", never "the product is designed and built". Scoping it this way is deliberate: the failure being fixed was mis-tracking one surface, and a ledger that silently spanned six would make the merchant number unreadable again.

Working rule ​

  1. Before implementing a screen, re-pull its design and re-read its SCREENS.md row — the Purpose cell carries the round notes, which is where a later round's changes are actually recorded.
  2. Update the ledger row in the same change as the code. A status that disagrees with the disk makes every count untrustworthy, which is worse than no ledger.
  3. A backend gap is not a reason to skip a screen. Build against the packages/data stub seam and record the backend item as its own QRS-###. If the design has a null/empty state, that state is the deliverable while the data is absent.
  4. Four screens are deferred by the design, not by us — More.dc.html renders Reviews, Announcements, Invite & Earn and Partner program as NOT BACKED YET rather than linking them. Building one would put a screen behind an unreachable entry. Their blocking field records why.