Skip to content

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 to accounts.balance without 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 to accounts.accounts.balance for 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.postings with 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_module and transaction_id are 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 has created_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's policies_satisfied YAML. 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_id in PENDING state → must return 422 with ACCOUNT_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 = VERIFIED on 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_tier populated on banking.customer_relationships within 5 seconds.
  • LOG: Every eIDV invocation logged to kyc.kyc_checks with provider, check_type, result. Test: complete eIDV → verify exactly one row in kyc_checks with 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_alerts within 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_reference field.
  • 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.