Repository navigation
#180 — design integration PR-4: vendored Cytoscape engine + Mermaid⇄Cytoscape picker - #192
Conversation
…ker (#180) Design integration PR-4. Vendors cytoscape.min.js 3.30.2 (UMD core only, MIT, SHA-256-pinned in assets/MANIFEST.toml) as the report's second graph engine behind a new settings-panel DAG-engine picker. Mermaid stays the static default; the flip happens in place (no reload) and persists with the appearance state under cute-dbt.appearance.v1. - templates/cyto-dag.js (first-party): longest-path preset layout (no layout plugin, no cytoscape-dagre, never EPL cytoscape-elk), canvas-text labels (XSS-safe by construction), hover context card (textContent-only DOM), click-to-highlight lineage with dim-complement -- per-click is in-place class mutation, never a render re-entry. - interaction.js: renderDag() becomes the engine dispatcher (renderMermaidDag keeps the existing path); window.cuteDagPalette is the single palette source for BOTH engines (the edge-vocab-completeness gate keeps grepping JOIN_COLORS_LIGHT/_DARK -- no second palette table exists), fixing the handoff's dark-theme from-edge-vanishing bug by construction; window.__cuteSelectNode drives the Inspect panel without rebuilding the DAG. - theme.js: engine pref + picker wiring + validation (closed vocabulary, unknown values coerce to mermaid). - Headless guards: picker switches engines in place (sentinel survives, cy instance lifecycle), hover-card appears, tap highlights lineage on the SAME cy instance; zero-egress gains a Cytoscape-selected arm over real file:// with DNS denied. - Goldens + insta regenerated (report grows ~+392 KB: the 373 KB bundle + the first-party engine + picker markup). Closes #180 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Warning Review limit reached
More reviews will be available in 30 minutes and 8 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 (3)
📒 Files selected for processing (16)
✨ 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 |
|
Ready to review this PR? Stage has broken it down into 8 individual chapters for you: Chapters generated by Stage for commit 663aa55 on Jun 10, 2026 11:09pm UTC. |
📄 Rendered report previewAll golden examples regenerated cleanly. 🟡 Golden examplesCommitted to
🐶 Live dogfood previewThis PR doesn't touch ▶ 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 27312231575 -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 introduces Cytoscape.js as an opt-in, interactive alternative DAG engine alongside the default static Mermaid engine, allowing users to switch engines in place via a settings-panel picker. The integration includes embedding the Cytoscape UMD core bundle, implementing a custom longest-path layout, and adding headless tests to verify zero-egress compliance and user interactions. Feedback on the implementation suggests using Object.create(null) for maps to prevent prototype lookup issues, applying the visibility class to the hover card before measuring its dimensions to ensure correct positioning, and simplifying the cy.fit call.
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.
…ps, reveal-before-measure, fit(28) - computeDepths/layoutPositions: Object.create(null) for every id-keyed map so a CTE legitimately named toString/constructor can never collide with a prototype property. - showCard: add .is-visible before measuring offsetWidth/Height (the chassis hides via opacity so measurement was already real; ordering is now robust to a display-based hide). - cy.fit(28): the documented number-as-padding form, verified against the vendored 3.30.2 getFitViewport source. - Goldens + chrome snapshot regenerated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…irement, DAG final-stroke AA fix (#203) * feat(render): three new AA-pinned themes — Dracula, Catppuccin Latte, Rosé Pine Dawn (8 total) + Solarized/Gruvbox AA touch-ups Lands the design pass-2 theme delta on the chassis (cute-dbt#198): - templates/report.css gains the dracula / latte / rosepine [data-theme] blocks verbatim from the pass-2 engine/tokens.css (incl. per-theme code-surface tokens); Solarized --diff-remove-fg #c5341c -> #b82d18 and Gruvbox --code-rem-sigil #fb4934 -> #fb6a5d per the pass-2 AA re-verification; the pinned AA table is replaced with the 8-theme README §2.3 table (do not re-brighten). - templates/theme.js THEMES becomes the 8-entry list, light family first (light/solarized/latte/rosepine/dark/tokyo/gruvbox/dracula); dark-family themes still toggle html.dark for the vendored DataTables dark rules. Static-markup contract kept: only the DATA was lifted from pass-2, not its runtime DOM-injection approach. - templates/report.html theme grid shows all 8 chips (static markup, the #188 contract), reordered light family first with pass-2 swatch dots. - headless appearance guard extended: latte (light family) + dracula (dark family) chips flip [data-theme] + the html.dark DataTables sync, and the grid lists exactly 8 chips. - insta snapshots (chrome + skeleton) regenerated for the above. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(render): retire diff-cells colour/marks control per design pass-2 Founder-confirmed 2026-06-10 (epic #197 open question 1): the #188 "Diff cells: colour / marks" control is retired — diff cells always render in colour (pass-2 README §2.3). - templates/report.html: the Diff-cells settings row (static markup) is removed; the settings-menu comment documents the retirement. - templates/theme.js: applyDiffStyle, the diffstyle pref default, the load() key, the .diff-seg sync/wire blocks and the boot apply are removed. A LEGACY persisted diffstyle key in cute-dbt.appearance.v1 is ignored gracefully: load() copies only the live keys and nothing sets data-diffstyle, so no error and no leftover attribute. - templates/report.css: the :root[data-diffstyle="marks"] rules are removed (a tombstone comment records the retirement). - headless appearance guard updated: asserts no .diff-seg / [data-diffstyle] markup survives, and a seeded legacy diffstyle key still hydrates the live keys with no data-diffstyle attribute after reload. - insta snapshots (chrome + skeleton) regenerated for the above. This commit is deliberately standalone so the retirement is trivially revertable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(render): design-2 chassis chrome — 28rem settings panel, two-layer legend final swatch, cyto card wrap, role_final AA stroke - Settings panel width 21rem -> 28rem (max-width 92vw, box-sizing border-box) with the narrow-viewport fallback min(28rem, 94vw), per the pass-2 engine/chrome.css — room for the 8-theme grid without wrapping. - Legend final-node swatch becomes the two-layer hexagon: a color-mix darkened edge layer + a ::before fill inset (pass-2 engine/base.css), mirroring the darker role_final stroke. - role_final stroke #E69F00 -> #b07400 (AA against the #fdf2dc fill) in BOTH DAG engines: the Mermaid classDef literal in renderDag and the ROLE_FILLS table cuteDagPalette feeds the Cytoscape engine. The #192 dark-bg palette variants are untouched — they cover edges/anchor only; node fills deliberately stay light in every theme, so the darker stroke only gains contrast against its own light fill. - Cytoscape node-card wrap fixes (width max-content, overflow-wrap anywhere, nc-row flex-wrap) per the pass-2 engine/chrome.css. - insta snapshots (chrome) regenerated for the above. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(render): per-theme AA token override for the #194 tier chips on Latte The cute-dbt#198 discovery check ran the WCAG math on the findings-surface tier chips (0.68em text) for all three new themes: - Dracula: total 6.55 / high 5.59 / advisory 6.08 — pass - Rosé Pine Dawn: total 6.11 / high 5.68 / advisory 4.56 — pass - Latte: total 4.91 / high 4.34 / advisory 4.37 — high+advisory a hair under AA 4.5 Fix per the issue's discovery contract: a per-theme token override scoped to .tier-chip (accent -> one-step-darker latte blue #1a5cdd, 5.13:1; muted -> Catppuccin subtext1 #5c5f77, 5.53:1). The chip markup/rules and the verbatim latte theme block are untouched. Pre-existing, out of scope here: shipped Solarized tier-high is 3.41:1 on main today (accent #268bd2 on the cream surface) — flagged on the PR for a follow-up. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test: regenerate golden examples for the design-2 chassis delta jaffle-shop / playground / diff-showcase re-rendered with the exact example-report-check matrix commands. Reviewed with git diff --text -U0 -- examples/: every changed line is one of the intended deltas (3 new theme blocks + AA touch-ups, 8-chip theme grid, diffstyle retirement, 28rem settings panel, two-layer legend swatch, cyto node-card wrap, role_final #b07400 stroke, latte chip override). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(render): un-cap the narrow-viewport settings panel at 94vw CodeRabbit on #203: the base .settings-panel rule's max-width: 92vw clipped the <=720px fallback width: min(28rem, 94vw), so the extra 2vw never applied and the 8-chip theme grid wrapped early on small screens. The media block now widens max-width alongside the fallback. (The same latent cap exists in the pass-2 engine/chrome.css — this honors the design's 94vw intent rather than its literal bytes.) Goldens + chrome snapshot regenerated. 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>
…217) * feat(adapters): design-2 layout restructure + DAG node-detail shelf (#201) Restructure the report body around the model -> test split (the pass-2 design canon, merged INTO shipped code - never a file replacement): - .dag-stage wraps .dag-canvas-col (Mermaid + Cytoscape hosts + legend) beside the new aside.dag-shelf (head: title + close; body). Clicking a DAG node opens the shelf: model-detail card from the #200 manifest_nodes lookup (tags -> name+materialized -> description -> model tests -> columns with click-to-expand test-count chips) + compiled SQL with the role badge riding the summary row. Given fixtures are deliberately NOT rendered in the shelf - they live in the Given panel (the #131 ordinal binding rides renderAllInputs' loop index). - Node->model mapping: final-select -> this model; import -> the ref() target of its bound given (the #131 bound_to_node seam); unknown -> card omitted, compiled SQL still shows. - window.__cuteSelectNode now opens the shelf - the #192 Cytoscape tap and the #194 findings pin both keep routing through this one seam (no renderDag per click; Mermaid's activate keeps its re-render). Model/test re-selection closes the shelf and re-centers the DAG. - section.test-section/.test-card below the DAG: the unit-test selector IS the card title (sizeSelectToWidest: static width, max-width clamped), the #91 scope toggle to its right (data-testid retained), the .test-badges row (tb-tag / untagged tb-muted / tb-meta - the overrides badge arrives with #202), the larger-font always-open description + details body. Founder decision on epic #197: always-open card, NOT a drawer; only the authoring-YAML drawer stays collapsible. - .model-findings (#194) preserved INTACT, placed ABOVE the model SQL + DAG near the model selection (founder decision on epic #197, superseding the audit's between-DAG-and-test-section proposal). - test-description-section and the left .panel-toggle (Inspect / All-inputs) retired: the left panel header reads Given and always renders all inputs; the #74 no-empty-landmark intent carries over via the hidden attribute on the in-card description. - The DAG hint subtitle becomes the #146-contract focusable button + CSS bubble (hover AND keyboard focus, aria-label parity). - Kept shipped: theme-aware cyto-dag.js palette, ModelPayload.path in renderModelSql (no <name>.sql regression), the authoring-YAML drawer labels and Diff/File toggles. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test: port-forward headless guards to the #201 shelf layout + new shelf guard Every re-target is deliberate, never collateral (#201): - findings_panel_renders_checklist_tiers_sketch_rationale_and_pin + cytoscape_hover_card_appears_and_tap_highlights_lineage_in_place: .left-panel-body .node-detail -> .dag-shelf-body .node-detail (the __cuteSelectNode seam survives; the pin still selects + scrolls + pin-flashes). - same_ref_givens / changed_cell_null-vs-string / cell_diff_toggle / fusion-csv / sql-literal / external-fixture / column-tooltip / incremental guards drop the show_all_inputs panel-toggle click (the Given panel always renders every input now); the helper is retired. - incremental_badges_modes_tooltip_and_this_given: BUBBLE_VIS scoped to the expected panel - the DAG hint is a second .expect-tooltip on the page since #201, so a bare first-match read the wrong bubble. - stacked_panel_does_not_blow_out_viewport_at_375px re-verified on the new layout (the .dag-stage flex row wraps below on narrow - the #157/#158 contract holds). - source_given fixture-card guard re-homed: the card renders in the Given panel; clicking the bound import CTE opens the shelf with compiled SQL and NO fixture card (the no-fixtures rule). - NEW dag_node_click_opens_shelf_with_model_card_and_close_clears_selection: shelf opens with compiled SQL + role badge on the summary; the final-select node renders the manifest_nodes model card (description + tags); an unmapped node omits the card but keeps compiled SQL; the close button clears body + baked Mermaid selection; a fresh test selection closes the shelf; the DAG-hint info button honors the #146 focus-reveals-bubble contract. - BDD: the #74 ordering scenario re-homed - the test section (hosting the description) renders between the cte-dag section and the panel-row. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test: regenerate golden examples + re-accept insta DOM snapshots for #201 examples/{jaffle-shop,playground,diff-showcase}-report.html regenerated with the exact ci.yml example-report-check recipe; every changed byte traces to the #201 templates (report.html DOM, interaction.js, report.css) - audited via git diff --text -U0. No root_path/username bytes. Insta skeleton + chrome snapshots re-accepted for the intended restructure only. 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
Vendors Cytoscape 3.30.2 as the report's second graph engine behind a new settings-panel DAG-engine picker. Mermaid stays the static default; Cytoscape is the opt-in interactive engine (hover context card, click-to-highlight transitive lineage with dim-complement, pan/zoom). The swap happens in place (no reload) and persists with the appearance state under
cute-dbt.appearance.v1.Closes #180
Acceptance criteria — evidence
assets/with aMANIFEST.tomlentry (version + SHA-25683e8c54a6bec655bfd81df07df605649c268af69aeca67a5ea2da54ea42dac81+ SPDX MIT), fetched from the npm registry tarball (https://registry.npmjs.org/cytoscape/-/cytoscape-3.30.2.tgz, bundle atpackage/dist/cytoscape.min.jsinside). Embedded viainclude_str!(asset_embed::CYTOSCAPE_JS) with a version-banner pin test. Core only — no layout plugin (first-party longest-path preset layout intemplates/cyto-dag.js; never EPLcytoscape-elk). The npm dist bundle ships nosourceMappingURLtrailer (verified — nothing to strip).fontFamily, no workers, no layout plugins; handlers bound from our JS to rendered elements (never click directives executing data); per-click mutates classes in place — a headless guard asserts the samecyinstance survives a tap (no render re-entry).window.cuteDagPalette()over the existingJOIN_COLORS_LIGHT/_DARKtables — no second palette table exists (an asset_embed test rejects one), so theedge-vocab-completenessgate's grep target stays accurate unchanged. Verified visually on all 5 themes (light/dark/tokyo/solarized/gruvbox):fromedges stay legible on every dark theme (the handoff's documented bug cannot recur — both engines share the dark palette by construction).cute-dbt.appearance.v1POD via theme.js (closed vocabulary, unknown values coerce tomermaid); Mermaid stays the static default; switch is in place — headless guard pins a window sentinel surviving the flip.ARCHITECTURE.md§5 +AGENTS.md.tests/headless_zero_egress.rsgainedevery_committed_example_stays_zero_egress_with_the_cytoscape_engine_selected— flips the picker on each committed example over realfile://with DNS denied, waits for the live cy canvas, asserts zero external requests. Both arms pass locally.tests/headless_toggle.rs):dag_engine_picker_switches_engines_in_place_and_persists(default Mermaid SVG → cy canvas in place → blob persists → flip back destroys cy) andcytoscape_hover_card_appears_and_tap_highlights_lineage_in_place(hover card via textContent; tap dims exactly the non-lineage branch; same-instance assertion; Inspect panel syncs via__cuteSelectNode).Size delta
Each golden grows +392,097 bytes (~+383 KiB) — cytoscape.min.js 373 KB + the first-party
cyto-dag.js+ picker markup (vs the ~+492 KB estimate, which assumed cytoscape-dagre; we ship core-only):Golden diffs spot-checked at
-U0: non-asset regions are exactly the picker row, the.cte-dag-cytohost, and the two new script blocks. The default-rendered DAG stays Mermaid, so the visible default in the goldens is unchanged.Gates (run directly — lefthook skips in fresh worktrees)
cargo fmt --check✅ ·cargo clippy --all-targets --locked -- -D warnings✅ (exit 0) ·cargo nextest run✅ 895/895 ·cargo test --test bdd✅ 97 scenarios ·headless_toggle -- --ignored✅ 34/34 ·headless_zero_egress -- --ignored✅ 2/2 (incl. the Cytoscape arm) ·RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --locked✅ ·cargo deny check✅ · crap4rs ✅ (1303 fns, 0 above threshold 25, worst 23.0) · goldens + insta regenerated. No new .feature files → feature-count gates untouched.Notes for reviewers
templates/*,src/adapters/{asset_embed,render}.rs, tests, goldens. No domain changes.width: 'label'node sizing (the spike-validated config);wheelSensitivitywas dropped to silence the other spike-noted warning.🤖 Generated with Claude Code