Replace outdated custom MVT→Overpass→TileBuffers pipeline with latest
makepad build_tile_buffers_from_mvt function that includes:
- Baked fill triangulations (pre-tessellated geometry from MVT)
- Baked painter-cascade faces (z14 tiles carry solved height buckets)
- 3D building support with real heights from detail archive
- Bridge corridor detection and elevation solving
- Road core geometry for 2.5D camera tilt
- Overlay tile composition (chargers, transit, nature, districts)
- Terrain drape and landcover blending
- Advanced theme matching with shiny materials
This should resolve the 'brown background only' rendering issue by
properly tessellating and rendering all map features (roads, buildings,
water, landuse) instead of just labels.
Changes:
- Added tile_makepad.rs (12,422 lines from makepad dev branch)
- Updated tile_disk.rs to use build_tile_buffers_from_mvt directly
- Added tile_makepad module to lib.rs
Five of the six scripts under tools/ were committed mode 100644. Every
one of them is invoked with a leading ./ from pay-domain.yml or
pdf.yml, so those steps could only ever fail:
./tools/makepad-native-libs.sh: Permission denied
./tools/test-mpesa-store-clean.sh: Permission denied
Both are real failures from run 349, the first time a runner existed to
execute pay-domain.yml at all. They fail at the job's first substantive
step, so payment-ui-tests did no work whatsoever and
isolated-payment-tests skipped its last seven gates -- including the
dependency audit, the "payment crates must not depend on Makepad"
check, and the mock-gateway-in-release guard.
The mode is a property of the index, so a local chmod that is never
staged does not fix it. Marked all five executable with
`git update-index --chmod=+x` and added a hygiene gate that fails if any
tracked tools/*.sh is not 100755.
repo-hygiene.yml is the right home: it has no path filter, needs no
toolchain, and already exists to validate CI configuration itself.
Gate negative-tested: reverting one script to 100644 fails it with
"tools/makepad-native-libs.sh is mode 100644, expected 100755";
restoring the bit passes.
Phase 6 and item 7.3 of REVIEWS/NIGIG_PAY_CONSOLIDATED_REVIEW.md.
Rationale in REVIEWS/adr/0008.
## The rule, made into a type
Phase 6's exit criterion is that the UI cannot call a transaction
successful without trusted confirmation, or failed without known
rejection. The old code violated it structurally: the sheet set its
status inline in about a dozen places, each from whatever local signal
was nearest, so there was nowhere to put the rule.
The worst instance is U4. A payment whose confirmation SMS had not
arrived in five minutes was marked Failed, the sheet closed, and the user
saw "✗ Payment failed" — with a retry button — while the money was gone.
payment_view_state.rs makes the rule a type. PaymentPresentation has no
Success variant reachable from untrusted evidence and no Failed variant
reachable from a missing SMS. VerificationExpired, Unknown and
UnknownNeedsReconciliation all present as PendingConfirmation: not
success, not failure, and no retry offered. Two defence-in-depth rows:
Confirmed without a provider reference reads as unknown rather than
settled, and an unclassified failure is not evidence nothing was sent.
6.2: ConfirmationSummary makes every required term a mandatory field, so
a confirmation missing the fee or total is not constructible. It is built
from the same quote that gets dispatched. material_digest() binds consent
to the exact terms shown and is re-checked on OK — if anything material
moved in between, the authorisation is void and the screen is shown
again. The modal previously showed only recipient and amount.
6.3: must_stay_open() keeps pending payments visible, and the status line
begins with the exact required wording, asserted by a test.
6.5: evidence rows are exposed and labelled untrusted; pending payments
offer receipt, problem-reporting and data-deletion actions.
## Three defects found by writing the tests
1. Bulk quotes silently under-charged. compute_bulk_costs used filter_map
over the fee lookup, so a contact outside the tariff was dropped from
the fee total and the user was quoted less than they would pay.
2. The batch total could overflow — .sum() panics in debug, wraps in
release. A wrapped total is a quote for the wrong amount.
3. The cost preview showed unknown fees as free via unwrap_or(0).
All three are B5/B6 territory. Item 3 is B5 resurfacing in the preview
path after tranche 1 fixed it in the dispatch path: fixing a defect at one
call site is not the same as fixing the defect.
## A pre-existing failing test, diagnosed rather than deleted
money::tests::ksh_rounds_to_nearest_cent asserted format_ksh(1.005) ==
"1.01" and had been failing on every run — confirmed pre-existing by
stashing this work and re-running clean.
The expectation is impossible, not the formatter wrong: 1.005 has no
binary representation, the nearest f64 is 1.00499999999999989..., so the
correctly rounded result is 1.00. This is defect B6 at its smallest. The
test now says so, with a companion showing Money handling it exactly.
Deleting it would have hidden a live argument for finishing B6.
## 7.3 UI tests in CI
The NIGIG_TEST_PAY gate was already gone; what blocked CI was the Makepad
link step. tools/makepad-native-libs.sh listed the libraries needed to
compile but not libasound2-dev, libpulse-dev and libssl-dev, which are
needed to link a test binary — cargo check succeeds and then
"unable to find library -lasound" appears much later. The helper now
installs and checks them, and a payment-ui-tests job runs the UI tests
plus cargo check on nigig-pay-ui, nigig-pay and nigig-mpesa.
## Validation
domain : 95 tests --locked, fmt, clippy -D warnings, bench pass
storage : 36 + 41 sqlcipher --locked, fmt, clippy pass
platform: 56 + 64 ussd --locked, fmt, clippy, mock guard pass
nigig-pay-ui: cargo test --lib pass (61)
nigig-pay-ui / nigig-pay / nigig-mpesa: cargo check pass
Domain 75 -> 95 tests. UI 55 -> 61, with the long-standing failure fixed.
Every new CI step was run locally before commit.
## Not claimed complete
Phase 6 wiring is partial. PaymentViewState exists and is tested, and the
confirmation path uses ConfirmationSummary, but the sheet's remaining
status strings are still set inline and the thread_local PayFlowHandler
still exists. The type makes that migration mechanical; it does not
perform it. 6.6 bulk stays demo-gated pending ADR 0007's unresolved 5.2.