ADR-036: Decision result publication — Snowflake to Neon¶
| Status | Accepted |
| Date | 2026-04-10 |
| Deciders | CTO, Head of Architecture, Head of Risk |
| Affects repos | bank-platform, bank-core, bank-risk-platform, bank-aml |
Status¶
Accepted — 2026-04-10
Context¶
The platform uses Neon for operational systems (system of record) and Snowflake for analytical and detection workloads. ADR-003 defines a one-way CDC pipeline from Neon → Snowflake that carries committed operational facts for analytical consumption.
Decisions generated in Snowflake — onboarding outcomes, risk-tier updates, fraud actions — must be applied back to Neon to take operational effect. The existing CDC path is append-only and analytical in nature; it is not a mechanism for returning approved decisions to the operational layer.
A controlled Snowflake → Neon publication model is therefore required. Without it, Snowflake-generated decisions would have no governed path into the operational system, or would require ad-hoc direct database writes that undermine auditability and safety.
Decision¶
Snowflake will publish versioned, idempotent, contract-based decision results to Neon through a dedicated decision inbox. The following principles govern the model:
- Contract-based publication — no direct table coupling between platforms. The decision result contract (defined in the schema contract artifact pack) is the only approved payload shape.
- Publish decisions, not raw data — raw features, intermediate scores, exploratory model output, and factor weights remain in Snowflake. Only approved, policy-sanctioned outcomes cross the boundary.
- Idempotent writes — every published decision carries a
decision_idandidempotency_key. Neon operational services must deduplicate on these before applying. - Neon remains system of record — Snowflake initiates the publication but Neon validates, stores, and applies the decision. Snowflake never writes directly to operational customer or application state.
- Human-readable explanations included — reason codes, reason labels, and plain-language explanations are part of the published contract, enabling operator visibility without exposing internal model internals.
- Versioned contracts — the
schema_versionfield is mandatory. Breaking changes require a new major version and a dual-run period before the old version is retired.
Architecture¶
Neon (operational facts)
→ CDC pipeline (ADR-003)
→ Snowflake (signals + risk/fraud/AML detection)
→ decision_curated.decision_result (approved outcome)
→ Publication path
→ Neon decision_inbox.decision_result_inbox
→ Operational apply service (idempotency check + state update)
→ decision_state tables (customer_decision_state, application_decision_state)
→ decision_delivery_log (audit trail)
Data contract¶
The decision result contract defines the following required fields:
| Field | Type | Notes |
|---|---|---|
decision_id |
uuid | Primary identifier |
idempotency_key |
string | Unique replay-safe key |
entity_type |
enum | CUSTOMER | APPLICATION | PAYMENT |
entity_id |
string | Operational entity reference |
decision_type |
enum | ONBOARDING | RISK_TIER | FRAUD_ACTION | SCREENING_ACTION |
decision_status |
enum | ACCEPT | REJECT | REFER | HOLD | CLEAR |
decision_summary |
string | One-line plain-language summary |
score_summary |
object | risk_score, risk_tier, fraud_score |
reasons |
array | reason_code, reason_label, reason_explanation, customer_visible |
produced_by |
string | Producing component identifier |
policy_refs |
array | Policy codes satisfied by the decision |
schema_version |
string | Semantic version of the contract |
effective_at |
timestamp | When the decision becomes operative |
expires_at |
timestamp | Optional — null for indefinite |
Full JSON schema is maintained in the schema contract artifact pack (decision-result.schema.json).
Platform interaction model¶
| Path | Purpose | Contract shape |
|---|---|---|
| Neon → Snowflake | Facts, history, analytical visibility | CDC envelope (ADR-003) |
| Snowflake → Neon | Approved operational outcomes | Decision publication contract (this ADR) |
| Snowflake → Snowflake | Internal curation and sharing | Curated tables and shares |
| Neon → Neon | Operational sync between Postgres estates | API-mediated upsert contracts |
Consequences¶
Positive: - Strong auditability — every applied decision is traceable to a Snowflake computation, a contract version, a policy reference, and a model version. - Explainability — operators see the decision, scores, and plain-language reasons without internal algorithm exposure. - Clean platform boundary — Neon remains the operational source of truth; Snowflake remains the analytical and scoring platform. Each side does its job. - Replay safety — idempotency keys make re-publication safe without duplicate effects.
Negative: - Additional infrastructure — requires the decision_inbox schema, operational apply service, and delivery log in Neon. - Contract governance overhead — schema versioning, compatibility rules, and ownership must be maintained as the decision model evolves. - Latency is near-real-time, not sub-second — acceptable for onboarding and risk-tier decisions but may need review for time-sensitive fraud action paths.
Related ADRs¶
- ADR-003 — Neon → Snowflake CDC pipeline (the one-way fact replication this ADR complements)
- ADR-010 — Financial crime architecture (AML/fraud detection in Snowflake)
- ADR-035 — Snowflake account configuration and data residency
Signoff record¶
| Date | Name | Role | Status |
|---|---|---|---|
| 2026-04-10 | Ross Millen | CTO | Approved |
| 2026-04-10 | Ross Millen | Head of Architecture | Approved |
| 2026-04-10 | Ross Millen | Head of Data | Approved |
Capabilities¶
| Capability | Description | Relationship |
|---|---|---|
| CAP-029 | Immutable audit log | enabled — every applied decision traceable to Snowflake computation and policy ref |
| CAP-038 | Real-time fraud scoring & block | enabled — fraud action published via decision inbox |
| CAP-062 | CDD automatic tier assignment | enabled — CDD tier decision published from Snowflake to Postgres |
| CAP-065 | Pre-approval engine (nightly eligibility scoring) | enabled — credit pre-approval decision published to Postgres via this contract |
| CAP-068 | Automated credit decisioning engine | enabled — credit decisioning output published via governed contract |
Related decisions¶
| ADR | Title | Relationship |
|---|---|---|
| ADR-003 | CDC pipeline — Neon Postgres to Snowflake via Firehose and Apache Iceberg | complementary direction — facts flow Neon to Snowflake via CDC |
| ADR-010 | Financial crime and fraud detection platform | fraud actions flow Snowflake to Neon via this ADR |
| ADR-019 | Intelligent customer home screen and financial intelligence layer | credit decision existence flag is a Tier 2 decision via this ADR |
| ADR-035 | Snowflake account configuration and data residency | Snowflake is the source of decisions |
| ADR-038 | Data access tier policy — Snowflake as the reporting and insight layer | Tier 2 decisions are the only data crossing Snowflake to Neon boundary |
All ADRs
Compiled 2026-05-22 from source/entities/adrs/ADR-036.yaml