MOD-060 — FATCA / CRS / AEOI Reporting Engine
Purpose
Automate the FATCA + CRS classification + annual XML report
preparation + submission to IRD (NZ) and ATO (AU). Same REP-005 GATE
shape as MOD-036 / MOD-057; adds PRI-004 LOG of every cross-border
data transmission. bank-wiki #35 Action C (part 2 of 2).
Architecture
Hybrid module:
- DCM — two MOD-060-owned tables in MOD-056's REGULATORY schema:
- FATCA_CRS_CLASSIFICATIONS (stateful — classifications updatable
when new self-certifications arrive)
- FATCA_CRS_DATA_TRANSMISSIONS (PRI-004 LOG — append-only)
- Two alerts: ALERT_FATCA_CRS_DUE_DATE (FR-259, daily schedule,
30-day window vs FATCA 31 Jul + CRS 30 Jun), ALERT_FATCA_CRS_
VALIDATION_FAILED (FR-258, 15-min schedule).
- dbt — DT_FATCA_REPORTABLE_ACCOUNTS + DT_CRS_REPORTABLE_ACCOUNTS
(1h target_lag, FULL refresh, cell-level + lineage) +
V_FATCA_CRS_VALIDATION (PASSED/FAILED — same shape as MOD-036/057
validation views so the shared gate reads uniformly).
- Lambda — submission orchestrator with the shared four-check
REP-005 GATE. On allow:
1. Fetches reportable accounts via the DT
2. Generates FATCA / CRS XML via xml-generator.ts (correct-shape
OECD schema; SHA-256 hash of body)
3. Writes the PRI-004 LOG row BEFORE the regulator POST —
recording the attempt even if the POST never acks
4. POSTs via IRD stub (NZ) or ATO stub (AU)
5. Records RETURN_SUBMISSIONS + bumps RETURN_RUNS.STATUS = SUBMITTED
- No Streamlit of its own — MOD-170 portal surfaces classification
status + transmission history.
- No new approval table — reuses REGULATORY.RETURN_APPROVALS
(MOD-036-owned). Same orchestrator ingest_role writes RETURN_RUNS +
RETURN_SUBMISSIONS alongside MOD-036's prudential rows and MOD-057's
statistical rows; return_code distinguishes the three surfaces.
Snowflake objects owned by MOD-060
| Object |
Type |
Schema |
Notes |
FATCA_CRS_CLASSIFICATIONS |
TABLE (DCM) |
REGULATORY |
Stateful register; INSERT/UPDATE; no DELETE/TRUNCATE. FR-257 / FR-260. |
FATCA_CRS_DATA_TRANSMISSIONS |
TABLE (DCM) |
REGULATORY |
PRI-004 LOG. Append-only. No UPDATE/DELETE/TRUNCATE to any role. |
ALERT_FATCA_CRS_DUE_DATE |
ALERT (DCM, post-dbt) |
REGULATORY |
FR-259 |
ALERT_FATCA_CRS_VALIDATION_FAILED |
ALERT (DCM, post-dbt) |
REGULATORY |
FR-258 |
DT_FATCA_REPORTABLE_ACCOUNTS |
DT (dbt) |
REGULATORY |
1h target_lag, FULL refresh; joins FATCA_CRS_CLASSIFICATIONS |
DT_CRS_REPORTABLE_ACCOUNTS |
DT (dbt) |
REGULATORY |
1h target_lag, FULL refresh |
V_FATCA_CRS_VALIDATION |
VIEW (dbt) |
REGULATORY |
PASSED/FAILED per (run_id, return_code) — read by shared gate |
SSM outputs
| Path |
Value |
/bank/{env}/risk-platform/fatca-crs/submission-orchestrator-arn |
Lambda ARN |
/bank/{env}/risk-platform/fatca-crs/classifications-table |
REGULATORY.FATCA_CRS_CLASSIFICATIONS |
/bank/{env}/risk-platform/fatca-crs/data-transmissions-table |
REGULATORY.FATCA_CRS_DATA_TRANSMISSIONS |
/bank/{env}/risk-platform/fatca-crs/event-source-name |
bank.risk-platform |
| Source |
Path |
Purpose |
| MOD-036 |
/bank/{env}/risk-platform/prudential-return-builder/return-approvals-table |
Shared approval-record table — gate reads here |
Dependencies
| Module |
Why hard |
| MOD-036 |
Owns RETURN_RUNS / RETURN_SUBMISSIONS / RETURN_APPROVALS (shared audit surface). |
| MOD-056 |
Owns the REGULATORY schema. |
| MOD-010 |
Customer profile (tax residency, self-certification, entity type) — input to classification. Bootstrap-resilient via adapter.get_relation. |
| MOD-042 |
CDC pipeline for account balance + interest data feeding annual FATCA/CRS reports. |
| MOD-102/104 |
Snowflake account + AWS bootstrap. |
| MOD-170 |
Approval workflow surface — without it, every report stays APPROVAL_REQUIRED. |
Policies satisfied
| Policy |
Mode |
How |
| REP-011 |
AUTO |
tests/policy/REP-011-auto.test.ts — FATCA_CRS_CLASSIFICATIONS declares FR-257 inputs; both reportable-account DTs use 1h target_lag + FULL refresh; orchestrator has daily cron trigger; XML generator emits valid FATCA_OECD + CRS_OECD root + SHA-256 hash. |
| REP-005 |
GATE |
tests/policy/REP-005-gate.test.ts — 5 negative + 1 positive against the shared evaluateGate(moduleId="MOD-060", …). |
| PRI-004 |
LOG |
tests/policy/PRI-004-log.test.ts — (a) schema evidence: FATCA_CRS_DATA_TRANSMISSIONS table declares the recipient + data_scope + legal_basis + transmitted_at fields; no UPDATE/DELETE/TRUNCATE grants anywhere. (b) orchestrator invariant: recordTransmission is called BEFORE every regulator submit() call. Gate-refusal path NEVER calls either. |
| NFR-024 |
LOG |
tests/policy/NFR-024-log.test.ts — FATCA_CRS_DATA_TRANSMISSIONS append-only; MOD-060 doesn't erode immutability of MOD-036's shared audit tables. (FATCA_CRS_CLASSIFICATIONS is intentionally UPDATEable — classification register is stateful, not an audit log.) |
- bank-wiki #35 Action C — parent handoff.
- MOD-036 design doc — shared audit-surface contract.
- MOD-057 design doc — sibling submission module.
packages/shared/src/regulatory-gate/gate.ts — canonical REP-005 evaluator (one call site per consumer module).