Skip to content

Use chart data from bundle (post-chart-transformation plugins) - #1

Merged
jphinspace merged 3 commits into
developfrom
bundle
Jul 24, 2026
Merged

Use chart data from bundle (post-chart-transformation plugins)#1
jphinspace merged 3 commits into
developfrom
bundle

Conversation

@jphinspace

@jphinspace jphinspace commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features
    • Added direct browser-based score rendering from chart data, including extended-range instruments, tempo changes, techniques, and cursor synchronization.
    • Added support for multiple independent player instances.
  • Bug Fixes
    • Improved rendering lifecycle, chart rebuilding, listener cleanup, and stale playback protection.
  • Documentation
    • Updated setup and usage documentation to reflect the client-side rendering workflow.
  • Tests
    • Added coverage for chart timing, quantization, tuning, score creation, note effects, and metadata.

@jphinspace

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

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

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: cb61e7b9-9b1d-4101-ab00-be3911c3d212

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 plugin replaces server-side GP5 conversion with direct client-side alphaTab score construction from renderer bundles. It adds chart quantization and score-builder modules, updates package and plugin metadata, refactors rendering lifecycle and cursor synchronization, and adds Node-based tests.

Changes

Bundle rendering migration

Layer / File(s) Summary
Rendering migration contracts
.specify/memory/constitution.md, README.md, package.json, plugin.json, requirements.txt, .gitignore
Documentation and project metadata now describe direct bundle-to-alphaTab rendering, while the GP5 route and Python runtime dependency are removed.
Chart quantization and tuning
src/chart-quantize.js, test/chart-quantize.test.mjs
Adds measure parsing, event merging, 32nd-note quantization, duration decomposition, and guitar/bass tuning generation with tests.
alphaTab score construction
src/score-builder.js, test/score-builder.test.mjs
Builds alphaTab score structures from bundle data, maps timing and techniques, handles rests and invalid strings, and tests metadata, tuning, effects, and measure behavior.
Persistent rendering and cursor lifecycle
screen.js
Uses a persistent alphaTab API, renders based on bundle-note identity, manages per-render listeners and stale async work, and synchronizes markers from audio timing.

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

Sequence Diagram(s)

sequenceDiagram
  participant Highway
  participant screen.js
  participant buildScoreFromBundle
  participant AlphaTabApi
  Highway->>screen.js: Provide bundle and currentTime
  screen.js->>buildScoreFromBundle: Build score from bundle
  buildScoreFromBundle-->>screen.js: Return alphaTab Score
  screen.js->>AlphaTabApi: renderScore(score)
  AlphaTabApi-->>screen.js: Report renderFinished or error
  Highway->>screen.js: Update audio.currentTime
  screen.js->>screen.js: Update beat marker
Loading

Suggested reviewers: byrongamatos

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.33% 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 reflects the main change: using bundle chart data after chart-transformation plugins instead of the old GP5 flow.
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 bundle

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

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)

150-167: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Both _countLE call sites use count - 1 as an index without clamping, so a NaN target dereferences element -1. _countLE returns 0 when the comparison is false for every element (which is what NaN does), and each site's "below the first element" early return also fails for NaN — so the derived index becomes -1 and the lookup throws on the rAF path.

  • screen.js#L150-L167: clamp with Math.max(0, Math.min(count - 1, beats.length - 2)) before reading beats[idx].time, and refresh the stale claim at lines 802-804 that NaN "resolves to lookupTick 0".
  • screen.js#L743-L749: clamp with Math.max(0, _countLE(arr, tick, b => b.start) - 1) before reading arr[ans].beat.
🤖 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 150 - 167, The `_countLE` results can produce index
-1 for NaN inputs, causing invalid array access. In screen.js lines 150-167,
clamp the computed `idx` to zero before reading `beats[idx]`; in screen.js lines
743-749, clamp the computed `ans` similarly before reading `arr[ans].beat`. Also
update the stale NaN behavior claim at screen.js lines 802-804 to reflect the
corrected handling.
🧹 Nitpick comments (2)
src/chart-quantize.js (1)

25-28: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Guard b.measure before treating it as a measure marker.

null >= 0 is true, so a beat with measure: null would split on every beat and render one-beat measures. Use a numeric typeof check before the >= 0 test, keeping omitted/no-marker beats grouped.

🤖 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/chart-quantize.js` around lines 25 - 28, Update the grouping condition in
the beats loop to require that b.measure has numeric type before applying the >=
0 measure-marker check. Preserve the existing cur.length guard and ensure null,
omitted, and other non-numeric measure values remain grouped with the current
measure.
src/score-builder.js (1)

27-36: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Use note.addBendPoint(...) for constructed bends.

Note.addBendPoint() updates maxBendPoint, but assigning note.bendPoints directly leaves it null/undefined on new notes. Renderer paths read note.maxBendPoint.value, so this can produce incorrect bend-glyph layout even though the test only checks hasBend and bendPoints.

🤖 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/score-builder.js` around lines 27 - 36, The constructed bend in the
bend-processing block must use Note’s addBendPoint API so maxBendPoint is
maintained. Replace direct assignment to note.bendPoints with calls to
note.addBendPoint for each BendPoint, preserving the existing points and
bendType 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.

Inline comments:
In `@README.md`:
- Line 56: Update the README test documentation to mention both Node test
modules, including test/chart-quantize.test.mjs alongside the existing
src/score-builder.js suite, while preserving the npm test command description.

In `@screen.js`:
- Around line 990-994: Separate ref presence from ref value in the chart-build
guards around _tvPendingNotesRef and _tvFailedNotesRef: add paired active flags,
set them whenever a build starts or fails, and clear them on successful
completion and teardown. Update buildInFlight and previouslyFailed in
_tvRenderFromBundle to use those flags, while preserving the notesRef
comparisons for non-null values; also ensure notes-less bundles receive distinct
chart identity so consecutive null notes can trigger a rebuild.

In `@src/chart-quantize.js`:
- Around line 71-78: Update the fallback beat configuration in the returned
object so beatTimes matches numBeats and spans the full len-second measure using
the expected subdivision spacing. Keep numBeats at 4 and ensure the generated
beatTimes contains the corresponding entries across the measure rather than the
hard-coded 0–3.5 second range.

In `@src/score-builder.js`:
- Around line 107-113: Strengthen the validation before constructing the Note in
the wire-processing loop: require wire.s to be a finite integer within [0,
stringCount), and require wire.f to be a valid finite fret value before
assigning either field. Preserve the existing seen filtering and add
score-builder tests covering undefined/fractional string indices and missing or
invalid frets alongside the out-of-range case.

In `@test/score-builder.test.mjs`:
- Around line 31-35: Update the tempo assertion in the score builder test to
inspect the tempo automation created on the first master bar by
buildScoreFromBundle, rather than asserting score.tempo. Verify the automation
contains the expected tempo value of 120 while leaving the other score
assertions unchanged.

---

Outside diff comments:
In `@screen.js`:
- Around line 150-167: The `_countLE` results can produce index -1 for NaN
inputs, causing invalid array access. In screen.js lines 150-167, clamp the
computed `idx` to zero before reading `beats[idx]`; in screen.js lines 743-749,
clamp the computed `ans` similarly before reading `arr[ans].beat`. Also update
the stale NaN behavior claim at screen.js lines 802-804 to reflect the corrected
handling.

---

Nitpick comments:
In `@src/chart-quantize.js`:
- Around line 25-28: Update the grouping condition in the beats loop to require
that b.measure has numeric type before applying the >= 0 measure-marker check.
Preserve the existing cur.length guard and ensure null, omitted, and other
non-numeric measure values remain grouped with the current measure.

In `@src/score-builder.js`:
- Around line 27-36: The constructed bend in the bend-processing block must use
Note’s addBendPoint API so maxBendPoint is maintained. Replace direct assignment
to note.bendPoints with calls to note.addBendPoint for each BendPoint,
preserving the existing points and bendType behavior.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dd8ee046-d8ca-4f77-a750-8a6a1f41211b

📥 Commits

Reviewing files that changed from the base of the PR and between 1285844 and e302181.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (15)
  • .gitignore
  • .specify/memory/constitution.md
  • README.md
  • package.json
  • plugin.json
  • requirements.txt
  • routes.py
  • rs2gp.py
  • screen.js
  • src/chart-quantize.js
  • src/score-builder.js
  • test/chart-quantize.test.mjs
  • test/score-builder.test.mjs
  • tests/conftest.py
  • tests/test_rs2gp_helpers.py
💤 Files with no reviewable changes (5)
  • requirements.txt
  • tests/test_rs2gp_helpers.py
  • tests/conftest.py
  • rs2gp.py
  • routes.py

Comment thread README.md Outdated
| `screen.js` | Frontend: alphaTab integration, cursor sync, UI |
| `src/chart-quantize.js` | Pure chart math: measures, quantization, tuning table (no alphaTab dependency) |
| `src/score-builder.js` | bundle → alphaTab `Score` builder (techniques, track/staff/bar assembly) |
| `test/` | Node tests for `src/score-builder.js` (`npm test`) |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document both Node test modules.

Line [56] omits test/chart-quantize.test.mjs, despite npm test running all test/*.test.mjs files and the constitution requiring both suites.

Proposed fix
-| `test/` | Node tests for `src/score-builder.js` (`npm test`) |
+| `test/` | Node tests for `src/score-builder.js` and `src/chart-quantize.js` (`npm test`) |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| `test/` | Node tests for `src/score-builder.js` (`npm test`) |
| `test/` | Node tests for `src/score-builder.js` and `src/chart-quantize.js` (`npm test`) |
🤖 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 `@README.md` at line 56, Update the README test documentation to mention both
Node test modules, including test/chart-quantize.test.mjs alongside the existing
src/score-builder.js suite, while preserving the npm test command description.

Comment thread screen.js
Comment on lines +990 to +994
const notesRef = bundle.notes || null;
const chartChanged = notesRef !== _tvCurrentNotesRef;
const buildInFlight = _tvPendingNotesRef !== null && _tvPendingNotesRef === notesRef;
const previouslyFailed = _tvFailedNotesRef !== null && _tvFailedNotesRef === notesRef;
if (chartChanged && !buildInFlight && !previouslyFailed) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

null doubles as both "no build in flight/failed" and a valid normalized notesRef, defeating both guards.

If bundle.notes is ever falsy (transient frames during a song/arrangement swap), notesRef is null, so _tvPendingNotesRef = null while a build is in flight is indistinguishable from "nothing in flight": buildInFlight stays false, chartChanged stays true (against the previous chart's array), and every frame bumps _tvInitToken and kicks off another build+renderScore — the per-frame storm this guard exists to prevent. The failure path has the same hole (_tvFailedNotesRef = null can never satisfy previouslyFailed), and two consecutive notes-less charts won't rebuild at all since both normalize to the same sentinel.

Separate the "is set" bit from the value.

🐛 Proposed fix
             const notesRef = bundle.notes || null;
             const chartChanged = notesRef !== _tvCurrentNotesRef;
-            const buildInFlight = _tvPendingNotesRef !== null && _tvPendingNotesRef === notesRef;
-            const previouslyFailed = _tvFailedNotesRef !== null && _tvFailedNotesRef === notesRef;
+            const buildInFlight = _tvPendingActive && _tvPendingNotesRef === notesRef;
+            const previouslyFailed = _tvFailedActive && _tvFailedNotesRef === notesRef;

Paired flags, set/cleared wherever the refs are today (declarations near line 211, _tvRenderFromBundle 657/665/677/703, renderFinished 588-589, error 610-611, _teardown 895-896):

let _tvPendingActive = false;  // a build is in flight for _tvPendingNotesRef
let _tvFailedActive = false;   // _tvFailedNotesRef holds a real failure

Also worth tracking chart identity with a monotonic counter rather than bundle.notes identity if the host can hand you a notes-less bundle for a real chart.

🤖 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 990 - 994, Separate ref presence from ref value in
the chart-build guards around _tvPendingNotesRef and _tvFailedNotesRef: add
paired active flags, set them whenever a build starts or fails, and clear them
on successful completion and teardown. Update buildInFlight and previouslyFailed
in _tvRenderFromBundle to use those flags, while preserving the notesRef
comparisons for non-null values; also ensure notes-less bundles receive distinct
chart identity so consecutive null notes can trigger a rebuild.

Comment thread src/chart-quantize.js
Comment on lines +71 to +78
const len = (typeof length === 'number' && length > 0) ? length : 60.0;
return {
startTime: 0.0,
endTime: len,
numBeats: 4,
beatTimes: Array.from({ length: 8 }, (_, i) => i * 0.5),
bpm: 120.0,
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

numBeats (4) and beatTimes (8 entries, spanning only 0-3.5 s) disagree, so fallback measures collapse note onsets.

createBeats sizes the measure as numBeats * SUBDIV = 32 slots, but quantizeThirtySecond walks all 8 beatTimes and can return up to 63 — clamped to slot 31. Combined with beatTimes covering 3.5 s of a len-second measure, every event past the 4th beat piles onto the last slot.

🐛 Make beatTimes match numBeats and span the measure
     return {
         startTime: 0.0,
         endTime: len,
         numBeats: 4,
-        beatTimes: Array.from({ length: 8 }, (_, i) => i * 0.5),
+        beatTimes: Array.from({ length: 4 }, (_, i) => (len * i) / 4),
         bpm: 120.0,
     };

test/chart-quantize.test.mjs only asserts endTime/numBeats/bpm, so this needs no test change.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const len = (typeof length === 'number' && length > 0) ? length : 60.0;
return {
startTime: 0.0,
endTime: len,
numBeats: 4,
beatTimes: Array.from({ length: 8 }, (_, i) => i * 0.5),
bpm: 120.0,
};
const len = (typeof length === 'number' && length > 0) ? length : 60.0;
return {
startTime: 0.0,
endTime: len,
numBeats: 4,
beatTimes: Array.from({ length: 4 }, (_, i) => (len * i) / 4),
bpm: 120.0,
};
🤖 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/chart-quantize.js` around lines 71 - 78, Update the fallback beat
configuration in the returned object so beatTimes matches numBeats and spans the
full len-second measure using the expected subdivision spacing. Keep numBeats at
4 and ensure the generated beatTimes contains the corresponding entries across
the measure rather than the hard-coded 0–3.5 second range.

Comment thread src/score-builder.js Outdated
Comment on lines +107 to +113
if (wire.s < 0 || wire.s >= stringCount) continue;
if (seen.has(wire.s)) continue;
seen.add(wire.s);
const note = new atModel.Note();
// RS string index 0 = lowest; alphaTab Note.string 1 = lowest.
note.string = wire.s + 1;
note.fret = wire.f;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

The bounds check doesn't catch the case it was written for: undefined/NaN/fractional wire.s.

undefined < 0 and undefined >= stringCount are both false (as are all NaN comparisons), so a missing or non-numeric string index sails through and produces note.string = NaN — the exact NaN-pitch corruption the comment above says is being prevented. A fractional s (e.g. 2.5) also passes. wire.f has no guard at all, so a missing fret yields a NaN realValue.

🐛 Proposed fix
             for (const wire of wireNotes) {
-                if (wire.s < 0 || wire.s >= stringCount) continue;
+                if (!Number.isInteger(wire.s) || wire.s < 0 || wire.s >= stringCount) continue;
+                if (!Number.isFinite(wire.f)) continue;
                 if (seen.has(wire.s)) continue;

Worth a test/score-builder.test.mjs case with { s: undefined } / { s: 2.5 } alongside the existing out-of-range test.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (wire.s < 0 || wire.s >= stringCount) continue;
if (seen.has(wire.s)) continue;
seen.add(wire.s);
const note = new atModel.Note();
// RS string index 0 = lowest; alphaTab Note.string 1 = lowest.
note.string = wire.s + 1;
note.fret = wire.f;
if (!Number.isInteger(wire.s) || wire.s < 0 || wire.s >= stringCount) continue;
if (!Number.isFinite(wire.f)) continue;
if (seen.has(wire.s)) continue;
seen.add(wire.s);
const note = new atModel.Note();
// RS string index 0 = lowest; alphaTab Note.string 1 = lowest.
note.string = wire.s + 1;
note.fret = wire.f;
🤖 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/score-builder.js` around lines 107 - 113, Strengthen the validation
before constructing the Note in the wire-processing loop: require wire.s to be a
finite integer within [0, stringCount), and require wire.f to be a valid finite
fret value before assigning either field. Preserve the existing seen filtering
and add score-builder tests covering undefined/fractional string indices and
missing or invalid frets alongside the out-of-range case.

Comment on lines +31 to +35
assert.equal(score.title, 'My Song');
assert.equal(score.artist, 'Someone');
assert.equal(score.tracks[0].name, 'Lead');
assert.equal(score.tempo, 120);
assert.deepEqual(score.tracks[0].staves[0].tuning, [64, 59, 55, 50, 45, 40]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Is Score.tempo pre-initialised (making the current assertion vacuous)?
curl -sL "https://cdn.jsdelivr.net/npm/@coderline/alphatab@1.8.2/dist/alphaTab.js" -o /tmp/at.js
grep -noP 'tempo\s*=\s*\d+' /tmp/at.js | head -20
grep -oP 'tempoAutomations' /tmp/at.js | wc -l

Repository: jphinspace/feedBack-plugin-tabview

Length of output: 175


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== candidates =="
fd -a 'score-builder|package.json|*.test.mjs' . | sed 's#^\./##' | head -80

echo "== package deps =="
if [ -f package.json ]; then
  cat package.json | sed -n '1,160p'
fi

echo "== test file excerpt =="
if [ -f test/score-builder.test.mjs ]; then
  wc -l test/score-builder.test.mjs
  cat -n test/score-builder.test.mjs | sed -n '1,90p'
fi

echo "== buildScoreFromBundle location =="
rg -n "buildScoreFromBundle|tempoAutomations|score\.tempo|masterBar\.tempo" -S .

Repository: jphinspace/feedBack-plugin-tabview

Length of output: 533


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import json, re, urllib.request, pathlib, sys

# Inspect the bundled/minified UMD source for Score tempo initialization and tempoAutomation handling.
for url in (
    "https://cdn.jsdelivr.net/npm/@coderline/alphatab@1.8.2/dist/alphaTab.js",
    "https://cdn.jsdelivr.net/npm/@coderline/alphatab@1.8.2/dist/alphaTab.min.js",
):
    print(f"\n== {url} ==")
    text = urllib.request.urlopen(url, timeout=20).read().decode("utf-8", "replace")
    hits = re.finditer(r"tempo\s*[=<>!]=\s*(\d+)", text)
    matched = list(hits) if matched is None else matched
    print("tempo=NUMBER hits:", len([m for m in hits]) if False else "SKIP")
PY

Repository: jphinspace/feedBack-plugin-tabview

Length of output: 2845


🏁 Script executed:

#!/bin/bash
set -u

echo "== repo files =="
git ls-files | sed -n '1,200p'

echo "== package/imports =="
for f in package.json test/score-builder.test.mjs src/score-builder.js src/score-builder.ts; do
  if [ -f "$f" ]; then
    echo "--- $f ($(wc -l < "$f") lines) ---"
    sed -n '1,140p' "$f" | cat -n
  fi
done

echo "== tempo references =="
rg -n "buildScoreFromBundle|score\.tempo|masterBar\.tempoAutomations|tempoAutomations|tempo:" -S . || true

Repository: jphinspace/feedBack-plugin-tabview

Length of output: 19994


🏁 Script executed:

#!/bin/bash
set -e

echo "== alphaTab bundle search with SSL options =="
for url in \
  "https://cdn.jsdelivr.net/npm/@coderline/alphatab@1.8.2/dist/alphaTab.js" \
  "https://cdn.jsdelivr.net/npm/@coderline/alphatab@1.8.2/dist/alphaTab.min.js"
do
  echo "--- $url ---"
  curl -fsSL "$url" > /tmp/at_bundle.js
  python3 - <<'PY' /tmp/at_bundle.js
import sys
import re
path = sys.argv[1]
text = open(path, encoding="utf-8", errors="replace").read()
print("length:", len(text))
for m in re.finditer(r"\btempo\b", text):
    start = max(0, m.start()-120); end = min(len(text), m.end()+120)
    print(f"\n@ {m.start()}:\n{text[start:end].replace(chr(10), ' ')}")
for m in re.finditer(r"\btempoAutomations\b", text):
    start = max(0, m.start()-180); end = min(len(text), m.end()+180)
    print(f"\nautomation @ {m.start()}:\n{text[start:end].replace(chr(10), ' ')}")
PY
done

Repository: jphinspace/feedBack-plugin-tabview

Length of output: 50390


Assert the tempo automation instead of score.tempo.

buildScoreFromBundle writes tempo as masterBar.tempoAutomations; Score.tempo falls back to 120 only when the first master bar has no tempo automation, so this assertion can pass even if tempo parsing is broken. Checking the created automation exercises the real builder output.

🤖 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 `@test/score-builder.test.mjs` around lines 31 - 35, Update the tempo assertion
in the score builder test to inspect the tempo automation created on the first
master bar by buildScoreFromBundle, rather than asserting score.tempo. Verify
the automation contains the expected tempo value of 120 while leaving the other
score assertions unchanged.

@jphinspace
jphinspace merged commit e9ce374 into develop Jul 24, 2026
1 check passed
jphinspace added a commit that referenced this pull request Jul 24, 2026
* Use chart data from bundle (post-chart-transformation plugins) (#1)

* Read chart data from bundle without gp5

* Code review

* PR comments

* Coderabbit feedback
jphinspace added a commit that referenced this pull request Jul 24, 2026
* Use chart data from bundle (post-chart-transformation plugins) (#1)

* Read chart data from bundle without gp5

* Code review

* PR comments

* Coderabbit feedback

Signed-off-by: Joe <jphinspace@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.

1 participant