Snowflake Adapter Parity Execution Plan
Purpose
This is the local commit-by-commit plan for bringing
contractforge-snowflake to the same maturity level as the Databricks and AWS
adapters.
The goal is capability and release-discipline parity, not identical file names. Snowflake should keep a Snowflake-native package shape, but every supported capability needs the same maturity signals:
- planner behavior;
- implementation;
- CLI surface;
- unit tests;
- real-account smoke coverage where the behavior touches Snowflake;
- docs and examples;
- evidence/control-table validation.
Current Baseline
As of the first live local smoke, Snowflake has:
- planning and publish-bundle support;
- local library-runner execution through a Snowflake session;
- table, SQL and staged-file source planning;
- append, overwrite, current-state upsert and hash-diff upsert runtime paths;
- basic quality, schema policy, state and control-table evidence;
- publish-to-stage and task/procedure rendering code paths;
- cost reconciliation and dashboard/maintenance helpers;
- a temporary live smoke harness under
.tmp/snowflake-smoke.
Known baseline gaps:
- the local smoke harness is not a first-class package/CLI command;
- CLI
rundoes not yet open a real connector session for non-dry-run runs; - stage publish, Snowpark procedure execution and task execution are not live-smoked;
- governance/access/cost/failure-path live coverage is incomplete;
- source/preparation parity is much thinner than Databricks/AWS;
- state/idempotency/locking is thinner than Databricks;
- control-table migrations and existing-table compatibility need hardening.
Commit Plan
Commit 01: Record The Parity Execution Plan
Goal: make this numbered execution plan visible in the repo.
Implementation items:
- add
docs/specs/snowflake-adapter-parity-execution-plan.md; - link it from
adapters/snowflake/README.md; - link it from
docs/README.md; - do not change runtime behavior.
Validation:
- inspect markdown links;
- no runtime tests required unless docs tooling is run.
Commit message:
docs: add Snowflake parity execution plan
Commit 02: Connector-Backed CLI Run
Goal: make contractforge-snowflake run execute a real local library-runner run
using Snowflake connector options.
Implementation items:
- split CLI code enough to keep
cli.pythin or add focused helpers undercontractforge_snowflake/cli_run.py; - add
--connect-optionstorun; - open a connector connection lazily only for non-dry-run execution;
- wrap connector connections with a session adapter that exposes
session.sql(...).collect(); - preserve current dry-run behavior;
- close owned connections on success and failure;
- redact connect-option values from errors/output.
Tests:
- CLI dry-run still avoids connector import;
- CLI non-dry-run opens
_connect, passes the session intorun_snowflake_contract, and closes it; - connector-session wrapper exposes
schema.names/schema.fieldsfrom cursor metadata; - connection failure returns a clear CLI error.
Live smoke:
contractforge-snowflake run `
--contract-uri .tmp\snowflake-smoke\contracts\orders_append.contract.json `
--environment-uri .tmp\snowflake-smoke\environment.json `
--connect-options .tmp\snowflake-smoke\connect-options.yaml
Commit message:
feat(snowflake): run contracts through connector-backed CLI
Commit 03: Promote Minimal Smoke To First-Class Package
Goal: replace the temporary .tmp smoke harness with a reusable adapter smoke
command.
Implementation items:
- add
contractforge_snowflake/smoke/models.py; - add
contractforge_snowflake/smoke/minimal.py; - add
contractforge_snowflake/smoke/runner.py; - add CLI command
smoke; - support
--connectionfor Snowflake CLI interop documentation and--connect-optionsfor connector execution; - support
--database,--schema,--table-prefix; - default to non-destructive
CF_SMOKE_*objects; - write summary JSON with target counts, control-table counts, run ids and warnings.
Tests:
- smoke contract generation is deterministic;
- smoke setup only touches configured schema/prefix;
- smoke summary marks all scenarios pass/fail;
- smoke command refuses broad cleanup unless
--execute-cleanupis supplied.
Live smoke:
contractforge-snowflake smoke --connect-options .tmp\snowflake-smoke\connect-options.yaml
Commit message:
feat(snowflake): add first-class minimal smoke runner
Commit 04: Control-Table DDL And Migration Hardening
Goal: make evidence table creation safe for existing Snowflake accounts.
Implementation items:
- keep all generated control-table identifiers quoted;
- add migration/compatibility inspection for existing unquoted uppercase control tables;
- avoid unconditional
CREATE DATABASEwhen the current role only owns schema objects and the database already exists; - add a deployment option for validate-only DDL;
- record skipped bootstrap statements in smoke summary;
- document minimum privileges for service users.
Tests:
- reserved words such as
triggerare quoted; - existing incompatible tables produce actionable errors;
- existing compatible tables are reused;
- service-role bootstrap can skip existing database/schema creation.
Live smoke:
- run minimal smoke with service role in existing
PUBLIC; - run minimal smoke in a new schema with admin role.
Commit message:
fix(snowflake): harden control table bootstrap
Commit 05: Runtime Metrics And Run Evidence Completeness
Goal: populate run evidence with row metrics and Snowflake query context closer to AWS/Databricks.
Implementation items:
- capture rows read before quality filters;
- capture rows written for append/overwrite;
- capture inserted/updated counts where Snowflake result metadata supports it;
- store query ids for adapter-owned statements when available;
- include warehouse, role, database, schema and Snowflake version in metadata;
- include command/query counts in
metrics_json; - preserve redaction in error paths.
Tests:
- append success evidence has row counts;
- overwrite success evidence has row counts;
- upsert/hash-diff records available write metrics;
- connector result metadata is normalized without Snowpark.
Live smoke:
- verify
ctrl_ingestion_runs.rows_read; - verify
metrics_jsoncontains query ids or documented nulls.
Commit message:
feat(snowflake): record runtime row and query metrics
Commit 06: Failure-Path Evidence Smoke
Goal: make Snowflake failure behavior match AWS/Databricks discipline.
Implementation items:
- add smoke scenario for missing source table;
- add smoke scenario for failing quality rule;
- persist
ctrl_ingestion_errors; - persist failed
ctrl_ingestion_runs; - ensure original exception still propagates for CLI non-zero exit;
- include redacted error text in summary.
Tests:
- runtime failure writes error evidence;
- quality abort writes quality/error/run evidence;
- secrets/password/token-like strings are redacted.
Live smoke:
contractforge-snowflake smoke-failure-paths --connect-options ...
Commit message:
feat(snowflake): validate failure path evidence
Commit 07: Source Registry And Source Parity Layer
Goal: move source handling out of the monolithic runtime execution module.
Implementation items:
- add
sources/registry.py; - add
sources/table.py; - add
sources/sql.py; - add
sources/stage_files.py; - add
sources/review.pyfor unsupported/review-required source families; - keep behavior identical for currently supported sources;
- return structured source metadata for evidence.
Tests:
- table/view/sql source SQL is unchanged;
- stage source SQL is unchanged;
- unsupported source types produce existing planner statuses;
- source metadata is available to evidence writer.
Commit message:
refactor(snowflake): introduce source registry
Commit 08: Preparation Registry And SQL-Compatible Transforms
Goal: reach baseline transform parity for Snowflake SQL-compatible operations.
Implementation items:
- add
preparation/registry.py; - support projection/column selection;
- support
transform.cast; - support
transform.derive; - support
transform.standardizefor trim/lower/upper; - support filters where represented by core semantic model;
- support deterministic deduplicate using
QUALIFY ROW_NUMBER(); - keep complex nested shape as
REVIEW_REQUIREDuntil live-tested.
Tests:
- casts render Snowflake SQL;
- derives render Snowflake SQL with dialect warning;
- standardization renders SQL functions;
- deduplicate requires deterministic ordering;
- unsupported nested shape stays review-required.
Live smoke:
- SQL-compatible transform scenario;
- deduplicate/upsert scenario.
Commit message:
feat(snowflake): add SQL-compatible preparation registry
Commit 09: Write-Mode Registry
Goal: split write modes and make them independently testable.
Implementation items:
- add
write_modes/registry.py; - add
write_modes/append.py; - add
write_modes/overwrite.py; - add
write_modes/upsert.py; - add
write_modes/hash_diff.py; - keep historical/snapshot soft-delete review boundaries explicit;
- centralize merge-key validation.
Tests:
- append SQL unchanged;
- overwrite SQL unchanged;
- upsert validates null/duplicate keys;
- hash-diff excludes declared columns;
- unsupported modes cannot execute silently.
Commit message:
refactor(snowflake): split write mode execution
Commit 10: Schema Policy And Schema Evidence
Goal: bring schema policy closer to Databricks/AWS maturity.
Implementation items:
- inspect target schema through
INFORMATION_SCHEMA.COLUMNSwhen connected; - maintain connector metadata fallback for local session wrapper;
- enforce strict/additive/permissive consistently;
- write
ctrl_ingestion_schema_changesfor additive changes; - classify type widening/incompatible changes;
- add schema change details to run evidence.
Tests:
- strict added/removed columns fail;
- additive nullable columns are applied;
- incompatible type changes fail or review according to policy;
- schema changes evidence is written.
Live smoke:
- additive column smoke;
- strict failure smoke.
Commit message:
feat(snowflake): add schema policy evidence
Commit 11: Quality Parity Expansion
Goal: implement and live-smoke supported quality rules.
Implementation items:
- confirm
not_null,required_columns,accepted_values,min_rows,unique_key,max_null_ratio, and row-level expressions; - reject aggregate quarantine without row predicate;
- add warn/fail/quarantine status handling;
- persist
ctrl_ingestion_qualityandctrl_ingestion_quarantine; - include quality summary in run evidence.
Tests:
- pass/warn/fail/quarantine unit tests;
- aggregate quarantine rejection;
- row-level quarantine filters target write.
Live smoke:
- passing quality;
- quarantined row quality;
- aborting quality.
Commit message:
feat(snowflake): expand quality and quarantine runtime
Commit 12: State, Idempotency And Locks
Goal: bring state handling toward Databricks maturity.
Implementation items:
- persist last success state for every run;
- support watermark candidate calculation;
- support previous watermark filtering;
- add idempotency lookup for declared idempotent runs;
- add lock acquire/release helpers;
- record lock/state evidence in control tables.
Tests:
- previous watermark filters source;
- successful run updates state;
- idempotent replay can skip;
- lock acquisition detects active lock;
- lock release does not mask original failures.
Live smoke:
- two-run watermark scenario;
- idempotent replay scenario.
Commit message:
feat(snowflake): add state idempotency and locks
Commit 13: Governance Comments And Tags
Goal: validate Snowflake annotations live.
Implementation items:
- implement table comments;
- implement column comments;
- implement tag application when tag objects exist;
- support validate-only mode for tags;
- persist
ctrl_ingestion_annotations; - document tag namespace requirements.
Tests:
- comments render/apply;
- missing tag can warn or fail by policy;
- annotation evidence redacts values.
Live smoke:
- comments smoke;
- tag validate-only smoke;
- optional tag apply smoke when tag object exists.
Commit message:
feat(snowflake): apply comments and tag annotations
Commit 14: Access Grants And Policy Review
Goal: mature access handling without unsafe destructive changes.
Implementation items:
- map grants to Snowflake privileges;
- implement validate-only grant plan;
- implement apply grants when explicitly requested;
- render row access policy SQL;
- render masking policy SQL;
- keep destructive revokes review-required;
- persist
ctrl_ingestion_access.
Tests:
- grant plan renders safe SQL;
- validate-only records evidence without grant;
- row/mask policy SQL validates required fields;
- destructive drift raises review-required.
Live smoke:
- validate-only grant smoke;
- optional grant apply smoke to test role.
Commit message:
feat(snowflake): add access grant and policy evidence
Commit 15: Stage Publish Live Smoke
Goal: prove publish bundles can be uploaded and consumed from a Snowflake stage.
Implementation items:
- add smoke setup for internal stage;
- publish artifacts to stage;
- load contract/environment artifacts back through runtime loader;
- run a staged-artifact contract through local connector-backed runtime;
- summarize manifest and artifact URIs.
Tests:
- stage URI validation;
- unsafe stage paths rejected;
- publish closes owned connections on failure.
Live smoke:
contractforge-snowflake smoke-stage-publish --connect-options ...
Commit message:
feat(snowflake): smoke stage publish artifacts
Commit 16: Snowpark Procedure Deployment
Goal: deploy and execute the stable Snowflake runtime procedure.
Implementation items:
- build/install adapter wheel for procedure import;
- upload wheel to stage;
- create or replace runtime procedure;
- call procedure with contract/environment artifact URIs;
- capture procedure query id and result;
- document required packages/imports.
Tests:
- procedure SQL renders deterministic imports/packages;
- unsafe wheel URIs are rejected;
- procedure call SQL is safe.
Live smoke:
- deploy procedure;
- run one append contract through procedure;
- verify target/evidence.
Commit message:
feat(snowflake): deploy stable Snowpark runner procedure
Commit 17: Task Graph Deployment And Execution
Goal: prove scheduled/dependency project execution in real Snowflake.
Implementation items:
- create task graph from project schedule and dependencies;
- deploy tasks calling stable runner procedure;
- support dry-run/apply/resume/suspend;
- run root task manually for smoke;
- poll task history;
- persist task evidence summary.
Tests:
- schedule timezone renders correctly;
- dependency
AFTERrenders correctly; - resume/suspend commands are explicit;
- task graph refuses missing artifact URI/procedure.
Live smoke:
contractforge-snowflake smoke-task-graph --connect-options ...
Commit message:
feat(snowflake): deploy and smoke task graph execution
Commit 18: Project CLI Parity
Goal: make Snowflake project commands as usable as AWS/Databricks equivalents.
Implementation items:
- split
deploy-projectimplementation if needed; - add
run-projector equivalent execute command; - add
--waitand status polling; - add summary-only and JSON output modes;
- add cleanup-plan command;
- add cost-gated apply flags.
Tests:
- project dry-run validates all steps;
- unsupported step blocks deployment;
- summary-only omits noisy artifacts;
- cleanup plan is non-destructive by default.
Live smoke:
- deploy two-step project;
- run/wait;
- verify both targets and evidence.
Commit message:
feat(snowflake): add project run and cleanup CLI
Commit 19: Cost Reconciliation Live Smoke
Goal: validate Snowflake cost evidence after Account Usage latency.
Implementation items:
- reconcile by structured query tag;
- record query history signals;
- record query attribution signals when available;
- include warehouse metering/task metadata where available;
- support delayed poll/retry configuration.
Tests:
- query history SQL filters by run id;
- missing Account Usage rows returns delayed/pending status;
- cost evidence insert is idempotent enough for repeated reconciliation.
Live smoke:
- run minimal smoke;
- reconcile cost for one run id;
- verify
ctrl_ingestion_costrows or documented pending status.
Commit message:
feat(snowflake): smoke query history cost reconciliation
Commit 20: Source Expansion For Stage Formats
Goal: broaden file-source support while keeping non-Snowflake extraction review-first.
Implementation items:
- support staged CSV with file format;
- support staged JSON with
VARIANTprojection; - support staged Parquet projection where feasible;
- classify external stage requirements;
- keep HTTP/JDBC/Kafka review-required unless pre-staged.
Tests:
- CSV staged read;
- JSON staged read;
- Parquet staged read or explicit review;
- unsafe file format/stage rejected.
Live smoke:
- stage small CSV;
- run bronze staged-file append;
- validate target and copy/source evidence.
Commit message:
feat(snowflake): expand staged file source support
Commit 21: Lineage And Explain Evidence
Goal: populate lineage/explain control tables.
Implementation items:
- write immediate ContractForge lineage during run;
- add optional delayed
ACCESS_HISTORYreconciliation; - capture
EXPLAINoutput for supported statements; - persist
ctrl_ingestion_lineage; - persist
ctrl_ingestion_explain.
Tests:
- lineage event includes source/target/run id;
- explain capture stores plan text;
- Account Usage latency is handled as pending.
Live smoke:
- verify lineage rows;
- verify explain rows.
Commit message:
feat(snowflake): record lineage and explain evidence
Commit 22: Documentation And Examples
Goal: document Snowflake operation at the same standard as AWS/Databricks.
Implementation items:
- add
docs/adapters/snowflake.md; - add service-user/PAT/key-pair setup guide;
- add minimal smoke guide;
- add project deploy guide;
- add governance/access guide;
- add cost reconciliation guide;
- update site docs if applicable;
- add real-world Snowflake example project.
Validation:
- docs links pass existing documentation tests;
- examples render with current CLI.
Commit message:
docs: add Snowflake adapter operations guide
Commit 23: Stabilization Matrix And CI Gates
Goal: make readiness measurable.
Implementation items:
- add
docs/specs/snowflake-stabilization-matrix.md; - list support status for every source/write/governance/evidence feature;
- map each row to tests and smoke command;
- add optional/manual GitHub workflow for Snowflake smoke;
- add packaging check for runtime extras.
Tests:
- documentation map includes matrix;
- packaging tests include
contractforge-snowflake[runtime]where feasible; - CI workflow syntax is valid.
Commit message:
docs: add Snowflake stabilization matrix
Commit 24: Release Candidate Cleanup
Goal: finish alpha-quality release discipline.
Implementation items:
- remove temporary
.tmpsmoke dependencies from docs; - ensure public API exports are stable;
- run full tests;
- run live minimal smoke;
- run live failure smoke;
- run live stage/procedure/task smoke where credentials allow;
- update README maturity status;
- tag known review-required limitations.
Validation:
uv run pytest;uv build;- live Snowflake smoke summary attached to release notes;
- no Snowflake SDK import on default import path.
Commit message:
chore(snowflake): prepare adapter alpha release
Running Status
Use this section as commits land.
| Commit | Status | Notes |
|---|---|---|
| 01 | Complete | Plan document and links added. |
| 02 | Complete | Connector-backed CLI run and focused tests pass. Service-role execution is unblocked by Commit 04. |
| 03 | Complete | First-class smoke package and CLI added; live packaged smoke passed with CFINGESTSVC. |
| 04 | Complete | Control-table DDL can skip existing database/schema bootstrap; live service-role smoke passed in CONTRACTFORGE_TEST_DB.PUBLIC. |
| 05 | Complete | Runtime rows/query metrics recorded in run evidence; live packaged smoke verified rows and query ids. |
| 06 | Complete | smoke-failure-paths added; live smoke verified missing-source and quality-abort evidence. |
| 07 | Complete | Source registry added for table/view/sql/stage sources; live success and failure smokes passed after refactor. |
| 08 | Complete | Preparation registry added with metadata projection, filters, Snowflake-native replacement transforms, deterministic deduplicate, and live transform/dedup smokes passing. |
| 09 | Complete | Write modes split into append/overwrite/upsert/hash-diff registry modules; focused tests and live success/failure smokes passed. |
| 08 | Pending | Preparation registry. |
| 09 | Pending | Write-mode registry. |
| 10 | Complete | Schema policy now inspects INFORMATION_SCHEMA with connector fallback, records additive schema-change evidence/run metrics, rejects incompatible type changes, and live additive/strict smokes passed. |
| 11 | Complete | Quality runtime now records per-rule summaries, propagates quality_status into run evidence, rejects aggregate quarantine, filters row-level quarantine writes, reports quarantined row metrics, and live pass/quarantine/abort smokes passed. |
| 12 | Complete | State runtime now quotes control-table columns, records failed state rows, supports previous watermark filtering/candidate recording, skips successful idempotency replays with evidence, and provides opt-in lock acquire/release with live watermark/idempotency smokes. |
| 13 | Complete | Table/column comments, qualified tag SQL, tag validate-only evidence, ignore/warn/fail policies, annotation evidence redaction, docs, and live comments/tag-validation smoke passed. |
| 14 | Complete | Grants, validate-only access evidence, row access policy SQL, masking policy SQL, destructive revoke review gating, access evidence redaction, docs, and live validate-only access smoke passed. |
| 15 | Complete | smoke-stage-publish creates a temporary internal stage, publishes the library-runner bundle, reloads manifest/contract/environment artifacts from @stage through connector-backed GET, runs the staged contract, and live smoke passed. |
| 16 | Complete | Procedure smoke command now stages Snowflake-compatible ZIP imports for the built core/adapter wheels, defaults procedure packages to the runtime dependency set, skips connector-only query-tag mutation inside the Snowpark handler, and live hosted procedure smoke passed with query id 01c4ea61-0001-6b57-0001-084600149952. |
| 17 | Complete | Task lifecycle SQL, graph-level task history query, smoke-task-graph, dry-run tests and focused suite passed. Live task graph smoke passed after task grants were provisioned. |
| 18 | Complete | Added run-project dry-run/live task execution with optional bounded task-history wait, summary-only JSON output, non-destructive cleanup-plan, tests, and docs. |
| 19 | Complete | Cost reconciliation now probes structured QUERY_TAG run ids, returns PENDING for delayed or unavailable Account Usage, deletes prior adapter-owned cost signals before insert, records query-history and optional query-attribution signals, exposes wait/poll CLI flags, and focused tests pass. Live Account Usage grants were validated for SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY and QUERY_ATTRIBUTION_HISTORY. Runtime query tags were fixed to store parseable JSON by using unquoted target names; fresh minimal smoke passed with run d8bc24b9-f36e-4e44-8383-115ca89a925a, and reconciliation remains correctly PENDING until Account Usage latency exposes that new run id. |
| 20 | Complete | Staged-file source rendering now supports CSV positional projections, JSON payload/typed projections and Parquet typed projections with named Snowflake file formats or stage defaults; unsupported staged formats are review-required and unsafe stage paths/column expressions/file-format mappings are rejected. Focused source tests pass. Live CSV staged-file append passed with run 0159e736-5c5e-4dfd-91cb-3b5373c36369, wrote 2 rows to CF_SMOKE_STAGEFMT_ORDERS, and temporary stage/file format/target objects were cleaned up. |
| 21 | Complete | Runtime execution now writes immediate ContractForge/OpenLineage-style lineage rows and EXPLAIN USING TEXT evidence, exposes delayed ACCESS_HISTORY reconciliation through API/CLI with PENDING handling, and focused Snowflake tests pass. Live minimal smoke wrote 5 lineage rows and 5 explain rows; ACCESS_HISTORY was reachable but still had 0 rows for run 5a8c49dc-2ccd-439e-9ae0-58bc7fcb02d0, matching the delayed pending path. |
| 22 | Complete | Added docs/adapters/snowflake.md operations guide, stabilization matrix, and updated adapter index/docs links. |
| 23 | Complete | Added docs/specs/snowflake-stabilization-matrix.md with scope, release gates, and blocked-gate unblock plan. |
| 24 | Complete | Updated README maturity status from "Planning" to "Alpha with real Snowflake validation". Marked known review-required limitations for blocked procedure/task gates. Focused tests passed. |
| 25 | Complete | Real Snowflake hosted procedure library-runner USGS GeoJSON frozen medallion executed bronze-to-gold against the same 30-feature baseline used for AWS/Databricks parity. Snowflake counts were bronze=1, silver=30, gold daily=2, gold bands=3 with 4 successful run rows, 16 quality rows, no quarantine rows and no errors. AWS and Databricks target/run evidence matched the four result counts and SUCCESS/PASSED statuses. Full tests passed. |
Execution Rule
Work through this file in order unless a blocking dependency forces a local swap. Each commit should update the status table, include tests for its change, and record any live-smoke command that was run.