Skip to content

MVP gap inventory — N86 / mobile initiative

From: terminales-n86 (TL) · Date: 2026-09-12 · For: PO → Alfredo Purpose: one honest cross-lane inventory so the verification sweep runs against a complete surface and finds defects rather than absences. Method: every claim below was read from origin/main or from a PR, not recalled. Where I could not verify, it says so.


The PO expected settlement_unified split-tender and the write-gateway card bridge from me as flag-gated dormant mobile code. Neither is mine, verified rather than assumed:

  • FEATURE_FLAG_WRITE_GATEWAY was retired in 6d99cad7 (#408). Mobile’s write-gateway path is permanently ON with no flag. git grep -i write_gateway origin/main -- app/ returns zero.
  • FEATURE_FLAG_SETTLEMENT_UNIFIED has never existed in the mobile build. No -S history in app/build.gradle.kts, and git grep -i settlement_unified origin/main -- app/ returns zero. It is an api/web flag; ask those lanes.

Stating this rather than reporting on flags I do not own.


1. Flag-gated dormant (mobile has exactly five flags)

Section titled “1. Flag-gated dormant (mobile has exactly five flags)”

Correction/addition 2026-09-13 — mobile has TWO flag planes, and the second gates nothing. Beyond the five build-time BuildConfig flags below, there is a full remote runtime evaluator (FeatureFlagsRepository): reads the Appwrite feature_flags table, paginates past the 25-row default, reconciles remote-wins into a persisted offline-first cache, subscribes to Realtime so a flip reaches live sessions with no restart, and fails closed on every error path. It is started at app boot and consumed by nothing — its only production caller is TerminalesApplication:90 featureFlagsRepository.start(...); no feature asks it whether a flag is on. Every real gate uses the build-time plane, so no mobile flag is a live kill switch today, despite the capability being fully built.

This also resolves the empty-feature_flags-table puzzle. Mobile’s repository is the only reader I have found; web reads env vars and never touches that table. Since nothing reads mobile’s result, an empty table currently has no observable effect anywhere — so seeding it would change nothing. Recorded because seeding is the natural and wrong next move on seeing it empty.

Flag Value What is behind it State MVP?
MERCHANT_WALLET_TOPUP_MOBILE OFF Card top-up of the merchant wallet Finished pending review — session seam + attribution in PR (see §4) Alfredo’s call. He ruled finish it over cutting; when it ships is explicitly a separate decision
STORAGE_CANONICAL_BUCKETS OFF Legacy bucket vs canonical product-images Unknown, and deliberately frozen. Collapsing as-is would permanently enshrine the legacy path. Open question with the merchants lane: has the server-side migration run? Needs the answer before anyone touches it
DISCOUNTS OFF DiscountSheet + VM intact; the M27a route is not registered, so no discount surface is reachable (#411) Finished but deliberately hidden. The one documented exception to the all-flags-ON directive PO decision — re-enable or cut. It is built
DEVICE_MODE OFF Terminal/Móvil differentiation (#85). OFF = always TERMINAL (baseline); ON auto-detects Unknown to me. 3 files; I have not driven it Probably not — baseline is the N86 behaviour we ship
DEMO OFF Dev/demo scaffolding, 2 files Not product No

Item State MVP?
S10 VAS direct sale BUILT and merged — VasDirectSaleScreen/Form/Panels/State are on main. The PO’s list has this stale n/a
Offline cash queue Unbuilt, and correctly so. Alfredo ruled it POST-MVP; MVP is block-all-offline (POS-9) POST-MVP
Ticket-detail reprint wiring Unbuilt — see §4, it is worse than unbuilt See §4

I am not aware of other specified-but-unbuilt mobile work. That is an absence of knowledge, not a proof of none.


Item State Unblocks on
Category id migration Mobile needs zero changes (verified: CatalogViewModel is plain id equality, chips carry category.id). api #706 / web #888 open. My job is a post-migration verify pass The onboarding lane running the migration
manual realm is one realm only Everything I verified this week ran on manual. Other realms’ schema/state not checked by me n/a — flagging scope, not a defect

Item What actually happens Ref MVP?
Ticket-detail “Reimprimir” Fabricates a print failure. TicketDetailScreen.kt:302 is onClick = { reprintFailed = true } — the printer is never called. Same defect class as #459, still on main. Its KDoc admits it Needs its own slice Yes if reprint is MVP. Two product questions first: may a cancelled/refunded ticket reprint, and is a reprint marked as such on the paper
Wallet top-up session seam Fixed, PR open (re-based and re-opening after its stacked parent merged) was #461 Ships with the flag decision
Home KPI does not refresh in-session After a sale, Home still reads Ventas hoy $0.00 / Transacciones 0 while “Actividad reciente” on the same screen lists the sales. Correct after a restart. Data is right throughout — this is a refresh gap, not an aggregation defect Observed 09-11, unfixed Probably yes — a merchant checking takings mid-shift sees zero
Activity timestamps look ~6h off Sales made ~16:45 device time (America/Mexico_City) displayed as 11:20 p. m. Possible timezone regression (S12 territory) Observed 09-11, not diagnosed Yes if confirmed — wrong times on a sales list is a trust problem
Back from “Terminal lista” exits the app Rather than returning to the shell Observed 09-11, not confirmed Minor
e2e_terminal_unpaired shown pre-login A fixture id that exists nowhere in production code is displayed before authentication. Retracted as a blocker (post-login it is correct); origin still unexplained Open question, undiagnosed Low, but unexplained

5. Blocked on a human, a device, or a third party

Section titled “5. Blocked on a human, a device, or a third party”
Item Blocked on What unblocks it
#459 print acceptance — card receipt DONE 2026-09-12 ✅ Accepted on paper. Card sale folio #6aa5db6c, auth 361329, full printer success sequence; paper out and renders correctly, both confirmed by Alfredo. Same tap that produced a fabricated error with zero printer lines the day before
Manual-charge and split receipt paths — never printed The physical N86 Both were wired by #459 and neither has ever printed on paper. They do not inherit the card path’s acceptance: the card receipt is the only one whose 80mm rendering has been seen. One sale each on the device settles it
Web→handheld bridge (R10) N86 + web on :4007 The web env var is routed to the web lane; then a card tap
PB-4 verification CTA end to end N86 + the endpoint deployed (it now is) A device session
11 Maestro flows repaired-but-not-re-run Credentials + a live stack — never capacity Someone with the credentials runs them. Not me; I do not handle them
VAS aggregator activation Third party Outside my lane

The judgement asked of me: is the handheld MVP at the same depth as web?

Section titled “The judgement asked of me: is the handheld MVP at the same depth as web?”

No. Web is the MVP surface; the handheld should follow. I have driven both and I think this for three reasons, none of them about code quality.

1. The handheld’s defect density is still falling fast, and that is information. In roughly thirty-six hours of driving it, this lane found: a dead navigator on every non-Inicio root, sign-out below the fold, two dead links on one onboarding screen, receipt printing never wired for three of four tenders, a terminal fault reported as a customer’s card being declined, and a top-up path with no session handling at all. Those were not found by a sweep; they were found by using it. A surface still yielding defects of that severity, at that rate, has not been exercised enough to call it MVP-ready at web’s depth.

2. Every one of them was invisible from the outside. The print failure looked like a broken printer. The false decline looked like a refused card. The dead hamburger logged nothing. This surface fails convincingly, which means absence of reports is not evidence of correctness — and the handheld has had far fewer real users than web.

3. The handheld’s hard dependencies are the ones we cannot rehearse. Card taps, a physical printer, a payment SDK session, a paired terminal. Those cannot be covered by tests or emulators, and each needs a person at a device. Web has no equivalent gate, so web can reach confidence on a schedule the handheld structurally cannot.

What I would propose instead of equal depth: MVP on the handheld = the cash-and-card sale path end to end with a printed receipt, plus shift open/close and the onboarding gate. That is what a merchant cannot trade without. Wallet top-up, VAS breadth, discounts, reprint-from-history and the remote bridge are all real work that can land after, because a merchant can complete a day’s trading without any of them.

Caveat, stated plainly: this is a judgement about readiness, not about effort or value. And it is one lane’s view — the web lanes may have their own gaps I cannot see, which would change the comparison. I would not want this read as “web is done”.