Single source of truth for the track ("program"/"patch") grammar, which was
implemented by hand in src/engine.js and pico-cp/app.py with no cross-check and
had quietly drifted.
- docs/track-format.md: formal grammar, container (programs.json) schema with a
version field, the new per-track playback-flow model (rep/end + relative goto;
default = loop forever), normalization rules, and a list of known divergences.
- tests/: golden vectors + a runner that loads the REAL engine.js and app.py
grammar (no copies; app.py via ast extraction) and compares both against the
spec. Exit non-zero on unexpected mismatch or round-trip break -> usable as CI.
Surfaces real divergences for follow-up: default accent pattern (no =pattern)
differs web vs device and affects shipped presets; euclid not parsed on device;
vol/cd dropped on device; unknown-sound fallback; tempo clamp; empty patch.
The rep/end playback-flow vectors are the acceptance test for building that.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
40 lines
1.7 KiB
Markdown
40 lines
1.7 KiB
Markdown
# 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
|
|
|
|
```sh
|
|
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`.
|