fix(editor): preserve the full computed anchor set when authoring one - #44
Conversation
The anchor lane shows the backend's computed/source anchors until the user authors their own, and the backend treats a non-empty `anchors_user` as the complete authored list (empty => recompute). Interacting with a single computed anchor (click / right-click edit / drag) promoted only that one anchor into `anchors_user`, and adding a first anchor in empty lane space pushed only the new one -- either way `anchors_user` became a one-element list, so every other computed anchor was silently dropped on the next save and vanished from the lane. Both authoring entry points now materialize the whole computed set into `anchors_user` on the first interaction, via a single undoable PromoteAnchorsCmd (undo restores the empty => recompute fallback), so only the anchor the user actually edits changes. The anchor edit dialog labels the value as the hand-position fret (index finger) and the width as hand span. Deferred: a persistent "reset to computed" action (undo already reverts a promotion; a durable reset needs the backend's absent-vs-empty save semantics handled explicitly -- its own follow-up). Tests: tests/anchor_authoring.test.js -- full-set promotion on click and on add-new, undo-restores-fallback, idempotent-when-authored. Confirmed the test fails against the pre-fix code (collapses 3 anchors to 1). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR changes computed-anchor editing so the first authoring action promotes the full computed set into ChangesAnchor Promotion Fix
Estimated code review effort: 3 (Moderate) | ~25 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
screen.js (1)
10975-10984: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winCollapse fallback promotion and insert into one undo step (screen.js:10975-10981)
_promoteAutoAnchorsIfNeeded(arr)adds aPromoteAnchorsCmdbeforeAddAnchorCmd, so the first authored anchor on fallback still takes two undo actions to return to recompute-on-save. If the “one undoable step” contract is intended, wrap both in a single history entry.🤖 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.js` around lines 10975 - 10984, The first authored anchor on fallback currently creates two separate history actions because _promoteAutoAnchorsIfNeeded(arr) pushes a PromoteAnchorsCmd before the AddAnchorCmd. Update the anchor insertion flow around the existing _promoteAutoAnchorsIfNeeded, AddAnchorCmd, and S.history.exec usage so promotion and insert are recorded as one undoable step, preserving the one-step undo contract. Ensure the combined action still sets S.anchorSel, calls draw(), and returns true as before.
🧹 Nitpick comments (1)
tests/anchor_authoring.test.js (1)
25-48: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoffBrace-matching extraction is fragile against future screen.js refactors.
Pulling functions/classes out of screen.js via
indexOf+ brace-matching works today, but silently breaks (throwsdecl not found) if a function is renamed, reformatted, or converted to an arrow function/method shorthand later. Since screen.js has no module boundaries to import from directly, this is a reasonable workaround, but worth flagging as a long-term maintenance cost.Consider exposing a small internal test-only export (e.g., attaching these functions to a
module.exportsguarded bytypeof module !== 'undefined') if screen.js is refactored in the future, to make this test harness robust to reformatting.🤖 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/anchor_authoring.test.js` around lines 25 - 48, The test harness in extractDecl/new Function is brittle because it depends on exact source text for _readAnchorSnapshot, _ensureAnchors, _bumpAnchorsDirty, _anchorsAreDirty, PromoteAnchorsCmd, AddAnchorCmd, _promoteAnchor, and _promoteAutoAnchorsIfNeeded. Update the anchor authoring tests to use a more stable internal test-only export from screen.js (or another explicit test hook) instead of indexOf/brace-matching, so future refactors like renames, formatting changes, or method-shorthand conversions do not break the suite.
🤖 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.
Outside diff comments:
In `@screen.js`:
- Around line 10975-10984: The first authored anchor on fallback currently
creates two separate history actions because _promoteAutoAnchorsIfNeeded(arr)
pushes a PromoteAnchorsCmd before the AddAnchorCmd. Update the anchor insertion
flow around the existing _promoteAutoAnchorsIfNeeded, AddAnchorCmd, and
S.history.exec usage so promotion and insert are recorded as one undoable step,
preserving the one-step undo contract. Ensure the combined action still sets
S.anchorSel, calls draw(), and returns true as before.
---
Nitpick comments:
In `@tests/anchor_authoring.test.js`:
- Around line 25-48: The test harness in extractDecl/new Function is brittle
because it depends on exact source text for _readAnchorSnapshot, _ensureAnchors,
_bumpAnchorsDirty, _anchorsAreDirty, PromoteAnchorsCmd, AddAnchorCmd,
_promoteAnchor, and _promoteAutoAnchorsIfNeeded. Update the anchor authoring
tests to use a more stable internal test-only export from screen.js (or another
explicit test hook) instead of indexOf/brace-matching, so future refactors like
renames, formatting changes, or method-shorthand conversions do not break the
suite.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 2e462095-9aad-49b2-ade1-4a2abcba2ad2
📒 Files selected for processing (3)
CHANGELOG.mdscreen.jstests/anchor_authoring.test.js
The empty-space first insert ran two history commands (PromoteAnchorsCmd to seed the computed set + AddAnchorCmd), so a single Ctrl+Z removed only the new anchor and left anchors_user seeded — _anchorEditCount stayed 1, so the save path still shipped the promoted set as authored and the arrangement never returned to recompute-on-save fallback. Contradicted the PR's own 'single undoable' intent. Fold the seed + insert into one PromoteAnchorsCmd (optional new-anchor arg, seeded by reference so selection/drag stay live). Already-authored inserts stay a plain single AddAnchorCmd. Drop the now-unused _promoteAutoAnchorsIfNeeded. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Review + fix pass (Claude Code): pushed a fix for an undo-semantics bug. Bug: the empty-space first anchor insert (while on the computed/source fallback) ran two history commands — Fix: fold seed + insert into a single (Note: the reference-identity of the clicked marker to an |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
tests/anchor_authoring.test.js (1)
18-47: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoffSandbox extraction technique is fragile to future refactors, but acceptable for now.
Regex/brace-matching extraction of named declarations from
screen.jssource, theneval'ing them vianew Function, works but silently produces confusing runtime errors (e.g.PromoteAnchorsCmd is not a constructor) if a target function/class is ever renamed or restructured inscreen.js, rather than a clear "declaration not found" failure. This is a test-only maintenance risk, not the security issue static analysis suggests (input is the project's own source, not external/untrusted data).Consider having
extractDecl()throw immediately if a declaration isn't found, to fail fast with an actionable message during refactors.🤖 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/anchor_authoring.test.js` around lines 18 - 47, The test’s declaration extraction in extractDecl() and the sandbox setup should fail fast when a target symbol is missing instead of later producing confusing constructor/runtime errors. Update the logic around extractDecl('function _readAnchorSnapshot('), extractDecl('class PromoteAnchorsCmd '), and the other listed symbols so that any rename or refactor in screen.js immediately throws a clear “declaration not found” style error with the missing header. Keep the behavior test-only and focused on making refactor failures actionable during sandbox construction.
🤖 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/anchor_authoring.test.js`:
- Around line 18-47: The test’s declaration extraction in extractDecl() and the
sandbox setup should fail fast when a target symbol is missing instead of later
producing confusing constructor/runtime errors. Update the logic around
extractDecl('function _readAnchorSnapshot('), extractDecl('class
PromoteAnchorsCmd '), and the other listed symbols so that any rename or
refactor in screen.js immediately throws a clear “declaration not found” style
error with the missing header. Keep the behavior test-only and focused on making
refactor failures actionable during sandbox construction.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 203de100-e4f9-4627-ac6f-07cdfadec95a
📒 Files selected for processing (2)
screen.jstests/anchor_authoring.test.js
Summary
anchors_useras the complete authored list (empty = recompute on save).anchors_user, and adding your first anchor in empty lane space pushed only the new one — either wayanchors_userbecame a one-element list, so every other computed anchor was silently dropped on the next save (and disappeared from the lane).anchors_useron that first interaction, as a single undoablePromoteAnchorsCmd(undo returns to the recompute-on-save fallback). Only the anchor you actually edit changes.Tests
node tests/anchor_authoring.test.js→ 5 passed. Full JS suite: 13 files, 0 failures.New
tests/anchor_authoring.test.jsbrace-extracts the real anchor source (screen.js is one IIFE) and pins:Confirmed the regression test fails against the pre-fix code (it collapses 3 computed anchors to 1).
Implements the anchor-authoring-semantics fix from the song editor design charrette (the highest-risk bug: fallback promotion collapsing a full computed anchor set).
Summary by CodeRabbit