Skip to content

fix(tests): section_coverage _afterEdit check fails on Windows (CRLF) checkouts - #116

Merged
byrongamatos merged 1 commit into
mainfrom
fix/section-coverage-test-crlf
Jul 7, 2026
Merged

fix(tests): section_coverage _afterEdit check fails on Windows (CRLF) checkouts#116
byrongamatos merged 1 commit into
mainfrom
fix/section-coverage-test-crlf

Conversation

@ChrisBeWithYou

@ChrisBeWithYou ChrisBeWithYou commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Not a product bug — a test-harness papercut that makes tests/section_coverage.test.js fail 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:

  • a CRLF checkout adds one character per line, shrinking the effective window (13 lines inside the method = 13 chars);
  • the method''s comment block grew in the merge wave, pushing the bump statement to offsets 384–402.

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

  • Tests
    • Improved a coverage-related test to more reliably inspect method content after edits, making it less sensitive to formatting or line-ending changes.
    • Kept the existing checks that confirm coverage updates are tracked correctly after edits.

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

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

No new commits to review since the last review.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3117e5f6-b885-43e9-9239-96fc89d7725f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The change modifies a single test file to make method body extraction more resilient. Instead of slicing a fixed 400-character window after _afterEdit() {, the test now scans forward from the opening brace and uses brace-depth balancing to extract the complete method body.

Changes

Test extraction robustness

Layer / File(s) Summary
Balanced brace extraction for method body
tests/section_coverage.test.js
The memo invalidation test now locates _afterEdit(), finds its opening {, and tracks brace depth to extract the full balanced method body instead of relying on a fixed 400-character slice, preserving assertions on _coverageEditGen++ and _covCache guarding.

Estimated code review effort: 1 (Trivial) | ~3 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 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 test fix for the Windows CRLF _afterEdit coverage check failure.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 fix/section-coverage-test-crlf

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.

🧹 Nitpick comments (1)
tests/section_coverage.test.js (1)

140-154: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Brace-balancing fix looks correct.

Resolves the CRLF windowing bug by scanning to the true matching } instead of a fixed-length slice. Depth tracking and the end > 0 guard 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

📥 Commits

Reviewing files that changed from the base of the PR and between 2222c59 and 44dbff8.

📒 Files selected for processing (1)
  • tests/section_coverage.test.js

@byrongamatos

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 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.

@byrongamatos

Copy link
Copy Markdown
Collaborator

Thanks @coderabbitai. The single nitpick (brace-matcher does not skip braces inside string/comment literals) is acknowledged and intentionally not addressed: the current _afterEdit() body contains no braces inside strings or comments, and adding a full literal-aware scanner to a test helper would overengineer a test-only fix. As CodeRabbit notes, it is not worth guarding against now; if the method grows to contain literal braces we will revisit. No actionable changes.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@byrongamatos Understood — that's a reasonable trade-off for a test-only helper. Since _afterEdit() currently has no braces inside strings or comments, the simple brace-matching approach is sufficient, and revisiting it if the method's complexity grows is a sensible plan. Thanks for the clarification.

(๑•̀ᴗ•́)و

@byrongamatos
byrongamatos merged commit 8a2252c into main Jul 7, 2026
1 check passed
byrongamatos added a commit that referenced this pull request Jul 7, 2026
…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>
byrongamatos added a commit that referenced this pull request Jul 7, 2026
…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>
byrongamatos added a commit that referenced this pull request Jul 7, 2026
…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>
byrongamatos added a commit that referenced this pull request Jul 7, 2026
* 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>
byrongamatos added a commit that referenced this pull request Jul 7, 2026
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>
byrongamatos added a commit that referenced this pull request Jul 7, 2026
* 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>
ChrisBeWithYou pushed a commit that referenced this pull request Jul 8, 2026
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
byrongamatos added a commit that referenced this pull request Jul 8, 2026
)

* 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>
@byrongamatos
byrongamatos deleted the fix/section-coverage-test-crlf branch July 8, 2026 06:07
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