Skip to content

feat(editor): "Song Fit" — one home for shift / fit-tempo / set-constant (tempo PR 9) - #234

Merged
byrongamatos merged 3 commits into
mainfrom
feat/editor-song-fit
Jul 12, 2026
Merged

feat(editor): "Song Fit" — one home for shift / fit-tempo / set-constant (tempo PR 9)#234
byrongamatos merged 3 commits into
mainfrom
feat/editor-song-fit

Conversation

@ChrisBeWithYou

@ChrisBeWithYou ChrisBeWithYou commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Tempo-track PR 9 — the surface pass that closes the assisted-tempo charrette (UX P1). The editor already has three ways to line a chart up to a recording, but they're scattered controls most people never connect. Song Fit gives them one discoverable home.

What's new

  • A Song Fit… button in the Tempo Map inspector opens a small menu with the three operations, each labelled by a shared consequence badge stating what it does to audio / grid / notes — every one begins "audio stays" (the non-negotiable: the audio never moves):
    • Shift everything… — nudge the whole chart earlier/later; a compact modal keeps the ±10ms arrows and routes through the undoable offset command.
    • Fit tempo to recording… — dispatches to the existing audio-Sync verb.
    • Set constant tempo… — prompt a BPM, then the conform vs. rebuild flatten (PR 3 / feat(editor): flatten dialog names both directions (conform vs rebuild) #225).
  • The inline Offset / Sync / BPM controls are left alone. Song Fit is a friendlier front door over the same undoable verbs — direct editing is unchanged. (This is the deliberate, low-regression scope; the inputs are not rerouted into dispatchers.)

One refactor

editorSetBPM's flatten flow is factored into a shared _editorFlattenSongToBpm(newBPM, opts) so "Set constant tempo" works from inside Tempo Map mode, where the inline BPM box doesn't offer flatten. editorSetBPM keeps its variable-map gate and delegates; the post-await session re-validation moved into the helper, so flatten_choice.test.mjs's source guard was retargeted to follow it (the variable-map re-check was relaxed to a session+grid guard so a constant song can still be re-flattened — the session-id check is the real protection).

Tests / gates

New src/song-fit.js; tests/song_fit.test.mjs (6: badge copy, choices-render-the-shared-badge single-source, extraction source guards). 125 JS suites green, lint 0 errors (3 pre-existing ratchet warnings). routes.py untouched.

Verified live

On AC/DC — Back In Black: the menu shows all three badges; Shift everything's +10ms moved the offset 0 → +20ms with the toolbar in step; Set constant tempo → 100 BPM → Conform produced "Whole song conformed to a constant 100.00 BPM — notes moved with the grid" — confirming the extracted helper works from Tempo Map mode. No page errors.

Seam note: shares the Tempo Map inspector innerHTML with #233 (PR 6's "Bar 1 here" button) — a trivial keep-both for whichever merges second.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a Song Fit… button to the Tempo inspector.
    • Offers three options: Shift everything…, Fit tempo to recording…, and Set constant tempo… (with clear timing/hold behavior hints).
    • Includes offset adjustment controls with keyboard support.
    • Actions are undoable and keep the audio fixed in place.
  • Bug Fixes

    • Prevents Song Fit actions from applying if the song/session changes while a prompt is open.
    • Improves reliability of tempo flattening after user confirmation.
  • Tests

    • Updated coverage for the shared constant-tempo flattening flow and Song Fit wiring.

…ant (tempo PR 9)

Tempo-track PR 9 (charrette UX P1). The editor already has three ways to line a
chart up to a recording — an Offset nudge, audio Sync, and the BPM flatten with
conform/rebuild — but they're scattered toolbar controls most users never
connect. Song Fit is one discoverable front door over them:

- A **Song Fit…** button in the Tempo Map inspector opens a small menu with the
  three operations, each labelled by a shared "consequence badge" stating what
  it does to audio / grid / notes ("audio stays · …" — the audio never moves):
  **Shift everything…** (offset nudge, keeps the ±10ms arrows in a compact
  modal), **Fit tempo to recording…** (dispatches to the existing Sync verb),
  and **Set constant tempo…** (prompt a BPM → the conform/rebuild flatten).
- The inline **Offset / Sync / BPM** controls are LEFT ALONE — Song Fit routes
  through the same undoable verbs; nothing about direct editing changes (the
  conservative scope: a new front door, not a behaviour swap).
- editorSetBPM's flatten flow (PR 3 / #225) is factored into a shared
  `_editorFlattenSongToBpm(newBPM, opts)` so "Set constant tempo" reaches it
  inside Tempo Map mode, where the inline BPM box doesn't offer flatten. The
  post-await session re-validation moved into the helper (the flatten source
  guard follows it); editorSetBPM keeps the variable-map GATE and delegates.

New module `src/song-fit.js` (`_consequenceBadgePure`, `_songFitChoicesPure`,
`_editorSongFit`, `_editorShiftEverything`). `tests/song_fit.test.mjs` (6:
badges, choices-are-badges single-source, extraction source guards);
`flatten_choice.test.mjs` guard retargeted to the extracted helper. 125 JS
suites green, lint 0-err (3 pre-existing ratchet warnings). routes.py untouched.

Verified live on AC/DC — Back In Black: Song Fit menu shows all three badges;
Shift everything's +10ms moved the offset 0→+20ms (toolbar in step); Set
constant tempo → 100 BPM → Conform → "Whole song conformed to a constant 100.00
BPM — notes moved with the grid" (the extracted helper working from Tempo Map
mode). No page errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EBQCHCNA81E9tHmSDHSe2Q
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 42a72425-aa42-4802-ad81-922702de2bea

📥 Commits

Reviewing files that changed from the base of the PR and between 7136502 and 1ccd975.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • src/main.js
  • src/tempo.js

📝 Walkthrough

Walkthrough

Adds a Song Fit control to the Tempo Map inspector with shift, recording-fit, and constant-tempo actions. Extracts shared constant-tempo flattening logic, exposes new entry points, routes actions through existing editor verbs, and adds source-level tests.

Changes

Song Fit tempo editing

Layer / File(s) Summary
Shared constant-tempo flattening
src/main.js, tests/flatten_choice.test.mjs, tests/song_fit.test.mjs
The flattening prompt and command execution move into _editorFlattenSongToBpm, which revalidates session state after the dialog; editorSetBPM delegates to it and source-level guards verify the wiring.
Song Fit choices and actions
src/song-fit.js, tests/song_fit.test.mjs
Adds three Song Fit choices, consequence hints, constant-BPM validation, offset controls, existing-verb dispatch, window exposure checks, and session revalidation.
Tempo Map inspector integration and changelog
src/tempo.js, CHANGELOG.md
Adds a Song Fit… button that invokes window.editorSongFit() when available and documents the new actions.

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

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant TempoInspector
  participant _editorSongFit
  participant editorSyncTempo
  participant editorNudgeOffset
  participant editorFlattenSongToBpm
  User->>TempoInspector: click Song Fit
  TempoInspector->>_editorSongFit: open choices
  _editorSongFit->>editorSyncTempo: fit tempo to recording
  _editorSongFit->>editorNudgeOffset: shift everything
  _editorSongFit->>editorFlattenSongToBpm: set constant tempo
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 62.50% 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 summarizes the main change: adding a Song Fit entry point for shift, fit-tempo, and set-constant actions.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/editor-song-fit

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: 2

🤖 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 `@src/song-fit.js`:
- Around line 42-50: Update the Song Fit flow around the awaited choice prompt
to snapshot S.sessionId before prompting and revalidate it afterward before
dispatching any choice. Thread the same session token through
_editorShiftEverything and _songFitSetConstant, validating after
_editorPromptText and before each Shift modal action so commands are not applied
to a replacement session; follow the existing protection pattern used by
_editorFlattenSongToBpm.

In `@tests/song_fit.test.mjs`:
- Around line 65-67: Update the editorSetBPM extraction in the test to end at
the next function assignment rather than a fixed 900-character offset. Use the
existing editorSetBPM marker and the following function-assignment boundary so
the complete function body is scanned, while preserving the assertions for
delegating to _editorFlattenSongToBpm and excluding inline TempoGridCmd usage.
🪄 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: 0669398d-fe9d-4230-8393-27c626bda64f

📥 Commits

Reviewing files that changed from the base of the PR and between a51d7e3 and 0a4f5d5.

📒 Files selected for processing (6)
  • CHANGELOG.md
  • src/main.js
  • src/song-fit.js
  • src/tempo.js
  • tests/flatten_choice.test.mjs
  • tests/song_fit.test.mjs

Comment thread src/song-fit.js Outdated
Comment thread tests/song_fit.test.mjs Outdated
@byrongamatos
byrongamatos merged commit 33521a4 into main Jul 12, 2026
3 of 4 checks passed

@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)
src/song-fit.js (1)

91-100: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Give the shift-value input an accessible name.

The numeric input only carries a title attribute; unlike _editorPromptText in src/ui.js, which sets aria-label on the input when there's no visible <label>, this input has no accessible name for screen readers beyond the unreliable title.

♿ Proposed fix
-        + '<input type="number" id="editor-shift-value" step="0.01" class="w-24 bg-dark-700 border border-gray-600 rounded px-2 py-1 text-sm text-center outline-none" title="Total shift in seconds (negative = earlier)">'
+        + '<input type="number" id="editor-shift-value" step="0.01" class="w-24 bg-dark-700 border border-gray-600 rounded px-2 py-1 text-sm text-center outline-none" title="Total shift in seconds (negative = earlier)" aria-label="Total shift in seconds (negative = earlier)">'
🤖 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 `@src/song-fit.js` around lines 91 - 100, Update the input with id
editor-shift-value in the shift editor markup to include an explicit aria-label
describing the total chart shift in seconds, while retaining its existing title
and behavior.
🤖 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 `@src/song-fit.js`:
- Around line 91-100: Update the input with id editor-shift-value in the shift
editor markup to include an explicit aria-label describing the total chart shift
in seconds, while retaining its existing title and behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b34f3d4f-3246-4a78-a031-ec94cd6db391

📥 Commits

Reviewing files that changed from the base of the PR and between 0a4f5d5 and 7136502.

📒 Files selected for processing (2)
  • src/song-fit.js
  • tests/song_fit.test.mjs
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/song_fit.test.mjs

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