All notable changes to this project will be documented in this file. The format is based on Keep a Changelog and this project adheres to Semantic Versioning.
replaycost overlay: pass--warehouse-size(Snowflake XS…6XL) or--credits-per-hour(non-Snowflake adapters) to translate wall-clock into dollars. Renders Run cost, Critical-path floor, Headroom (= run − floor; the prize for better parallelization), and Idle cost (the $ equivalent of thread-idle warehouse-seconds). Defaults to $2.00/credit (Snowflake Standard On-Demand); override with--rate-per-credit. Snowflake's 60-second minimum-billing floor is applied automatically; pass--no-minimum-billingto see raw wall-clock × rate.- New module
dbt_dag_opt.costwithCostInputs,CostReport,compute_cost(),credits_per_hour_for(), andcost_inputs_from_replay(). Designed primitive-first so a futurewhatifsimulator can callcompute_costagainst simulated schedules and diff the resultingCostReports. scripts/demo.sh+tests/fixtures/demo_project/— narrated end-to-end demo script driving every subcommand against a synthetic 24-model DAG with a shared bottleneck, 4 threads, and ~7.5-min wall-clock. Fixture is regenerable viatests/fixtures/generate_demo_fixture.py.
Initial PyPI release. Complete rewrite of the pre-release prototype.
dbt-dag-opt analyzeCLI (Typer) with two input modes:- File mode:
--manifestand--run-resultspoint at local dbt artifacts. - Cloud mode:
--account-id,--job-id, optional--run-id, andDBT_CLOUD_TOKENenv var (or--token) pull artifacts from the dbt Cloud Admin API.
- File mode:
analyze --show-pathto render the full chain of node ids for each longest path in the table output.analyzetable includes a Bottleneck column naming the slowest model on each path. A bottleneck that appears across multiple rows is a shared-node optimization target.dbt-dag-opt replaysubcommand: reconstructs the observed schedule fromrun_results.json'sthread_id+ per-phasetimingdata, joined againstmanifest.json'sparent_map. Reports per-thread utilization, observed critical path (walked backwards from the last-completing node), and top idle gaps with parent-node attribution.- Output formats:
analyze→table(rich terminal, default),json(valid,jq-friendly),jsonl.replay→text(rich terminal summary, default),json(full replay report including raw events). --top Nto limitanalyzeresults;--top-idle-gaps Nforreplay;--outputto write any command to a file.- Typed exceptions (
ArtifactLoadError,DbtCloudAPIError,InvalidArtifactError,GraphError). - Package ships with
py.typed(PEP 561). - Integration fixture at
tests/fixtures/dbt_dugout/— a real Snowflake dbt run (57 nodes, 4 threads) used to smoke-testreplayend-to-end. - CI matrix across Python 3.10 / 3.11 / 3.12.
- PyPI publishing via Trusted Publishers (OIDC) on tag push.
- Replaced per-source recursive DFS + ProcessPoolExecutor with a single iterative DP over topological order. O(V + E) across all sources, no recursion-limit risk, no 20s per-task timeout.
- Node weights are now attached to the target node of each path hop (fixes a bug where parent weights were assigned to outgoing edges).
- Adjacency list replaces full-edge-list rescan on every DFS step.
- Output is valid JSON by default (prototype's
longest_paths.jsonwas a stream of comma-separated fragments opened in append mode — not parseable).