Skip to content

#159 — strategy-correct incremental expect-semantics tooltip - #161

Merged
cmbays merged 1 commit into
mainfrom
fix-159-incremental-expect-tooltip
Jun 10, 2026
Merged

cmbays merged 1 commit into
mainfrom
fix-159-incremental-expect-tooltip

Conversation

@cmbays

@cmbays cmbays commented Jun 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

The incremental expect-semantics tooltip (templates/report.html, the #146 focusable-button + CSS-bubble) was merge/append-centric. It is mechanically wrong for insert_overwrite (replaces whole partitions — nothing merges) and microbatch (per-window batches), and loose for delete+insert. A dbt unit test compares the compiled SELECT for the chosen is_incremental branch and never exercises the materialization strategy (dbt-core#8664), so this is a copy-precision correctness fix — not a per-strategy code path (Bucket 1a, Bar A).

Before / after copy

Before:

For an incremental-mode unit test, Expected is the result of the materialization — the rows that will be merged or inserted — not the resulting model itself (the final table after the merge).

After (strategy-invariant — true for all 5 strategies):

Expected is the output of the model's compiled SELECT on the incremental branch — the rows the configured incremental strategy will apply to the table — not the table's final state after the run.

The single tip var drives both the visible CSS bubble and the aria-label (the #146 pattern), so one edit keeps them in sync.

Changes

  • Template: generalize the tip string (one edit → bubble + aria-label).
  • Headless (tests/headless_toggle.rs): extend incremental_badges_modes_tooltip_and_this_given to assert the new strategy-invariant phrase renders in both the bubble and the aria-label, and that the old merged or inserted wording is absent. RED before the template edit, GREEN after.
  • BDD (features/incremental_models.feature + steps): update prose + matching step regexes to strategy-generic phrasing (step bodies still assert the is_incremental_mode payload bool — behaviour unchanged).
  • Byte-identity regen: the 3 golden examples (jaffle-shop/playground/diff-showcase) + the chrome HTML insta snapshot. Intended-only — verified each is exactly the 3-line tip flip, no unrelated churn.
  • Dogfood (same PR): add explicit incremental_strategy='merge' to the live dbt-project/models/marts/order_events_incremental.sql (config-only; dbt parse validated) so the --pr-diff self-dogfood exercises the tooltip on a fresh CI-compiled manifest.

Verification

All gates green locally (lefthook skipped on the worktree push-range quirk, so each gate run directly):

  • cargo fmt --all --check — EXIT 0
  • cargo clippy --all-targets --locked -- -D warnings — EXIT 0
  • cargo nextest run — 731 passed, 27 skipped
  • cargo test --test bdd — 85 scenarios / 543 steps passed
  • RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --document-private-items --locked — EXIT 0
  • new headless test -- --ignored (RED→GREEN) + headless_zero_egress (no regression) — pass
  • cargo deny check — advisories/bans/licenses/sources ok
  • non-mirror-guard, baseline-required-grep, feature-count (12), mdbook build book, fixture-manifest gates — all pass
  • intended-only example diff confirmed via git diff --text -U0 (each example: -3 +3, the tip flip only)

Closes #159

🤖 Generated with Claude Code


Open in Stage

The expect-semantics tooltip (templates/report.html) said Expected is
"the rows that will be merged or inserted ... (the final table after the
merge)". That wording is merge/append-centric: it is mechanically wrong
for `insert_overwrite` (replaces whole partitions — nothing merges) and
`microbatch` (per-window batches), and loose for `delete+insert`.

Generalize to the strategy-invariant truth (true for all five
strategies — append/merge/delete+insert/insert_overwrite/microbatch):

  "Expected is the output of the model's compiled SELECT on the
   incremental branch — the rows the configured incremental strategy
   will apply to the table — not the table's final state after the run."

A dbt unit test compares the compiled SELECT for the chosen
is_incremental branch and never exercises the materialization strategy
(dbt-core#8664), so this is a copy-precision correctness fix, not a
per-strategy code path. The single `tip` string drives both the visible
CSS bubble and the aria-label (the #146 focusable-button pattern), so
one edit keeps them in sync.

- headless: extend incremental_badges_modes_tooltip_and_this_given to
  assert the new strategy-invariant phrase renders in BOTH the bubble
  and the aria-label, and that the old "merged or inserted" wording is
  absent (RED before the template edit, GREEN after).
- BDD: update incremental_models.feature prose + matching step regexes
  to strategy-generic phrasing (the step bodies assert the
  is_incremental_mode payload bool — behaviour unchanged).
- byte-identity regen: the 3 golden examples
  (jaffle-shop/playground/diff-showcase) + the chrome HTML insta
  snapshot — intended-only (the 3-line tip flip, nothing else).
- dogfood: add explicit incremental_strategy='merge' to the live
  dbt-project order_events_incremental model (config-only; `dbt parse`
  validated) so the --pr-diff self-dogfood exercises the tooltip on a
  fresh CI-compiled manifest.

Closes #159

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 9, 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 38 minutes and 55 seconds. Learn how PR review limits work.

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

⌛ 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: cee081b7-7c1e-4654-bf0f-6cc628a76797

📥 Commits

Reviewing files that changed from the base of the PR and between 94a06b6 and 44a5f2d.

⛔ Files ignored due to path filters (1)
  • tests/snapshots/render_integration__rendered_chrome_jaffle_shop.snap is excluded by !**/*.snap
📒 Files selected for processing (8)
  • dbt-project/models/marts/order_events_incremental.sql
  • examples/diff-showcase-report.html
  • examples/jaffle-shop-report.html
  • examples/playground-report.html
  • features/incremental_models.feature
  • templates/report.html
  • tests/headless_toggle.rs
  • tests/steps/incremental_models.rs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-159-incremental-expect-tooltip

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.

@ghost

ghost commented Jun 9, 2026

Copy link
Copy Markdown

Ready to review this PR? Stage has broken it down into 5 individual chapters for you:

Title
1 Generalize incremental tooltip copy in report template
2 Update BDD feature and step definitions
3 Verify tooltip copy in headless tests
4 Regenerate example reports and update dogfood model
5 Other changes
Open in Stage

Chapters generated by Stage for commit 44a5f2d on Jun 9, 2026 5:29am UTC.

@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 updates the incremental model unit-test tooltip copy to be strategy-invariant, making it accurate for all five incremental strategies instead of being specific to merge or append. The changes are applied across the HTML report template, Cucumber feature files, step definitions, integration test snapshots, and headless tests. There are no review comments, and I have no feedback to provide.

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.

@github-actions

github-actions Bot commented Jun 9, 2026

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
jaffle-shop-report.html ▶ Open ↗ ⬇ Download
diff-showcase-report.html ▶ Open ↗ ⬇ Download
playground-report.html ▶ Open ↗ ⬇ Download

🐶 Live dogfood preview

This PR's own dbt-project/ diff, freshly compiled by fusion into an ephemeral manifest (never committed) and rendered with --pr-diff. Regenerated every PR — the live self-dogfood, not a committed example.

Report View Download
dbt-project-report.html ▶ Open ↗ ⬇ Download

▶ Open ↗ opens the report in your browser in one click —
published to this repo's GitHub Pages under /pr-161/.
⬇ 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 27185910075 -R breezy-bays-labs/cute-dbt -n report-preview-playground
open report-preview-playground/playground-report.html

Posted by report-preview.yml for 44a5f2d3c15a77a0536f148e0a466c9c8ee511bb. Affordance only — never blocks merge.

@cmbays
cmbays merged commit 29c5b98 into main Jun 10, 2026
31 checks passed
@cmbays
cmbays deleted the fix-159-incremental-expect-tooltip branch June 10, 2026 00:01
github-actions Bot added a commit that referenced this pull request Jun 10, 2026
cmbays added a commit that referenced this pull request Jun 10, 2026
…olumn tooltips (#188)

* feat(adapters): design integration PR-2 - engine merge (settings panel, unified/split diffs) + port-forward

Replace the template's ~2100-line inline engine with two first-party
include_str! assets: templates/interaction.js (the merged redesign
interaction engine) and templates/theme.js (the appearance engine), wired
through asset_embed::{INTERACTION_JS,THEME_JS} with banner-pin +
end-of-file-sentinel tests (the REPORT_CSS pattern).

Engine merge (handoff -> shipped, our behaviors win every conflict):
- Settings panel: static Appearance markup (style/theme/accent/density/
  diff-style/diff-layout) in the template, wired by theme.js; persists
  under cute-dbt.appearance.v1; DataTables dark syncs via html.dark. The
  cog + panel are now universal (themes apply to baseline reports too);
  the #139 context-lines/normalize rows stay PR-diff-only.
- Diff renderers: GitHub-grade two-column line-number gutters, shared
  diffBody/diffNumbers helpers, hunk folds keep the #132/#136 contract,
  and a NEW split (side-by-side) renderer - diffViewsHtml emits BOTH
  layouts over the same BlockDiff lines verbatim (kind/text/emphasis; no
  Rust diff-engine change); CSS shows one per html[data-difflayout] with
  a responsive fallback.
- Code cards: file-path headers (defined_in on the YAML drawer,
  <model>.sql on the Model-SQL card), single-gutter line numbers on
  plain blocks (highlightLines*), incremental badge relocated into the
  Model-SQL card header (static span removed per handoff README section 3).
- DAG: theme-aware edge palette (JOIN_COLORS_LIGHT/_DARK + dagEdges),
  __cuteRerenderDag re-tint hook; Cytoscape surface deliberately
  excluded (Bucket 2).

Port-forward audit (the fork predates these; shipped behavior kept):
- #156 stable DAG node identity: already present in the handoff fork's
  JS; the Rust side never forked. Verified, no regression.
- #158 minmax(0,1fr) stacked-panel fix: PR-1 chassis kept it; the 375px
  headless regression stays green.
- #161 strategy-correct expect-semantics tooltip: kept OUR wording (the
  handoff carried the pre-#159 merge/insert copy - rejected).
- #166 column tooltips: kept OUR payload shape + focusable-button/CSS-
  bubble renderer (the handoff's body-appended th.has-col-meta renderer
  targets the not-yet-existing ModelPayload.column_meta - rejected;
  belongs to handoff PR-3).

Also: report.css drops its PR-1 bridge layer per its own contract and
gains the .settings-row-stack chrome; the edge-vocab-completeness gate +
BDD legend steps re-point at templates/interaction.js and now check both
palettes; headless guards added for the appearance toggles, the split
renderer, the gutters and the relocated badge; goldens + insta
snapshots regenerated (byte-identity re-verified CI-style).

Closes #178

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

* feat(adapters): column-header tooltips to the handoff spec (th-trigger, accent keys, value chips) + gemini fixes

Christopher's review override on PR #188: the #166-tooltip deferral is
reversed — the column-header tooltips must match the handoff spec in
this PR, adapted to OUR shipped per-table column_meta payload (NOT
ModelPayload.column_meta, which stays PR-3).

Spec match (handoff engine/interaction.js + base.css, README section 2.2):
- The WHOLE header cell is the hover/focus trigger — the info icon
  (buildColTooltip's focusable button + per-th bubble) is gone.
  decorateColHeader marks a metadata-bearing th with .has-col-meta +
  data-col-name/desc/tests; showColTip fills + positions the single
  body-appended #col-tooltip bubble with the handoff's positioning math
  verbatim (position:fixed, horizontal clamp, flip-above on bottom
  overflow — never clipped by the .table-fit scroller).
- Bubble content per spec: .ct-desc (description, larger) ->
  "Data tests" label -> per-test .ct-test rows with .ct-key (accent
  color), .ct-vals > .ct-val chips for accepted_values args, .ct-detail
  muted mono for relationships/range detail. CSS ported from the
  handoff base.css (comment bodies kept free of close-sequences per the
  README porting-bug warning).
- Render-layer POD (adapter, not domain): ColumnMetaPayload.tests is
  now Vec<ColumnTestPayload {name, values, detail}> built by
  column_test_payload, the section-2.2 display mapping: unique /
  not_null -> bare prose names; accepted_values -> "accepted values" +
  values chips; relationships -> detail "model.field" (ref()/source()
  unwrapped to the last quoted arg); accepted_range (any namespace) ->
  detail "min-max" / ">= min" / "<= max"; any other test keeps its
  package-qualified raw identifier with no values/detail.
- A11y (the #166 contract carried onto the th): tabindex="0" so
  keyboard users reach the tip via focusin; aria-label on the trigger
  summarizes description + tests; the singleton bubble is aria-hidden;
  hover AND focus both reveal; decorated headers SHED the native title
  (undecorated headers keep theirs); :focus-visible outline added.

Guards updated:
- headless: column_header_tooltips_th_trigger_hover_focus_and_skip_
  bare_columns — th-trigger semantics (no icon/button in any th),
  tabindex/aria/title assertions, focus AND hover reveal + hide,
  .ct-key/.ct-val/.ct-detail content over an accepted_values +
  relationships fixture, given-table input-model resolution.
- BDD: the report_generation scenario matches the structured entries'
  display `name` ("not_null" -> "not null"); payload contract otherwise
  unchanged.
- render.rs unit tests pin the full section-2.2 mapping table.

Gemini review threads (PR #188, both applied): theme.js gains an
ES5-safe qsaForEach helper replacing NodeList.prototype.forEach at
every control-wiring site, and reflowTables binds jQuery locally.

Goldens + the chrome insta snapshot regenerated; byte-identity
re-verified CI-style; visual check against the handoff reference.html
confirms the tooltip treatment matches.

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

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
cmbays added a commit that referenced this pull request Jun 11, 2026
… reconstruction, overrides badge, info tips (#220)

Three body-appended singleton tips (#model-tooltip / #fmt-tooltip /
#ov-tooltip) on mouseenter AND focusin behind focusable triggers: the
Given header renders ref( + .gt-model pill + ), the Expected panel gains
its model pill (header fallback or fixture-view bar, bar order
[model pill][mode badge][row count] with the Diff/File toggle far
right), the format badge shows for ALL formats incl. dict and
reconstructs the fixture client-side (sql/csv/yaml), and the test badge
row gains the 'overrides . N' badge with grouped key = value rows.

Founder decision (epic #197) applied: the incremental-branch mode badge
and the prior-model-state this-badge keep the #146 focusable-trigger
CSS-bubble mechanism with the pass-2 badge-borne styling - the separate
expected-panel i button is retired, the pass-2's JS info-tip twin for
those badges is not ported (exactly one mechanism), and the LOCKED D4
invariant holds (tooltip rides is_incremental_mode === true, never the
this-given proxy, never full-refresh).

Column-header tooltips: detail strings now render as ct-vals/ct-val
chips (ct-detail retired); per-table column_meta sourcing unchanged.
The #161 idempotent clear-list extends to .expected-model-badge.

Every interpolated tip value passes through escapeHtml (payload strings
are attacker-adjacent YAML). Goldens regenerated (template-only deltas,
payload byte-stable, double-render byte-identical); explore pages
untouched.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
cmbays added a commit that referenced this pull request Jun 11, 2026
…ted badges left, 13.44px tip text (#234)

* fix(adapters): pass-2 conformance — edge-aware tooltip bubbles, expected badges left, 13.44px tip text (#232)

Executes the three fix recipes from the 2026-06-11 design-conformance
audit (epic #197 pass-2 spec):

- R2 (audit D2): renderExpectedPanel always emits the .fixture-view-bar
  meta row for table renders — [model pill][mode badge][N rows] reading
  left under the Expected title, mirroring Given; the right-aligned,
  order-reversed .panel-header fallback is retired (sql-format /
  external-fixture early-return paths keep the header placement,
  spec-consistent). The #178 persistent-rowcount rescue is untouched.
- R1 (audit D1): edge-aware CSS bubbles — belt-and-braces right-anchor
  for header-placed badges (the spec's base.css precedent), a geometry-
  only data-tip-edge tagger on the delegated mouseenter/focusin path
  (visibility stays pure CSS — the #146/#161 contract intact), and the
  shared bubble max-width capped at min(70vw, calc(100vw - 16px)).
  Opportunistic D18: positionTipNear resets left before measuring
  offsetWidth (stale-width clamp overshoot).
- R3 (audit D3): bubble text 0.78rem (7.8px at Sakura's 62.5% root) →
  13.44px, matching the column-tooltip description (12px shell base ×
  1.12em).

Headless: three new RED-first pins (375px-class viewport containment,
computed-size equality vs #col-tooltip .ct-desc, no-diff meta-row
structure) + existing placement pins updated to the spec-true bar
location; the #146 focus-reveals-bubble guard stays green. Goldens
regenerated with the CI commands; every byte delta traces to the
R1/R2/R3/D18 blocks.

Closes #232

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

* test: 1px tolerance on #232 viewport-edge assertions (review suggestion)

getBoundingClientRect returns fractional px in headless Chrome; the
exact bounds (right <= vw, left >= 0.0) were a flake vector. 1px
tolerance mirrors the #157 sub-pixel precedent — the guarded
regression is 23-47px of clipping, so the teeth are intact.

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

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
cmbays added a commit that referenced this pull request Jun 11, 2026
…l-tip ct anatomy (#236)

Concern 1 — given column-header tooltips: the JS binder never regressed;
the given-side column_meta payload (#165/#166) only ever resolved
ref()-to-MODEL and 'this' inputs. A seed-ref given (the committed
jaffle-shop ref('raw_customers') wire shape) and a source('a','b') given
carried NO column metadata, so their headers offered no tooltip while
the expected table's did — the symptom found reviewing PR #230. Fix:

- domain: SourceNode ingests authored per-column descriptions
  (with_column_descriptions builder, the Node precedent; fusion
  ManifestSource.columns via serialize_dbt_columns, dbt-schemas
  manifest_nodes.rs @ 9977b6cb, verified on the committed playground
  fixture's synthea_raw.patients.Id)
- adapter: WireSource parses the columns map (empty-string unset
  descriptions dropped, the #165 rule)
- render: resolve_given_ref_node resolves givens over dbt's refable set
  (model | seed | snapshot); column_meta_for_source merges source column
  descriptions + column-scoped tests attached to the source node; shared
  attached_column_tests keeps both arms deterministic
- honest degrade preserved: a metadata-less given column renders NO
  trigger — never an empty bubble

Concern 2 — model-badge tooltip anatomy: the model-ref tip's test rows
now ride the COLUMN tooltip's own .ct-test/.ct-key/.ct-vals anatomy via
the shared ctTestHtml builder (never a parallel chip system); test names
keep the readable-on-dark color-mix accent treatment; the
.mt-mtests/.dt-* dress is retired inside the tip (the shelf card keeps
its light-surface .dt-* chips). The .col-tooltip .ct-key color stays
#233's lane — untouched.

Guards: 3 new headless tests (seed+source given tooltips on hover AND
focus per the #146/#161 contract, honest-degrade no-empty-bubble, model
tip chip anatomy + computed accent color), 3 new render payload tests,
domain/adapter ingestion tests; the #202 model-tip pin updated to the
new anatomy. Goldens regenerated (the playground source given now ships
a real Id tooltip); insta chrome snapshot rebaselined.

Closes #235

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.

bug: incremental expect-semantics tooltip is merge/append-centric — wrong for insert_overwrite/microbatch

1 participant