by Intelliverse X

Lifecycle feature matrix

The canonical end-to-end map of a Kiosk-X vending machine's life — from the pallet to decommission — with every cell backed by an executable eval. Rows are lifecycle stages; manufacturer columns cover Reyeah (RK3288 board, com.ruiye.jd APK, /apk/* protocol) and ZHZN/CSM (T3568 board, Python agent, /zhzn/* gateway); channel coverage spans the vending APK, operator Android app, operator web console, the web emulator, and the Partner API. A USA-operability column tracks currency, language, tax, and compliance posture.

This is a living document: the eval-run ledger at the bottom records the latest execution against the live stack (api.kiosk-x.ai).

How the evals run

Layer Command What it proves
API evals (in-process) pytest tests/test_lifecycle_matrix.py -q Every automatable cell against the app + in-memory store; runs in CI with the full suite
Live probes python scripts/lifecycle_matrix_live.py --base https://api.kiosk-x.ai The same cells against the deployed stack, using a fresh throwaway operator + fresh machine serials (never mutates the shared demo fleet, never calls /sandbox/reset)
Emulator walkthrough /emulator/lifecycle (10 steps, real routes) Browser-visible E2E: unbox → boot → claim → subscribe → stock → vend → refill → OTA → earning

Cell IDs (LM-nn) appear in test names (test_lm05r_… = row 5, Reyeah column) so a matrix cell can always be traced to its eval and back.

Lifecycle at a glance

flowchart LR A[Install / unbox] --> B[First power-on\n+ network] B --> C[Auto-provision\non first contact] C --> D[Operator claims\nserial] D --> E[Nayax bind\n+ subscribe] E --> F[Planogram, pricing,\nrestock] F --> G[Selling: cash / card /\ncart / age-gated / promo] G --> H[Settlement, faults,\nreconciliation] H --> I[OTA upgrades,\nads, QR revenue] I --> F I --> J[Decommission\n/ transfer] J --> C

Status legend

The matrix

Channels key: API · Emulator · Vending APK · Operator APK · Web console

# Stage Reyeah ZHZN Channels verified USA operability Evals
1 Physical install & unboxing BLOCKED-HW (runbook in machine-client.md; demo unit ...011 installed) BLOCKED-HW (no ZHZN test unit; wiring doc in zhzn repo WIRING_AND_DEPLOY.md) 110 V US power, standard footprint manual runbook
2 First power-on + network BLOCKED-HW live · PASS emulated (boot step drives real routes) BLOCKED-HW live · PASS agent-emulated (fake-VMC PTY harness) E English boot UI pending OTA (ROUTED: RCA/OTA agent) lm-walkthrough boot, zhzn agent E2E
3 Auto-provision on first contact PASS — unknown serial on /apk/getEquipment lands in unclaimed pool, boots to working USD grid; strict mode rejects PASS — /zhzn/register maps serial→machine code, provisions; fleet-secret auth; strict-map allowlist A, E USD grid from first boot LM-03r, LM-03z
4 Operator signup / onboarding PASS — admin creates account, operator signs in (Intelliverse or demo password), sees empty fleet; onboarding checklist same (manufacturer-agnostic) A, W, O English console; US operator accounts LM-04 ×2
5 Machine registration / claiming PASS — fresh-serial register AND claim-of-provisioned-board with unclaimed-vend transfer; cross-tenant 409 PASS — ZHZN board claimable through the same Partner API A, E, W LM-05r ×2, LM-05z
6 Nayax terminal binding PASS — real Device Number bind replaces provisional placeholder; webhook resolves bound terminal only; conflict 409; physical reader tap: BLOCKED-HW n/a hardware path (ZHZN uses MDB-RS232; same cloud binding applies) A, W Nayax = US cashless standard; real merchant creds BLOCKED-BIZ LM-06
7 Planogram / product catalog PASS — operator aisle edit ⇄ device getGoods; on-device manager-menu save persists PASS via Partner API (grid config served by /zhzn/config) A, V(manager menu), W Catalog imagery reseed ROUTED: demo-imagery agent LM-07 ×2
8 Pricing in USD + tax PASS — catalog, goods, and equipment config all $ (¥→$ landed in 31b4ad7, now a hard regression gate); salesTaxRate per machine + tax-inclusive liability estimate in orders summary PASS (same pricing store) A, E, W Core USA row: USD everywhere, tax-inclusive posture (operator remits from gross), rate validation LM-08 ×4
9 Restock flows PASS — fill-all and per-aisle PASS (same inventory API) A, E, O, W LM-09
10 Vend: cash PASS — settles immediately as cash processor, stock decrements PASS at gateway level (agent reports outcome; motor BLOCKED-HW) A, E USD LM-10r
11 Vend: card / Nayax PASS — order pending until signed webhook settles same webhook path once terminal bound A, E Real Nayax merchant BLOCKED-BIZ LM-11r
12 Vend: scan-to-pay PASS as designed — scan-to-pay surfaces are the QR pages (/play, /advertise); no card-on-file product checkout exists (product decision, not a gap) same QR surfaces A, V(QR) Stripe checkout surfaces ROUTED: Stripe-audit agent LM-12
13 Vend: multi-unit cart PASS — cart num bills & decrements correctly; over-stock refused atomically gateway supports quantity per dispense A LM-13r
14 Vend: age-gated PASS — unverified restricted vend refused; ageVerify one-shot unlocks exactly one transaction gateway machines inherit same order gate A, V Tobacco 21 enforced server-side; ID-scanner hardware calibration BLOCKED-HW LM-14
15 Vend: $0 promo / KX credit PASS — demo-task completion mints machine-bound KX- code → validDiscountCode → $0 promo order; funding-source enforcement ROUTED: funding-enforcement agent (its suite: test_funding_enforcement.py) credits are machine-bound, manufacturer-agnostic A, V(QR) LM-15
16 Settlement + webhook idempotency + stockMismatch PASS — replay is a no-op; empty/faulted lane flags stockMismatch+needsRefund; unsigned webhook 401 ZHZN settlement forwards to UserManagement complete endpoint (exactly-once, deduped) A HMAC-signed webhooks; real Nayax secret BLOCKED-BIZ LM-16 ×3
17 Dispense-failure reconciliation PASS — ordersUpdate MOTOR_JAM → needsRefund → operator refund books payState 4 PASS — failed report with orderId routes to dispense/complete with success:false A, O, W LM-17r, LM-17z
18 Faults PASS — submitFault marks lane faulted (blocks vends), operator sees reason, clears via aisle PUT agent surfaces board return-codes; same aisle-fault store A, V, W LM-18
19 Telemetry / MQTT presence + remote dispense PASS — api_drop command queue round-trip; MQTT bridge live (mq.kiosk-x.ai:1883 open); physical motor BLOCKED-HW PASS — dispense queue leased exactly-once with crash-safe re-delivery A, E LM-19r, LM-19z, test_mqtt_bridge.py
20 OTA upgrade PASS — publish rollout → device offer → apkUp → 100% adoption auto-complete; pause/resume/cancel; rollout to physical ...011 ROUTED: RCA/OTA agent PASS — /zhzn/upgrade serves signed manifest (version/url/sha256) A, E, V English/USD APK variant is the payload (ROUTED) LM-20r ×2, LM-20z
21 Ads / attract loop PASS — loop never empty, direct campaigns take priority, house fills; player-safe: no remote video until RK3288 sign-off; proof-of-play recorded same loop served per machine A, E, V Real DOOH demand BLOCKED-BIZ (Vistar/PX/Blindspot creds); mediation mocks live LM-21 (+127-test mediation matrix)
22 QR monetization on-machine PASS reachability per machine; deep flows owned by their suites: ads chatbot (ROUTED: ad-chat resilience agent), game worlds (ROUTED: gameworld-bridge agent), spin/scratch/draws (test_prize_mechanics.py), QuestX (test_free_product_play.py), multiplayer (test_multiplayer_game.py) same A, V(QR) LM-22
23 Subscriptions / billing PASS — subscribe machine (USD) then cancel; billing account/wallet surfaces same A, W USD plans; card-on-file/Stripe checkout ROUTED: Stripe-audit agent LM-23 ×2
24 Reporting / exports PASS — orders summary (USD + tax estimate), payments summary, billing CSV export same A, W USD reports LM-24
25 Migration off vendor cloud PASS (cloud half) — migrated board's first contact auto-provisions, claim keeps continuity, apkUp reports build; downloads page ships kioskx APKs only. Physical APK swap on deployed units BLOCKED-HW + runbook below ZHZN units never used the vendor cloud (agent is ours from day one) — n/a A, V LM-25 ×2
26 Decommission / transfer PASS — new: POST /machines/{no}/decommission returns board to unclaimed pool, frees the Nayax Device Number, keeps revenue on the old operator's books; transfer = decommission + claim same endpoint A, W LM-26 ×3
27 This matrix stays published PASS — served at /guides/lifecycle-matrix with mermaid + S3 mirror W LM-27

USA-readiness bottom line

Reyeah: USA-operable for cash + Nayax cashless vending today at the cloud level — USD on every money surface (catalog, goods, orders, reports, subscriptions), English console/docs, Tobacco-21 age gate enforced server-side, tax-inclusive pricing with per-machine tax-liability estimates. Server-side currency is now guaranteed (31b4ad7 forces $ in the equipment config regardless of fixture drift). Remaining gaps are device-side: the Chinese/vape-banner APK cleanup and the OTA rollout to the deployed demo unit are in flight (RCA/OTA agent), and motor/ID-scanner/Nayax-tap verification needs the physical machine.

ZHZN: cloud gateway fully implemented and tested (register / config / pending / report / heartbeat / upgrade, exactly-once settlement forwarding), USD/English by construction since the device runs our agent, enabled on the live deployment since 2026-08-12 (KIOSKX_ZHZN_DEVICE_SECRET CI-bootstrapped into kiosk-x-secrets and wired in the deployment — kube-infra b534dd65; live proof: lifecycle_flavors_live.py run 8657773248, existing-zhzn PASS), but never validated against a physical ZHZN unit (BLOCKED-HW). The one-APK universality question is settled per the zhzn repo's committed docs: a single shared APK across manufacturers is not feasible (incompatible boards and wire protocols) — ZHZN ships as our headless Python agent speaking /zhzn/*, which is exactly what this matrix's ZHZN column evaluates.

Migration runbook (deployed vendor-cloud machine → Kiosk-X)

Status: cloud path proven by eval (LM-25); device steps require a site visit.

  1. Build: CI produces reyeah-vending-kioskx.apk with UrlConfigString.baseUrl patched to https://api.kiosk-x.ai (see apk-rollouts.md); hosted on the downloads page.
  2. On the machine (manager PIN → Android settings): uninstall the vendor APK first — the kioskx build is signed with our key, so in-place update is refused. Install the kioskx APK.
  3. First contact: the board calls getEquipment with its existing serial; the cloud auto-provisions it into the unclaimed pool and it boots to a working USD grid immediately (LM-25 verified).
  4. Claim: operator registers the serial (console or POST /api/v1/machines/register); any vends taken before claiming follow the machine (LM-05r verified).
  5. Nayax: bind the reader's real Device Number (POST /machines/{no}/nayax) so settlement webhooks resolve (LM-06). Binding wires up the record; it does not give us the reader. See step 6.
  6. What breaks / does not carry over: vendor-cloud order history, ad configuration, and planogram do NOT migrate (the vendor cloud is opaque to us) — re-enter the planogram (LM-07) and restock counts. Everything from first contact onward is continuous. The Nayax terminal does not migrate either, and that half is not ours to finish: on a second-hand cabinet the VPOS usually stays in the previous operator's Nayax Core organisation, commissioned for their old machine type. Its MDB profile and its settlement destination can only be changed by that actor (or moved by Nayax support), so card can be dead — or paying someone else — on a board that is otherwise fully migrated. Scan & Pay (Stripe QR) has no such dependency and is the card path that migrates cleanly. Details + the four ways to close it: docs/payments-nayax.md → "What migration cannot move".
  7. Verify: cash vend + card vend that produces a real Nayax transactionId in your own payout report (a Kiosk-X-side settlement label is not proof) + ordersUpdate reconcile, then enroll the machine in the current OTA rollout.

Routed items (other in-flight agents own these)

Failure / surface Owner State when verified
Equipment config.info.moneySign ¥ server-side RCA/OTA currency agent LANDED (31b4ad7) — eval hardened into a permanent regression gate (LM-08)
APK ¥/Chinese/vape-banner + OTA rollout to unit ...011 RCA/OTA agent In flight (reyeah repo dirty: localize gates, attract-banner overlay)
ZHZN one-APK universality + emulator harness verdict ZHZN-universality agent Verdict landed in the zhzn repo docs: one shared APK is NOT feasible — different board (T3568 vs RK3288), different wire protocol, no shared driver code; chosen path is the headless Python device agent against /zhzn/* (its "emulator harness" is a fake-VMC PTY, not an Android APK loop). Live enablement (fleet secret) still waits on its GO-LIVE doc; 4 commits unpushed
Product catalog imagery reseed (S3) demo-imagery agent LANDED (ad92acb — S3-hosted product shots for every seeded product)
Stripe checkout surfaces (ads self-serve, billing portal) Stripe-audit agent Simulated-checkout path verified; live keys are theirs to wire
Ad-chat session resilience ad-chat agent HMAC session-resume commit landed (280f1dd)
Funding-source enforcement (spec §4) funding-enforcement agent Suite test_funding_enforcement.py green (14 tests)
GameWorld rewards bridge gameworld-bridge agent Suite test_gameworld_bridge.py green; bridge fail-closed without secret (LM-22)
Operator web console deep parity PDF-parity console eval loop (kiosk-x-operator repo) Console reachable; API contracts it consumes covered here

Blocked items and exactly what unblocks each

Cell Blocker Unblocked by
Physical install, power-on, motor dispense, cash acceptor (rows 1, 2, 10, 19) BLOCKED-HW Site visit to demo unit 866903013700011 (or ...044)
Nayax reader tap-to-pay E2E (rows 6, 11) BLOCKED-HW + BLOCKED-BIZ Physical VPOS Touch + live Nayax merchant credentials & webhook secret
ID-scanner age-gate hardware (row 14) BLOCKED-HW AptPay/scanner calibration on the physical unit
ZHZN entire physical column BLOCKED-HW A ZHZN/CSM test unit (T3568 + Y-lift)
~~ZHZN live gateway (row 3z live)~~ UNBLOCKED 2026-08-12 KIOSKX_ZHZN_DEVICE_SECRET CI-bootstrapped + wired (kube-infra b534dd65); live existing-zhzn PASS (run 8657773248). Read-back/rotate + per-device provisioning documented in kube-infra kiosk-x/secret-placeholder.yaml
Real programmatic DOOH revenue (row 21) BLOCKED-BIZ Vistar / Place Exchange / Blindspot / Adomni credentials
Live Stripe money movement (rows 12, 23) BLOCKED-BIZ Live Stripe keys in the kiosk-x-stripe secret (Stripe-audit agent)

Eval-run ledger

Latest live run: 2026-08-11T21:07:42Z against https://api.kiosk-x.ai — BLOCKED-CFG 1, PASS 28

Cell Status Evidence ms
LM-00-health PASS health={'db': 'ok', 'redis': 'ok'}, readiness=pass, uptime=120s 284.8
LM-04-onboarding PASS operator lm-live-8648245569@evals.kiosk-x.ai created + signed in, empty fleet 226.6
LM-03r-autoprovision PASS unknown serial 866908648245570 booted to USD grid (10 lanes) 156.7
LM-03z-zhzn-live BLOCKED-CFG gateway disabled: KIOSKX_ZHZN_DEVICE_SECRET unset on live 51.9
LM-05r-claim-transfer PASS claimed 866908648245570; pre-claim vend transferred (totalOrders=1) 310.0
LM-06-nayax-bind PASS bound 017997981, signed webhook resolved + settled to owner 336.0
LM-07-planogram PASS operator edit visible on device planogram 283.6
LM-08-usd-pricing PASS public pricing catalog is USD-clean 61.0
LM-08-tax-estimate PASS tax-inclusive estimate 0.16 at rate 0.08875 504.0
LM-08-equip-moneysign PASS equipment config.info.moneySign is $ 190.3
LM-09-restock PASS fill-all + per-aisle restock 148.6
LM-10r-cash-vend PASS cash vend booked $1.99 239.7
LM-11r-card-vend-settle PASS card vend pending → webhook settled 388.8
LM-13r-cart PASS cart x2 billed $3.98 261.1
LM-14-age-gate PASS Tobacco-21 gate: refused unverified, allowed verified 294.0
LM-16-webhook-idempotent PASS signed replay returned the same order (no dup) 296.0
LM-16-unsigned-webhook PASS unsigned webhook rejected 401 47.7
LM-17r-reconcile-refund PASS MOTOR_JAM → needsRefund → refunded 434.5
LM-18-faults PASS fault visible to operator, cleared via aisle PUT 297.8
LM-19r-api-drop PASS api_drop enqueue → pending → ack → sale 303.4
LM-20r-ota-loop PASS publish → offer → install report → 100% adoption 289.3
LM-21-ad-loop PASS loop has 6 player-safe slots 166.6
LM-22-qr-surfaces PASS /play + /advertise render per machine 99.8
LM-23-subscriptions PASS subscribed (USD) then cancelled 144.4
LM-24-reports PASS orders/payments summaries + billing CSV 146.3
LM-25-migration PASS migrated serial 866908648245587: first contact → claim → build report 202.7
LM-26-decommission PASS decommissioned 866908648245588, reader 017962977 freed + rebound 398.9
LM-27-guides PASS matrix served on /guides/lifecycle-matrix 68.7
LM-02e-emu-lifecycle PASS 10-step walkthrough on fresh serial 866908222664731 587.3