metronome/tests
Me Here 9701f49913 Firmware: parse euclid, GM note-numbers, and unknown-sound fallback
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>
2026-05-31 00:15:25 -05:00
..
adapters Firmware: parse euclid, GM note-numbers, and unknown-sound fallback 2026-05-31 00:15:25 -05:00
fixtures Firmware: parse euclid, GM note-numbers, and unknown-sound fallback 2026-05-31 00:15:25 -05:00
.gitignore Formalize track format: spec + golden-vector conformance suite 2026-05-30 23:54:20 -05:00
README.md Formalize track format: spec + golden-vector conformance suite 2026-05-30 23:54:20 -05:00
run.mjs Formalize track format: spec + golden-vector conformance suite 2026-05-30 23:54:20 -05:00

Track-format conformance tests

Golden-vector suite that pins the track ("program"/"patch") format to a single meaning and checks that both implementations agree:

  • websrc/engine.js
  • firmwarepico-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 has in (a patch), norm (expected normalized meaning, see spec §5), a status, and optional expectFail listing impls known to differ today.
  • adapters/js_adapter.mjs — loads the real src/engine.js grammar (no copy) and normalizes.
  • adapters/py_adapter.py — extracts the real pico-cp/app.py grammar functions via ast (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 in expectFail; expected, not a failure.
  • ✗ FAIL — an unexpected mismatch (a regression). Investigate.
  • ★ fixed — an impl listed in expectFail now passes; remove it from expectFail.

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.