Spaces:
Running
Running
Download scripts/test_subset_acceptance.mjs from jasonmdong/notepilot: direct link, hf CLI and curl.
- Browser
- Download file 4.57 kB
-
https://huggingface.co/spaces/jasonmdong/notepilot/resolve/main/scripts/test_subset_acceptance.mjs
- Command line
-
hf download hf://spaces/jasonmdong/notepilot/scripts/test_subset_acceptance.mjs
-
curl -L -o test_subset_acceptance.mjs https://huggingface.co/spaces/jasonmdong/notepilot/resolve/main/scripts/test_subset_acceptance.mjs
4.57 kB
| // The authoritative acceptance rule: E subset-of D, singles and chords alike. | |
| // The rule itself is pure, so it is executed here (not pattern-matched); the | |
| // wiring around it is asserted against the served source. | |
| import assert from 'node:assert/strict'; | |
| import fs from 'node:fs'; | |
| import vm from 'node:vm'; | |
| const app = fs.readFileSync(new URL('../static/app.js', import.meta.url), 'utf8'); | |
| // ---- run the real helper ------------------------------------------------- | |
| const src = app.slice(app.indexOf('function expectedSubsetOfDetected'), | |
| app.indexOf('function detectedPitchesFromSalience')); | |
| const ctx = vm.createContext({}); | |
| vm.runInContext(src + '\nthis.f = expectedSubsetOfDetected;', ctx); | |
| const sub = ctx.f; | |
| const ACCEPT = true, REJECT = false; | |
| const cases = [ | |
| // singles | |
| ['single exact', [67], [67], ACCEPT], | |
| ['single + one extra', [67], [48, 67], ACCEPT], | |
| ['single + many extras', [67], [48, 60, 64, 67, 72], ACCEPT], | |
| ['single wrong neighbour', [67], [66], REJECT], | |
| ['single absent', [67], [48, 60, 64], REJECT], | |
| // chords | |
| ['chord exact', [67, 71], [67, 71], ACCEPT], | |
| ['chord + extras', [67, 71], [48, 52, 55, 67, 71], ACCEPT], | |
| ['chord missing one', [67, 71], [48, 52, 55, 67], REJECT], | |
| ['chord one wrong', [67, 71], [67, 72], REJECT], | |
| // larger chord | |
| ['triad + extras', [48, 52, 55], [48, 52, 55, 60, 67], ACCEPT], | |
| ['triad missing one', [48, 52, 55], [48, 52], REJECT], | |
| // the spec's numeric examples | |
| ['spec {4,6} in {1..5}', [4, 6], [1, 2, 3, 4, 5], REJECT], | |
| ['spec {4,5} in {1..5}', [4, 5], [1, 2, 3, 4, 5], ACCEPT], | |
| // extra-hand notes | |
| ['extra hand, single', [67], [48, 52, 55, 67], ACCEPT], | |
| ['extra hand, partial chord',[67, 71], [48, 52, 55, 67], REJECT], | |
| ]; | |
| let pass = 0; | |
| for (const [name, E, D, want] of cases) { | |
| const got = sub(E, D); | |
| assert.equal(got, want, `${name}: expected ${want}, got ${got} E=${JSON.stringify(E)} D=${JSON.stringify(D)}`); | |
| pass++; | |
| } | |
| // degenerate input must never accept | |
| assert.equal(sub([], [60]), false, 'empty expected must not accept'); | |
| assert.equal(sub([60], []), false, 'empty detected must not accept'); | |
| // ---- wiring assertions --------------------------------------------------- | |
| const frame = app.slice(app.indexOf('function handleFollowerFrame'), app.indexOf('function traceFollowerFrame')); | |
| // compare against the real CALL, not the comment that mentions it | |
| assert.ok(frame.indexOf('tryGestureSubsetAdvance()') < frame.indexOf('if (out.advance) deliverFollowerAdvance('), | |
| 'the subset rule must run BEFORE the follower proposal (no follower veto)'); | |
| const accept = app.slice(app.indexOf('function tryGestureSubsetAdvance'), app.indexOf('function logGesture')); | |
| assert.match(accept, /maxJump: 0/, 'exactly one event, never a jump'); | |
| assert.match(accept, /attack\.serial !== g\.attackSerial/, 'gesture must be bound to its own token'); | |
| assert.match(accept, /attack\.serial > _hostConsumedAttackSerial/, 'token must be unconsumed'); | |
| assert.match(accept, /g\.consumed = true/, 'gesture consumed exactly once'); | |
| assert.match(accept, /_hostConsumedAttackSerial = attack\.serial/); | |
| assert.match(accept, /seek\(state\.tracker\.position/, 'follower re-anchored after direct acceptance'); | |
| // singles and chords must NOT diverge in this path | |
| assert.doesNotMatch(accept, /length === 1|length > 1|isChord/, 'singles and chords share one rule'); | |
| // D must not be built from the score | |
| const build = app.slice(app.indexOf('function detectedPitchesFromSalience'), app.indexOf('function beginGesture')); | |
| for (const forbidden of ['expectedPitches', 'tracker.score', '_minFreq', 'leadPitchFromEvent']) { | |
| assert.ok(!build.includes(forbidden), `D construction must not consult ${forbidden}`); | |
| } | |
| // observability | |
| const log = app.slice(app.indexOf('function logGesture'), app.indexOf('function logGesture') + 1600); | |
| for (const field of ['gestureId','detectedPitches','expectedPitches','subsetSatisfied', | |
| 'missingExpectedPitches','extraDetectedPitches','accepted', | |
| 'trackerBefore','trackerAfter','followerPositionBefore','followerPositionAfter']) { | |
| assert.ok(log.includes(field), `gesture record must carry ${field}`); | |
| } | |
| console.log(`PASS: subset acceptance — ${pass} matrix cases, singles+chords unified, follower cannot veto, D is score-independent`); | |