Skip to content

#199 — design-2 fold steppers: gutter +/− steppers, expand-step setting, split-view folds, per-diff fold toggle, copy-icon buttons - #213

Merged
cmbays merged 4 commits into
mainfrom
render-199-design2-folds
Jun 11, 2026
Merged

cmbays merged 4 commits into
mainfrom
render-199-design2-folds

Conversation

@cmbays

@cmbays cmbays commented Jun 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Design-2 integration PR-2 (epic #197): ports the pass-2 directional fold model onto the shipped diff renderers. No payload change; no src/domain change — templates/* + headless guards + goldens only.

Closes #199

What landed

  • settings.expandStep in cute-dbt.settings.v1 (default 20, clamp 0–500, 0 = all; NaN-tolerant hydrate) + the static #settings-expand-step row in report.html (the #178 — design integration PR-2: engine merge (settings panel, unified/split diffs) + port-forward #188 static-markup contract — markup copied from the pass-2 prototype's settings row). Read live by expandFold/contractFold — changing it needs no re-render.
  • Unified renderer: fold band gains data-fold-dir (leading fold with the hunk below expands UP, else DOWN), gutter .fold-steppers (+ expands by step, − contracts by step, disabled at bounds), far-right .fold-collapse-all once anything is revealed, label progression Show N unchanged lines → All N lines shown, and updateFoldControl re-parks the control adjacent to the remaining hidden run / below the run when fully revealed. Enter/Space on the band still activates (expand-by-step); reveal stays parent-scoped via closest("code, tbody") (the polish: bold red/green diff text (drop github-style fill) + type-aware NULL in cell diffs #132 duplicate-fold-id rule).
  • Split renderer folds long context runs with the same fold model (fold row: stepper gutter + colspan label cell) and gains the ds-c-num 3.8em / ds-c-code auto <colgroup> for a true 50/50; setAllFolds drives both layouts from one control set.
  • Per-diff fold toggle (buildFoldToggleBtn, aria-pressed) in the Model-SQL and Model-YAML diff code headers; the top-of-report .diff-expand-all strip is removed (design intent), along with its now-dead diffAllExpanded / renderExpandAllToggle / bindDiffViewControls JS and CSS. window.__cuteExpandAllFolds / __cuteCollapseAllFolds remain and mirror every fold control (label + aria-expanded + steppers + collapse-all state) — the headless hooks stay the test seam.
  • copyIconBtn (inline-SVG icon, aria-label="Copy", copied-class flash, execCommand fallback) replaces the absolutely-positioned text Copy in the Model-SQL header and is added to the Model-YAML header; code-header padding per engine/base.css (the 4.8rem right-reserve for the old absolute button is gone). Functional-SVG-only iconography (README §2.4) — no icon fonts, nothing external.
  • a11y: steppers, collapse-all, fold toggle and copy buttons are real focusable <button>s with aria labels (the #145 — surface incremental-model unit-test semantics #146 rule — no hover-only affordances).

Guard supersessions (#132/#136 → #199) — updated deliberately, never deleted

Guard Old assertion New assertion
block_diff_folds_long_context_runs_and_reveals_on_activate click reveals all + relabels "Hide N unchanged lines"; second band-click re-collapses activate = expand-by-step (step 20 ≥ hidden 4 ⇒ one activation reveals all); label "All N lines shown" + + disabled + collapse-all visible; re-collapse via .fold-collapse-all. Kept: parent-scoped reveal, control stays visible, aria-expanded truth, Enter/Space activation, short-block-never-folds. Added: data-fold-dir / steppers / collapse-all markup
global_expand_collapse_mirrors_every_fold mirror = hidden-state + aria + label via foldLabel #136 bidirectional mirror retained on the new control anatomy (label, stepper disabled-states, collapse-all visibility); also pins the retired .diff-view-controls strip at 0 nodes (was: asserted 1)
settings_context_lines_refolds_block_diffs_live contextLines re-render unchanged + extended: expandStep needs NO re-render (block mounted before the change steps by the new value on next activation)
split_diff_renders_the_same_block_diff_as_unified line/emphasis/gutter parity, no split folds parity extends to folds: same directional control anatomy + count, colgroup geometry, band activation + setAllFolds mirror on the split <tbody>
model_sql_section_defaults_to_diff_and_toggles_to_raw / yaml_diff_drawer_defaults_to_diff_and_toggles_to_authored header = filename + view toggle + per-diff fold toggle (aria-pressed) and inline-SVG copy-icon button (real <button>, aria-label="Copy") in both headers
render_block_diff_honors_a_configurable_fold_pad fold-pad arithmetic unchanged — pad arithmetic and labels survive the new model

New guards:

  • expand_step_steppers_reveal_contract_directionally_and_persist — + reveals exactly step lines toward the hunk, − re-hides them mirroring direction, collapse-all restores, up/down direction proofs (c3,c4 from the top on a down fold; c5,c6 from the bottom on an up fold), control re-parking, 0–500 input range, and cute-dbt.settings.v1 persistence across reload.
  • per_diff_fold_toggle_drives_its_own_diffs_folds — the header toggle expands/restores every fold in its own diff (unified and split) with aria-pressed + label tracking.

Goldens / snapshots

All three goldens regenerated per the example-report-check recipe (jaffle-shop, playground, diff-showcase); git diff --text -U0 -- examples/ audited — every changed byte traces to the fold/stepper/copy-button/strip/settings delta (inlined interaction.js/report.css/report.html blocks ×3). Two insta snapshots regenerated (golden_report__rendered_report_skeleton — static Copy button removal + settings row; render_integration__rendered_chrome_jaffle_shop — the same template delta), diff-reviewed the same way. The diff-showcase's existing long-context SQL diff already folds, so the steppers + per-diff toggle + copy icons manifest in the committed showcase with no fixture change.

Gates (run directly in the worktree — not via lefthook)

Gate Result
cargo fmt --check ✅
cargo clippy --all-targets --locked -- -D warnings ✅ (exit 0)
cargo nextest run ✅ 1050 passed
cargo test --test bdd ✅ 109 scenarios / 684 steps
cargo test --test headless_zero_egress --locked -- --ignored ✅ 2 passed
cargo test --test headless_toggle --locked -- --ignored ✅ 38 passed (incl. the 2 new guards)
RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --locked ✅
cargo deny check ✅
goldens byte-audit ✅ intended-only
cargo llvm-cov nextest + crap4rs --config crap4rs.toml --coverage lcov.info ✅ PASS — 0 above threshold (25), worst 23.0

Out of scope (per the collision contract)

Expect-tooltip, panel-toggle/show_all_inputs, findings-panel surfaces (#201/#202); data contracts (#200). The ## Discovery question on the issue (aria-live for the toggle label) is left open — the toggle already exposes state via aria-pressed.

🤖 Generated with Claude Code


Open in Stage

@ghost

ghost commented Jun 11, 2026 •

Copy link
Copy Markdown

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

Title
1 Define expandStep setting and static markup
2 Implement directional fold model and steppers
3 Add folds to split-view renderer
4 Replace global expand-all with per-diff toggle
5 Implement copy-icon buttons in code headers
6 Update headless tests for new design
7 Other changes
Open in Stage

Chapters generated by Stage for commit 0865893 on Jun 11, 2026 2:59am UTC.

@coderabbitai

coderabbitai Bot commented Jun 11, 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 40 minutes and 7 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: 309933f4-2762-43a4-9862-4c0a3c8528c2

📥 Commits

Reviewing files that changed from the base of the PR and between 637644c and 0865893.

⛔ Files ignored due to path filters (2)
  • tests/snapshots/golden_report__rendered_report_skeleton.snap is excluded by !**/*.snap
  • tests/snapshots/render_integration__rendered_chrome_jaffle_shop.snap is excluded by !**/*.snap
📒 Files selected for processing (7)
  • examples/diff-showcase-report.html
  • examples/jaffle-shop-report.html
  • examples/playground-report.html
  • templates/interaction.js
  • templates/report.css
  • templates/report.html
  • tests/headless_toggle.rs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch render-199-design2-folds

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

github-actions Bot commented Jun 11, 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
playground-report.html ▶ Open ↗ ⬇ Download
diff-showcase-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-213/.
⬇ 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 27320800683 -R breezy-bays-labs/cute-dbt -n report-preview-playground
open report-preview-playground/playground-report.html

Posted by report-preview.yml for 0865893b40078779287f96cfd93804d1366b929a. 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 introduces a new step-expansion model for hunk folds (cute-dbt#199), replacing the old top-of-report controls strip with per-diff fold toggles and gutter steppers (+/−) for both unified and split layouts. It also replaces the text-based Copy button with an inline-SVG copy-icon button in the code headers. The review feedback highlights three key areas for improvement: correcting the copy-to-clipboard button to properly handle and display copy failures using the existing .copy-failed CSS class, refactoring the per-diff fold toggle to dynamically check the fold state instead of relying on a local state variable that can get out of sync, and updating setAllFolds to keep these toggle buttons synchronized with the actual fold states.

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 templates/interaction.js
Comment thread templates/interaction.js Outdated
Comment thread templates/interaction.js
cmbays pushed a commit that referenced this pull request Jun 11, 2026
…findings)

Applies all three Gemini findings — each holds the new controls to the
same symmetric-DOM-mirror standard the #136 guards assert:

1. copyIconBtn signals failure truthfully: success flashes 'copied',
   failure flashes 'copy-failed' (title AND aria-label carry the
   outcome; both reset after the flash). Write strategy now mirrors
   copySql — writeText, then the shared execCommand fallbackCopy (which
   reports its own success) on rejection/absence. The .copy-failed CSS
   is no longer dead.
2. buildFoldToggleBtn is stateless: the click derives intent from the
   DOM at activation time (any hidden folded line in this diff =>
   expand-all, else collapse-all) instead of a cached boolean that
   desyncs under per-hunk stepping or the __cute hooks.
3. setAllFolds keeps the per-diff toggles truthful: every fold mutation
   funnels through updateFoldControl -> syncFoldToggles, which relabels
   each toggle (text + aria-pressed) from ITS OWN diff's DOM truth via
   the root accessor stored on the element. Per-root truth is
   deliberately stronger than relabeling 'toggles in scope' to one
   shared state: a partial-scope op never lies about an untouched
   sibling diff, and per-hunk steppers stay covered too.

New/extended guards (headless_toggle):
- per_diff_fold_toggle_drives_its_own_diffs_folds: (a) global
  __cuteExpandAllFolds flips the toggle's label/aria-pressed; a click
  after the global op acts on DOM truth and collapses; (b) stepping the
  unified fold fully keeps the toggle truthful while the split twin
  still holds hidden rows, and the next click expands the remainder.
- NEW copy_icon_button_signals_failure_truthfully: both write paths
  stubbed to fail in-page (writeText rejects, execCommand false) =>
  copy-failed + 'Copy failed' title/aria-label, never 'copied', reset
  to rest state after the flash.

insta render_integration snapshot regenerated (inlined interaction.js).

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

cmbays commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 11, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

github-actions Bot and others added 4 commits June 10, 2026 22:59
…ep setting, split-view folds, per-diff fold toggle, copy-icon buttons

Ports the pass-2 directional fold model onto the shipped diff renderers
(cute-dbt#199, design package design-return-2):

- settings.expandStep in cute-dbt.settings.v1 (default 20, clamp 0–500,
  0 = all; NaN-tolerant hydrate) + the static #settings-expand-step row
  (the #188 static-markup contract). Read live by expandFold/contractFold
  — no re-render on change.
- Unified renderer: data-fold-dir (leading fold expands UP toward the
  hunk, else DOWN), gutter .fold-steppers (+ by step / − by step,
  disabled at bounds), per-hunk .fold-collapse-all once anything is
  revealed, label progression Show N unchanged lines → All N lines
  shown, and updateFoldControl re-parks the control adjacent to the
  remaining hidden run (below the run when fully revealed). Reveal stays
  parent-scoped via closest(code, tbody) — the #132 duplicate-fold-id
  rule.
- Split renderer folds long context runs with the SAME fold model (fold
  row: stepper gutter + colspan label cell) and gains the
  ds-c-num/ds-c-code colgroup (3.8em/auto) for a true 50/50; setAllFolds
  drives both layouts from one control set, so __cuteExpandAllFolds /
  __cuteCollapseAllFolds keep mirroring every fold control (label +
  aria-expanded + steppers + collapse-all — the #136 symmetric-mirror
  invariant on the new anatomy).
- Per-diff fold toggle (buildFoldToggleBtn, aria-pressed) in the
  Model-SQL and Model-YAML diff code headers; the #132 top-of-report
  .diff-expand-all strip is removed (diffAllExpanded /
  renderExpandAllToggle / bindDiffViewControls retired with it).
- copyIconBtn (inline-SVG icon, aria-label Copy, copied-class flash,
  execCommand fallback) replaces the absolutely-positioned text Copy in
  the Model-SQL header and is added to the Model-YAML header; code-header
  padding per engine/base.css. Functional-SVG-only iconography (README
  §2.4) — no icon fonts, nothing external, zero-egress untouched.

No payload change; no src/domain change. Goldens + insta snapshots
regenerated — every changed byte traces to this delta.

Closes #199

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

Deliberate guard migration (never deleted, each replaced with the
new-behavior assertion):

- block_diff_folds_long_context_runs_and_reveals_on_activate: activate =
  expand-by-step (default step 20 >= hidden 4 still reveals all in one
  activation); the 'Hide N unchanged lines' relabel assertion is
  superseded by 'All N lines shown' + disabled + stepper + visible
  collapse-all; re-collapse moved from band-click to the explicit
  .fold-collapse-all. Kept: parent-scoped reveal, control stays visible,
  aria-expanded truth, Enter/Space keyboard activation, short-block
  never folds, new data-fold-dir/steppers markup assertions.
- global_expand_collapse_mirrors_every_fold: the #136 bidirectional
  mirror retained on the new control anatomy (label, stepper
  disabled-states, collapse-all visibility); now also pins the retired
  top-of-report .diff-view-controls strip at 0 nodes.
- settings_context_lines_refolds_block_diffs_live: contextLines
  re-render still live; extended with the expandStep no-re-render proof
  (a block mounted before the setting change steps by the new value).
- split_diff_renders_the_same_block_diff_as_unified: parity extends to
  folds — same directional control anatomy, count, colgroup geometry,
  band activation + setAllFolds mirror on the split tbody.
- model_sql_section_defaults_to_diff_and_toggles_to_raw /
  yaml_diff_drawer_defaults_to_diff_and_toggles_to_authored: assert the
  per-diff fold toggle + the inline-SVG copy-icon button (real focusable
  <button>, aria-label Copy) in both code headers.
- NEW expand_step_steppers_reveal_contract_directionally_and_persist:
  + reveals exactly step lines toward the hunk, − re-hides them
  mirroring direction, collapse-all restores, up/down direction proofs,
  control re-parking, and cute-dbt.settings.v1 persistence across
  reload.
- NEW per_diff_fold_toggle_drives_its_own_diffs_folds: the header
  toggle expands/restores every fold in its own diff (unified + split)
  with aria-pressed + label tracking.

render_block_diff_honors_a_configurable_fold_pad is unchanged — its
fold-pad arithmetic and labels survive the new model.

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

Applies all three Gemini findings — each holds the new controls to the
same symmetric-DOM-mirror standard the #136 guards assert:

1. copyIconBtn signals failure truthfully: success flashes 'copied',
   failure flashes 'copy-failed' (title AND aria-label carry the
   outcome; both reset after the flash). Write strategy now mirrors
   copySql — writeText, then the shared execCommand fallbackCopy (which
   reports its own success) on rejection/absence. The .copy-failed CSS
   is no longer dead.
2. buildFoldToggleBtn is stateless: the click derives intent from the
   DOM at activation time (any hidden folded line in this diff =>
   expand-all, else collapse-all) instead of a cached boolean that
   desyncs under per-hunk stepping or the __cute hooks.
3. setAllFolds keeps the per-diff toggles truthful: every fold mutation
   funnels through updateFoldControl -> syncFoldToggles, which relabels
   each toggle (text + aria-pressed) from ITS OWN diff's DOM truth via
   the root accessor stored on the element. Per-root truth is
   deliberately stronger than relabeling 'toggles in scope' to one
   shared state: a partial-scope op never lies about an untouched
   sibling diff, and per-hunk steppers stay covered too.

New/extended guards (headless_toggle):
- per_diff_fold_toggle_drives_its_own_diffs_folds: (a) global
  __cuteExpandAllFolds flips the toggle's label/aria-pressed; a click
  after the global op acts on DOM truth and collapses; (b) stepping the
  unified fold fully keeps the toggle truthful while the split twin
  still holds hidden rows, and the next click expands the remainder.
- NEW copy_icon_button_signals_failure_truthfully: both write paths
  stubbed to fail in-page (writeText rejects, execCommand false) =>
  copy-failed + 'Copy failed' title/aria-label, never 'copied', reset
  to rest state after the flash.

insta render_integration snapshot regenerated (inlined interaction.js).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mini fix delta)

All three examples re-rendered per the example-report-check recipe after
merging origin/main (#204/#205/#211/#212). Byte audit: every changed
line traces to the truthful fold-toggle/copy-outcome fix (a4c95d7) —
main's cross-join/source-binding golden content came through the merge
intact.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cmbays
cmbays force-pushed the render-199-design2-folds branch from 6dc5fee to 0865893 Compare June 11, 2026 02:59
@cmbays
cmbays merged commit fb70a27 into main Jun 11, 2026
32 checks passed
@cmbays
cmbays deleted the render-199-design2-folds branch June 11, 2026 03:03
github-actions Bot added a commit that referenced this pull request Jun 11, 2026
cmbays pushed a commit that referenced this pull request Jun 11, 2026
…howcase) + golden regen

Conflict resolution by REGENERATION, never manual picking: all three
examples re-rendered from the merged tree with the ci.yml recipe.
Non-payload bytes are byte-identical to origin/main's goldens (the
#213 template/CSS delta carries through untouched); the payload delta
vs origin/main is exclusively the #200 contract fields — manifest_nodes,
ModelPayload.description, the native-scalar overrides, and the three
\u003c= escapes inside new description content. The #214
external-fixture given rides through unchanged (no existing payload
key altered). Double-render byte-identity verified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cmbays pushed a commit that referenced this pull request Jun 11, 2026
- tests/steps/world.rs: kept BOTH accumulators — main's ContextPlan
  (#216) and the explore fields/structs (#100).
- tests/steps/report_generation.rs: the NEW #216 context-report
  invocation (landed on main pre-verb) gains the report verb.
- examples: report goldens taken from main and verified byte-identical
  over the merged tree under the report verb; explore goldens
  REGENERATED over the merged tree (stale twice: #214 changed the
  playground manifest, #216 added payload fields tests.html embeds) +
  double-render byte-identity + leak-grep clean.
- ci.yml/lefthook.yml auto-merged: verb-aware gate + tripwire +
  feature-count 16 intact (no upstream bump — no renumber).

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.

feature: design-2 integration PR-2 — gutter fold steppers + expand-step setting + split-view folds + per-diff fold toggle + copy-icon buttons

1 participant