Skip to content

feat(editor): harden the assisted-tempo suggest engine (tempo PR 7) - #231

Merged
byrongamatos merged 2 commits into
mainfrom
feat/editor-suggest-hardening
Jul 12, 2026
Merged

feat(editor): harden the assisted-tempo suggest engine (tempo PR 7)#231
byrongamatos merged 2 commits into
mainfrom
feat/editor-suggest-hardening

Conversation

@ChrisBeWithYou

@ChrisBeWithYou ChrisBeWithYou commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

What & why

Tempo-track PR 7 (charrette rhythm c1–c7). Hardens the assisted-mapping onset-fit engine (Suggest ▸ G) so it reads music the way a transcriber does — stopping where the audio stops agreeing instead of snapping the grid onto syncopations or a single bad transient. Everything is in the pure fence (src/tempo-suggest.js); _suggestFitPure's signature is unchanged (opts bag), so PR 8 can still build on it.

The seven changes

Change Why
c1 Snap window is a fraction of the beat (gridInt/beatsInBar), not the bar (_suggestBeatWinPure) The old ±12%-of-bar was ±0.48 beat in 4/4 and grew with the meter, so a syncopation could be snapped as the downbeat. Still floored at 25 ms.
c2 One-bar comb corroboration (_suggestCombPure) A candidate downbeat is scored by the onset support of the whole bar's pulse, not one hit.
c6 Confidence = comb × continuity × consistency A bare or off-tempo bar reads as less certain than a fully-played, steady one.
c3 Median stretch (_suggestMedianPure) + a single >25%-of-a-bar correction stops One bad snap can't drag the whole grid the way a plain EMA (α=0.35) could.
c4 A snap implying ~half/double the bar stops (phase) Halftime backbeat / double-time hat is a metric-phase ambiguity, not tempo drift.
c5 Miss classification (_suggestAnyOnsetInPure): silent bar stops, sustained bar marches A held passage keeps going; true silence stops. Trailing-drop now keys on a miss flag, not confidence, so a real low-comb hit survives.
c7 Named refusals: out-of-range tempo (outside 40–300 BPM) stops (bpm-range); the HUD names each stop reason silence / phase / tempo change / out-of-range read differently instead of one generic line.

Suggestions stay proposal-only (ghost poles) — nothing commits without an accept.

Verification

  • npm test118 pass. tests/tempo_suggest.test.mjs gains 7 fixtures, one per failure mode, each verified to FAIL on the pre-hardening engine (c1 grabs the syncopation → 4.35 vs 4.0; c2 scores equal confidence; c3–c7 lack the stops). The pre-existing drift fixture was updated to a fully-played onset stream so the new comb confidence is exercised — a deliberate pin update, called out in the diff.
  • npm run lint — 0 errors (3 pre-existing ratchet warnings).
  • Live on the testbed: Suggest (G) on AC/DC — Back In Black proposed 96 barlines; ghost poles render alongside the real barlines; no page errors.

Note (scope)

c5's retroactive confidence backfill for a re-entering sustained passage is not included — the stop/march classification is, but back-filling a prediction's confidence when a later onset confirms it is a follow-up. Everything else in c1–c7 lands here.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Improvements
    • Enhanced assisted tempo mapping with stricter beat-relative snapping and stronger beat-pattern corroboration for steadier suggestions.
    • Improved tempo drift handling to be more resilient to occasional timing outliers.
    • More reliable stop behavior when audio is silent, phase is ambiguous, tempo changes suddenly, or tempo falls outside the supported range.
    • Suggestions remain proposal-only (not automatically applied).
  • UX Updates
    • HUD suggestion text now includes clearer stop details, with an “unknown” fallback when needed.
  • Tests
    • Expanded coverage for the hardened tempo-suggestion behavior.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c16e94c1-5897-4100-963e-3225dbe94cbe

📥 Commits

Reviewing files that changed from the base of the PR and between 5c6910b and 41f0ff2.

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

📝 Walkthrough

Walkthrough

Assisted tempo mapping now uses beat-relative snap windows, full-bar onset corroboration, median drift tracking, explicit stop details, and updated HUD messaging. Tests cover snapping, confidence, drift, stopping conditions, tempo bounds, and HUD text.

Changes

Assisted tempo mapping

Layer / File(s) Summary
Hardened suggestion matching and marching
src/tempo-suggest.js, tests/tempo_suggest.test.mjs
Suggestion matching uses beat-relative windows, bar-level comb corroboration, median stretch samples, explicit stop details, and miss-based proposal pruning. Tests cover the updated marching behavior and hardening scenarios.
Stop-detail state and HUD integration
src/tempo-suggest.js, src/tempo.js, CHANGELOG.md
Stop details are stored and exposed to the tempo HUD, which renders detail-specific guidance; the changelog documents the updated behavior.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant OnsetStream
  participant _suggestFitPure
  participant _suggestCompute
  participant TempoMapHUD
  OnsetStream->>_suggestFitPure: provide beat onsets
  _suggestFitPure->>_suggestFitPure: corroborate bars and track drift
  _suggestFitPure-->>_suggestCompute: return proposals and stop details
  _suggestCompute->>TempoMapHUD: expose suggestion state
  TempoMapHUD->>TempoMapHUD: render stop-specific guidance
Loading

Possibly related PRs

🚥 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 summarizes the main change: hardening the assisted-tempo suggest engine.
Docstring Coverage ✅ Passed Docstring coverage is 82.35% which is sufficient. The required threshold is 80.00%.
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-suggest-hardening

Comment @coderabbitai help to get the list of available commands.

The onset-fit march (Suggest ▸ G) now reads music the way a transcriber
would — it stops guessing where the audio stops agreeing instead of
snapping the grid onto syncopations or a single bad transient. All in
the pure fence (src/tempo-suggest.js); _suggestFitPure's signature is
unchanged (opts bag), so PR 8 can still build on it.

- c1 beat-relative window: the snap window is now a fraction of the
  BEAT (gridInt/beatsInBar), not the whole bar — the old ±12%-of-bar was
  ±0.48 beat in 4/4 and scaled with meter, so a syncopation could be
  snapped as the downbeat. New _suggestBeatWinPure; still floored at 25ms.
- c2 one-bar comb corroboration (_suggestCombPure): a candidate downbeat
  is scored by the onset support of ALL the bar's implied beats, not the
  single downbeat onset.
- c6 confidence is a PRODUCT of comb × continuity × consistency, so a
  bare-downbeat or off-tempo bar reads as less certain than a fully-
  played, steady one.
- c3 median stretch (_suggestMedianPure) resists one bad snap the way a
  plain EMA (α=0.35) could not; a single correction > 25% of a bar STOPS
  (stopDetail 'tempo-jump') rather than dragging the whole grid.
- c4 phase: a snap implying ~half/double the bar is a metric-phase
  ambiguity (halftime backbeat, double-time hat) — stop ('phase').
- c5 miss classification (_suggestAnyOnsetInPure): a bar with NO onset is
  silence — stop ('silence'); a bar whose onsets just miss the downbeat is
  sustained — keep marching. Trailing-drop now keys on a miss flag, not
  confidence, so a real low-comb hit survives.
- c7 named refusals: out-of-range tempo (outside 40-300 BPM) stops
  ('bpm-range'), and _suggestHudTextPure names each stop reason in the HUD
  (_suggestStopDetail wired through tempo.js).

tests/tempo_suggest.test.mjs: +7 fixtures, one per failure mode, each
verified to FAIL on the pre-hardening engine (c1 grabs the syncopation,
c2 scores equal confidence, c3-c7 lack the stops). The existing drift
fixture was updated to a fully-played onset stream so the new comb
confidence is exercised (deliberate pin update). 118 JS green, lint
0-err. Verified live: Suggest on AC/DC proposed 96 barlines, ghosts
render, no errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EBQCHCNA81E9tHmSDHSe2Q
@ChrisBeWithYou
ChrisBeWithYou force-pushed the feat/editor-suggest-hardening branch from eb8fd3b to 5c6910b Compare July 12, 2026 22:54
@byrongamatos
byrongamatos merged commit 2716f97 into main Jul 12, 2026
4 checks passed
@byrongamatos
byrongamatos deleted the feat/editor-suggest-hardening branch July 12, 2026 23:22
byrongamatos added a commit that referenced this pull request Jul 15, 2026
…272)

The #231 scope-note follow-up: misses bridged BETWEEN two corroborated
hits are retroactively lifted to 75% of the weaker flank's INTRINSIC
strength (comb x consistency — the closing hit's published conf is
already continuity-penalized for the very gap being backfilled, so
using it would double-count). Trailing misses keep the floor and still
drop; locked pins corroborate at full trust; backfilled bars never
outrank a real hit.


Claude-Session: https://claude.ai/code/session_01EBQCHCNA81E9tHmSDHSe2Q

Co-authored-by: ChrisBeWithYou <chris@rifflarr.local>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: byrongamatos <xasiklas@gmail.com>
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