refactor(editor): extract beatOf/timeOf tempo-map converter (Phase A1) - #133
Conversation
Workspace-shell time-model foundation (charrette §1.1/§1.10, Phase A1). The musical-beat <-> seconds math that _makeTimeRemap and snapTime each computed inline is now ONE named, shared @pure:beat-converter pair, so every musical-time quantity (ruler, snap, loop, playhead, and — from A2 on — notes) reads a single implementation. - beatOf(beats, t): seconds -> fractional beat. Exact inverse of timeOf within a grid gap; before the first / after the last beat it extrapolates along that gap's local tempo, so the pair stays invertible outside the grid too. - timeOf(beats, beat): fractional beat -> seconds, the mirror. - < 2 beats => both are the identity (no tempo map => notes stay seconds-primary, §1.3.4). Non-finite input and zero-width gaps guarded. _makeTimeRemap now routes interior times through the converter — remap IS timeOf(new, beatOf(old, t)) within the grid — while KEEPING its legacy constant-shift on the tails, so the extraction is behaviour-identical across the whole domain. snapTime snaps in the beat domain: timeOf(round(beatOf(t)·subs)/subs). No note-model change (that is A2). Tests: tests/beat_converter.test.js (13) — inverse both directions (exact); the converter reproduces the pre-refactor _makeTimeRemap in the interior (the charrette identity); the SHIPPED _makeTimeRemap and snap math match the pre-refactor code across the whole domain (the no-behaviour-change proof); both-tail extrapolation; the <2-beats identity; and adversarial guards (empty/null/NaN/Inf/zero-width). These reference beatOf/timeOf, absent on main, so the suite fails on main. tests/tempo_ride_parts.test.js: +3 — its hand-assembled sandbox extracts the real _makeTimeRemap, which now needs the converter block in scope. Full JS suite green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013kpQfrmvrUHsZ8asuPnuW4
|
Warning Review limit reached
Next review available in: 32 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThis PR extracts beat/time conversion into shared pure helpers in ChangesBeat converter extraction
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Strengthen tests/beat_converter.test.js after review: pin the converter's exact-inverse at the reported exact-tie input, prove the snapTime tie-break divergence is a measure-zero float ULP (agrees one ULP either side), and add snap idempotency + one-subdivision-bound invariants. No product-code change: the extracted converter is a provably exact inverse with no mapping drift. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@coderabbitai review |
✅ Action performedReview finished.
|
Workspace-shell time-model foundation — Phase A1 (charrette §1.1/§1.10). First step of the beat-primary time model; a pure refactor with no behaviour change, parallel-safe with the open feature-PR backlog (barely touches chrome).
What
The musical-beat ⇄ seconds math that
_makeTimeRemapandsnapTimeeach computed inline is now ONE named, shared@pure:beat-converterpair, so every musical-time quantity (ruler, snap, loop, playhead, and — from A2 on — notes) reads a single implementation.beatOf(beats, t)— seconds → fractional beat. Exact inverse oftimeOfwithin a grid gap; before the first / after the last beat it extrapolates along that gap's local tempo, so the pair stays invertible outside the grid too.timeOf(beats, β)— fractional beat → seconds, the mirror.< 2beats ⇒ both are the identity (no tempo map → notes stay seconds-primary, §1.3.4). Non-finite input and zero-width gaps guarded._makeTimeRemapnow routes interior times through the converter — remap istimeOf(new, beatOf(old, t))within the grid — while keeping its legacy constant-shift on the tails, so the extraction is behaviour-identical across the whole domain.snapTimesnaps in the beat domain:timeOf(round(beatOf(t)·subs)/subs).No note-model change — that is A2. This PR only extracts + names the converter and rewires the two existing callers to it.
Tests —
tests/beat_converter.test.js(13)_makeTimeRemapin the interior (the charrette identity)_makeTimeRemapand snap math match the pre-refactor code across the whole domain — the no-behaviour-change proof<2-beats identity, adversarial guards (empty / null / NaN / Inf / zero-width)beatOf/timeOfdo not exist onmain, so the suite fails on main (would-fail-on-main).tests/tempo_ride_parts.test.js(+3): its hand-assembled sandbox extracts the real_makeTimeRemap, which now needs the converter block in scope. Full JS suite green.🤖 Generated with Claude Code
https://claude.ai/code/session_013kpQfrmvrUHsZ8asuPnuW4
Summary by CodeRabbit
Bug Fixes
Tests