From 36034b27f39bcd23012dbb0bdecf0a30af43e230 Mon Sep 17 00:00:00 2001 From: Johan Stolk Date: Sun, 11 Oct 2026 10:45:06 +0200 Subject: [PATCH 1/4] fix(diagnostic): launch the renamed feedBack-diagnostic pack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Core renamed the seeded calibration pack from slopsmith-diagnostic-basic-guitar.sloppak to feedBack-diagnostic-basic-guitar.sloppak (and its title/artist to "FeedBack Diagnostic — Basic Guitar" / "FeedBack") in #900. The diagnostic launcher still asked for the old path, so the backend answered "File not found" and the engine verifier got 0 notes. Point dlcRelativePath at the new name, match both names when recognising a diagnostic session (markers are compared lowercased), and update the title/artist fallback. Adds tests for the filename recognition. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Johan Stolk --- screen.js | 13 +++++++++---- test/_loader.js | 1 + test/diagnostic_filename.test.js | 33 ++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 test/diagnostic_filename.test.js diff --git a/screen.js b/screen.js index bd9025c..1767a8b 100644 --- a/screen.js +++ b/screen.js @@ -264,7 +264,10 @@ function _ndSyncMlGate(token, wantsMl, audio) { } catch (_) { /* downlevel / transient — leave state so a later sync retries */ } } +// Lowercase — compared against the lowercased filename. Core renamed the +// seeded pack to feedBack-… (#900); keep the legacy name for older libraries. const _ND_DIAGNOSTIC_FILENAME_MARKERS = [ + 'feedback-diagnostic-basic-guitar.sloppak', 'slopsmith-diagnostic-basic-guitar.sloppak', ]; @@ -16777,11 +16780,13 @@ function createNoteDetector(options = {}) { const _DIAGNOSTIC_TRACK_CATALOG = [ { id: 'basic-guitar-6', - title: 'Slopsmith Diagnostic — Basic Guitar', - artist: 'Slopsmith', + // Core seeds this as feedBack-diagnostic-… (#900; formerly + // slopsmith-diagnostic-…). The filename match covers both names. + title: 'FeedBack Diagnostic — Basic Guitar', + artist: 'FeedBack', arrangement: 'Diagnostic Guitar', - filenameIncludes: 'slopsmith-diagnostic-basic-guitar.sloppak', - dlcRelativePath: 'diagnostics-builtin/slopsmith-diagnostic-basic-guitar.sloppak', + filenameIncludes: 'diagnostic-basic-guitar.sloppak', + dlcRelativePath: 'diagnostics-builtin/feedBack-diagnostic-basic-guitar.sloppak', instrument: 'guitar', stringCount: 6, reportProfile: 'basic-guitar-v1', diff --git a/test/_loader.js b/test/_loader.js index 660c9f3..8b61c53 100644 --- a/test/_loader.js +++ b/test/_loader.js @@ -253,6 +253,7 @@ function loadDetectionCore({ sandboxBeforeRun } = {}) { // do. Expose the raw functions; tests pass state in directly. return { yinDetect: rewrapYin(sandbox._ndYinDetect), + filenameLooksDiagnostic: sandbox._ndFilenameLooksDiagnostic, hpsDetect: rewrapYin(sandbox._ndHpsDetect), freqToMidi: sandbox._ndFreqToMidi, midiFromStringFret: midiFromStringFretWrapped, diff --git a/test/diagnostic_filename.test.js b/test/diagnostic_filename.test.js new file mode 100644 index 0000000..e64be37 --- /dev/null +++ b/test/diagnostic_filename.test.js @@ -0,0 +1,33 @@ +// The built-in calibration pack was renamed in core from +// slopsmith-diagnostic-basic-guitar.sloppak to feedBack-diagnostic-… (core +// #900). Both names must still be recognised as the diagnostic track, with the +// case-insensitive match the library's filenames need. +const { test } = require('node:test'); +const assert = require('node:assert'); +const fs = require('node:fs'); +const path = require('node:path'); +const { loadDetectionCore } = require('./_loader'); + +const { filenameLooksDiagnostic } = loadDetectionCore(); + +test('current core name (feedBack-…) is a diagnostic track', () => { + assert.strictEqual( + filenameLooksDiagnostic('diagnostics-builtin/feedBack-diagnostic-basic-guitar.sloppak'), true); +}); + +test('legacy name (slopsmith-…) is still a diagnostic track', () => { + assert.strictEqual( + filenameLooksDiagnostic('diagnostics-builtin/slopsmith-diagnostic-basic-guitar.sloppak'), true); +}); + +test('ordinary songs are not diagnostic tracks', () => { + assert.strictEqual(filenameLooksDiagnostic('Uriah Heep - Shadows Of Grief.feedpak'), false); + assert.strictEqual(filenameLooksDiagnostic(''), false); + assert.strictEqual(filenameLooksDiagnostic(null), false); +}); + +test('the launcher points at the pack core seeds today', () => { + const src = fs.readFileSync(path.join(__dirname, '..', 'screen.js'), 'utf8'); + assert.match(src, + /dlcRelativePath: 'diagnostics-builtin\/feedBack-diagnostic-basic-guitar\.sloppak'/); +}); From 5501f43f2563d181e879b434b52c6b73c3a8e54a Mon Sep 17 00:00:00 2001 From: Johan Stolk Date: Sun, 11 Oct 2026 13:36:55 +0200 Subject: [PATCH 2/4] fix(diagnostic): match only the two real diagnostic pack names The previous commit widened the catalog's filenameIncludes to the suffix diagnostic-basic-guitar.sloppak, so an unrelated pack with that suffix would be taken for the diagnostic track (and the return-to-previous-song capture skipped). The catalog entry now reuses _ND_DIAGNOSTIC_FILENAME_MARKERS, the new and legacy full names, through a small _ndTrackMatchesFilename helper. Reported by CodeRabbit on #83. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Johan Stolk --- screen.js | 18 ++++++++++++------ test/_loader.js | 1 + test/diagnostic_filename.test.js | 19 ++++++++++++++++++- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/screen.js b/screen.js index 1767a8b..b22a624 100644 --- a/screen.js +++ b/screen.js @@ -271,6 +271,14 @@ const _ND_DIAGNOSTIC_FILENAME_MARKERS = [ 'slopsmith-diagnostic-basic-guitar.sloppak', ]; +// True when a lowercased filename contains one of the track's pack names. +// filenameIncludes is a string or a list of names. +function _ndTrackMatchesFilename(track, lowerFn) { + if (!track || !track.filenameIncludes || !lowerFn) return false; + return [].concat(track.filenameIncludes) + .some((m) => lowerFn.includes(String(m).toLowerCase())); +} + function _ndFilenameLooksDiagnostic(fn) { const lower = String(fn || '').toLowerCase(); if (!lower) return false; @@ -16781,11 +16789,11 @@ function createNoteDetector(options = {}) { { id: 'basic-guitar-6', // Core seeds this as feedBack-diagnostic-… (#900; formerly - // slopsmith-diagnostic-…). The filename match covers both names. + // slopsmith-diagnostic-…). Match exactly those two pack names. title: 'FeedBack Diagnostic — Basic Guitar', artist: 'FeedBack', arrangement: 'Diagnostic Guitar', - filenameIncludes: 'diagnostic-basic-guitar.sloppak', + filenameIncludes: _ND_DIAGNOSTIC_FILENAME_MARKERS, dlcRelativePath: 'diagnostics-builtin/feedBack-diagnostic-basic-guitar.sloppak', instrument: 'guitar', stringCount: 6, @@ -16839,8 +16847,7 @@ function createNoteDetector(options = {}) { if (!diagFn) return; const prevLower = prevFn.toLowerCase(); if (prevLower === diagFn.toLowerCase()) return; - if (track.filenameIncludes - && prevLower.includes(String(track.filenameIncludes).toLowerCase())) { + if (_ndTrackMatchesFilename(track, prevLower)) { return; } const hw = resolveHw(); @@ -17004,8 +17011,7 @@ function createNoteDetector(options = {}) { const currentHw = resolveHw(); const info = (currentHw && currentHw.getSongInfo) ? currentHw.getSongInfo() : {}; for (const track of _DIAGNOSTIC_TRACK_CATALOG) { - if (track.filenameIncludes - && fn.includes(String(track.filenameIncludes).toLowerCase())) { + if (_ndTrackMatchesFilename(track, fn)) { return track; } } diff --git a/test/_loader.js b/test/_loader.js index 8b61c53..090bc6e 100644 --- a/test/_loader.js +++ b/test/_loader.js @@ -254,6 +254,7 @@ function loadDetectionCore({ sandboxBeforeRun } = {}) { return { yinDetect: rewrapYin(sandbox._ndYinDetect), filenameLooksDiagnostic: sandbox._ndFilenameLooksDiagnostic, + trackMatchesFilename: sandbox._ndTrackMatchesFilename, hpsDetect: rewrapYin(sandbox._ndHpsDetect), freqToMidi: sandbox._ndFreqToMidi, midiFromStringFret: midiFromStringFretWrapped, diff --git a/test/diagnostic_filename.test.js b/test/diagnostic_filename.test.js index e64be37..1200d4e 100644 --- a/test/diagnostic_filename.test.js +++ b/test/diagnostic_filename.test.js @@ -8,7 +8,7 @@ const fs = require('node:fs'); const path = require('node:path'); const { loadDetectionCore } = require('./_loader'); -const { filenameLooksDiagnostic } = loadDetectionCore(); +const { filenameLooksDiagnostic, trackMatchesFilename } = loadDetectionCore(); test('current core name (feedBack-…) is a diagnostic track', () => { assert.strictEqual( @@ -31,3 +31,20 @@ test('the launcher points at the pack core seeds today', () => { assert.match(src, /dlcRelativePath: 'diagnostics-builtin\/feedBack-diagnostic-basic-guitar\.sloppak'/); }); + +test('the catalog matches only the two real pack names, not any similar suffix', () => { + const track = { filenameIncludes: ['feedback-diagnostic-basic-guitar.sloppak', + 'slopsmith-diagnostic-basic-guitar.sloppak'] }; + assert.strictEqual(trackMatchesFilename(track, + 'diagnostics-builtin/feedback-diagnostic-basic-guitar.sloppak'), true); + assert.strictEqual(trackMatchesFilename(track, + 'diagnostics-builtin/slopsmith-diagnostic-basic-guitar.sloppak'), true); + assert.strictEqual(trackMatchesFilename(track, 'my-own-diagnostic-basic-guitar.sloppak'), false); + assert.strictEqual(trackMatchesFilename(track, ''), false); + assert.strictEqual(trackMatchesFilename({ filenameIncludes: 'x.sloppak' }, 'a/x.sloppak'), true); +}); + +test('the catalog entry reuses the two filename markers', () => { + const src = fs.readFileSync(path.join(__dirname, '..', 'screen.js'), 'utf8'); + assert.match(src, /filenameIncludes: _ND_DIAGNOSTIC_FILENAME_MARKERS,/); +}); From 988e957df0b393b2f7bc046d1755891c3f10d9b3 Mon Sep 17 00:00:00 2001 From: Johan Stolk Date: Sun, 11 Oct 2026 13:56:07 +0200 Subject: [PATCH 3/4] fix(diagnostic): compare the exact pack basename Containment still matched names like my-feedback-diagnostic-basic-guitar .sloppak. Compare the (already URI-decoded) filename's last path segment against the two pack names instead, as the CodeRabbit finding on #83 asked. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Johan Stolk --- screen.js | 7 ++++--- test/diagnostic_filename.test.js | 3 +++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/screen.js b/screen.js index b22a624..8b173f6 100644 --- a/screen.js +++ b/screen.js @@ -271,12 +271,13 @@ const _ND_DIAGNOSTIC_FILENAME_MARKERS = [ 'slopsmith-diagnostic-basic-guitar.sloppak', ]; -// True when a lowercased filename contains one of the track's pack names. -// filenameIncludes is a string or a list of names. +// True when a lowercased (already URI-decoded) filename's basename is exactly +// one of the track's pack names. filenameIncludes is a string or a list. function _ndTrackMatchesFilename(track, lowerFn) { if (!track || !track.filenameIncludes || !lowerFn) return false; + const base = String(lowerFn).split(/[\\/]/).pop(); return [].concat(track.filenameIncludes) - .some((m) => lowerFn.includes(String(m).toLowerCase())); + .some((m) => base === String(m).toLowerCase()); } function _ndFilenameLooksDiagnostic(fn) { diff --git a/test/diagnostic_filename.test.js b/test/diagnostic_filename.test.js index 1200d4e..a862130 100644 --- a/test/diagnostic_filename.test.js +++ b/test/diagnostic_filename.test.js @@ -40,6 +40,9 @@ test('the catalog matches only the two real pack names, not any similar suffix', assert.strictEqual(trackMatchesFilename(track, 'diagnostics-builtin/slopsmith-diagnostic-basic-guitar.sloppak'), true); assert.strictEqual(trackMatchesFilename(track, 'my-own-diagnostic-basic-guitar.sloppak'), false); + assert.strictEqual(trackMatchesFilename(track, 'my-feedback-diagnostic-basic-guitar.sloppak'), false); + assert.strictEqual(trackMatchesFilename(track, 'feedback-diagnostic-basic-guitar.sloppak'), true); + assert.strictEqual(trackMatchesFilename(track, 'sub\\dir\\slopsmith-diagnostic-basic-guitar.sloppak'), true); assert.strictEqual(trackMatchesFilename(track, ''), false); assert.strictEqual(trackMatchesFilename({ filenameIncludes: 'x.sloppak' }, 'a/x.sloppak'), true); }); From 17d0f43837099ebdbbbcb69668e6f2a4f366e43a Mon Sep 17 00:00:00 2001 From: Johan Stolk Date: Sun, 11 Oct 2026 19:48:01 +0200 Subject: [PATCH 4/4] fix(diagnostic): one exact-basename rule for diagnostic filenames _ndFilenameLooksDiagnostic (used by the playSong wrapper to keep or clear the diagnostic return state) still matched by substring, so a look-alike pack kept stale return state while _getDiagnosticTrackForSession rejected it. Route it through _ndTrackMatchesFilename so both agree. Reported by CodeRabbit on #83. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Johan Stolk --- screen.js | 8 +++++--- test/diagnostic_filename.test.js | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/screen.js b/screen.js index 8b173f6..f8f123b 100644 --- a/screen.js +++ b/screen.js @@ -280,10 +280,12 @@ function _ndTrackMatchesFilename(track, lowerFn) { .some((m) => base === String(m).toLowerCase()); } +// Same exact-basename rule as the catalog match, so the playSong wrapper and +// _getDiagnosticTrackForSession agree on what counts as the diagnostic pack. function _ndFilenameLooksDiagnostic(fn) { - const lower = String(fn || '').toLowerCase(); - if (!lower) return false; - return _ND_DIAGNOSTIC_FILENAME_MARKERS.some((m) => lower.includes(m)); + return _ndTrackMatchesFilename( + { filenameIncludes: _ND_DIAGNOSTIC_FILENAME_MARKERS }, + String(fn || '').toLowerCase()); } // Escape untrusted text before interpolating into an innerHTML string. diff --git a/test/diagnostic_filename.test.js b/test/diagnostic_filename.test.js index a862130..4d76ece 100644 --- a/test/diagnostic_filename.test.js +++ b/test/diagnostic_filename.test.js @@ -24,6 +24,9 @@ test('ordinary songs are not diagnostic tracks', () => { assert.strictEqual(filenameLooksDiagnostic('Uriah Heep - Shadows Of Grief.feedpak'), false); assert.strictEqual(filenameLooksDiagnostic(''), false); assert.strictEqual(filenameLooksDiagnostic(null), false); + // Look-alikes are not the diagnostic pack (same rule as the catalog match). + assert.strictEqual(filenameLooksDiagnostic('my-feedBack-diagnostic-basic-guitar.sloppak'), false); + assert.strictEqual(filenameLooksDiagnostic('feedBack-diagnostic-basic-guitar.sloppak.bak'), false); }); test('the launcher points at the pack core seeds today', () => {