Acceptance criteria¶
Every module in the systems register has a policies_satisfied list. Each row in that list is a compliance obligation. Each obligation maps to a specific type of automated test. This page defines that mapping and provides the acceptance criterion template for each mode.
This replaces the sprint/epic framing — there are no epics. There are modules. A module is not Built until every row in its policies_satisfied list has a passing automated test.
Satisfaction mode → test type¶
| Mode | What it means | Required test | Must include negative test? |
|---|---|---|---|
| GATE | The system structurally prevents the action if the condition is not met. No bypass path. | Integration test: attempt the action without meeting the gate condition → must fail with the correct error code | Yes — the negative case (the gate blocks) is the primary evidence |
| AUTO | The system executes the action automatically without human intervention when triggered. | Automated test: trigger the condition → verify the action fires without any manual step in the path | No, but verify no manual bypass exists |
| CALC | The system produces a calculated output. The calculation is documented and verifiable. | Data pipeline test: run the calculation against known inputs → verify output matches independently computed result | No, but include boundary cases |
| ALERT | The system delivers an alert to the correct recipient within a defined latency when the condition is met. | Alert delivery test: trigger the condition → verify alert reaches the target within the SLA | No, but include the latency assertion |
| LOG | The system writes an immutable audit record with required fields when the event occurs. | Audit trail test: trigger the event → verify record exists with all required fields; attempt UPDATE/DELETE → must fail | Yes — immutability test is required for all LOG satisfactions |
Writing acceptance criteria for a module¶
For each row in the module's policies_satisfied list, write one acceptance criterion using this template:
[MODE] (POLICY-CODE): [One sentence describing what is verified]
Test: [Specific test scenario — what input, what expected output, what is asserted]
GATE example¶
GATE (AML-003): Account activation is blocked if eIDV status is not VERIFIED.
Test: Attempt to transition an account from PENDING to ACTIVE with kyc_status = PENDING
via the account state machine API → must return HTTP 422 with error_code = KYC_NOT_VERIFIED.
Negative: same call with kyc_status = VERIFIED → must succeed.
AUTO example¶
AUTO (AML-002): CDD tier is set automatically on every new customer after eIDV completes.
Test: Complete an eIDV flow for a new party_id → verify banking.customer_relationships.cdd_tier
is populated within 5 seconds with no manual trigger. Verify no customer_id exists
with cdd_tier = NULL after onboarding completes.
CALC example¶
CALC (CLQ-002): Intraday liquidity position equals the sum of all postings since start of day.
Test: Post 10 known debit/credit pairs, retrieve the liquidity position endpoint,
verify the returned value equals the independently computed sum of amounts.
Include one near-zero balance case and one overdraft case.
ALERT example¶
ALERT (GOV-002): LCR below 110% internal threshold fires alert to Treasury and CRO.
Test: Insert synthetic posting data that produces LCR = 109% in the Snowflake DT,
trigger the monitoring evaluation, verify the alert appears in the MOD-076
alert queue within 5 minutes addressed to the Treasury and CRO roles.
LOG example¶
LOG (GOV-006): Every agent back-office action has an immutable audit record.
Test: Perform a customer data view action via the back-office API → verify a record
exists in platform.agent_action_log with correct staff_id, action_type, party_id,
and timestamp. Attempt UPDATE on that record via any DB role → must fail.
Attempt DELETE on that record → must fail.
Per-module acceptance criteria¶
Detailed acceptance criteria for each module are documented in the module's own technical design document, produced by the agent at build time and stored in the code repository under docs/design/MOD-xxx.md.
The criteria below cover the modules with the highest compliance risk — those with GATE satisfactions on the critical payment and onboarding paths. All other modules follow the same template.
MOD-001 Double-entry posting engine¶
- GATE (PAY-001): A posting cannot be written with unbalanced debit/credit legs. Test: attempt single-leg insert → must roll back. Balanced pair → must succeed. Negative: mismatched amounts across legs → reject.
- AUTO (CLQ-006): Capital position endpoint derives from summing ledger entries only — no hardcoded or cached balance bypass path. Test: verify endpoint total equals
SUM(postings.amount)for the account; verify no admin endpoint can write toaccounts.balancewithout a corresponding posting row. - AUTO (REP-004): Statutory P&L and balance sheet are derivable from the ledger with no manual restatement path. Test: verify
SUM(postings.amount)reconciles toaccounts.accounts.balancefor all test accounts; verify no DB role can directly update the balance column without posting through MOD-001. - CALC (CLQ-002): Intraday liquidity position is derivable from raw posting balances alone (full LCR calculation is MOD-032's scope). Test: post N known debit/credit pairs, retrieve the intraday position endpoint, verify returned value equals independently computed
SUM(postings.amount)per account. Include near-zero balance and overdraft-facility boundary cases. - LOG (PAY-007): Every payment posting produces an immutable ledger record. Test: insert a valid posting → verify row written to
accounts.postingswith all required fields. Attempt UPDATE on that row via any DB role → must fail. Attempt DELETE → must fail. - LOG (OPS-007): The double-entry ledger provides an immutable audit trail for operational risk event reconstruction. Test: verify
source_moduleandtransaction_idare non-nullable and populated on every inserted row; verify no role can UPDATE or DELETE any posting row.
REP-004 vs REP-005 flag: An earlier version of this page listed
LOG (REP-005)— "every posting hascreated_at,source_module,transaction_id". REP-005 is the Data Quality policy; that LOG test is valid but REP-005 is not currently in MOD-001'spolicies_satisfiedYAML. The YAML (six policies above) is binding. Adding REP-005 LOG as a 7th policy to MOD-001.yaml is recommended in a follow-on wiki update.
MOD-007 Account state machine¶
- GATE (AML-002): A PENDING account cannot initiate a payment. Test: POST to payment endpoint with
from_account_idin PENDING state → must return 422 withACCOUNT_NOT_ACTIVE. - GATE (AML-007): A RESTRICTED account cannot initiate a payment. Same test pattern with RESTRICTED state.
- GATE (AML-003): Account cannot transition to ACTIVE without
kyc_status = VERIFIEDon the party. Test: attempt state transition without verified KYC → must fail.
MOD-009 eIDV and document verification¶
- GATE (AML-003): Account activation blocked if eIDV not VERIFIED. Test: attempt account open without VERIFIED eIDV → 422.
- AUTO (AML-002): CDD tier set automatically post-eIDV. Test: complete eIDV → verify
cdd_tierpopulated onbanking.customer_relationshipswithin 5 seconds. - LOG: Every eIDV invocation logged to
kyc.kyc_checkswith provider, check_type, result. Test: complete eIDV → verify exactly one row inkyc_checkswith all required fields.
MOD-013 Real-time sanctions screener¶
- GATE (AML-007): A party with an active confirmed sanctions match cannot initiate any payment. Test: set
kyc.sanctions_results.result_status = CONFIRMED_MATCH, attempt payment → must fail. - ALERT (AML-006): A confirmed match creates an alert in the compliance case queue. Test: trigger a list match event → verify alert in
aml.aml_alertswithin 60 seconds. - LOG (AML-007): Every false-positive adjudication logged with decided_by and rationale. Test: adjudicate a false positive → verify record in
kyc.false_positive_decisions.
MOD-020 Pre-payment validation suite¶
- GATE (PAY-001): All validation checks must pass before payment is authorised. Test: fail each of the five checks independently → each must block with the correct
error_code. No check is skippable. - GATE (PAY-005): Fraud score ≥ 0.85 blocks payment. Test: mock fraud scorer returning 0.90 → payment rejected with
FRAUD_SCORE_EXCEEDED. - GATE (AML-007): Sanctions check is non-bypassable in the validation sequence. Test: attempt to call MOD-001 directly without MOD-020 validation reference → must fail on missing
validation_referencefield.
MOD-049 Consent capture¶
- GATE (PRI-001): No secondary data use can occur without a consent record for that purpose. Test: attempt to initiate a marketing action for a customer with no consent record → must fail.
- LOG: Every consent grant and withdrawal is immutable. Test: withdraw consent → verify withdrawal record written. Attempt to UPDATE the grant record → must fail.
MOD-050 Disclosure enforcement¶
- GATE (CON-004): Loan acceptance API blocked if no disclosure event on record. Test: call the acceptance endpoint without prior disclosure → must return 403 with
DISCLOSURE_REQUIRED. - GATE (PAY-004): FX acknowledgement required before cross-border transfer executes. Test: initiate FX transfer without acknowledgement event → must fail.
Completeness check¶
Before a module is assigned to an agent, the orchestrator should verify:
For each row in module.policies_satisfied:
→ Is there a written acceptance criterion with the correct mode type?
→ Does the criterion include a specific test scenario (not just a description)?
→ For GATE and LOG: is there a negative/immutability test defined?
A module assigned without complete acceptance criteria will produce incomplete tests. The orchestrator is responsible for this check, not the agent.