Skip to content

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). - dbtDT_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

SSM inputs (read)

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).