Skip to content

feat(editor): fretted playability lint, advisory (view-modality P9 / VA.8) - #200

Merged
byrongamatos merged 3 commits into
mainfrom
feat/editor-playability-lint
Jul 11, 2026
Merged

feat(editor): fretted playability lint, advisory (view-modality P9 / VA.8)#200
byrongamatos merged 3 commits into
mainfrom
feat/editor-playability-lint

Conversation

@ChrisBeWithYou

@ChrisBeWithYou ChrisBeWithYou commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

What

The fretted sibling of the drum limb-lint, same constitution (F5.4): advisory only — a pure lint pass that names the physical question and lets the charter answer it. Never blocks, never auto-fixes.

Rules (one @pure:playability-lint block, thresholds as named consts)

  • stretch — simultaneous fretted notes spanning more than the active anchor window (+1 fret tolerance). Open strings never count toward the span (open-position idioms aren't stretches).
  • overlap — two notes on one string overlapping in time, sustain-aware, including the same-instant case.
  • open-bend — a bend authored on an open string (needs a bender). ⚠ Adapted from the prompt: the "open-string pitch vs tuning" check has no data to run on — notes carry {string, fret} only, pitch is always derived — so the rule ships as this physical check plus bad-fret (outside 0–24 / non-integer), the data-bug-catcher half.
  • legato-jump — an HO/PO arrival or a pitched slide's reach whose fret gap exceeds the active anchor window (same-string chains only).

Anchors resolve authored-first (anchors_user → computed anchors, the dual-list precedence the tempo remap uses); no anchors degrades to a 4-fret default window.

Surface

Flagged notes wear a 2px amber underline in both String view and the rolldrawNotes hoists one memoized Set, recomputed only when editGen/the arrangement changes (the draw-coalesce dirty path), never per frame. A count chip by the note-count readout opens a popover listing every issue; clicking a row seeks + selects the notes. Click-away rides the teardown registry. Hidden on keys parts and drum mode.

Tests

tests/playability_lint.test.mjs (9, real-import): a flag/no-flag boundary per rule, anchor-width participation, cross-string/open-string exemptions, sustain-aware overlap, junk/empty/no-anchors degradations, dual-list precedence, and full-pass ordering. Full suite 91/91 · ESLint 0 errors · CHANGELOG updated.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EBQCHCNA81E9tHmSDHSe2Q

Summary by CodeRabbit

  • New Features
    • Added advisory fretted playability linting (non-blocking, non-auto-fixing) covering stretch, overlap, open-bend/invalid frets, and difficult legato or slide jumps.
    • Added an editor lint status chip and popover UI that lists issues and lets you jump to/select affected notes.
    • Notes flagged by lint are highlighted with amber underlines in fretted and piano-roll views.
  • Documentation
    • Updated the changelog with the new lint checks and UI behavior details.
  • Tests
    • Added a dedicated automated test suite for the lint rules, edge cases, and issue ordering.

…VA.8)

A pure lint pass over the active fretted part (design V13.5/V14), the
fretted sibling of the drum limb-lint and under the same constitution:
ADVISORY ONLY — names the physical question, never blocks, never
auto-fixes (guitar has real outliers: big hands, benders, altered
technique).

Rules (one @pure:playability-lint block, thresholds as named consts with
tuning invited from the pedagogy seat):
- stretch: simultaneous fretted notes spanning more than the active
  anchor window (+1 fret tolerance); open strings never count toward the
  span (open-position idioms are not stretches).
- overlap: two notes on ONE string overlapping in time, sustain-aware
  (one string sounds one note), incl. the same-instant case.
- open-bend: a bend authored on an open string (needs a bender). ADAPTED
  from the prompt's 'open-string pitch vs tuning' check: notes carry
  {string, fret} only — pitch is always derived — so there is no
  independent pitch to cross-check; the rule pairs with bad-fret
  (fret outside 0-24 / non-integer), the data-bug-catcher half.
- legato-jump: an HO/PO arrival or a pitched slide's reach whose fret
  gap exceeds the active anchor window (same-string chains only).

Anchors resolve authored-first (anchors_user, falling back to computed
anchors — the dual-list precedence the tempo remap uses), through
_activeAnchorAtPure; no anchors → a default 4-fret window.

Surface: flagged notes wear a 2px amber underline in BOTH String view
and the roll (drawNotes hoists one memoized Set — the lint recomputes
only when editGen / the arrangement changes, the draw-coalesce dirty
path, never per frame); a count chip by the note-count readout opens a
popover listing the issues; clicking one seeks + selects. The popover's
click-away listener rides the teardown registry.

tests/playability_lint.test.mjs (9): a flag/no-flag boundary per rule,
anchor-width participation, cross-string and open-string exemptions,
sustain-aware overlap, the junk/empty/no-anchors degradations, dual
anchor-list precedence, and full-pass ordering. Suite 91/91, ESLint 0
errors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EBQCHCNA81E9tHmSDHSe2Q
Signed-off-by: ChrisBeWithYou <chris@rifflarr.local>
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@byrongamatos, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 46 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

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.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8ef58345-d948-4cd8-a034-30c240c7a907

📥 Commits

Reviewing files that changed from the base of the PR and between d84df13 and b0b6772.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • assets/v3-theme.css
  • screen.html
  • src/main.js
📝 Walkthrough

Walkthrough

Adds an advisory fretted playability lint system with four pure rule passes, memoized results, count-chip and popover UI, amber note underlines, editor initialization wiring, and Node-based rule tests.

Changes

Fretted playability lint

Layer / File(s) Summary
Lint rules and validation
src/playability-lint.js, tests/playability_lint.test.mjs
Adds anchor-aware stretch, overlap, open-note, bad-fret, and legato-jump checks, aggregates results by time, and tests rule boundaries, degradation, precedence, and constants.
Cached results and editor popover
src/playability-lint.js, screen.html, assets/v3-theme.css, src/main.js
Caches applicable results, exposes lint controls, renders issue rows, supports seek-and-select interactions, and wires initialization and status refresh into the editor.
Flagged note rendering
src/draw.js
Passes flagged-note membership into fretted and piano-roll renderers and draws amber underlines for flagged notes.
Feature changelog
CHANGELOG.md
Documents the advisory lint rules, UI indicators, and implementation locations.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Editor
  participant playabilityLint
  participant ArrangementState
  participant drawNotes
  participant LintPopover

  Editor->>playabilityLint: initPlayabilityLint()
  playabilityLint->>ArrangementState: read active arrangement and notes
  playabilityLint-->>drawNotes: provide flagged note indices
  drawNotes-->>Editor: render amber note underlines
  Editor->>LintPopover: editorToggleLintPopover()
  LintPopover->>playabilityLint: request issue rows
  playabilityLint-->>LintPopover: render issues with seek data
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: an advisory fretted playability lint added to the editor.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/editor-playability-lint

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

@coderabbitai coderabbitai 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.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CHANGELOG.md`:
- Line 20: Update the flagged-notes description in CHANGELOG.md to replace
“yellow” with “amber,” matching the UI terminology and PR objective.
- Around line 26-28: Remove internal references such as “the prompt’s” and “the
charter” from the changelog entry, and rewrite the affected sentence as a
direct, user-facing explanation of the open-bend and bad-fret behavior without
mentioning development or validation processes.

In `@screen.html`:
- Around line 151-152: The playability-lint chip and popover lack accessible
disclosure and focus management. Update the chip trigger to reference
`editor-lint-pop` via `aria-controls` and keep `aria-expanded` synchronized with
its open state; add an accessible label to the popover. When opening, focus the
first issue row, and when closing—including Escape handling—return focus to the
chip.

In `@src/playability-lint.js`:
- Around line 106-113: Update the overlap detection loop in the byString
processing to compare each note against all earlier sustaining notes that remain
active, rather than only list[k - 1]. Preserve same-instant detection, report
every sustain-aware conflict, and add a regression test covering one long
sustain followed by at least two later attacks.
- Around line 246-250: renderPopover() binds each row to mutable array index k,
allowing changed lint ordering to select the wrong issue. Assign each issue a
stable identifier derived from its affected note/range, store that key in the
row’s data attribute, and update the click handler to resolve the current lint
result by that stable key before seeking and selecting; apply the same change to
the related handler around the additional referenced lines.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7a665e73-9205-4ed7-b2a1-d5c7a9216a3b

📥 Commits

Reviewing files that changed from the base of the PR and between 2ec753b and d28b3e9.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • assets/v3-theme.css
  • screen.html
  • src/draw.js
  • src/main.js
  • src/playability-lint.js
  • tests/playability_lint.test.mjs

Comment thread CHANGELOG.md Outdated
Comment thread CHANGELOG.md Outdated
Comment thread screen.html Outdated
Comment on lines +151 to +152
<!-- Playability-lint popover (P9) — anchored bottom-right of the timeline. -->
<div id="editor-lint-pop" class="hidden absolute right-3 bottom-2 z-30 editor-lint-pop"></div>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add accessible disclosure and focus management.

The chip should expose aria-controls and synchronized aria-expanded, while the popover should have an accessible label. Opening it should focus the first issue row, and closing it should restore focus to the chip (including Escape handling); otherwise keyboard and screen-reader users may not be able to review the issues reliably.

Based on the PR objective that the count chip opens an issue popover for review.

Also applies to: 250-250

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@screen.html` around lines 151 - 152, The playability-lint chip and popover
lack accessible disclosure and focus management. Update the chip trigger to
reference `editor-lint-pop` via `aria-controls` and keep `aria-expanded`
synchronized with its open state; add an accessible label to the popover. When
opening, focus the first issue row, and when closing—including Escape
handling—return focus to the chip.

Comment thread src/playability-lint.js Outdated
Comment thread src/playability-lint.js
ChrisBeWithYou and others added 2 commits July 10, 2026 18:32
- Overlap rule: scan EVERY still-active predecessor on the string, not
  just the immediate one — a long sustain (t=1..6) overlaps attacks at
  t=2 AND t=3 and both conflicts are named now. Regression test added.
- Popover rows bind to a rendered SNAPSHOT instead of indices into fresh
  lint results, and an open popover re-renders when the lint changes
  under it — a mid-review edit can no longer remap clicks.
- Accessible disclosure: aria-controls/aria-expanded on the chip,
  role=dialog + label on the popover, focus lands on the first row on
  open and returns to the chip on close, Escape closes.
- CHANGELOG wording: amber (the shipped color), product language instead
  of internal planning terms.

Suite 91/91, ESLint 0 errors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EBQCHCNA81E9tHmSDHSe2Q
Signed-off-by: ChrisBeWithYou <chris@rifflarr.local>
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.

2 participants