memlnaut-nisps/tests/cpp
monkey-w1n5t0n dbe0f5d8ba fix(ml): one named example capacity; train() and trainAsync() no longer diverge
Phase 2, S35. Two real defects from one root cause, both confirmed by trace
rather than taken from the audit:

1. Divergence. WasmIML built its TS Dataset mirror with a cap of 100 while
   every addExample() ALSO pushed into the C++ FIFO ring, capped at 128. Since
   train() reads the C++ ring and trainAsync() reads the TS mirror, past 100
   examples the two trained on different datasets — silently.
2. Latent OOB read. nisps_ml_train sizes its sample-weight span by the C++
   side's example_count() (up to 128), but wasm-iml.ts allocates that heap
   buffer from the TS dataset's size (<=100). Once the ring exceeds the mirror,
   the span reads past the end of the caller's allocation.

Fix: name the capacity ONCE as nisps::ml::kDefaultMaxExamples = 128, used by
FixedStorage's default template arg, DynamicStorage's default ctor arg, and the
MLP<> alias (which is the only real FixedStorage instantiation path and carried
its own independent 128 literal — the last copy of this dual truth). Expose it
through nisps_ml_describe and have the TS side read it instead of hardcoding.
Dataset's constructor default is removed entirely: a default was what invited
this bug class, and the sole call site now always supplies the describe() value.

ABI NOTE: this extends nisps_ml_describe from a 6-int to a 7-int descriptor.
nisps_ml_describe always writes 7 ints regardless of the caller's buffer, so
every call site had to grow in the same change or it would overflow the WASM
heap by 4 bytes per call. All five sites updated: three in wasm-iml.ts (init
defaults, init per-instance, reshape re-describe — the finding said there were
two), one in wasm-worker.ts, one in tests/cpp/parity_wasm.mjs. The parity
harness's expected-dims check now also pins the new max_examples slot.

Regression test: tests/cpp/test_mlp_storage_defaults.cpp — pins the two storage
policies to one constant, and drives MLPCore<DynamicStorage> exactly as
bindings.cpp does past the old TS cap, asserting it saturates at 128 and not at
100. Fail-before/pass-after confirmed by temporarily setting the constant to
100: 2 failures, named. Reverted: green.

Audit correction: the cited dataset.ts:81 is the FIFO eviction check; the
hardcoded default was at dataset.ts:45.

Gates: run-all-tests.sh ALL GREEN, parity PASS.
2026-07-21 13:22:38 +02:00
..
.gitignore Stream 11: verification infrastructure (golden vectors + parity + lint + CI + Playwright migration) 2026-04-29 19:50:55 +03:00
engine_impulse.cpp Stream 11: verification infrastructure (golden vectors + parity + lint + CI + Playwright migration) 2026-04-29 19:50:55 +03:00
engine_impulse_baseline.bin Stream 11: verification infrastructure (golden vectors + parity + lint + CI + Playwright migration) 2026-04-29 19:50:55 +03:00
ml_golden_vectors.cpp Stream 11: verification infrastructure (golden vectors + parity + lint + CI + Playwright migration) 2026-04-29 19:50:55 +03:00
parity_check.cpp feat(pipeline)!: P4 core — input/output chains + curve catalog in nisps/ 2026-07-18 11:52:53 +02:00
parity_diff.mjs feat(pipeline)!: P4 core — input/output chains + curve catalog in nisps/ 2026-07-18 11:52:53 +02:00
parity_wasm.mjs fix(ml): one named example capacity; train() and trainAsync() no longer diverge 2026-07-21 13:22:38 +02:00
test_dsp_biquad.cpp feat(nisps/dsp): lean DSP primitives ported from maximilian (meml-1v6) 2026-04-29 16:08:49 +03:00
test_dsp_delay.cpp feat(nisps/dsp): lean DSP primitives ported from maximilian (meml-1v6) 2026-04-29 16:08:49 +03:00
test_dsp_pitch_shift.cpp feat(nisps/dsp): lean DSP primitives ported from maximilian (meml-1v6) 2026-04-29 16:08:49 +03:00
test_dsp_reverb.cpp feat(nisps/dsp): lean DSP primitives ported from maximilian (meml-1v6) 2026-04-29 16:08:49 +03:00
test_engine_analysis.cpp feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6) 2026-04-29 16:09:12 +03:00
test_engine_breakor.cpp feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6) 2026-04-29 16:09:12 +03:00
test_engine_channel_strip.cpp feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6) 2026-04-29 16:09:12 +03:00
test_engine_elysiamorf.cpp feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6) 2026-04-29 16:09:12 +03:00
test_engine_memlcelium.cpp feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6) 2026-04-29 16:09:12 +03:00
test_engine_no_op.cpp feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6) 2026-04-29 16:09:12 +03:00
test_engine_paf_synth.cpp feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6) 2026-04-29 16:09:12 +03:00
test_engine_verb_fx.cpp feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6) 2026-04-29 16:09:12 +03:00
test_engine_xiasri.cpp feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6) 2026-04-29 16:09:12 +03:00
test_helpers.hpp feat: nisps build + host test harness 2026-04-29 15:22:01 +03:00
test_main.cpp feat: nisps build + host test harness 2026-04-29 15:22:01 +03:00
test_math.cpp feat: nisps build + host test harness 2026-04-29 15:22:01 +03:00
test_mlp_feedback.cpp feat(ml)!: P3 core — geometric dislike in nisps/, jolt/OU + geo ABI 2026-07-14 04:16:21 +02:00
test_mlp_geo_dislike.cpp refactor(nisps): delete dead core/ML mass; keep the legacy feedback modes 2026-07-21 12:48:27 +02:00
test_mlp_inference.cpp feat(nisps/ml): MLP library with fixed-architecture template + spread-aware RL (meml-wmh) 2026-04-29 15:55:43 +03:00
test_mlp_init.cpp feat(nisps/ml): MLP library with fixed-architecture template + spread-aware RL (meml-wmh) 2026-04-29 15:55:43 +03:00
test_mlp_jolt.cpp feat(slp-workshop): new MEMLCelium-based mode + port Jolt & OU-noise RL learning 2026-06-28 22:15:36 +02:00
test_mlp_loss.cpp feat(nisps/ml): MLP library with fixed-architecture template + spread-aware RL (meml-wmh) 2026-04-29 15:55:43 +03:00
test_mlp_ou_noise.cpp feat(slp-workshop): new MEMLCelium-based mode + port Jolt & OU-noise RL learning 2026-06-28 22:15:36 +02:00
test_mlp_rl.cpp feat(nisps/ml): MLP library with fixed-architecture template + spread-aware RL (meml-wmh) 2026-04-29 15:55:43 +03:00
test_mlp_serialize.cpp feat(nisps/ml): MLP library with fixed-architecture template + spread-aware RL (meml-wmh) 2026-04-29 15:55:43 +03:00
test_mlp_storage_defaults.cpp fix(ml): one named example capacity; train() and trainAsync() no longer diverge 2026-07-21 13:22:38 +02:00
test_mlp_storage_parity.cpp feat(wasm)!: P2.2 — nisps_ml_create honours dims; runtime-shaped browser MLP + reshape 2026-07-14 03:38:06 +02:00
test_mlp_training.cpp feat(nisps/ml): MLP library with fixed-architecture template + spread-aware RL (meml-wmh) 2026-04-29 15:55:43 +03:00
test_mode_breakor_events.cpp test(nisps/modes): host C++ tests for stream 4 mode layer (meml-beb) 2026-04-29 16:27:03 +03:00
test_mode_concepts.cpp feat(slp-workshop): new MEMLCelium-based mode + port Jolt & OU-noise RL learning 2026-06-28 22:15:36 +02:00
test_mode_learning.cpp feat(slp-workshop): new MEMLCelium-based mode + port Jolt & OU-noise RL learning 2026-06-28 22:15:36 +02:00
test_mode_paf_synth.cpp feat(modes): ModeBase input-pin API for single/dual joystick 2026-06-28 21:17:51 +02:00
test_mode_voice_space.cpp test(nisps/modes): host C++ tests for stream 4 mode layer (meml-beb) 2026-04-29 16:27:03 +03:00
test_pipeline.cpp feat(pipeline)!: P4 core — input/output chains + curve catalog in nisps/ 2026-07-18 11:52:53 +02:00
test_ring_buffer.cpp feat: nisps build + host test harness 2026-04-29 15:22:01 +03:00
test_rng.cpp feat: nisps build + host test harness 2026-04-29 15:22:01 +03:00
test_vcv_iml_parity.cpp feat(vcv): reunify module onto core MLP — thin iml.hpp adapter (P6) 2026-07-18 13:01:28 +02:00