Skip to content

Roadmap

Each task is one GitHub issue, sized for one agent session (≤ 30 min) and one PR that leaves main green. The issue is the specification (ADR-0013): a YAML manifest, the decisions already made, acceptance criteria mapped to named tests, and its dependencies (also recorded as GitHub "blocked by" links). This page is the index.

Start a session with:

Implement issue #N. Follow AGENTS.md.

A task is ready when every issue it depends on is closed. Tasks without a path between them in the graph can run in parallel, for example M1-T1 ∥ M1-T2, M1-T6 ∥ M1-T4, and M3-T1 alongside M1-T4…T7.

M0, the baseline, is done: the monorepo skeleton, contracts, wallet stub, schema, docs, CI and Pages, DecisionModeRouter, and a green ./gradlew presubmit. Every open question is resolved by a working assumption and an ADR (PRD §7).

Dependency graph

flowchart LR
  subgraph M1
    M1T1["M1-T1"]
    M1T2["M1-T2"]
    M1T3["M1-T3"]
    M1T4["M1-T4"]
    M1T5["M1-T5"]
    M1T6["M1-T6"]
    M1T7["M1-T7"]
  end
  subgraph M2
    M2T1["M2-T1"]
    M2T2["M2-T2"]
    M2T3["M2-T3"]
    M2T4["M2-T4"]
    M2T5["M2-T5"]
  end
  subgraph M3
    M3T1["M3-T1"]
    M3T2["M3-T2"]
    M3T3["M3-T3"]
    M3T4["M3-T4"]
    M3T5["M3-T5"]
  end
  M1T2 --> M1T3
  M1T1 --> M1T4
  M1T3 --> M1T4
  M1T4 --> M1T5
  M1T1 --> M1T6
  M1T5 --> M1T7
  M1T6 --> M1T7
  M1T4 --> M2T1
  M2T1 --> M2T2
  M2T2 --> M2T3
  M1T7 --> M2T3
  M1T7 --> M2T4
  M2T2 --> M2T4
  M2T3 --> M2T5
  M2T4 --> M2T5
  M1T2 --> M3T1
  M1T3 --> M3T1
  M3T1 --> M3T2
  M1T7 --> M3T2
  M3T2 --> M3T3
  M3T3 --> M3T4
  M3T4 --> M3T5
  M2T1 --> M3T5
  M2T4 --> M3T5

M1 · Phase 1: correct and resilient on the existing wallet API

Exit criteria: A till can pay, be declined and reverse. The wallet's slow, down and ambiguous modes produce fast, correct responses, and no money is lost or doubled.

Task Issue Title Depends on Proves
M1-T1 #1 Local ledger repositories and inbound idempotency gate — FR-2, NFR-6, F6, F7, F8
M1-T2 #2 Wallet v1 HTTP client with deadline-capped timeouts and outcome classification — NFR-1, NFR-4, FR-3, FR-4
M1-T3 #3 Resilient wallet adapter: circuit breaker and bulkheads M1-T2 NFR-2, NFR-3, FR-6, F2
M1-T4 #4 POST /v1/payments end to end with DirectDebitStrategy M1-T1, M1-T3 FR-1, FR-2, FR-3, FR-4, FR-5, FR-6, NFR-1, NFR-6, F1, F6
M1-T5 #5 Payment read and reversal intake (tombstones, advisory lock) M1-T4 FR-7, FR-8, FR-9, FR-10, F10
M1-T6 #6 Postgres work queue engine (SKIP LOCKED, lease, backoff, DEAD) M1-T1 NFR-7
M1-T7 #7 Compensation workers (RESOLVE_UNKNOWN, REVERSE) and stale-request sweeper M1-T5, M1-T6 FR-5, FR-10, NFR-4, F4, F5

M2 · Operate it: switches, stand-in, observability, failure proof

Exit criteria: On-call can tell a wallet outage from customer behaviour, orphaned money is visible, safety switches work without a deploy, and every row of the fault matrix is an automated test.

Task Issue Title Depends on Proves
M2-T1 #8 Runtime switches stored in Postgres (kill switch, cohort %, stand-in on/off) M1-T4 FR-12, FR-15
M2-T2 #9 Degradation policy and stand-in approval with atomic exposure caps (off by default) M2-T1 FR-14, FR-15
M2-T3 #10 Stand-in post-recovery debit worker and stand-in reversal M2-T2, M1-T7 FR-15, FR-10
M2-T4 #11 Metrics, Prometheus alert rules and orphan reconciler M1-T7, M2-T2 NFR-8, G2
M2-T5 #12 Failure-mode test suite (fault matrix) and k6 load smoke M2-T3, M2-T4 G1, G2, G3, G4, F1, F2, F3, F9, F13

M3 · Phase 2: hold/capture and cutover

Exit criteria: HOLD_CAPTURE works end to end against the wallet v2 stub and can be ramped by cohort and rolled back with the kill switch. Production enablement is gated on Wallet sandbox contract tests (A9).

Task Issue Title Depends on Proves
M3-T1 #13 Wallet v2 (holds) HTTP client and resilient adapter M1-T2, M1-T3 FR-11
M3-T2 #14 HoldCaptureStrategy: hold-based decision and hold compensation M3-T1, M1-T7 FR-11, FR-4, FR-5
M3-T3 #15 Capture worker (HELD → CAPTURING → CAPTURED) M3-T2 FR-11, FR-13, F11
M3-T4 #16 Hold reaper and TTL safety check at startup M3-T3 FR-13
M3-T5 #17 Cutover wiring: mixed-mode proof, kill switch mid-flight, runbook M3-T4, M2-T1, M2-T4 FR-12, G5, F12

Definition of done (every task)

  • ./gradlew presubmit is green, including the Testcontainers ITs, which must run and not be skipped.
  • Each acceptance criterion has a test whose display name starts with AC-n and a requirement id.
  • Contract changes go into api/** first and code second. The stub is updated in the same PR.
  • A behaviour change that diverges from an ADR or a PRD assumption needs an ADR or a PRD update in the same PR.
  • The task's TODO(Mx-Ty) markers are closed.

Deferred (not scheduled)

  • Outbox relay to Kafka (Debezium or a polling publisher), when a consumer exists (A13, ADR-0011).
  • Daily wallet-statement reconciliation (needs a statement API from the Wallet team).
  • Risk/fraud dependency, using the same primitives with its own bulkhead and breaker.
  • Adaptive concurrency limits instead of a fixed bulkhead size.
  • Archival of DONE work items, expired idempotency keys and published outbox rows.
  • Dashboards, and authentication of actuator endpoints (A15).