You are right that my first pass at R1 fell short. It deferred an item on a
judgement call, and it fixed three defects without regression tests naming
them. Four gaps, all closed here.
## 1. S8 was deferred; it is now done as far as the platform allows
I skipped certificate pinning as "wasted work if the endpoints get dropped".
That was my call to make about effort, not an external blocker.
Investigated properly: Makepad's HttpRequest exposes no pinning API. Its
only TLS control is set_ignore_ssl_cert, which weakens verification. Pinning
is not implementable at this layer without patching the platform crate.
What *is* enforceable is the property pinning mostly buys — that a mistyped,
injected or attacker-supplied URL cannot be dialled. check_transport gates
every request on HTTPS plus a four-host allowlist, at all three dial sites
in both copies of the client.
7 tests: lookalike hosts (api.coingecko.com.evil.example), embedded
credentials (https://evil@real/), explicit ports, plain HTTP, malformed
URLs, and an assertion that TLS is never disabled. Verified by disabling the
allowlist: 3 tests fail.
## 2. The 13-digit phone defect had no test naming it
I fixed it and moved on. It now has a regression test quoting the original
duplicated branches, plus a property test that normalisation output is
either empty or exactly a valid 10-digit 07/01 number — no third outcome.
## 3. The fee-policy UI wiring was untested
The domain guard had 11 tests; the wiring that connects it to the pay sheet
had none, so nothing proved the sheet actually consults it. Four tests now
cover the shipped policy: it identifies the bundled tariff, refuses once
stale, still quotes while current, and keeps "unknown band" distinct from
"stale table".
## 4. The exchange client had no tests at all
It does now, via the transport module above.
## A test that failed against itself
tls_verification_is_never_disabled_in_this_module asserts the module never
calls set_ignore_ssl_cert — and the literal in the assertion put the string
in the file, so it failed on first run. The needle is now assembled at
runtime. Recorded because it is exactly the kind of thing that gets
"fixed" by deleting the test.
## Completion standard, now written into the plan
A phase is done when: no item is deferred on a judgement call; no capability
is removed to satisfy a review item; defects found while implementing are
fixed in the same phase even if absent from the review; every fix carries a
test that fails without it; and CI enforces it.
## Validation
domain 148 / storage 41 / platform 64 / mpesa 29 pass
nigig-pay-ui 72 (was 66) / nigig-mpesa 20 pass
clippy -p nigig-pay-ui --no-deps -D warnings 0 errors
builds: pay-ui, pay, mpesa, core pass
allowlist injection: 3 tests fail when disabled pass
pin-capture guard pass
Pre-existing and untouched: `cargo test -p nigig-pay --lib` fails to build
on clean HEAD (ClassifiedTransaction not in scope in transact.rs). Verified
by stashing. The transport tests are exercised through the nigig-mpesa copy.