Repository navigation
#165 — column-header tooltips: authored descriptions + column-level data tests - #166
Conversation
…165) Adds the TestMetadata POD (generic-test name / namespace / untyped kwargs — fusion dbt-schemas nodes.rs shape) and four tolerant Node fields: column_descriptions (non-empty authored prose only, a separate map from the .contract column-set so a description edit can never flag state:modified.contract), plus column_name / attached_node / test_metadata (the column-scoped test attribution). with_* builders keep the many existing Node::new call sites unchanged (the with_incremental_mode precedent). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ce (#165) Manifest adapter: WireColumn gains description (fusion serializes an unset one as "" — dropped at translation); WireNode gains column_name / attached_node / test_metadata (domain TestMetadata deserializes the wire verbatim, the Checksum/DependsOn reuse precedent). Render: ColumnMetaPayload {description, tests} computed in Rust — column_meta_for_model resolves authored descriptions + COLUMN-SCOPED generic tests (column_name set AND attached_node = the owning model; model-level tests with column args are out of v1 scope), summarized as package-qualified names plus key args for accepted_values (values) and relationships (to/field). Each given resolves the model that OWNS its columns (ref(...) input model; this = the target model), the expect table resolves the target model; maps are filtered to the rendered FixtureTable's columns and omitted when empty (no empty bubbles). Template: a focusable th <button> + CSS bubble on :hover AND :focus with aria-label (the #146 expect-tooltip contract, never a native title). One divergence: the bubble is position:fixed with JS-set coordinates because the th lives inside the .table-fit overflow-x scroller that would clip an absolute bubble; visibility stays pure CSS. Click is swallowed so tapping the info button never re-sorts the DataTable. The Diff grid's unified column axis shares the same map. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…pin (#165) Headless (Chrome): focus reveals the bubble (the keyboard path a native title never had); exactly one tooltip button per table — the described+tested column gets it, a bare column gets NONE (the no-empty-bubbles negative path); a given table resolves its own input model's metadata. BDD (extends report_generation.feature — no new .feature file, the feature-count gate stays 12): the embedded payload lists unique/not_null for the fixture's tested key column with the empty authored description dropped, and carries no entry for an undescribed, untested column. Real-fixture pin: the fusion-compiled jaffle-shop manifest's column descriptions, empty-description drop, unique/not_null attribution, and accepted_values kwargs all survive ingestion. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…#165) Live dogfood (dbt-project, YAML only): unique/not_null on order_events_incremental.order_id (the merge key) and authored descriptions on the staging columns the marts unit tests mock — the PR-diff preview report now surfaces the tooltips on given/this/expect tables. Synthetic showcase (playground): the fct_encounters_incremental model gains columns with descriptions + unique/not_null on encounter_id in the source YAML and the manifest (hand-edited, byte-stable JSON round-trip — synthetic-only, no regen, no root_path). The two new test nodes are mirrored into the BASELINE so the arm-2 "modified node with zero unit tests" scoping path cannot surface them as junk model cards (they pre-exist the synthetic PR). MANIFEST.toml shas updated. Goldens regenerated with the exact CI invocations; all three are byte-identical to the renderer output and now show the affordance: descriptions, unique/not_null, accepted_values (values: ...), relationships (to/field), dbt_expectations.* namespacing, and the this-given resolution. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Warning Review limit reached
More reviews will be available in 29 minutes and 14 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 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 configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (18)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
📄 Rendered report previewAll golden examples regenerated cleanly. 🟡 Golden examplesCommitted to
🐶 Live dogfood previewThis PR's own
▶ Open ↗ opens the report in your browser in one click — The Pages preview may take ~1 min to update after this comment Alternative: GitHub CLI# gh CLI >= 2.63 extracts into ./report-preview-playground/.
gh run download 27248614343 -R breezy-bays-labs/cute-dbt -n report-preview-playground
open report-preview-playground/playground-report.htmlPosted by |
There was a problem hiding this comment.
Code Review
This pull request implements column-header tooltips (cute-dbt#165) to display authored column descriptions and column-level data tests in the generated reports. It updates manifest ingestion to parse test attributions and column descriptions, builds the metadata payload in the rendering adapter, and adds interactive tooltips in the HTML template. Feedback on these changes highlights a potential performance bottleneck in column_meta_for_model due to redundant full-manifest scans, suggesting caching or pre-grouping. Additionally, a UI issue was identified where the position: fixed tooltips can become detached from column headers during scrolling, and it is recommended to reposition or hide them on scroll events.
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.
… (#175) The baseline arm's models_in_scope arm 2 (the self-modified, zero-unit-tests explorer signal) iterated the full modified set without a resource_type filter. The modified set spans every nodes resource type — fusion's state:modified matcher (crates/dbt-scheduler/src/ node_selector.rs match_state at dbt-labs/dbt-fusion@9977b6cbb1b7610655 36300037560d8e3c037011) is resource-agnostic, with resource-type narrowing a separate orthogonal selector method — so a newly added generic test node (or any modified non-model node) leaked into the scoped model set and rendered as a junk model card in baseline mode (observed live on PR #166). Arm 2 now admits only resource_type == "model", the same projection arm 1 already applies via resolve_target_model and the PrDiff arm applies in select_in_scope_pr_diff. Regression coverage: a table test across resource types (test/seed/snapshot/analysis/operation excluded; model control included), the checksum-modified test-node case, the mixed modified set, an end-to-end baseline-arm select_in_scope test, and a pin test on the PrDiff arm's existing filter so the two arms cannot drift. PR #166's baseline mirroring of its synthetic test nodes is no longer load-bearing for card scoping (left in place; documented in the PR). All three golden examples verified byte-identical. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Land Claude Design Phase-1's chassis CSS — the semantic token layer, the
five AA-pinned [data-theme] blocks (Light/Dark/Tokyo/Solarized/Gruvbox),
the four html[data-style] direction packs, the density layer and the
tokenized component rules — replacing the template's custom <style> block
body. <html> gains data-style="soft" data-difflayout="auto". Pure
visual; zero payload/JS change.
Placement: templates/report.css (first-party, beside the template it
styles) embedded via include_str! as asset_embed::REPORT_CSS and
interpolated {{ report_css|safe }}. Deliberately OUTSIDE assets/ — the
provenance gate walks every file under assets/ and would demand an
upstream pin this authored file doesn't have. Banner-pin test (head
banner + end-of-file sentinel) fails CI on a truncated copy; a
comment-balance test pins the handoff's documented porting bug (a star
followed by slash inside a comment body once ate the [hidden] rule).
The merged file carries the handoff's per-theme AA contrast table as the
"AA pins — do not re-brighten" comment block; no token color altered.
Two reconciliations with shipped behavior the handoff forked before:
the cute-dbt#157 minmax(0,1fr) stacked-track fix (a 375px headless
regression test pins it) and the cute-dbt#165/#166 column-tooltip
trigger contract (the handoff's body-appended .col-tooltip bubble waits
for the engine DOM in PR-2/PR-3). A clearly-marked PR-1 bridge layer
keeps the pre-engine diff-line DOM block-laid (whitespace: pre) and the
copy-button clearance until cute-dbt#178 lands the engine.
Regenerated the 3 golden examples + 2 insta snapshots; the deltas are
the html attr line + the style-block body only (zero payload changes).
All 29 headless toggle tests + zero-egress + 787 nextest + 86 BDD
scenarios green.
Closes #177
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…r, 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>
…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>
…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>
…ps, covered-by contrast, overrides-badge clip, baseline banner (#244) * fix(adapters): #240 — review-2 render defects: tooltip overflow, given-header tooltips, covered-by contrast, overrides-badge clip, baseline banner Five founder-reported defects from the PR #239 review (issue #240): A — long mono tokens (dbt_expectations.expect_table_row_count_to_be_between) painted 55px past the model tip's painted background: overflow-wrap on the .col-tooltip shell + wrapping .ct-val chips. B — given column headers with no manifest metadata were silently hover-dead (third report): EVERY fixture header is a trigger now; metadata-less ones reveal a truthful fallback naming the owning node (never an empty bubble — the honesty invariant strengthens). C — .finding-covered-by code rode Sakura's light #f1f1f1 code bg at ~1.2:1 on dark themes: themed var(--bg-alt)/var(--text) re-skin (5.9–14.8:1 measured across all 8 themes). D — .ov-tooltip nowrap rows painted long override values past the bubble and the viewport edge: rows flex-wrap + overflow-wrap, singleton width capped at calc(100vw - 16px), positionTipNear clamps against documentElement.clientWidth (scrollbar-safe). E — code.diff-scope-baseline same root cause as C, same fix. Goldens regenerated (jaffle-shop, playground, diff-showcase) — every hunk is the embedded template change; snapshot updated likewise. Closes #240 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test: #240 — universal hover-parity guard + containment + AA pins (the guard-methodology fix) Why #166/#236 validations passed while the founder's experience stayed broken: they asserted tooltip reveal on columns KNOWN to carry manifest metadata (existential), while the founder hovered undeclared columns — hover-dead by the old design, outside every assertion universe. The new guards quantify universally and pin geometry: - fixture_header_tooltips_universal_after_view_toggle_and_sort: EVERY visible given/expected header must reveal a non-empty bubble on a real mouseover — initial render, after a real Diff→File toggle, after a real column sort, and after the round-trip (the #145/#146 wipe class). - model_tip_long_test_name_wraps_inside_bubble: content containment (scrollWidth ≤ clientWidth + 1; no descendant past the bubble edge). - ov_tip_long_value_contained_in_bubble_and_viewport_at_right_edge: long-override containment + viewport containment at a true right-edge trigger geometry. - covered_by_test_ids_meet_aa_contrast_on_every_theme + baseline_banner_path_meets_aa_contrast_on_every_theme: the #206/#227/ #231/#233 effective-backdrop AA family extended to defects C/E, all 8 themes (RED at 1.2:1 pre-fix). Three #235-era pins are deliberately rewritten to the new contract (metadata-less headers are fallback triggers, never dead): the no-EMPTY- bubble honesty invariant is preserved and strengthened. All five new guards captured RED against the unfixed templates (stash- verified) and GREEN after the fix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: dbt-project README touch — render the live dbt-project preview row for #240 validation Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(adapters): #240 — givenOwnerLabel accepts double-quoted ref()/source() inputs (PR #244 review) dbt accepts both quote styles in a given's input:, and dbt-fusion ships the authored string VERBATIM — a ref("stg_payments") given compiles onto the manifest wire double-quoted, unnormalized (verified against a real fusion 2.0.0-preview.177 compile of the dogfood project). The owner-label regexes behind the metadata-less fallback bubble were single-quote-only, degrading double-quoted inputs to the raw-string fallback. Quote-class + backreference now accepts both styles (mixed quotes stay unparsed -> truthful raw-input fallback). New headless guard given_owner_label_accepts_double_quoted_ref_and_source (RED without the regex fix, stash-verified). Goldens + chrome snapshot regenerated; every hunk is the embedded regex/comment change. The repo's Rust-side parsers (parse_ref_name / parse_source_ref) share the single-quote-only gap pre-dating this PR; tracked separately. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(adapters): #240 — latte 'Covered by' label AA (4.37 -> 5.53) + sweep transition hazard (PR #244 verification residual) The covered-by CODE pills pass AA on all 8 themes, but the 'Covered by ' prefix label (.finding-covered-by .f-label, 11.88px weight-400 so the 4.5 floor applies) rode the verbatim latte --text-muted: #6c6f85 on the finding row's #eff1f5 fill = 4.37:1. The established #227/#231 deepened stand-in extends to this label via the narrowest token override (:root[data-theme=latte] .finding-covered-by .f-label { --text-muted: #5c5f77 }) — re-measured empirically on the actual finding-row backdrop: 5.53:1. rosepine (4.56) stays verbatim; the latte theme block stays pinned. Guard changes (the existential-vs-universal lesson applied to AA sweeps): - the covered-by sweep now measures EVERY text run in the quoted line (code pills AND the f-label prefix), tags entries by element kind, and asserts the label run is present — stash-verified RED at latte 4.37 without the override, GREEN at 5.53 with it; - both #240 sweeps (covered-by + baseline path) inject '* { transition: none !important }' for the sweep's duration: body transitions background/color over 120ms, so an instant setAttribute + getComputedStyle read can land mid-transition (verifier-observed false readings). Goldens + chrome snapshot regenerated; every hunk is the embedded CSS override/comment. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(adapters): #240 — trim whitespace-only column descriptions + post-flip top clamp (PR #244 CodeRabbit threads) Thread 1 (applied): a whitespace-only authored description (' ') passed the hasMeta gate untrimmed, suppressing the cute-dbt#240 truthful fallback and opening an effectively-empty bubble on a description-only column — the exact state the never-empty-bubble contract forbids. decorateColHeader (the single writer of data-col-desc) now trims once; aria-label, the fallback arm, and the bubble all read the trimmed value. New headless guard whitespace_only_description_degrades_to_truthful_fallback (stash-verified RED untrimmed, GREEN trimmed). Thread 2 (applied): positionTipNear gains the post-flip top clamp (top < 8 -> 8) — at pathological viewport heights the flipped position (trigger top - bubble height) goes negative, pushing the bubble above the screen. Mirrors the horizontal clamp; resolves the clamp half of cute-dbt#246 (the fmt-tooltip overflow half stays there). The existing right-edge containment guard now also pins top >= 0. Goldens + chrome snapshot regenerated; every hunk is the embedded trim/clamp change. 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>
Summary
Column headers on the unit-test given/expected DataTables now carry a focusable ⓘ tooltip showing the column's authored description plus its column-level data tests (unique, not_null, accepted_values with its values, relationships with to/field, package-qualified tests like
dbt_expectations.*) — so you can see a column is expected-unique while reading fixture rows.Closes #165
What changed
TestMetadataPOD (generic-test name / namespace / untyped kwargs) + four tolerantNodefields:column_descriptions(non-empty prose only, kept SEPARATE from the.contractcolumn-set so a description edit never flagsstate:modified.contract),column_name,attached_node,test_metadata. Additivewith_*builders (thewith_incremental_modeprecedent).columns[*].description(fusion serializes an unset description as""— dropped at translation) and the test-node attribution fields; singular tests (notest_metadata) and model-level tests (column_name: null) tolerated per ADR-5.ColumnMetaPayload {description, tests}computed fully in Rust (JS only renders): per-table maps resolved against the model that owns the table's columns —ref(...)given → the input model,thisgiven → the target model, expect → the target model — filtered to the rendered table's columns, key omitted when empty (no empty bubbles).<button>+ CSS bubble on:hoverAND:focus/:focus-visible,aria-labelfor AT, bubblearia-hidden, never a nativetitle. One deliberate divergence: the bubble isposition:fixedwith JS-set coordinates, because thethlives inside the.table-fitoverflow-xscroller that would clip an absolutely-positioned bubble (#145 — surface incremental-model unit-test semantics #146's bubble hangs off the un-clipped panel header; this one cannot). Visibility itself stays pure CSS. A click on the button is swallowed so it never re-sorts the DataTable. The Diff grid's unified column axis shares the same map.Scope decisions (settled at issue triage — not re-litigated here)
testnodes withcolumn_nameset and attached (attached_node) to the owning model. Model-level tests with column args are deferred.columnsmap (works without--project-root). No raw-YAML path.Additional v1 boundaries surfaced while building:
source(...)givens resolve to nothing (manifestsourcesare not ingested in v0.x), seed-backedref(...)givens likewise (resolve_target_modelis model-only), and column-name matching is exact-case.dbt-fusion verification (research-first)
Pinned at
dbt-labs/dbt-fusion@9977b6cbb1b761065536300037560d8e3c037011:DbtColumn { name, data_type, description }—crates/dbt-schemas/src/schemas/dbt_column.rs;serialize_dbt_column_desc+#[serialize_always]means an unset description hits the wire as"", never an absent key — the adapter drops empties.ManifestDataTest { column_name, attached_node, test_metadata }—crates/dbt-schemas/src/schemas/manifest/manifest_nodes.rs(#[skip_serializing_none]⇒ singular tests OMITtest_metadata).TestMetadata { name, kwargs (defaulted), namespace }—crates/dbt-schemas/src/schemas/nodes.rs.Cross-checked against the REAL committed fixtures (not just synthetic JSON): jaffle-shop carries
unique/not_null/accepted_values/relationshipswithnamespace: nulland an EMPTY description onstg_customers.customer_id; playground carries 10 singular tests withouttest_metadata, 33 model-level tests with nullcolumn_name, anddbt_expectations-namespaced tests — all pinned by a new real-fixture ingestion test.Tests
summarize_column_testarg rendering; per-owner given/this/expect resolution; empty-map wire omission.features/report_generation.feature(no new .feature file — the feature-count gate stays 12) with payload-fact scenarios over the real subprocess + committed fixture.Dogfood + goldens
unique/not_nullonorder_events_incremental.order_id+ staging descriptions on the columns the marts unit tests mock.fct_encounters_incrementalgains columns/descriptions +unique/not_nullonencounter_idin BOTH the source YAML and the manifest (hand-edited via a verified byte-stable JSON round-trip; synthetic-only, no recompile, no root_path). The playground fixture already carried rich column metadata ondim_payers/mart_dq_summary, so all three goldens now show descriptions, unique/not_null,accepted_values (values: …),dbt_expectations.*, and thethis-given resolution.column_meta-only (Python structural diff, not just eyeballs).Finding (out of lane, not fixed here)
StateComparator::models_in_scopearm 2 inserts EVERY modified node with zero unit tests — without filteringresource_type == "model". A baseline-mode PR that adds a generic test node surfaces it as a junk "model" card named by its hash suffix (observed live when the new synthetic test nodes briefly rendered asa165c01d01/b165c01d02cards). Worked around in the fixture by mirroring the test nodes into the baseline; worth its own issue.Gates (all run directly — lefthook skips in fresh worktrees)
cargo fmt --all --check✓cargo clippy --all-targets --locked -- -D warnings— exit 0 ✓ (one justified#[allow(clippy::struct_field_names)]:attached_nodemirrors the dbt wire key)cargo nextest run— 746 passed ✓cargo test --test bdd— 86 scenarios / 550 steps ✓cargo test --test headless_zero_egress --locked -- --ignored✓;cargo test --test headless_toggle --locked -- --ignored— 29 passed ✓RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --document-private-items --locked✓cargo deny check✓Zero-egress invariants hold: no new resource refs, pure-CSS visibility + text-node DOM building, no JS parsing engines — all metadata computed in Rust.
🤖 Generated with Claude Code