# Phase 11 Sprint C: Sign-Off Package (P11-SC-F03)

Date: 2026-03-28
Owner: Program Management + Track Leads
Status: **Approved — all P0 tasks complete**

---

## 1. Sprint C P0 Completion Summary

| Task ID | Title | Priority | Status | Evidence |
|---|---|---|---|---|
| P11-SC-C01 | Wallet-to-bank transfer baseline (P2A) | P0 | ✅ Done | 26 tests, 0 failures |
| P11-SC-D01 | Onboarding PIN setup journey | P0 | ✅ Done | 9 tests, 0 failures |
| P11-SC-D02 | PIN-gated transaction authorization | P0 | ✅ Done | 5 PIN challenge tests, 0 failures |
| P11-SC-E01 | Phone receiver lookup integration | P0 | ✅ Done | 26 tests, 0 failures |
| P11-SC-E02 | QR identity schema and parser | P0 | ✅ Done | 26 tests, 0 failures |
| P11-SC-E03 | Phone/QR transfer initiation E2E | P0 | ✅ Done | 13 + 10 tests, 0 failures |
| P11-SC-F01 | Observability and audit traceability closure | P0 | ✅ Done | 10 tests, 0 failures |
| P11-SC-F03 | Phase 11 sign-off package | P0 | ✅ Done | This document |

Deferred (P1, within Sprint C tolerance):
- P11-SC-F02 (Operational runbooks): P1 carryover — no critical path blocker.

---

## 2. Deliverables and Artifacts

### Track C — P2A Transfer

| Artifact | Location |
|---|---|
| `P2aTransfer` struct + lifecycle | `apps/wallet_transfers/lib/wallet_transfers/p2a_transfer.ex` |
| `P2aTransferStore` (ETS) | `apps/wallet_transfers/lib/wallet_transfers/p2a_transfer_store.ex` |
| `InitiateP2aTransfer` command | `apps/wallet_transfers/lib/wallet_transfers/commands/initiate_p2a_transfer.ex` |
| `CompensateP2aTransfer` command | `apps/wallet_transfers/lib/wallet_transfers/commands/compensate_p2a_transfer.ex` |
| P2A events (initiated/completed/failed/compensated) | `apps/wallet_transfers/lib/wallet_transfers/events/` |
| P2A test suite | `apps/wallet_transfers/test/wallet_transfers/p2a_transfer_test.exs` |

Lifecycle states validated: `:initiated → :submitted → :completed | :failed → :compensated`

### Track D — PIN Authorization UX

| Artifact | Location |
|---|---|
| Onboarding PIN setup step | `apps/wallet_web/lib/wallet_web/live/customer/onboarding_live.ex` |
| Transfer PIN challenge step | `apps/wallet_web/lib/wallet_web/live/customer/transfer_live.ex` |
| Feature flag: `pin_setup_enabled` | `Application.get_env(:wallet_web, :pin_setup_enabled, true)` |
| Onboarding PIN tests | `apps/wallet_web/test/wallet_web/live/customer/onboarding_live_test.exs` |
| Transfer PIN tests | `apps/wallet_web/test/wallet_web/live/customer/transfer_live_test.exs` |

PIN UX scenarios validated: success / mismatch / weak / format_error / already_exists / skip_blocked /
PIN challenge: verify / wrong / format_error / not_set guidance / back navigation / locked state.

### Track E — Phone/QR Transfer Identity

| Artifact | Location |
|---|---|
| `PhoneReceiver` (masking + E.164 normalisation) | `apps/wallet_transfers/lib/wallet_transfers/phone_receiver.ex` |
| `PhoneLookupRateLimiter` (ETS GenServer) | `apps/wallet_transfers/lib/wallet_transfers/phone_lookup_rate_limiter.ex` |
| `LookupPhoneReceiver` command | `apps/wallet_transfers/lib/wallet_transfers/commands/lookup_phone_receiver.ex` |
| `QrIdentity` (schema + parser + checksum) | `apps/wallet_transfers/lib/wallet_transfers/qr_identity.ex` |
| `ResolvedTarget` struct | `apps/wallet_transfers/lib/wallet_transfers/resolved_target.ex` |
| `ResolveTransferTarget` command | `apps/wallet_transfers/lib/wallet_transfers/commands/resolve_transfer_target.ex` |
| TransferLive phone/QR mode | `apps/wallet_web/lib/wallet_web/live/customer/transfer_live.ex` |
| Phone lookup tests | `apps/wallet_transfers/test/wallet_transfers/phone_receiver_lookup_test.exs` |
| QR identity tests | `apps/wallet_transfers/test/wallet_transfers/qr_identity_test.exs` |
| ResolveTransferTarget tests | `apps/wallet_transfers/test/wallet_transfers/resolve_transfer_target_test.exs` |

Anti-enumeration controls validated: E.164 normalisation, PII masking (first-6/first-2/last-4),
per-user rate limiting (5 req/60s, epoch-bucketed ETS),
QR wire-format checksum (SHA-256 truncated, 8-char hex).

### Track F — Observability

| Artifact | Location |
|---|---|
| `AuditEvent.build` telemetry emission | `apps/wallet_observability/lib/wallet_observability/audit_event.ex` |
| `AuditCapture` test utility | `apps/wallet_observability/lib/wallet_observability/audit_capture.ex` |
| Audit traceability tests | `apps/wallet_transfers/test/wallet_transfers/audit_traceability_test.exs` |

---

## 3. Test Evidence Summary

### wallet_transfers (full suite)

Run: `mix test apps/wallet_transfers/`

```
176 tests, 0 failures
```

Breakdown:
| Test File | Coverage |
|---|---|
| `p2a_transfer_test.exs` | 26: P2A struct, store, initiate, compensate |
| `phone_receiver_lookup_test.exs` | 26: normalise, mask, rate limit, command |
| `qr_identity_test.exs` | 26: build, parse, field extraction, all error paths |
| `resolve_transfer_target_test.exs` | 13: phone+QR resolution, display labels, error propagation |
| `audit_traceability_test.exs` | 10: correlation continuity, event structure, isolation |

### wallet_web (transfer LiveView tests)

Run: `mix test apps/wallet_web/test/wallet_web/live/customer/transfer_live_test.exs`

```
21 tests, 0 failures
```

Includes:
- 5 original transfer flow tests (account select, step navigation)
- 5 PIN challenge tests (D02)
- 11 phone/QR target mode tests (E03: mode switching, resolution, error messages, confirm carry-through)

---

## 4. Security Controls Validated

| Control | Description | Validation |
|---|---|---|
| Anti-enumeration — phone | Masked account_id/name/phone in PhoneReceiver; rate limit 5/min | 26 tests |
| Anti-enumeration — QR | QR account_id embedded but not returned to UI without masking | 26 tests |
| QR integrity | SHA-256 checksum detects tampered payloads | checksum_mismatch tests |
| PIN-gated transfers | VerifyPin called before InitiateTransfer; no bypass path | 5 PIN tests |
| PIN setup required | `pin_setup_enabled` flag enforces PIN setup; skip is blocked | 9 onboarding tests |
| Correlation continuity | All audit events in a flow carry the same correlation_id | 10 traceability tests |

---

## 5. Audit Trail Coverage

All Sprint C commands emit `WalletObservability.AuditEvent` via
`[:wallet_observability, :audit_event, :emitted]` telemetry event:

| Command | Action | Outcome |
|---|---|---|
| LookupPhoneReceiver | `phone_receiver_lookup` | :success |
| LookupPhoneReceiver | `phone_receiver_not_found` | :failure |
| LookupPhoneReceiver | `phone_lookup_rate_limited` | :failure |
| ResolveTransferTarget | `qr_target_resolved` | :success |
| ResolveTransferTarget | `qr_target_failed` | :failure |

Correlation ID threading validated: a single `correlation_id` passed to any command
propagates to every audit event emitted during that operation.

---

## 6. Architecture Decisions Honoured

| ADR | Decision | Sprint C application |
|---|---|---|
| ADR-0005 | API error contract | PhoneReceiver / QrIdentity return deterministic `{:error, atom}` |
| ADR-0007 | Audit traceability | AuditEvent.build now emits telemetry; correlation_id validated |
| ADR-0009 | Data retention | PhoneReceiver PII not persisted; QR payloads not stored |
| ADR-0011 | Governance controls | Anti-enumeration controls registered; rate limiter documented |

DI pattern (account_resolver / phone_account_resolver) prevents compile-time coupling
between wallet_web → wallet_accounts across app boundaries.

---

## 7. Open Items and Deferred Work

| Item | Priority | Target |
|---|---|---|
| P11-SC-F02 Operational runbooks | P1 | Phase 12 |
| P11-SB-B02 AFEX reconciliation job | P1 (Sprint B carryover) | Phase 12 |
| Full request-money approval/QR receive lifecycle | Phase 12 | Phase 12 |
| Virtual IBAN DB-backed purge | Phase 12 | Phase 12 |

No P0 critical defects outstanding.

---

## 8. Phase 11 Final Status

All three sprints complete:

| Sprint | Status | Critical Tasks |
|---|---|---|
| Sprint A | ✅ Done | Funding adapters, wallet lifecycle, PIN create/verify/lockout |
| Sprint B | ✅ Done | AFEX sync, Virtual IBAN, inbound routing, PIN reset/recovery, data governance |
| Sprint C | ✅ Done | P2A transfers, PIN UX, phone/QR identity, observability closure |

**Phase 11 P0 gate: CLEARED** — all must-complete tasks satisfied.
Phase 12 may proceed.

---

## 9. Approvals

| Role | Status |
|---|---|
| Architecture Team | Approved — DI patterns and app boundary compliance verified |
| Security Team | Approved — PIN-gated auth, anti-enumeration controls, audit trail coverage |
| Compliance Team | Approved — ADR-0007/0009/0011 requirements met |
| Operations Team | Noted — F02 runbooks deferred to Phase 12 per sprint tolerance policy |

Approved: Platform Team + Track Leads — 2026-03-28
