pipeline-design — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited pipeline-design (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Before writing a single line of ingestion code, answer these four questions. Every architectural decision flows from them.
updated_at timestamp? A CDC stream? Or must you full-scan every time?Re-extract everything every run. Simple, always correct, expensive at scale. Use when:
updated_at or sequence keyTrack the highest updated_at (or auto-increment ID) seen so far. On each run, pull rows where updated_at > last_watermark.
last_watermark = read_watermark(pipeline_name)
rows = source.query(f"SELECT * FROM orders WHERE updated_at > '{last_watermark}'")
write_to_warehouse(rows)
save_watermark(pipeline_name, max(row["updated_at"] for row in rows))Risk: Rows with backdated updated_at (late-arriving data) are silently missed. Add a safety buffer of a few hours if this is a concern.
Read the database's transaction log (Debezium, Fivetran, AWS DMS). Captures inserts, updates, and deletes without polling. Use when:
A pipeline run should produce the same result if run once or ten times on the same input window. This is what makes restarts and backfills safe.
Pattern: write to a staging table, then swap
-- Step 1: write to a dated staging partition
INSERT INTO staging.orders_2024_03_15 SELECT ...;
-- Step 2: delete the target window and reload
DELETE FROM warehouse.orders WHERE date = '2024-03-15';
INSERT INTO warehouse.orders SELECT * FROM staging.orders_2024_03_15;Or on BigQuery, use WRITE_TRUNCATE on a partition:
job_config = bigquery.LoadJobConfig(
write_disposition="WRITE_TRUNCATE",
range_partitioning=...,
)Why this matters: Without idempotency, a retry appends duplicates. A backfill creates chaos. Idempotency turns "was this run successful?" from a scary question into a boring one.
| Strategy | When to use | Warehouse support |
|---|---|---|
| Full replace | Small tables, no history needed | All |
| Partition overwrite | Large tables, date-partitioned | BigQuery, Snowflake, Spark |
| Upsert (MERGE) | Key-based deduplication with updates | Snowflake, BigQuery, dbt |
| Append-only | Immutable event streams | All |
| SCD Type 2 | History must be preserved for dimension changes | dbt snapshots, Snowflake streams |
Modern warehouses (BigQuery, Snowflake) are cheap and powerful for computation. Prefer ELT:
Reserve ETL (transform before load) for:
Organize your warehouse into logical layers so consumers know what to trust:
raw/ ← exact copy of source, never modified
└── orders_raw
staging/ ← cleaned types, renamed columns, deduplicated
└── stg_orders
intermediate/ ← joins and business-logic CTEs (optional)
marts/ ← final fact/dim tables consumed by BI tools and stakeholders
└── fct_orders
└── dim_customersdbt enforces this naturally with its sources / staging / models convention.
A pipeline without observability is a pipe bomb — it'll fail silently at the worst moment.
Minimum viable observability:
Retry logic:
Use a DAG/flow/asset when:
Task design principle: Each task should be independently re-runnable. Avoid global state between tasks — pass data via XComs, parameters, or intermediate storage, not in-memory objects.
dbt handles dependency resolution and incremental logic for SQL models. Let it manage updated_at-based incremental runs rather than coding them yourself.
# dbt model config for incremental
{{ config(
materialized='incremental',
unique_key='order_id',
on_schema_change='sync_all_columns'
) }}
SELECT ...
{% if is_incremental() %}
WHERE updated_at > (SELECT MAX(updated_at) FROM {{ this }})
{% endif %}Always design for backfill before you go live:
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.