# M3: export, CLI and device checkpoint A pack Branch: `m3-export-cli` → `main` ## What changed - **`internal/export`** (build plan 4.4): - `Folder(p, dest, overwrite)` writes `.xpj` and `_[ProjectData]/` with every pool file. The data folder is created even when empty, as the device does. Everything is written under a temporary name in `dest` and renamed at the end; an existing project is only removed once the new one is complete. - `Zip(p, path, overwrite)` puts the same two entries at the zip root. The .xpj is stored (it is already gzip), the WAVs are deflated. It writes to a temp file and renames. - Typed errors for the app: `*ExistsError` (ask, then retry with overwrite) and `*MissingError` (every missing source file in one message, nothing written). - **`internal/wav`**: added `DecodeFile` / `Decode`, which turn 8/16/24/32-bit PCM and 32-bit float into float32 per channel. This is the preview fallback from build plan section 9; the header reader came in M2. - **`internal/project`**: added `PoolFiles()`. - **`cmd/mpckit-cli`**: the throwaway CLI. It starts from a blank or loaded (`-load`) project, then applies `-pad A1=file.wav`, `-tune B1=-24,0`, `-mute A3=1`, `-clear`, `-copy/-move/-swap A1:B5`, `-seq 2=Name,BPM,BARS` (adds the sequence if missing) and `-rmseq` in command-line order, and exports with `-out DIR` or `-zip FILE` (`-force` to replace). `-move` warns when the pad has recorded notes. - **`tools/checkpoint-a/`**: a Go program that builds `mpckit-checkpoint-a.zip`, so it runs the same in cmd, PowerShell and sh with only Go installed: `go run ./tools/checkpoint-a [-zip FILE] [-folder E:\] [-force]`. `-folder` also writes the projects unzipped, e.g. straight onto the card. `tone.go` generates the WAV-pack tone with plain or extensible headers. `README.md` has the per-project checklist and an empty results table. - **Docs**: build plan checkpoint A points at the checklist. - `.gitignore` for the built zip. ## Checkpoint A pack Each risky item is in its own project, so one that fails to load doesn't hide the rest: | Project | Covers | |---|---| | MpckitKit | A1 kit (A1–A4, B1); A2 tuning extremes on B2–B7 (±24 st, ±90 ct, both combined); A3 hats choking in group 1; A5 sequences of 1 and 64 bars | | MpckitMute | A3: mute groups 16 and 32 written to the file | | MpckitTempo | A5: 30, 300, 20 and 999 BPM | | MpckitWav | Extensible-header WAVs (48k/24 stereo, 44.1k/16 stereo and mono) against a plain control | ## Testing `go vet ./...` and `go test ./...` pass. - **Export**: the folder and zip exports of the model-built MpckitT1 hold a .xpj that decompresses byte-identical to `testdata/accepted/MpckitT1.xpj` and WAVs byte-identical to their sources, with the expected names. Also covered: empty project (empty data folder), refusing then replacing an existing export (no stale files kept, no temp files left), all missing sources reported together with nothing written, and a loaded DemoFile exported under a new name. - **CLI**: `mpckit-cli -name MpckitT1 … -tune B1=5,0 -seq 1=Verse,96,8 -seq 2=Chorus,96,4` reproduces MpckitT1.xpj byte-identical. Pad and sequence parsing is unit-tested. - **Decoder**: the five 44.1 kHz files in the WAV test pack decode to within 1/64 of the 16-bit control; boundary values tested for each format. - **Windows**: `GOOS=windows go vet ./...` and `go build` of the CLI and the pack builder pass. (Not run on Windows itself.) The first version of the pack was built by a shell script driving the CLI; the Go builder's output is byte-identical to it, both in the zip and with `-folder`. A second `-folder` run refuses to overwrite without `-force`. - **Tone**: the plain 44.1k/16 mono output is byte-identical to the WAV pack's control file. Python's `wave` module reads its extensible output. - **Pack**: extracted and checked with Python's own json/gzip (not our reader): header, pool lists match the files in each data folder, tuning/pitch, mute groups, and all length fields. `sliceInfo.End` for each DemoFile sample matches the value the device itself wrote. ## Not done here M3's done-when also needs **device checkpoint A to pass**, which is a run on the MPC Sample. No UI work starts until then. Once results are in, I'll record them in the format doc and build plan and update the limits (`MaxMuteGroup`, `MaxBars`, BPM range).