MOD-160 — Cross-module acceptance suite¶
Purpose¶
Nightly end-to-end acceptance scenarios that cross system-domain boundaries, validating that independently-deployed modules work together as a bank. Per-module integration tests verify a module behaves correctly given correct configuration; MOD-160 verifies the modules compose correctly — that data and events flow across boundaries and user-facing outcomes materialise.
FR scope: requirements: []. Tooling module.
Architectural decisions: ADR-045.
Architecture¶
EventBridge Scheduler (nightly 02:00 NZST)
└── dispatcher Lambda
├── reads scenario manifest from src/config/scenarios.ts
├── for each scenario:
│ check required SSM paths via dependency-check
│ if any missing → status=skipped (not failed)
│ else → invoke bank-acceptance-{scenario_id}-{stage}
│
├── aggregate {passed, failed, skipped, errored}
├── PutMetricData → BankPlatform/Acceptance/E2EAcceptanceSuitePass
└── on any failure → SNS publish to bank-ops-acceptance-{stage}
Deployment scope¶
dev and uat ONLY. Production monitoring is MOD-076's domain. Stages allow-list + sst.config short-circuit + workflow option list + unit test.
Scenarios (initial set)¶
| ID | Description | Required modules |
|---|---|---|
| s001 | Customer onboarding with PASS eIDV | MOD-009 / 010 / 013 / 157 |
| s002 | Account activation after KYC verified | MOD-007 / 009 |
| s003 | Inbound credit posted + balance + notification | MOD-001 / 003 / 063 |
| s004 | Outbound payment passes validation, posts, audit | MOD-020 / 001 / 003 / 022 |
| s005 | Payment to SANCTIONED counterparty blocked | MOD-013 / 020 / 157 |
| s006 | Daily accrual posts interest to ledger + balance | MOD-005 / 001 / 003 |
| s007 | Notification dispatched, captured by MOD-157 log | MOD-063 / 157 |
| s008 | FAIL eIDV identity → account stays Pending | MOD-009 / 007 |
Each scenario declares the SSM paths the dispatcher checks before
invoking. As modules land in dev/uat, more scenarios graduate from
skipped → passed/failed.
How skipped works (the resilience design)¶
Per the spec: "scenarios that depend on modules not yet deployed are automatically skipped". Three distinct result categories:
| status | meaning | metric counted |
|---|---|---|
passed |
Flow completed, asserts green | yes |
failed |
Flow ran, an assert failed | yes (E2EAcceptanceSuitePass=0) |
skipped |
Required SSM path missing | no |
error |
Scenario Lambda itself threw | yes (E2EAcceptanceSuitePass=0) |
Custom metric E2EAcceptanceSuitePass = 1 only when every enabled
(non-skipped) scenario passed. Skipped scenarios don't push the
metric to 0 — that's the whole point. As more modules land, more
scenarios run, more pass-bar moves up.
Reporting¶
- CloudWatch metric:
BankPlatform/Acceptance/E2EAcceptanceSuitePass,ScenariosPassed,ScenariosFailed,ScenariosSkipped(Stage dimension). - CloudWatch dashboard:
bank-acceptance-{stage}— pass tile, per-scenario time series. - SNS alert:
bank-ops-acceptance-{stage}— fires when any scenario fails or errors. Subscriber-side dedup (6 h) is out of scope here; topic is the publish point.
Lambda fleet¶
- dispatcher (1×) — schedule target.
- scenario-runner (8× — one per scenario_id, all sharing the
same code archive). Each named
bank-acceptance-{s001..s008}-{stage}.
The scenario-runner code currently routes to placeholder
implementations in src/scenarios/index.ts that return
{passed: false, reason: 'not yet implemented'}. This is the
honest state — the dispatcher already gated on SSM paths (so this
Lambda only runs when its target modules ARE deployed); the
not-implemented state will surface as failed in the dashboard,
prompting whoever lands those modules to write the assertion.
SSM outputs¶
| Path | Value |
|---|---|
/bank/{stage}/mod160/dispatcher/{fn-name,fn-arn} |
Dispatcher Lambda |
/bank/{stage}/mod160/schedule/name |
Schedule name |
/bank/{stage}/mod160/alert-topic/arn |
SNS topic for failures |
/bank/{stage}/mod160/dashboard/name |
CloudWatch dashboard name |
Dependencies¶
- MOD-157 — provider stubs make scenarios deterministic.
- MOD-158 — seed customers/accounts exist for scenarios to use.
- Optional: MOD-159, MOD-001, MOD-009, MOD-020 etc. — the scenarios that exercise these are skipped until those modules land.
Constraints¶
- No prod deploy.
- Scenarios that need additional IAM (HTTP calls to other modules, reads from MOD-158's Neon, etc.) extend the scenario-runner role's policy as they're written. Initial role has SSM read + logs only.
- Adding a scenario: append a manifest entry to
src/config/scenarios.tsAND implement insrc/scenarios/index.ts. The dispatcher picks it up automatically because the scenario-runner-lambda stack iterates the manifest's scenario_ids when creating Lambdas.