Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
doc-engine / consumer (push) Successful in 3m56s
Payment domain, storage, platform and UI / payment-ui-tests (push) Failing after 4s
doc-engine / engine (push) Successful in 15s
nigig-map / test (push) Failing after 2s
Payment domain, storage, platform and UI / isolated-payment-tests (push) Failing after 1m58s
sms / gates (push) Successful in 3s
sms / robius-sms (push) Successful in 22s
sms / android (push) Successful in 21s
sms / nigig-sms (push) Successful in 4m6s
sms / supply-chain (push) Successful in 4s
R2.1. Review items 2.7 and 5.3.
## SessionRegistry was built in Phase 5 and never wired
The pump still read:
while let Some(ev) = robius_ussd::next_event() {
... if let Some(id) = h.current.take() { ... }
}
next_event() drains a process-wide queue and its entries carry no session
id, so every event was applied to whatever `current` happened to be.
Reproduced before changing anything: payment A is dispatched then abandoned
with events still queued; payment B starts; the pump drains A's ResultText
and SessionEnded and applies both to B. An abandoned payment settles the one
that replaced it.
## Now
- Dispatch claims the single in-flight slot. The USSD backend returns no
session handle, so the intent id is the correlation id — enough, because
the registry only has to tell this payment from the previous one.
- Every event is admitted against the live operation before it can touch an
intent. Foreign and stale events are logged and dropped.
- Terminal events are de-duplicated; progress chatter still repeats freely.
ussd_duplicate_key mirrors ProviderSignal::duplicate_key in the platform
crate, and a test pins the two together.
- All six terminal and teardown paths retire the session id, so a late
duplicate cannot revive a closed operation.
6 tests, including the abandoned-payment scenario by name. Verified by
removing the close call: that test goes red. CI gate asserts the pump still
admits, dispatch still claims, and at least six paths still close — matching
the method rather than a receiver literal, because rustfmt wraps the call.
## What this does not do
The pump still lives in PayFlowHandler, which still owns the pending-store
writes and the bulk queue. Moving *ownership* to PaymentCoordinator changes
who cancels on teardown and who observes an out-of-order callback, which is
what ADR 0007's device matrix exists to check. That is now tracked as R2.1b.
The correlation defect — the one that could settle the wrong payment — is
closed, and it did not need a device. I had previously filed the whole of
R2.1 as device-blocked; that was too coarse.
## Validation
nigig-pay-ui 78 (was 72) / nigig-mpesa 20 pass
domain 148 / storage 41 / platform 64 / mpesa 29 pass
clippy -p nigig-pay-ui --no-deps -D warnings 0 errors
builds: pay-ui, pay, mpesa, core; default and --no-default pass
correlation injection: abandoned-session test fails without it pass
pin-capture guard pass
53 lines
2.5 KiB
TOML
53 lines
2.5 KiB
TOML
|
|
[package]
|
|
name = "nigig-pay-ui"
|
|
version = "0.1.0"
|
|
edition = "2021"
|
|
description = "Shared payment UI and logic for nigig-mpesa and nigig-pay."
|
|
|
|
[features]
|
|
## This leaf crate stays default-off on purpose. The app crates above it
|
|
## enable `demo` through their own defaults and depend on this crate with
|
|
## `default-features = false`, so a packaging build that passes
|
|
## `--no-default-features` to the app actually turns the automation off
|
|
## instead of having it re-enabled here.
|
|
##
|
|
## Original note, still applicable:
|
|
## USSD automation is ON by default in the app crates.
|
|
##
|
|
## Review item 0.1 asked for dispatch behind a compile-time flag. That was
|
|
## implemented as default-off, which made the *334# automation — the app's
|
|
## primary function — unreachable in an ordinary build, and unreachable at
|
|
## all from the APK crate until 9f0e133.
|
|
##
|
|
## The containment requirement has not been dropped; it has moved to release
|
|
## packaging, which is where a shipping decision belongs. A Play-listed build
|
|
## must be produced with `--no-default-features` (plus the features it does
|
|
## want), and the unresolved Google Play policy risk is recorded in
|
|
## REVIEWS/adr/0007-payment-platform-boundary.md.
|
|
##
|
|
## Turning it off for a build:
|
|
## cargo build -p pageflipnav --no-default-features --features native
|
|
default = []
|
|
## Enable USSD dispatch, auto-retry, and bulk pay.
|
|
## Production builds must NOT enable this until authorized provider integration exists.
|
|
demo = []
|
|
|
|
[dependencies]
|
|
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "a79f0dce4d477e2232344facca0798d3f25043ec"}
|
|
nigig-core = { path = "../../nigig-core" }
|
|
nigig-pay-domain = { path = "../../nigig-pay-domain" }
|
|
# Session correlation (review items 2.7 / 5.3). The registry that refuses an
|
|
# out-of-order or foreign USSD callback lives here; before R2.1 it was built
|
|
# and never wired, and the pump matched events to "whatever is current".
|
|
nigig-pay-platform = { path = "../../nigig-pay-platform" }
|
|
nigig-pay-storage = { path = "../../nigig-pay-storage" }
|
|
nigig-uikit = { path = "../../nigig-uikit" }
|
|
robius-ussd = { path = "../../robius-ussd", features = ["serde"] }
|
|
robius-fingerprinting = { path = "../../robius-fingerprinting" }
|
|
serde = { version = "1", features = ["derive"] }
|
|
serde_json = "1"
|
|
chrono = { version = "0.4", features = ["serde"] }
|
|
zeroize = "1"
|
|
robius-contacts = { version = "0.1.0", path = "../../robius-contacts" }
|
|
robius-file-picker = { git = "https://github.com/project-robius/robius", rev = "b766e62b0600f5d2ee21cc6995648346fc277bd8" }
|