Close three real parser divergences the conformance suite flagged on the device side (pico-cp + pico-explorer) — cases where the firmware produced a different groove/sound than the web for the same patch: - Euclidean (k,n,rot) shorthand (e.g. kick:4(3,8)) — was silently dropped to a plain bar; now expands to the same hits as engine.js (added _euclid + parsing). - GM note-number lane sounds (e.g. 36:4) — now resolve to the voice name (GM_NUM). - Unknown sound names fall back to beep, matching the web. vol/cd are NOT carried by the firmware by design: they are web-authoring fields (the device has a hardware volume knob and no count-in). Documented as an intentional, permanent host difference rather than a bug; the vol-and-countin vector stays as expectFail[py] to mark the boundary. tests/adapters/py_adapter.py: extract the new SOUND_GM/GM_NUM/_euclid nodes. fixtures: euclid/unknown-sound/gm-note-number now pass on both engines. docs §6 updated. node tests/run.mjs: 33 pass / 9 known, round-trips stable. pico-explorer parser spot-checked identical to pico-cp. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| adapters | ||
| fixtures | ||
| .gitignore | ||
| README.md | ||
| run.mjs | ||
Track-format conformance tests
Golden-vector suite that pins the track ("program"/"patch") format to a single meaning and checks that both implementations agree:
- web —
src/engine.js - firmware —
pico-cp/app.py
The spec is docs/track-format.md. Any new implementation (e.g. a Rust engine) must pass the
same vectors — that is what keeps "the same groove on the device and in the browser" true.
Run
node tests/run.mjs # table of pass / known-divergence / FAIL per case
node tests/run.mjs -v # also print expected-vs-actual diffs for unexpected failures
Exit code is non-zero on any unexpected failure or round-trip (idempotency) break, so it works as a CI gate.
Layout
fixtures/track-format.json— the vectors. Each hasin(a patch),norm(expected normalized meaning, see spec §5), astatus, and optionalexpectFaillisting impls known to differ today.adapters/js_adapter.mjs— loads the realsrc/engine.jsgrammar (no copy) and normalizes.adapters/py_adapter.py— extracts the realpico-cp/app.pygrammar functions viaast(no copy) and normalizes.run.mjs— runs every vector through both adapters and reports.
Reading the result
✓ pass— implementation matches the spec for that vector.· known— a divergence/feature listed inexpectFail; expected, not a failure.✗ FAIL— an unexpected mismatch (a regression). Investigate.★ fixed— an impl listed inexpectFailnow passes; remove it fromexpectFail.
When you fix a divergence in code, delete that impl from the case's expectFail. When you
implement the new playback-flow tokens (rep / end), those cases flip to pass.