MOD-080 — Statutory financial reporting¶
Module: MOD-080 (statutory-financial-reporting) System: SD06 (risk-platform) Repo: bank-risk-platform Phase: 1 ADR: ADR-046 — SD06 data product architecture (Snowflake-native orchestration, dbt transformation layer, view-as-product, EventBridge at external boundaries only)
⚠️ PENDING CFO REVIEW. The chart of accounts (
seeds/chart_of_accounts.csv) + internal account purposes (seeds/internal_account_purposes.csv) are a working v1 baseline, not the bank's signed statutory taxonomy. Before MOD-080 is allowed to push to a real ERP in UAT or prod, the CFO + finance controller must sign off on the GL classification + IFRS line-item mapping. Tracked indocs/handoffs/MOD-080-cfo-coa-governance.handoff.md.
Purpose¶
Snowflake-native statutory close pipeline that produces the four IFRS
financial statements (trial balance, P&L, balance sheet, cash flow)
on the regulatory schedule (monthly / quarterly / annual), archives
them to a 7-year Object-Lock-COMPLIANCE S3 bucket, and pushes a
structured GL feed to the bank's ERP via HMAC-signed webhook. Every
period close is gated by an FR-263 reconciliation check that
compares cumulative trial-balance closing balances against SD01
accounts.balance per (gl_account_code × jurisdiction × currency)
with a $0.10/line tolerance and a 2-minute CDC lag exclusion (per
scope rulings Q3 + Q1).
The S3 archive is the regulatory artefact — Object Lock COMPLIANCE
mode means not even root can delete or shorten retention before
expiry. Per scope ruling Q2: archive precedes ERP push, archive
success commits the period, ERP push failure does NOT roll back the
archive or the bank.statutory.report_produced event. ERPs go down
for maintenance; the push retries independently without re-archiving.
Functional + non-functional scope¶
| Code | Requirement |
|---|---|
| FR-261 | Generate trial balance, P&L, balance sheet, and cash flow statement at the regulatory cadence per jurisdiction (NZ + AU). All four published as STATUTORY views over dbt-managed Dynamic Tables. |
| FR-262 | Push structured GL feed to the bank's ERP via API integration within 2 hours of period end. HMAC-signed webhook; 30s timeout; every attempt logged to STATUTORY.ERP_PUSH_LOG. |
| FR-263 | Reconciliation gate before publish — cumulative trial-balance closing vs SD01 accounts.balance per (gl_account_code × jurisdiction × currency); $0.10/line tolerance (Q3); 2-min CDC lag exclusion (Q3 + Q1); breach → period marked NEEDS_MANUAL_REVIEW, archive does NOT happen, ERP push does NOT happen, bank.statutory.reconciliation_variance_detected event fires + DCM alert routes to MOD-076 SNS. |
| FR-264 | 7-year minimum immutable storage for auditor access — S3 Object Lock COMPLIANCE mode, 2555-day default retention, explicit Deny on s3:DeleteObject* for defense-in-depth. |
| NFR-006 | All financial figures persisted as NUMBER(p,s) (never FLOAT) — same precedent as the MOD-032 / MOD-035 saga. Every aggregation explicitly cast to NUMBER(20,2) to short-circuit Snowflake's FLOAT-promotion rule. |
| NFR-024 | REPORT_RUNS, ERP_PUSH_LOG, RECONCILIATION_RUNS are append-only. BANK_DBT_ROLE has SELECT only. Runtime grant verification in tests/integration/snowflake-immutability.test.ts. |
| NFR-019 | All Lambdas and DCM tasks structurally logged (per-period report_run_id / recon_run_id / push_id correlation IDs). |
| NFR-010 | Unattended-success-rate ≥90% — measured via V_PERIOD_CLOSE_METRICS (succeeded / total per period_type per month); alarm ALERT_PERIOD_CLOSE_FAILURE routes to MOD-076 SNS on any FAILED or NEEDS_MANUAL_REVIEW outcome. |
| Policy | Mode | How satisfied |
|---|---|---|
| REP-004 | AUTO | All four IFRS statements are dbt-managed Dynamic Tables refreshed every 15 min (1 hour for cash flow). Period detection is a Snowflake task running hourly; orchestrator runs on a 30-min EventBridge schedule. No manual extraction path. Verified: tests/policy/REP-004-auto.test.ts. |
| REP-001 | AUTO | The trial_balance_period DT (substrate for all four IFRS statements + the ERP feed CSV) reads from int_classified_postings ← stg_postings, the same CDC-fed staging chain MOD-039 / MOD-040 / MOD-041 use. Single source of truth in fact, not just claim. Verified: tests/policy/REP-001-auto.test.ts. |
| GOV-006 | LOG | ERP_PUSH_LOG.SOURCE_PERIOD_ID + SOURCE_TRIAL_BALANCE_RUN_ID + PAYLOAD_SHA256 lineage triple traces every ERP journal entry back to the SD01 postings. Manifest.json under each S3 archive prefix carries per-file sha256. Append-only structurally (tests/policy/GOV-006-log.test.ts) and at runtime (tests/integration/snowflake-immutability.test.ts). |
Architecture¶
Module type¶
Hybrid: DCM v2 declarative + dbt models + 3 Lambdas (orchestrator, reconciliation, ERP push) + S3 immutable archive bucket. No Python UDFs (the FR-263 variance check is pure SQL inside the reconciliation Lambda; no statistical/ML code).
ADR-056 readiness (greenfield from day 1)¶
has_dbt_project: truefrom initial deploy.- profiles.yml hybrid
env_var('NAME', 'placeholder-default')form. - All seed data via dbt seed CSVs (no MERGE...VALUES).
- Per-table grants (
STATUTORYis single-owner; no co-residency). target.warehouseon every DT.- All financial columns typed
NUMBER(p,s)not FLOAT. - Every aggregation cast inline to
NUMBER(20,2).
Data flow¶
SD01 accounts.postings ──┐
SD01 accounts.accounts ──┤
SD01 accounts.account_products ──┘
│
▼ CDC (MOD-042) → BANK_{ENV}_CORE.RAW.{POSTINGS, ACCOUNTS, ACCOUNT_PRODUCTS}
│
▼
stg_postings + stg_accounts + stg_account_products (bootstrap-resilient adapter.get_relation)
│
▼
stg_chart_of_accounts (CTAS UNION of chart_of_accounts.csv + internal_account_purposes.csv)
│
▼
int_classified_postings (joins postings × accounts × CoA; signed_amount per bookkeeping convention)
│
▼
trial_balance_period (DT — INCREMENTAL, target_lag=15 min, cluster=(period_id, gl_account_code))
│
┌──────────┼──────────┬──────────────┬──────────────┐
▼ ▼ ▼ ▼ ▼
profit_and_ balance_ cash_flow_ reconciliation_ v_period_close_
loss_period sheet_ statement_ status_current metrics
(DT 15m INC) period period (DT 5m INC) (VIEW)
(DT 15m (DT 1h FULL —
INC) LAG join non-
equality forces FULL,
per MOD-098 lesson)
│ │ │ │
▼ ▼ ▼ ▼
v_pnl_period v_balance_ v_cashflow_ v_reconciliation_
sheet_ period status_current
period
──── Period-close orchestration ────
PERIOD_CLOSE_DETECTOR (Snowflake task, hourly)
inserts a PENDING REPORT_RUNS row when value_date crosses a period_end_date
│
▼
period-close-orchestrator Lambda (EventBridge schedule, every 30 min)
│
├──▶ reconciliation Lambda (FR-263)
│ ├─ on variance → mark NEEDS_MANUAL_REVIEW
│ │ + publish bank.statutory.reconciliation_variance_detected
│ │ + ALERT_RECONCILIATION_VARIANCE → MOD-076 SNS (independently)
│ │ ABORT.
│ └─ on clean → continue.
│
├──▶ compose statement bundle (4 statements + erp_gl_feed.csv + manifest.json with sha256)
│
├──▶ S3 archive ◀── Q2: PRECEDES ERP push. Archive failure aborts.
│ Object Lock COMPLIANCE 2555-day. The regulatory artefact.
│
├──▶ UPDATE REPORT_RUNS.outcome = 'SUCCEEDED' + s3_archive_path
│ + publish bank.statutory.report_produced
│
└──▶ erp-push Lambda (FR-262)
├─ HMAC-SHA256 sign payload, POST to /bank/{env}/erp/api-endpoint
├─ log every attempt to ERP_PUSH_LOG with full lineage
└─ failure does NOT roll back archive or report_produced event (Q2)
ALERT_PERIOD_CLOSE_FAILURE → MOD-076 SNS independently
Refresh cadence rationale¶
| DT | Lag | Mode | Why |
|---|---|---|---|
trial_balance_period |
15 min | INCREMENTAL | The substrate. Statutory close is monthly/quarterly/annual; intra-period freshness is just for ad-hoc treasury queries. 15 min trades freshness for cost — much smaller than MOD-041's 1-min (which has a 60s SLA). |
profit_and_loss_period |
15 min | INCREMENTAL | Aligned with TB. Aggregates only WHERE statement_section='PROFIT_AND_LOSS'. |
balance_sheet_period |
15 min | INCREMENTAL | Aligned with TB. Cumulative window function for closing balances. |
cash_flow_statement_period |
1 hour | FULL | LAG join with non-equality predicate forces FULL refresh per MOD-098 saga (ADR-056 lesson 002758). 1-hour cadence is fine for cash flow — it's a derived/period-end statement, not intra-period. |
reconciliation_status_current |
5 min | INCREMENTAL | Rapid feedback for the variance-investigation dashboard. CDC lag exclusion via DATEADD('minute', -2, period_end_date::TIMESTAMP_LTZ). |
CDC lag compensation (Q1 + Q3)¶
Per scope ruling Q3, postings created within 2 minutes of
period_end_date are excluded from the variance check. The
exclusion is applied in two places:
reconciliation_status_currentDT — the published view'slag_excluded_movementcolumn already factors in the 2-min buffer.- Reconciliation Lambda — the cumulative TB closing query
filters
WHERE period_end_date <= ?::DATEand joins to the already-lag-compensatedV_RECONCILIATION_STATUS_CURRENTview.
The 2-minute window is recorded on every variance event +
reconciliation_runs row (CDC_LAG_EXCLUSION_MINUTES column) so
auditors know what was excluded.
Q2: archive-precedes-push semantics¶
The orchestrator's flow is strictly ordered:
- Reconciliation gate → if variance, ABORT (no archive).
- Compose statement bundle (4 statements + ERP feed + manifest).
- S3 archive — failure here aborts the run as FAILED.
- UPDATE
REPORT_RUNS.outcome = 'SUCCEEDED'+ publishbank.statutory.report_produced. - ERP push — wrapped in try/catch; failure logs ERP_PUSH_LOG with
OUTCOME = 'FAILED' | 'TIMEOUT'but does NOT roll back the archive or the report_produced event. TheALERT_PERIOD_CLOSE_FAILUREalarm fires independently from the ERP_PUSH_LOG state.
Rationale: the S3 archive IS the regulatory artefact (FR-264). Once archived, the period is "produced" for compliance purposes regardless of whether the ERP has received it. ERP push is a downstream operational concern; ERPs go down for maintenance; the push can be retried separately without re-archiving (the archive's content doesn't change between retry attempts — bytes-identical, hash-stable).
Snowflake objects owned¶
| Object | Type | Owner | Notes |
|---|---|---|---|
STATUTORY schema |
(created) | this module | Single-owner — no co-residency complications. dcm/pre-dbt.sql does CREATE SCHEMA IF NOT EXISTS + USAGE grant. |
REPORT_RUNS |
TABLE (DCM) | this module | Period-close audit log (REP-004 / GOV-006 LOG). Append-only inserts on start, UPDATE-once on completion (UPDATE granted to ingest_role only). BANK_DBT_ROLE: SELECT. |
ERP_PUSH_LOG |
TABLE (DCM) | this module | Every ERP push attempt. GOV-006 LOG. Append-only; lineage triple (source_period_id + source_trial_balance_run_id + payload_sha256). BANK_DBT_ROLE: SELECT. |
RECONCILIATION_RUNS |
TABLE (DCM) | this module | Every variance check (FR-263 audit). Append-only. DETAIL_VARIANCES is VARIANT JSON of the worst-50 offending lines. BANK_DBT_ROLE: SELECT. |
EB_PUBLISH_CURSOR |
TABLE (DCM) | this module | Operational cursor for future EB-publisher-style usage. UPDATE granted to ingest_role; BANK_DBT_ROLE: SELECT. |
PERIOD_CLOSE_DETECTOR |
TASK (DCM) | this module | Hourly schedule. INSERTs PENDING REPORT_RUNS rows when value_date crosses a period_end_date. |
ALERT_RECONCILIATION_VARIANCE |
ALERT (DCM, post-dbt) | this module | Routes to MOD-076 SNS when reconciliation_runs has any HAS_UNEXPLAINED_VARIANCE = TRUE row in last 4h. |
ALERT_PERIOD_CLOSE_FAILURE |
ALERT (DCM, post-dbt) | this module | Routes to MOD-076 SNS when REPORT_RUNS has any FAILED or NEEDS_MANUAL_REVIEW row in last 48h. NFR-010 monitoring. |
TRIAL_BALANCE_PERIOD |
DYNAMIC TABLE (dbt) | this module | INCREMENTAL, target_lag=15 min, cluster=(period_id, gl_account_code). |
PROFIT_AND_LOSS_PERIOD |
DYNAMIC TABLE (dbt) | this module | INCREMENTAL, target_lag=15 min. |
BALANCE_SHEET_PERIOD |
DYNAMIC TABLE (dbt) | this module | INCREMENTAL, target_lag=15 min. Cumulative window function for closing balances. |
CASH_FLOW_STATEMENT_PERIOD |
DYNAMIC TABLE (dbt) | this module | FULL refresh, target_lag=1 hour (LAG join non-equality forces FULL — MOD-098 lesson). |
RECONCILIATION_STATUS_CURRENT |
DYNAMIC TABLE (dbt) | this module | INCREMENTAL, target_lag=5 min. Lag-compensated. |
V_TRIAL_BALANCE_PERIOD |
VIEW (dbt) | this module | Published contract per ADR-046 §3 — read by reconciliation Lambda + orchestrator's composeStatementBundle + MOD-036. |
V_PNL_PERIOD |
VIEW (dbt) | this module | Published contract — IFRS P&L. |
V_BALANCE_SHEET_PERIOD |
VIEW (dbt) | this module | Published contract — IFRS Balance Sheet. |
V_CASHFLOW_PERIOD |
VIEW (dbt) | this module | Published contract — IFRS indirect-method Cash Flow. |
V_RECONCILIATION_STATUS_CURRENT |
VIEW (dbt) | this module | Published contract — variance-investigation dashboard source. |
V_PERIOD_CLOSE_METRICS |
VIEW (dbt) | this module | NFR-010 monitoring — unattended_success_rate_pct per period_type × month. |
CHART_OF_ACCOUNTS |
TABLE (dbt seed) | this module | ⚠ PENDING CFO REVIEW. ~35 rows v1 (NZ/AU products + INTERNAL_* GL classifications). |
INTERNAL_ACCOUNT_PURPOSES |
TABLE (dbt seed) | this module | ⚠ PENDING CFO REVIEW. 15 rows (CASH_NZ, INTEREST_INCOME_COLLECTOR, etc.). |
REPORTING_PERIODS |
TABLE (dbt seed) | this module | 36 rows = 12 monthly + 4 quarterly + 1 annual covering 2026–2028. |
STG_CHART_OF_ACCOUNTS |
TABLE (dbt CTAS) | this module | Materialised TABLE not VIEW — ADR-056 091905 precedent (VALUES lineage breaks change-tracking through DT chains). |
Out-of-band Snowflake objects¶
None. Unlike MOD-041 / MOD-039, this module has no Python UDFs.
SSM outputs¶
| Path | Value | Consumer |
|---|---|---|
/bank/{env}/risk-platform/statutory/trial-balance-view |
STATUTORY.V_TRIAL_BALANCE_PERIOD |
MOD-036 prudential return builder + ad-hoc treasury queries (FR-261). |
/bank/{env}/risk-platform/statutory/pnl-view |
STATUTORY.V_PNL_PERIOD |
MOD-036 + executive dashboards. |
/bank/{env}/risk-platform/statutory/balance-sheet-view |
STATUTORY.V_BALANCE_SHEET_PERIOD |
MOD-036 + executive dashboards. |
/bank/{env}/risk-platform/statutory/cashflow-view |
STATUTORY.V_CASHFLOW_PERIOD |
MOD-036 + executive dashboards. |
/bank/{env}/risk-platform/statutory/reconciliation-status-view |
STATUTORY.V_RECONCILIATION_STATUS_CURRENT |
Variance-investigation dashboard (FR-263). |
/bank/{env}/risk-platform/statutory/period-close-metrics-view |
STATUTORY.V_PERIOD_CLOSE_METRICS |
NFR-010 dashboard (unattended success rate). |
/bank/{env}/risk-platform/statutory/reports-bucket |
bank-{env}-statutory-reports |
Auditor signed-URL fetch; ERP push Lambda reads the GL feed CSV. |
/bank/{env}/risk-platform/statutory/period-close-lambda-arn |
Lambda ARN | Ops dashboards + CloudWatch alarms. |
/bank/{env}/risk-platform/statutory/reconciliation-lambda-arn |
Lambda ARN | Ops dashboards. |
/bank/{env}/risk-platform/statutory/erp-push-lambda-arn |
Lambda ARN | Ops dashboards. |
SSM consumed¶
| Path | Origin |
|---|---|
/bank/{env}/snowflake/databases/risk |
MOD-102 |
/bank/{env}/snowflake/account-locator |
MOD-102 |
/bank/{env}/snowflake/warehouses/etl |
MOD-102 |
/bank/{env}/snowflake/warehouses/dbt |
MOD-102 |
/bank/{env}/snowflake/roles/domain-{nonprod\|prod} |
MOD-102 |
/bank/{env}/iam/lambda/bank-risk-platform/arn |
MOD-104 |
/bank/{env}/observability/adot-layer-arn |
MOD-104 |
/bank/{env}/eventbridge/bank-risk-platform/arn |
MOD-104 |
/bank/{env}/eventbridge/bank-risk-platform/dlq-arn |
MOD-104 |
/bank/{env}/sns/alarm-intake/arn |
MOD-076 — referenced by both DCM alerts. |
/bank/{env}/kms/operational/arn |
MOD-104 — for SSE-KMS on the statutory-reports bucket. |
/bank/{env}/erp/api-endpoint |
NOT YET PROVISIONED — see docs/handoffs/MOD-080-needs-erp-setup.handoff.md. ERP push Lambda fails at runtime until this exists. |
/bank/{env}/erp/api-secret-name |
NOT YET PROVISIONED — see same handoff. Secret in Secrets Manager containing { "hmac_key": "..." }. |
Events¶
Published¶
bank.statutory.report_produced (Source: bank.risk-platform,
DetailType: statutory_report_produced)
JSON Schema authoritative source:
docs/event-schemas/bank.statutory.report_produced.v1.schema.json.
{
// Standard envelope (ADR-051)
"event_id": "uuid",
"event_time": "2026-05-01T01:30:00.000Z",
"schema_version": "1.0",
"trace_id": "uuid",
"idempotency_key": "sha256(report_run_id|period_id|trial_balance_run_id)",
// Payload
"report_run_id": "rr-001",
"period_id": "2026-M04",
"period_type": "MONTHLY",
"period_end_date": "2026-04-30",
"trial_balance_run_id": "tb-2026-04-30T23:00:00Z",
"s3_archive_path": "s3://bank-prod-statutory-reports/monthly/2026-M04",
"reports_produced": ["trial_balance", "profit_and_loss", "balance_sheet", "cash_flow_statement"],
"gl_lines_count": 245
}
Subscribers: - SD08 dashboard period-close panel (display "April 2026 closed"). - MOD-036 prudential-return-builder — picks up the lineage handle. - Audit / ops monitoring.
bank.statutory.reconciliation_variance_detected (Source: bank.risk-platform,
DetailType: statutory_reconciliation_variance_detected)
JSON Schema authoritative source:
docs/event-schemas/bank.statutory.reconciliation_variance_detected.v1.schema.json.
{
"event_id": "uuid",
"event_time": "2026-05-01T01:25:00.000Z",
"schema_version": "1.0",
"trace_id": "uuid",
"idempotency_key": "sha256(recon_run_id|period_id)",
// Payload
"recon_run_id": "recon-2026-04-30-...",
"period_id": "2026-M04",
"period_type": "MONTHLY",
"period_end_date": "2026-04-30",
"gl_lines_with_variance_count": 3,
"total_variance_dollars": "152.40",
"max_variance_dollars": "98.50",
"tolerance_dollars_per_line": "0.10",
"cdc_lag_exclusion_minutes": 2
}
The independently-fired DCM alert ALERT_RECONCILIATION_VARIANCE
routes to the same MOD-076 SNS topic — this event is the structured
counterpart for downstream subscribers that need detail.
Consumed¶
None. The only inbound trigger is the EventBridge 30-min schedule (internal SD06; not an external event).
Operational¶
Curating the chart of accounts¶
⚠ Working v1 only — PENDING CFO REVIEW. The seeds/chart_of_accounts.csv
file is a baseline shaped from MOD-001's product taxonomy +
typical NZ/AU bank GL conventions; it is NOT the bank's signed
statutory taxonomy. Until the CFO/finance-controller sign-off
described in MOD-080-cfo-coa-governance.handoff.md is in hand,
this module must not push to a real ERP in UAT or prod. The
dev deploy uses a synthetic ERP webhook for testing.
When CFO sign-off lands, replace the CSVs and re-deploy. The seed materialises into TABLE rows; old rows for retired account codes are over-written by the seed (full-replace mode).
Investigating a NEEDS_MANUAL_REVIEW outcome¶
When ALERT_RECONCILIATION_VARIANCE fires (or a customer reports
a period-close failure), the on-call's investigation:
- Find the
RECONCILIATION_RUNSrow for the period:SELECT * FROM STATUTORY.RECONCILIATION_RUNS WHERE period_id = '<X>' ORDER BY started_at DESC LIMIT 5;. - Read
DETAIL_VARIANCESJSON — top-50 worst offending GL lines withgl_account_code + jurisdiction + currency + variance_dollars. - Cross-reference against
V_RECONCILIATION_STATUS_CURRENTfor the live (lag-compensated) view of the same period. - Inspect the most-variant lines in
int_classified_postingsto see which postings are the source.
Common root causes:
- CDC paused / behind — MOD-042 stream backed up; the 2-min
exclusion isn't enough; check BANK_{env}_CORE.RAW.POSTINGS
freshness.
- New GL account code added to SD01 not in chart_of_accounts.csv
yet — int_classified_postings.is_unclassified will be TRUE.
- Internal-purpose-code mismatch — SD01 internal accounts
whose account_number doesn't match the prefix patterns in
int_classified_postings.sql. Long-term fix: SD01 ships an
explicit internal_purpose_code column (out of MOD-080 scope).
After resolving the variance, manually mark the REPORT_RUNS row
as MANUALLY_RESOLVED (a follow-on outcome distinct from
SUCCEEDED) and re-trigger the orchestrator.
Retrying a failed ERP push¶
The Q2 invariant means the archive is already in S3 when the ERP push fails. To retry:
- Confirm
OUTCOMEof the latestERP_PUSH_LOGrow for the period (SELECT * FROM STATUTORY.ERP_PUSH_LOG WHERE source_period_id = '<X>' ORDER BY pushed_at DESC LIMIT 5;). - Manually invoke the
mod-080-erp-push-{env}Lambda with the archive path and incrementedattempt_number. The orchestrator itself does NOT retry automatically — operational ownership of ERP outage windows sits with the ops team. - Each attempt logs separately. Idempotency on the ERP side is
enforced via the
X-Bank-Payload-SHA256+X-Bank-Push-Idheaders — the ERP de-duplicates on these.
Why the variance + period-close alerts route to MOD-076 specifically¶
Same pattern as MOD-041 k-7. MOD-076 owns the SNS alarm-intake topic that fans out to on-call PagerDuty + Slack. Per-module SNS topics fragment the on-call experience.
Why FR-264 uses Object Lock COMPLIANCE not GOVERNANCE¶
GOVERNANCE mode lets bucket-owner / root override retention. COMPLIANCE mode does NOT — once set, the only way to delete an object before expiry is to wait. This is what makes FR-264's "immutable storage for auditor access" claim binding. Other audit trails in the platform (e.g. CloudWatch logs) use GOVERNANCE because operational override is occasionally legitimate; the statutory archive has no legitimate override case.
Open dependencies¶
These outbound handoffs must land before MOD-080 can exit Built → Deployed in UAT or prod:
| Handoff | Status | Owner |
|---|---|---|
MOD-080-cfo-coa-governance.handoff.md |
Open. Blocks UAT + prod ERP push. | CFO + Finance Controller |
MOD-080-needs-erp-setup.handoff.md |
Open. Blocks all ERP push functionality. | Platform / IT (ERP integration) |
MOD-080-needs-MOD-076-sns-topic-ssm.handoff.md |
Open. Blocks DCM alert routing. Same shared dep MOD-041 + MOD-056 raised. | MOD-076 |
MOD-080-needs-MOD-042-projections.handoff.md |
Acknowledged 2026-05-08. MOD-042 has shipped core-statutory-projections.sql covering all three views; pending operator-apply per env. See processed/2026-05-08/MOD-080-MOD-042-projections-response.handoff.md. |
MOD-042 |
The dev deploy works with bootstrap-resilient adapter.get_relation
on the SD01 raw tables and a synthetic ERP webhook — no production
data flows until the dependencies land. Once MOD-042 operator
applies core-statutory-projections.sql to dev, the next dbt build
of stg_postings / stg_accounts / stg_account_products picks up
real CDC rows automatically (no MOD-080 code change).