Skip to content

#268 — vars change tiers: precedence-aware attribution + honest blast-radius copy - #287

Merged
cmbays merged 4 commits into
mainfrom
domain-268-vars-tiers
Jun 12, 2026
Merged

cmbays merged 4 commits into
mainfrom
domain-268-vars-tiers

Conversation

@cmbays

@cmbays cmbays commented Jun 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Closes #268 (epic #262, slice C3 — the big-batch differentiator: fusion's own state:modified cannot see var-value edits).

Per changed dbt_project.yml var, the project-change panel's vars row now carries precedence-resolved per-var entries with affected-model lists at honest evidence tiers, plus reference chips on in-scope models. A vars edit never widens the in-scope set (founder v3: contextualize-don't-widen).

Precedence (fusion's, mirrored exactly)

CLI --vars > package-scoped project vars > global project vars > inline var() default (ConfiguredVar::call_as_function, configured_var.rs:55-129 @ 9977b6cb…). The inline default is LOWEST — a call-site default never overrides a project value, so carrying one never subtracts a model. CLI --vars is unobservable → an explicit in-row caveat, never a guess. Root-project vars extend into every package's namespace (load_vars.rs:28-42); a package-scoped pin masks a global edit for exactly that package (stated per row). Package-scope keys in vars: expand per inner var; the total order is pinned by exhaustive property tests.

Tiers (per AC#1, the research evidence)

  • DIRECT — var('x') in a Jinja-evaluated region of the model's raw_code. Call grammar exhaustive per fusion var.rs:25-92,111-126: var('x') / var("x"), positional + default= kwarg defaults incl. None and map defaults (brace/string-aware region ends so a dict default never truncates), and var.has_var('x'). {# #} comments, {% raw %} blocks, plain SQL text, and lookalikes (myvar(, varchar(, graph.var() never count; a SQL -- comment inside {{ }} does (Jinja evaluates it — true positive).
  • CONFIG — recursive unrendered_config scan: braced strings (project-file / schema-YAML sources) and bare expression strings (fusion's inline-config() raw-text preservation, utils.rs:713-721).
  • MACRO — depends_on.macros transitive closure over manifest macro bodies; each hit names its mediating macro (stg_enc (via add_dq_flags)).
  • UNKNOWN residual (AC#2) — in-row copy, never a report-global hedge: causes enumerated (dynamic var() names, var-to-var value indirection, CLI --vars overrides, Python models), what WAS checked stated (Checked: 34 models' SQL and configs plus 89 macro bodies on the showcase), "at least N" framing, the disabled-membership caveat, and the never-widened statement. Dynamic var(expr) callers surface as a cannot-rule-out bucket; .py models skip the SQL scan and are counted honestly.

Override-pinned unit tests are subtracted: fusion re-binds var with overrides.vars at unit-test compile (unit_test.rs:603-609) — pinning tests are listed as insulated.

R1b cap (AC#3)

Past 10 names a tier list collapses to its explicit count — "at least 47 models read this var directly in SQL — listed, not individually rendered" — with the full list in a collapsed <details>. Same cap constant as the #267 config-tree rows.

Build gate (AC#4, the #145 lesson)

Non-empty macros[].depends_on verified on REAL fixtures from BOTH engines before relying on the MACRO tier:

  • dbt-core 1.11 committed fixtures: jaffle-shop 324/485 macros non-empty, playground 639/910;
  • dbt-fusion 2.0.0-preview.177 local dogfood compile: 334/510;
  • adapter-dispatch indirection confirmed resolved in both (macro.dbt.current_timestamp → macro.dbt_duckdb.duckdb__current_timestamp).

Dogfood (visible in the golden showcase)

examples/diff-showcase-report.html now renders, byte-gated:

  • dq_quarantine_threshold (10 → 5): DIRECT mart_dq_summary, MACRO stg_synthea__encounters + stg_synthea__medications (via add_dq_flags), and the insulated test_mart_dq_summary_zero_quarantined_when_all_valid (overrides now in the synthetic manifest, matching the committed source YAML);
  • default_state_grid_density (weekly → monthly, the new second vars hunk): CONFIG mart_date_state_grid;
  • both in-scope models carry their var-reference chips beside the domain: config-tree change attribution — fqn prefix matching, scope widening + provenance chips #267 config chips.

Intended side effect of the fixture edit: in baseline-mode examples/playground-report.html the dq unit test now reads changed: true (its overrides differ from the baseline manifest — a truthful struct diff).

Tests

  • 33 domain unit tests in src/domain/vars.rs incl. house-style exhaustive property tests: precedence total order over every presence combination, package-vs-global resolution, masking arms (pin-both-sides / pin-only-new), scanner call-form grammar, changed_vars union semantics + scope expansion edge cases.
  • Render-view tests (tier lines, R1b cap, honest note fragments, payload chip wire shape), CLI gather test, 4 BDD scenarios (tiered attribution + no-widening, reference chip, insulated pin, honest zero-scan copy), 2 new headless guards (vars row visible, var chips) + the updated showcase guard.
  • The 8-theme AA matrix guard extends to the three new tier-chip classes (56 measurements; recipes reuse the existing AA-gated token pairs).

Gates (all run directly, not via lefthook-in-fresh-worktree)

cargo fmt --check · clippy --all-targets --locked -D warnings (incl. the new-stable lints the pre-push hook surfaced) · nextest --all-targets --locked 1527 passed · BDD 23 features / 182 scenarios passed · headless pair (headless_toggle -- --ignored 83 passed, headless_zero_egress -- --ignored 11 passed) · cargo doc both modes -D warnings · cargo deny check · crap4rs scorecard PASS (0 above threshold, worst 24.1) · goldens + chrome snapshot regenerated over the merged tree (post-#286) with intended-only audit · fixture MANIFEST SHAs updated.

🤖 Generated with Claude Code


Open in Stage

cmbays and others added 4 commits June 12, 2026 04:20
…l entries, reference chips, no widening

Per changed dbt_project.yml var, the project-change panel row now
carries precedence-resolved entries (fusion's order mirrored exactly:
CLI --vars > package-scoped vars > global vars > inline var() default,
the default LOWEST) with affected-model lists at honest evidence tiers:

- DIRECT — var('x') in a Jinja-evaluated region of the model's
  raw_code (call grammar exhaustive per fusion var.rs:25-92,111-126,
  incl. var.has_var and map defaults; {# #} comments and {% raw %}
  blocks never count)
- CONFIG — recursive unrendered_config scan (braced and bare
  expression strings; covers project-file, schema-YAML, inline
  config() and hooks)
- MACRO — depends_on.macros transitive closure over manifest macro
  bodies, the mediating macro named per hit
- UNKNOWN residual — in-row copy enumerating the causes (dynamic
  names, var-to-var indirection, CLI --vars masking, Python models),
  stating what WAS checked, 'at least N' framing, the
  disabled-membership caveat, and the contextualize-don't-widen
  statement

A global edit is masked per package pinned by an unchanged
package-scoped value; unit tests pinning the var in overrides.vars are
reported insulated (the override always wins). R1b cap: past 10 names
a tier list collapses to its count with the full list in a <details>
('listed, not individually rendered'). In-scope models referencing an
edited var get var-reference chips beside the #267 config chips —
context only, the in-scope set NEVER widens on a vars edit (founder
v3: contextualize-don't-widen).

Build gate (the #145 lesson): non-empty macros[].depends_on verified
on REAL fixtures from BOTH engines — dbt-core 1.11 (jaffle 324/485,
playground 639/910 committed fixtures) and dbt-fusion
2.0.0-preview.177 (334/510, local dogfood compile); dispatch
indirection confirmed resolved in both.

Dogfood: the diff-showcase patch gains the second vars hunk
(default_state_grid_density weekly→monthly) and the synthetic
playground manifest gains a DIRECT reader (mart_dq_summary), a
CONFIG-driven node (mart_date_state_grid), a MACRO-mediated pair (via
add_dq_flags), and the override-pinned unit test matching the
committed source YAML — all four tiers plus the insulation note are
visible in examples/diff-showcase-report.html, and both in-scope
models carry their reference chips.

The 8-theme AA matrix guard extends to the three new tier-chip classes
(56 measurements); all goldens + the chrome snapshot regenerated over
the merged tree, intended-only audited.

Closes-by-PR: cute-dbt#268 (epic #262, slice C3).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…on, type alias, trailing comma)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@cmbays, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 25 minutes and 50 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5e5855c0-8922-4dbf-aac6-9e848c93f5a2

📥 Commits

Reviewing files that changed from the base of the PR and between 0121902 and 1763a86.

⛔ Files ignored due to path filters (1)
  • tests/snapshots/render_integration__rendered_chrome_jaffle_shop.snap is excluded by !**/*.snap
📒 Files selected for processing (20)
  • examples/diff-showcase-report.html
  • examples/explore/tests.html
  • examples/jaffle-shop-report.html
  • examples/playground-report.html
  • features/project_definition.feature
  • src/adapters/render.rs
  • src/cli/mod.rs
  • src/domain/mod.rs
  • src/domain/project_def.rs
  • src/domain/vars.rs
  • templates/interaction.js
  • templates/report.css
  • templates/report.html
  • tests/fixtures/MANIFEST.toml
  • tests/fixtures/playground-current.json
  • tests/fixtures/playground-pr-diff.patch
  • tests/headless_toggle.rs
  • tests/steps/builders.rs
  • tests/steps/project_definition.rs
  • tests/steps/world.rs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch domain-268-vars-tiers

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown
Contributor

📄 Rendered report preview

All golden examples regenerated cleanly.

🟡 Golden examples

Committed to examples/ and byte-identity gated — the canonical reports contributors and consumers browse. Stable across PRs.

Report View Download
diff-showcase-report.html ▶ Open ↗ ⬇ Download
jaffle-shop-report.html ▶ Open ↗ ⬇ Download
playground-report.html ▶ Open ↗ ⬇ Download

🐶 Live dogfood preview

This PR doesn't touch dbt-project/, so there's no live dogfood preview.

▶ Open ↗ opens the report in your browser in one click —
published to this repo's GitHub Pages under /pr-287/.
⬇ Download fetches the same self-contained HTML as a workflow
artifact (auth-gated; works fully offline). Either way the report
makes zero external resource requests.

The Pages preview may take ~1 min to update after this comment
posts. On PRs from forks the Open link is unavailable (read-only
token) — use Download.

Alternative: GitHub CLI
# gh CLI >= 2.63 extracts into ./report-preview-playground/.
gh run download 27404482074 -R breezy-bays-labs/cute-dbt -n report-preview-playground
open report-preview-playground/playground-report.html

Posted by report-preview.yml for 1763a86bc6d9be8a7071301772809f78edffd070. Affordance only — never blocks merge.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements static vars change attribution at honest tiers (DIRECT, CONFIG, MACRO, and UNKNOWN residual) in cute-dbt. It introduces a static scan over the manifest to resolve precedence-aware var edits and displays them in the project definition panel with tiered affected-model lists, package masking, and unit test insulation. It also adds var-reference chips to in-scope models in the report. The reviewer identified a compilation issue in src/domain/vars.rs where OsStr is used with eq_ignore_ascii_case, which is not implemented for OsStr, and provided a suggestion to convert it to a &str slice first.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/domain/vars.rs
@cmbays
cmbays merged commit ed0579f into main Jun 12, 2026
33 checks passed
@cmbays
cmbays deleted the domain-268-vars-tiers branch June 12, 2026 08:40
github-actions Bot added a commit that referenced this pull request Jun 12, 2026
@cmbays

cmbays commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

Overnight orchestration wrap-up

Merged as ed0579f (squash) under Christopher's overnight authority — CI fully green, 1 HIGH Gemini thread rejected with proof (the claimed OsStr::eq_ignore_ascii_case compile error is false — stabilized Rust 1.53, the green CI matrix on this exact head is the compile proof, and the pattern is clippy's own suggested fix for the lint it clears). Issue #268 auto-closed ✔.

What shipped (#262 C3, the big-batch slice): the vars tier scanners (DIRECT via fusion's exhaustive var() call grammar with Jinja-region guarding; CONFIG via recursive unrendered_config walk; MACRO via depends_on transitive closure with the mediating macro named), fusion's var precedence pinned by total-order property tests (CLI > package > global > inline default LOWEST), the locked honest blast-radius copy rendered verbatim in the golden (in-row, enumerated causes, "at least N", what WAS checked), the R1b cap shared with #267, override-insulated unit tests subtracted, and zero scope widening — vars contextualize, never widen, per the founder-locked decision.

This completes the #262 lane's buildable arc for the night: C1 (#266) + C2 (#267) + C3 (#268) + C4 (#269) all merged. Remaining: C5 (#270, explorer pane — now unblocked) and the macro epic (#265, needs shaping).

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

domain: vars attribution tiers — precedence-resolved panel lists + reference chips, no widening

1 participant