fix(tests): section_coverage _afterEdit check fails on Windows (CRLF) checkouts - #116
Conversation
…ts went red The memo-invalidation check sliced a fixed 400-character window from the start of _afterEdit() and regexed for the _coverageEditGen++ bump. A fixed character window silently shrinks by one char per line on a CRLF (Windows) checkout, and comment growth inside the method had already pushed the bump to offset 384-402 — so the test passed on CI (LF) but failed on every Windows clone of current main. Brace-match the whole method body instead; the assertions themselves are unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JEoFeTPSnz4NpwwCG52hnu
|
Important Review skippedNo new commits to review since the last review. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe change modifies a single test file to make method body extraction more resilient. Instead of slicing a fixed 400-character window after ChangesTest extraction robustness
Estimated code review effort: 1 (Trivial) | ~3 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
tests/section_coverage.test.js (1)
140-154: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueBrace-balancing fix looks correct.
Resolves the CRLF windowing bug by scanning to the true matching
}instead of a fixed-length slice. Depth tracking and theend > 0guard are correctly implemented.One minor robustness caveat: the raw brace count doesn't skip braces inside string/comment literals, so a future edit adding an unbalanced
{/}inside a comment within_afterEdit()could silently break extraction again. Not worth guarding against now given the current method body's content, but worth keeping in mind if the method grows.🤖 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 `@tests/section_coverage.test.js` around lines 140 - 154, The brace-matching logic in the section coverage test is currently vulnerable to braces that appear inside string or comment literals within _afterEdit(). Update the extraction in the _afterEdit() body scan to ignore braces that are not actual syntax delimiters, or otherwise make the matcher resilient to future comment/string edits so the balanced-body check remains correct.
🤖 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.
Nitpick comments:
In `@tests/section_coverage.test.js`:
- Around line 140-154: The brace-matching logic in the section coverage test is
currently vulnerable to braces that appear inside string or comment literals
within _afterEdit(). Update the extraction in the _afterEdit() body scan to
ignore braces that are not actual syntax delimiters, or otherwise make the
matcher resilient to future comment/string edits so the balanced-body check
remains correct.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: d7f4ca43-7833-45d9-9dfb-fc547882c8cf
📒 Files selected for processing (1)
tests/section_coverage.test.js
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
Thanks @coderabbitai. The single nitpick (brace-matcher does not skip braces inside string/comment literals) is acknowledged and intentionally not addressed: the current |
|
Tip For best results, initiate chat on the files or code changes.
(๑•̀ᴗ•́)و |
…l (read-first) (#119) * feat(editor): in-key highlight on the fretted lanes — capo-aware sounding pitch Roadmap 4.16a remainder (guitar-lane scale-degree tint). Extends the merged song key/scale highlight (#108) from the piano roll to guitar/bass lanes. - New _soundingPitchPure: openMidi + tuning offset + CAPO + fret, capo added exactly ONCE. Chart frets are capo-relative — verified against core lib/song.py pitch_from_base, the single source of the formula the tuner and highway scale-degree derivation share. - The flagged double-count trap is now pinned in code and tests: _absolutePitch (string-moves) still deliberately omits capo (it cancels when comparing two pitches on one arrangement) and both helpers document the division of labor. - Out-of-key fretted notes dim (body alpha cc->55, softened fret number — the piano-roll treatment; never red), unresolvable pitches stay fully lit. Highlight context is hoisted once per draw, zero per-note arrangement work. Key controls now show for any pitched arrangement. Tests: tests/fret_key_highlight.test.js (8 cases) — the formula against known pitches, Drop-D + capo composition, the capo-flips-membership case an uncapoed resolver gets wrong, and the omits-capo pin on _absolutePitch. Full JS suite green except tests/section_coverage.test.js, which fails on current MAIN itself (pre-existing _afterEdit/#107 merge interaction). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JEoFeTPSnz4NpwwCG52hnu * feat(editor): per-part view switcher — any fretted part opens in the piano roll (read-first) EDITOR-VIEW-MODALITY-DESIGN P1 (VA.1+VA.2, decisions V1-V4/V9). The editing view was derived from the arrangement NAME; it is now a per-part choice. - viewFor(part): per-part pref in editor localStorage keyed song + stable part id (never index/display-name; keys parts piano-locked). Kind inference stays the default. - isKeysMode() split: piano-SURFACE predicate (draw geometry, hit-testing, viewport) vs new isKeysArr() keys-DATA predicate (string moves, chord-sibling grouping, anchors, resize chord-expansion) — a fretted part in the roll still groups chords and keeps string-move machinery (P5 position cycling depends on exactly this). - Read-first roll for fretted parts: one sounding-pitch mapping (_rollMidiForNote via _soundingPitchPure — capo once) hoisted per pass and shared by draw, hitNote, marquee, and updatePianoRange; null pitches skip, never render wrong. - Edit-lock (V4): central gate in EditHistory.exec (typeof-guarded for extracted-test envs) + the live-mutating drag starts (move/resize) + dblclick add + EOF right-click edit; selection still works; a visible pill + status explain why. Lock lifts live on switching back. - Toolbar String/Piano-roll segmented switcher + registry cycleViewMode; selection/drag/note-UI cleared on switch (V3). STACKED ON #115 (feat/editor-key-highlight-guitar) — needs its _soundingPitchPure; merge #115 first. Tests: tests/view_switcher.test.js (11) — pure view resolution, pref persistence/rename stability over stub localStorage, sounding-pitch roll mapping + viewport fit (asserts NOT the wire packing), and the exec gate (inert+notice / regression / live-unlock). Full suite green except the pre-existing CRLF section_coverage failure (#116). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JEoFeTPSnz4NpwwCG52hnu * feat(editor): review fixes for #119 (view switcher) Read-only roll (fretted part in the piano roll) was enforced only at the EditHistory exec chokepoint and the mouse/right-click-add handlers. Two gaps: - exec blocked ALL commands, including songScope (drum tab, tempo grid) edits, so switching an unrelated part into the roll froze tempo/drum editing. songScope commands now pass through the lock (exec + undo/redo). - Several note-edit paths bypass EditHistory entirely and so escaped the lock: note-scope undo/redo, promptSlide/promptSlideUnpitch, the inspector setters (editorInspectorSetTech/SetFlag), and the context-menu editorToggleTech. The context menu opens in the roll under the default right-click behavior and the inspector renders for any selection, so all were reachable. Each is now guarded with _rollReadOnly()/_rollLockNotice. Regression tests (tests/view_switcher.test.js) fail on pre-fix code. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: ChrisBeWithYou <chris@rifflarr.local> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: byrongamatos <xasiklas@gmail.com>
…ility domain (#121) * fix(editor): route live MIDI record through the host midi-input domain EDITOR-VIEW-MODALITY-DESIGN P4 (VD.4, decision V7) — closes the compat drift flagged in the DAW-workspace doc (open question #3): the editor called private navigator.requestMIDIAccess while the org converged on the core midi-input capability domain (window.feedBack.midiInput v1). - Backend adapter (@pure:midi-adapter): domain preferred whenever the host ships v1; older hosts fall back to the private Web-MIDI path unchanged; 'none' disables Record with an honest title. - ONE routing function: the domain handle delivers raw bytes (e.data); the private path unwraps its MIDIMessageEvent to the same bytes — _recMidiOnMessage(e) became _recMidiOnData(bytes), body unchanged. - Start stays SYNCHRONOUS (the user-gesture constraint that keeps the transport anchor honest): the domain session pre-opens at modal-open and on device change; _recMidiConnect only attaches the listener and returns ok|pending|fail ('pending' = pre-open in flight, retry lands). - Sessions are the domain's SHARED refcounted kind: Stop detaches the listener but keeps the session for follow-up takes; modal close releases our ref (never yanks the device from drums/input wizard). - Device picker normalizes both source shapes to one {id, label} row; editor.recordMidiDeviceId persistence unchanged. Tests: tests/midi_domain.test.js (8) — backend selection (unknown future domain versions NOT assumed compatible), picker normalization, and behavioral-equivalence routing over raw bytes: on/off pairing, vel-0-off, channel filter, CC64 pedal deferral, cross-channel pedal isolation, idle gating. Full suite green except pre-existing CRLF section_coverage (#116). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JEoFeTPSnz4NpwwCG52hnu * fix(editor): review fixes for #121 (midi input domain) - guard _recMidiEnsureOpen against stale/superseded async opens via a generation counter; a resolution that lands after a newer open or after teardown self-closes its orphaned session ref instead of leaking it or resurrecting a handle onto a torn-down session. - release the domain MIDI session in editorStopRecordMidi (Stop hides the modal, so the modal-close teardown never ran, holding the refcounted session open indefinitely). - add tests/midi_domain_leak.test.js pinning both leaks (fail pre-fix). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(editor): make Stop-teardown regression test behavioral (#121) Address CodeRabbit nitpick: invoke editorStopRecordMidi against a stubbed DOM/transport and a fake open domain handle, asserting the session is actually closed and the handle released — instead of pattern-matching the function body. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: ChrisBeWithYou <chris@rifflarr.local> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: byrongamatos <xasiklas@gmail.com>
…op pass (#122) * feat(editor): loop A/B compare — alternate recording and guide per loop pass Roadmap 1.6, the last Phase-1 slice that was waiting on #109 (it mutes the reference through the mixer transparent _refGain). The ear-training loop: while looping, each pass alternates RECORDING (reference audible, claps off) and GUIDE (reference muted, claps on — overriding the claps pref in both directions), so a charter hears their chart against the artist one pass apart. - Phase flips ride the loop wrap (before _restartPlaybackAt so the ramp lands with the wrap); every (re)start/seek begins on the recording pass; stop mid-guide-pass restores the fader level; clearing the loop region disarms A/B; song load resets it (session-only by design). - Arming A/B with a region set but looping off arms the loop too. - _guideTimerSync now schedules whenever A/B is active (guide passes need claps even with the pref off). - Toolbar A/B button next to Loop + registry toggleLoopAB (Alt+B). Tests: tests/loop_ab.test.js (5) — pref-override truth table, strict two-cycle, mute-only-during-active-playing-guide (incl. the stop-restores case), and a composed 4-pass alternation. Full suite green except the pre-existing CRLF section_coverage failure (#116). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JEoFeTPSnz4NpwwCG52hnu * feat(editor): review fixes for #122 (loop A/B) - ref fader no longer un-mutes an active A/B guide pass (route ref bus moves through the A/B-aware target; guarded for the @pure sandbox) - mid-play A/B arming delegates to _setLoopRegionEnabled so the cursor seeks into the loop region instead of riding pre-loop audio - disabling the loop mid-guide-pass restores the recording to its fader level instead of leaving it silently muted - regression tests drive the real stateful runtime; all 3 fail pre-fix Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(editor): address CodeRabbit review on #122 (loop A/B) - reset A/B phase + ref gain BEFORE the first playbackTick/_guideTimerSync so a fresh start/seek can't schedule a guide pass off a stale phase (and the first-play fade stays the last ref-gain automation) - on song load, also reapply ref gain + sync scheduler + refresh controls so a load mid-guide-pass never leaves a stale mute or button styling Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: ChrisBeWithYou <chris@rifflarr.local> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: byrongamatos <xasiklas@gmail.com>
* feat(editor): read-only Tab preview of the current part EDITOR-VIEW-MODALITY-DESIGN P3 (VA.4, decisions V8/V12): tab ships as a linked READ-ONLY preview now; an editable tab view waits for the module split (R2) and its rhythm layer. Recon outcome, stated honestly: the Tab View plugin owns the only arrangement->GP converter in the org (rs2gp.py, plugin-local — core has no RS->GP path), and its endpoint reads the SAVED pack from the library. So the cheapest honest integration is frontend-only: an editor modal that fetches /api/plugins/tabview/gp5/<file>?arrangement=N and renders with the same pinned alphaTab 1.8.2 CDN idiom (fontDirectory, Page layout, player disabled — no soundfont download). Zero new conversion code, zero routes.py touch. - "As last saved" labeling + Refresh button; cache-busted re-conversion. - Layout runs once per load, never per frame; API destroyed + mount cleared on close; a seq guard drops superseded renders on rapid refresh. - Clean degradation with specific messages: Tab View plugin missing (404), host too old (501), keys parts (packing has no tab), unsaved session, offline CDN. Tests: tests/tab_preview.test.js (4) — guard truth table + ordering, URL encoding/coercion, HTTP message mapping incl. body truncation. Full suite green except the pre-existing CRLF section_coverage failure (#116). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JEoFeTPSnz4NpwwCG52hnu * feat(editor): review fixes for #123 (read-only tab preview) Four review fixes to the read-only Tab preview, each with a regression test that fails on pre-fix code: - Gate onKeyDown while the preview modal is open so editor shortcuts (fret digits, f, Delete, transport) can no longer mutate the chart or pollute undo/redo behind the read-only proofreading lens; Escape closes it. Mirrors the partsViewMode read-only gate. - Exclude drums arrangements from the preview guard (non-fretted, like keys) — mirrors the editor-wide KEYS_PATTERN + /^drums/i gate; a legacy guitar-encoded drums arrangement no longer engraves nonsense tab. - Inline the non-fretted regexes in the @pure:tab-preview block so it no longer references the outer KEYS_PATTERN global — self-contained and extractable, matching the parts-view @pure convention. - Re-check the stale-render sequence after the error-body read (await resp.text()) on the failure path, symmetric with the success path's arrayBuffer() checkpoint, so a superseded error can't destroy a newer render or stomp its status. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(editor): a11y + guard-order coverage for tab preview (CodeRabbit) - Tab preview modal: role=dialog, aria-modal, labelled by its title, and an accessible name on the close button (Esc already closes it via the onKeyDown gate). - Add a guard-order test: an unsaved keys part reports the fretted-only reason, not Save-first (non-fretted check precedes the filename check). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: ChrisBeWithYou <chris@rifflarr.local> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: byrongamatos <xasiklas@gmail.com>
EDITOR-VIEW-MODALITY-DESIGN P2 (VD.1, decision V6): one grid, density presets, never a second data path or a parallel "game-style" editor. - Lane geometry now routes through a density lane table: Full = one row per piece (today's grid unchanged), Compact = the community 7-row family shape (crash/hi-hat/ride/toms/floor-toms/snare/kick, mirroring core lib/drums.py PRESET_RB4 family boundaries). - Render/selection grouping ONLY: hits keep real piece-ids + per-piece colors; every piece maps to exactly one row (collapse never hides data); hit lookup matches any row member. - Add in a compact row writes the family's CANONICAL piece; a time-only drag keeps the hit's original piece (hh_open never silently becomes hh_closed); crossing rows assigns the target family's canonical — in Full both rules reduce to today's behavior exactly. - "Rows: Full/Compact" button next to Edit Drums (drum mode only), registry command toggleDrumDensity; localStorage pref, never pack. Tests: tests/drum_density.test.js (7) — full-mode identity, total coverage/uniqueness of the compact mapping, canonical membership, junk pref fallback, purity, and the same-row/cross-row drag semantics. Full suite green except the pre-existing CRLF section_coverage failure (#116). Claude-Session: https://claude.ai/code/session_01JEoFeTPSnz4NpwwCG52hnu Co-authored-by: ChrisBeWithYou <chris@rifflarr.local> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: byrongamatos <xasiklas@gmail.com>
* feat(editor): undoable part rename, kind-guarded DAW-workspace 2.2b (first half — rename; reorder is a separable follow-up), unblocked by #101: the merge-not-rebuild save keeps type/unknown keys across a rename, and sloppak sessions carry a stable manifest id. - RenameArrangementCmd: captured-index targeting (undo after a switch lands on the right part), exec/rollback refresh the selector, the stable id never changes (view prefs + manifest merge survive). - The hard limit, enforced honestly: the NAME still drives kind inference (KEYS_PATTERN -> piano roll + notation sidecar, /bass/i -> 4-lane layout, /^drums/i -> drum routing), so a rename that would change the inferred instrument is REFUSED with an explanation — silently re-laning a 6-string chart as a bass would strand notes on invisible strings. Cross-kind moves stay "add a new part". - Duplicate names refused case-insensitively (pack name discipline); empty/overlong refused; exact no-op fails silently. - Toolbar pencil button next to remove-arr + registry renamePart. Tests: tests/rename_part.test.js (6) — kind table (incl. the anchored KEYS_PATTERN nuance: "Electric Piano" is NOT a keys name by the layout rules), guard truth table, and the real command round-tripped through EditHistory (selector refresh, id stability, captured-index targeting). Full suite green except pre-existing CRLF section_coverage (#116). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JEoFeTPSnz4NpwwCG52hnu * feat(editor): review fixes for #124 (part rename) Guard the rename against BOTH name interpreters, not one: the live lane/roll router keys off prefix-anchored KEYS_PATTERN while the save side (routes.py _KEYS_NAME_RE / _TYPE_BASS_RE) keys off word-boundary matches. They disagree on names like "Electric Piano" (save-keys, runtime-guitar) and "Synthwave Lead" (runtime-keys, save-guitar), so a one-facet guard let a rename silently re-lane a chart on save/reload or on the next draw. _renameGuardPure now refuses when either _arrKindPure or _arrSaveKindPure moves; regression tests cover both directions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: ChrisBeWithYou <chris@rifflarr.local> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: byrongamatos <xasiklas@gmail.com>
DAW-workspace 2.2b (second half; rename shipped as #124). Completes the 2.2b remainders that were unblocked by #101. - New < / > buttons next to the arrangement selector + registry commands movePartEarlier/movePartLater: one-slot moves, per-end disabling so the affordance always tells the truth. - Order persists: sloppak saves ship the CLIENT S.arrangements array as the full snapshot and the manifest merge keys entries by id — verified against _buildSaveBody before building. - A move renumbers arrangement indices, so the undo history RESETS (the remove-arrangement rationale) — which is also why the move itself is not undoable: move it back. Blocked mid-recording (a take pins its arrangement index). Selection cleared; selector rebuilt; currentArr follows the moved part. Tests: tests/reorder_part.test.js (4) — pure target math (ends, degenerate inputs), the real handler over an injected env (object identity through the swap, currentArr follow, history reset, selection clear), the clean-no-op-at-ends case (no gratuitous reset), and the recording block. Full suite green except pre-existing CRLF section_coverage (#116). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JEoFeTPSnz4NpwwCG52hnu
) * feat(editor): part reorder — move earlier/later, persisted on save DAW-workspace 2.2b (second half; rename shipped as #124). Completes the 2.2b remainders that were unblocked by #101. - New < / > buttons next to the arrangement selector + registry commands movePartEarlier/movePartLater: one-slot moves, per-end disabling so the affordance always tells the truth. - Order persists: sloppak saves ship the CLIENT S.arrangements array as the full snapshot and the manifest merge keys entries by id — verified against _buildSaveBody before building. - A move renumbers arrangement indices, so the undo history RESETS (the remove-arrangement rationale) — which is also why the move itself is not undoable: move it back. Blocked mid-recording (a take pins its arrangement index). Selection cleared; selector rebuilt; currentArr follows the moved part. Tests: tests/reorder_part.test.js (4) — pure target math (ends, degenerate inputs), the real handler over an injected env (object identity through the swap, currentArr follow, history reset, selection clear), the clean-no-op-at-ends case (no gratuitous reset), and the recording block. Full suite green except pre-existing CRLF section_coverage (#116). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JEoFeTPSnz4NpwwCG52hnu * feat(editor): review fixes for #125 (part reorder) Gate part-reorder to sloppak sessions. The new order persists only on the full-arrangement snapshot that _buildSaveBody ships for sloppak saves; an archive save writes just the active arrangement keyed by arrangement_index, so a client-side reorder was silently lost on reload and, worse, the stale index re-targeted the moved part into the wrong original slot. Hide the buttons for non-sloppak (matching +Keys/Record) and refuse in the handler so the command-palette/keyboard paths can't bypass the hidden buttons. Regression test: archive sessions refuse the move (fails on pre-fix code). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: ChrisBeWithYou <chris@rifflarr.local> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: byrongamatos <xasiklas@gmail.com>
Not a product bug — a test-harness papercut that makes
tests/section_coverage.test.jsfail on every Windows clone of current main while CI stays green.Root cause
The memo-invalidation check slices a fixed 400-character window from the start of
_afterEdit()and regexes it for_coverageEditGen++. Two things compound:On CI''s LF checkout the token still squeaks inside the window → green. On a Windows (autocrlf) clone it ends 2 characters past the cutoff → red. Verified: the bump is present and correct in
_afterEdit()on main; only the test''s window is wrong.Fix
Brace-match the whole method body instead of slicing a character count. The assertions themselves are unchanged. 14/14 now pass on a CRLF checkout.
🤖 Generated with Claude Code
https://claude.ai/code/session_01JEoFeTPSnz4NpwwCG52hnu
Summary by CodeRabbit