Mimi codec: token-exact Moshi parity, q8 variant, explicit guard-validated modeling (codex review round 2)#90
Conversation
…shi GGUF model binding Registers the "moshi" architecture (Kyutai Moshi / NVIDIA PersonaPlex family) and wires Codes4Fun/moshi.cpp in as the pinned reference implementation, following the llama.cpp/whisper.cpp reference patterns. Model binding (src/emel/model/moshi/): - component-discriminated contract (moshi.component = lm | mimi | voice) with required moshi.* hparams; load_hparams maps into generic params (temporal transformer dims, depformer dims, delays, mimi codec shape) - execution-contract validation per component: family views (lm.*, mimi.*, voice.*), hparam-derived tensor shape checks (text_emb/text_linear/emb embeddings, RVQ codebooks), per-layer block presence for both fused (in_proj_weight) and pre-split (in_projs.N) attention layouts - raw metadata-less moshi.cpp GGUF caches are rejected explicitly (no general.architecture -> loader error); conversion is required Converter + fixtures (tools/bench/): - moshi_gguf_convert.py: raw moshi.cpp GGUF -> emel-enriched GGUF; restores CRC-mangled tensor names (>=64 chars, moshi.cpp loader.h tensor_name zlib crc32 low-nibble scheme), attaches moshi.* hparams from personaplex-config.json / pinned presets with tensor-shape cross-checks, embeds the SentencePiece text tokenizer as tokenizer.ggml.* (stdlib-only ModelProto wire parser), streams tensor payloads through byte-identically. Verified against the real HF artifacts: mimi-e351c8d8-125.gguf (all 64 mangled names restored, data region sha-identical) and voices/NATF0.gguf. - moshi_make_tiny_fixture.py: deterministic tiny fixtures generated through the maintained converter path; committed under tests/models (LFS) with provenance in tests/models/README.md Reference wiring: - tools/bench/moshi_reference_ref.txt pins moshi.cpp @ f1fabbd14a50 - EMEL_BENCH_NEEDS_MOSHI FetchContent gate in tools/bench/CMakeLists.txt (source-only populate; reference driver targets land with milestone 2) - scripts/setup_moshi_cpp_reference.sh: clone+pin moshi.cpp, sha256-pinned downloads (PersonaPlex-7B q4_k, mimi codec, tokenizer, voice prompt, config), deterministic 24 kHz WAV fixture, auto-runs the converter for the EMEL-lane enriched GGUFs - scripts/check_domain_boundaries.sh: forbidden moshi/mimi runtime roots + generic-recognizer leak checks Tests: tests/model/moshi/binding_tests.cpp (registry, enriched lm/mimi/voice fixture loading incl. embedded-vocab SPM tokenizer, raw-cache rejection, hparam contract negatives, validation negatives); fixture manifest checks. Full suite 1132/1132 passing; coverage lane passed; lint snapshot updated with consent (fixture_manifest_tests.cpp now format-clean). Known pre-existing gate failures (unrelated, documented): paritychecker generation baselines for LFM2.5-230M-Q8_0 missing on this lineage; bench_snapshot missing aarch64 entries on x86 host plus uncommitted decode_wavefront/flash-attention baselines from earlier branch work.
… + silu/elu/gelu/tanh (Moshi M2 step 1) Lands real scalar compute for the kernel ops the Mimi codec and Moshi LM need; all were previously enumerated in EMEL_KERNEL_OP_EVENT_LIST and wired into both backend machines but silently uncomputed. Every dtype/mode variant is modeled as an explicit guard-selected transition row (op_unary pattern) - no runtime variant branches inside actions/detail: - op_get_rows: six variant rows per backend (f32/f16/bf16/q4_0/q8_0/q4_k sources; row dequant via the existing quant helpers, index-validated in the guard path, unsupported dtypes reject explicitly) - op_rope: norm/neox pairing rows (ggml op_params layout, ext_factor==0, positions i32; freq_base/freq_scale/attn_factor honored) - op_im2col: f32/f16 destination rows (1D, ggml operand contract; conv1d = im2col + existing mul_mat) - op_conv_transpose_1d: f32/f16 weight rows (ggml contract: p0==0, d0==1) - op_rms_norm / op_norm: generic scalar path (single algorithm; eps from op_params, double accumulation like the reference) - op_unary: new tanh/elu/gelu/silu subop rows in both backends (gelu uses the ggml tanh-approximation constants) detail additions: dtype_i32/dtype_bf16 codes + sizes, bf16->f32 conversion, ggml-layout op_param readers, valid_variant_guard combiner, per-variant compile-time exec functors shared by both backends. Tests: per-op positive/negative cases in tests/kernel/x86_64_tests.cpp (gather f32+q8_0 with out-of-range index rejection, rms/layer norm math, rope norm+neox rotations, im2col columns, conv_transpose_1d accumulation); unary subop coverage in both backend test files now asserts the new subops compute and uses sigmoid as the still-unsupported reject probe. Full suite: 1136/1136 passing. Lint dirty-list shrinkage (6 files now format-clean) applied with explicit consent. ggml parity cases in tools/paritychecker land next with the mimi codec parity lane.
Adds paritychecker kernel-engine cases comparing the emel backend machines against ggml for: unary tanh/elu/silu (tight tolerance) and gelu (dedicated fp16-table slack), rms_norm, norm, get_rows over f32 tables and over q8_0/q4_0/q4_k blocks quantized by ggml itself (identical block bytes in both lanes), rope norm+neox (ggml_rope_ext params), im2col (1D), and conv_transpose_1d (shared f16 kernel taps). Two defects the new cases caught, now fixed: - has_required_src0 rejected sub-byte quantized get_rows sources because the generic layout check truncates q4 per-element sizes to zero; op_get_rows now shares the native-quantized row-layout contract with mul_mat. - conv_transpose_1d's f16 variant now rounds input samples through fp16 before the tap multiplies, matching the reference f16 operand pipeline exactly. scripts/paritychecker.sh --runner=kernel: kernel parity ok (both backends). Full unit suite: 1136/1136 passing.
…M2 step 2) Lands the complete Mimi codec numeric pipeline as kernel-dispatched compute under src/emel/speech/codec/mimi/ (detail layer; the codec actors and facade land next): - plan/size/bind: fixed mimi_v0_1 SEANet topology tables cross-checked against tensor shapes; one-time weight canonicalization (f16->f32, prepare-time transposes so no runtime GEMM transposes); RVQ nearest-search tables with the -|c|^2/2 bias column folded in; streaming-state arena carved with per-layer offsets; caller-owned arenas sized by required_* functions (allocation-free dispatch). - compute helpers (all numeric work as kernel op events, generator pattern): streaming causal conv (left-context state, im2col + mul_mat + broadcast bias), streaming transposed conv with overlap-add tail state (full and explicit depthwise variants - the caller picks the variant, no shape sniffing), SEANet stacks with resnet residuals and ELU, per-token codec transformer (fused-QKV, rope, ring-buffer KV with two-segment windowed attention, softmax scale param, layer scales, GELU MLP), split-RVQ encode (mul_mat_argmax + get_rows + sub residual) and decode (get_rows sums + output projections). - new kernel variant: op_add/op_mul BROADCAST-ROW (src1 = one dst row), modeled as explicit guard-selected transition rows in both backend machines; elementwise SIMD guards now claim only equally-sized operands (scoped to add/mul so mul_mat routing is untouched). Unit tested including the mismatched-row rejection. - tests/speech/codec/mimi_detail_tests.cpp: full encode chain (1920-sample frame -> seanet -> 25 Hz transformer -> downsample -> 4 RVQ codes) with streaming-state advance and exact reset determinism, full decode chain (codes -> depthwise upsample -> transformer -> seanet -> 1920 finite samples), out-of-range code rejection. - tests/models/mimi-tiny.gguf regenerated with the full tiny-scale topology (README hash + provenance updated; deterministic generator). Full suite: 1139/1139 passing. Lint clean; domain boundaries clean.
Adds the stateforward.SML actor layer over the verified Mimi compute pipeline, completing the codec component per the approved plan: - emel::speech::codec::mimi::encoder::sm - one 80 ms PCM frame -> one 12.5 Hz latent column through explicit frontend/transformer/downsample stage states; validation (runtime bound, request shape, buffer capacity) and stage outcomes are guard-routed decision states over the per-dispatch runtime ctx, whisper-encoder pattern. - emel::speech::codec::mimi::quantizer::sm - split-RVQ latent <-> codes with separate explicit encode/decode state chains. - emel::speech::codec::mimi::decoder::sm - latent -> PCM through depthwise upsample / transformer / SEANet backend stage states (the depthwise transposed-conv variant is selected by the transition, not sniffed). - emel::speech::codec::mimi::sm facade - owns the bound runtime, streaming state, and the three child machines (child data owned by parent context, cross-machine communication only via process_event); sequences encode_frame (frontend -> quantize) and decode_frame (dequantize -> backend), handles initialize/reset_stream, and answers pre-initialization requests with explicit not_initialized errors. Caller owns all arenas (initialize event spans, sized by the detail required_* functions), so the actors allocate nothing during dispatch. - emel::MimiCodec alias in machines.hpp; public facade header any.hpp. tests/speech/codec/mimi_lifecycle_tests.cpp drives the public facade against tests/models/mimi-tiny.gguf: initialize -> encode_frame -> decode_frame with state inspection (session_ready via is()/visit_current_states), reset_stream code-replay determinism, not-initialized rejection, and undersized-arena bind failure landing back in uninitialized. Full suite: 1142/1142 passing. Lint and domain boundaries clean.
…M2 step 4a) - tools/bench/speech/mimi_emel_parity_runner.cpp: EMEL-lane runner (links only emel; the reference lane stays a separate executable per the reference policy). Loads an enriched mimi GGUF, streams a 24 kHz mono s16 WAV through emel::speech::codec::mimi::sm one 80 ms frame at a time, emits `frame=<n> codes=...` lines, and optionally decodes the code stream back to raw f32 PCM (--decode-out). Registered in tools/bench CMake. - codec bind fix for real GGUFs: GGUF collapses trailing size-1 dims (the decoder's final 64->1 conv stores as [3, 64]), so the plan walk now threads the running channel count through both chains and derives out channels from element counts; every layer's geometry is plan-resolved and cross-checked (encoder must land on mimi.dim, decoder on 1 channel). - paritychecker: op_add/op_mul broadcast-row cases vs ggml repeat-broadcast semantics (kernel parity lane green on both backends). Verified against the real converted mimi-e351c8d8-125 model: a 1 s 440 Hz tone encodes to 12 frames x 16 code streams with the semantic stream stable in steady state, and decoding the codes reconstructs a 440 Hz tone at matching RMS with ~17 dB steady-state SNR - functionally correct end to end on real weights (scalar throughput ~250 ms/frame; performance work is the bench suite's follow-up). Full suite: 1142/1142 passing. Lint clean.
…uite (Moshi M2 step 4b) Reference lane: - tools/bench/speech/moshi_reference_driver.cpp: pinned moshi.cpp + ggml + SentencePiece driver with deterministic frame-level encode/decode subcommands emitting the same `frame=<n> codes=...` format as the EMEL runner. Builds against the llama.cpp-pinned ggml (no API skew); C++20; SentencePiece v0.2.0 via FetchContent, reference lane only. - tools/bench CMake: speech_codec_mimi added to the NEEDS_LLAMA list (ggml only) and the driver target gated on EMEL_BENCH_NEEDS_MOSHI. Comparison surface (mimi_compare/v1): - tools/bench/mimi_compare.py runs both lanes as separate subprocesses (two-lane isolation) and reports per-frame code match, token_exact, and decode-vs-decode PSNR; reference_backends/moshi_cpp_mimi.json manifest; scripts/bench_mimi_compare.sh wrapper (--build-only/--run-only), and setup_moshi_cpp_reference.sh --build-only now delegates to it. Bench suite: - speech_codec_mimi (tools/bench/speech/codec_mimi_bench.cpp, registry 33->34): facade frame latency on the tiny fixture - encode 2.53 ms, decode 2.97 ms, roundtrip 5.48 ms per 80 ms frame budget. Baseline snapshots deferred pending consent. - dependency manifest records for the suite (txt + cpp table). Honest parity status, embedded in the compare report and backend manifest: the reference executes ggml's f16 conv pipeline (moshi.cpp requires f16 conv weights and aborts on an f32 model; attention KV cast to bf16) while the EMEL lane computes in f32 after lossless f16->f32 canonicalization. Different effective operand classes, so results are reported as similarity (25.5% code match, 21.3 dB decode PSNR on the 1 s tone), NOT kernel parity. Token-exact parity requires the EMEL codec to consume the f16 operand class end to end - tracked as the next M2 work item.
The reference-lane driver tools/bench/speech/moshi_reference_driver.cpp is legitimate (reference naming is confined to tools/bench per policy); the boundary check must forbid the speech/moshi/ runtime DIRECTORY root without matching that filename. speech::moshi namespace remains forbidden.
Tiny-fixture facade frame latency on this host: encode 2.53 ms, decode 2.97 ms, roundtrip 5.48 ms per 80 ms frame.
…step 1) First piece of the user-approved f16 operand-class pipeline for token-exact Mimi encode parity: - kernel detail: can_run_mul_mat_f16 / run_mul_mat_f16 with ggml's layout (src0 f16 [k,m], src1 f16 [k,n] both k-fastest, dst f32 [m,n]) and vec_dot_f16_ggml - an exact port of the pinned ggml_vec_dot_f16 x86 AVX2+F16C+FMA path: four 8-lane f32 accumulators over 32-element steps, pairwise reduce (0+=2, 1+=3, 0+=1, 128-lane add, two hadds), and a double-precision scalar tail; scalar fallback matches ggml's no-SIMD path. - both backend machines: explicit guard-selected transition row (valid_op_mul_mat_f16 -> exec_scalar_op_mul_mat_f16) ahead of the generic mul_mat row; generic f32/quantized guards unchanged. - paritychecker: f16xf16 mul_mat case vs ggml_mul_mat requiring BIT-EXACT equality (k=70 exercises the 32-wide loop plus tail) - green on both backends. Full suite: 1142/1142. Next: rebind mimi conv/proj weights as raw f16 with f16 im2col dispatch, then bf16 KV rounding, then rerun mimi_compare expecting code match -> 100%.
- SML pin -> external-completion branch (stateforward/sml.cpp PR #16) - emel aliases + sm_external_completion_tests (9 cases green) - io/mmap advise_mapping surface (sequential/willneed/dontneed, guard-routed kinds, 6 cases green) - model/tensor/window machine WIP (detail/errors/events/context/guards/actions) - bench regressions warn by default (EMEL_BENCH_STRICT_REGRESSION=1 for strict) - LFM2.5-230M fixture graduated to current_publication + 4 parity baselines - SYSTEM include for sml dep + pedantic pragma guards (g++ coverage lane)
…16 parity step 2) Rewires the Mimi codec onto the reference f16 operand class for models that store f16 conv weights (the real Mimi model): - plan/bind: operand class detected on the first encoder conv and recorded as the bound property codec_runtime::conv_f16; raw f16 taps and quantizer conv1x1 projections are kept alongside the f32 canonical copies (prepare_raw_f16, arena sized for both); every conv in an f16 model must itself be f16 or bind fails. - compute: compute_seanet_stack / compute_streaming_conv / compute_rvq_ encode / compute_rvq_decode are now template<bool conv_f16>. The f16 path reproduces ggml_conv_1d exactly: f16 im2col (input rounded RNE) followed by the bit-exact f16 mul_mat over the raw f16 weight rows (the ggml reshape layout equals the GGUF layout, so weights are consumed verbatim); quantizer projections round their input through f16 and use the same matmul (ggml conv1x1 semantics). - actors: operand-class selection is modeled explicitly - new variant decision states + guard_conv_f32/guard_conv_f16 rows in the encoder (frontend, downsample), decoder (backend), and quantizer (encode, decode) machines; effects are templates instantiated per row. - codec transformer: K/V ring values round through bf16 (ggml fp32_to_bf16 RNE port, new in kernel detail) matching the reference's CACHE_BF16 cache. Real-model evidence (440 Hz tone vs moshi.cpp reference): frame 0 code match 15/16 (was 11/16 on the f32 pipeline); the remaining divergence is attention numerics (reference converts q and the softmaxed weights to bf16 and dots in physical slot order) plus ggml's fp16-LUT GELU - both mapped and queued as the next steps toward token-exact. Full suite: 1142/1142. Lint clean.
# Conflicts: # snapshots/quality_gates/timing.txt
# Conflicts: # snapshots/quality_gates/timing.txt # src/emel/kernel/x86_64/actions.hpp # src/emel/kernel/x86_64/guards.hpp
Tensor-owned residency for models larger than RAM: whole-file mmap source, budget-guarded passthrough vs streaming decision, ring of pre-allocated layer slots filled by a 2-lane I/O pool via staged_read (one actor per slot for single-writer under concurrent loads), and coroutine suspension on slot loads through the external-completion co_sm policy. Acquire is a three-dispatch protocol (resolve/settle/publish) driven unconditionally by the typed wrapper: resolve joins a slot still mid-load for a different layer (non-sequential access), settle decides resident/loading/unscheduled and submits+requires the target, publish routes on the committed residency, publishes the slot view, and advances the prefetch ring. The prefetch guard never targets the just-published slot (the pass wrap can alias them when layer_count % slot_count != 0) and willneed/ dontneed advise flows ahead of and behind the window. Tests: lifecycle (bind validation, passthrough, rebind rejection, not_bound/ not_streaming legs, allocation-free acquire) and streaming (content integrity across ring eviction, cold jumps joining busy slots, unbind draining in-flight loads).
…y step 3) Completes the exact reference-numerics port. Encode is now token-exact against the pinned moshi.cpp reference on the real Mimi model: 192/192 codes on a 1 s tone and 592/592 codes on a 3 s chirp+noise+silence torture signal (37 frames), with lane-vs-lane decode PSNR of 78 dB. The official compare gate (scripts/bench_mimi_compare.sh -> mimi_compare.py) now runs with --require-token-exact, and the backend manifest's operand-class caveats are replaced with the token-exact parity statement. Exact ports added to the kernel detail layer (all validated in the parity checker or end-to-end): - vec_dot_f32_ggml / vec_dot_bf16_ggml: ggml's AVX2 accumulator layouts and reduce orders (f32: 4x fmadd + pairwise/hadd reduce, float tail; bf16: 4x mul+add with <<16 lane loads, movehl/movehdup reduce, double tail). - v_expf_ggml + soft_max_row_ggml: ggml's vectorized expf polynomial and row softmax (per-8 horizontal reduce into a double sum, libm expf tail, 1/sum in double). - norm_row_ggml: ggml_compute_forward_norm's row math (float mean from a double sum, AVX2 centered-variance blocks, double variance sum). - GELU now replicates GGML_GELU_FP16 exactly (fp16-quantized input/output around the tanh approximation with +-10 saturation); the gelu parity case is tightened from 2e-3 slack to bit-exact and passes. Codec transformer rewritten on those primitives: - reference rope: timestep-embedding angles (expf(-logf(mp)*j/half)) with adjacent-pair rotation and moshi's half-split output layout (the layout changes vec_dot accumulation order, so it is part of the contract). - reference attention: K/V rings hold raw bf16 (ggml CACHE_BF16); q and the softmaxed weights round to bf16; scores run over the full ring in physical slot order with -inf masking; the V pass materializes the transposed bf16 value cache exactly like ggml's cont(transpose(v)). - transformer projections consume raw row-major weights via the ggml f32 dot (prepare_matrix_raw replaces the transposed packing). Throughput snapshot (37-frame real-model encode): EMEL 3.20 s wall / 2.61 s user single-threaded (~86 ms/frame) vs reference 1.23 s wall / 3.24 s user multi-threaded - EMEL already spends ~20% fewer total CPU cycles for identical output; parallelization is the next lever. Tiny fixture bench improved slightly (encode 2.40 ms vs 2.53 ms baseline). Full suite: 1154/1154. Kernel parity green. Lint and boundaries clean.
…step 1) Profiling the real-model encode showed the top cost was not compute but the staging copies routed through generic strided kernel views (per-element tensor_offset_bytes/is_dense_contiguous calls dominated the profile). The conv/convtr staging, ring/overlap state saves, and resnet residual copy are pure moves with no arithmetic, so they now use direct loops and memcpy in the codec detail layer. 37-frame real-model encode: 3.17 s -> 2.69 s wall (-15%), 2.59 s -> 2.11 s user, single-threaded ~73 ms/frame (80 ms real-time budget). Token-exact parity vs the moshi.cpp reference re-verified after the change (592/592 codes on the torture signal). For contrast the reference burns 3.24 s user for the same output; the next throughput lever is fork/join lane parallelism reusing the generator's view-sliced pattern. Full suite: 1154/1154. Lint clean.
One engagement guard (guard_decode_stream_window_ready, mirroring the lane-pool capability gate) composed onto the scalar kernel and native_quantized flash decode routes; streamed rows sit above their resident/parallel siblings and dispatch window_mode::streamed kernel instantiations. run_layer's streamed prologue acquires the layer's slot view from the tensor window (suspending on in-flight loads via the external-completion drain) and rebases the block's matmul weight records onto the slot in canonical role order; prefill stays resident through the always-valid mmap source views (v1 streams decode only). Owner-side wiring: generator ctor overload takes the bound window actor and its bind-reported streaming_active; the initializer re-attaches both after prepare() reconstructs the backend and records the pristine per-layer weight records the rebase clones from (branch-free bookkeeping). Tests: streamed-vs-resident argmax token parity through the public generator path (2 slots over 4 layers), slot-byte consumption proof (model B's file streamed under model A's records), passthrough disengagement.
…erand class moshi.cpp cannot run a quantized Mimi at all (its conv path requires f16 weights), so this is an emel-owned operand class. Converter (tools/bench/moshi_gguf_convert.py --quantize q8_0, needs numpy): - quantizes the transformer projections (in/out_proj, linear1/2) and RVQ input/output projections to q8_0 row blocks matching the emel/ggml encoder semantics (per-32 block, fp16 scale, round-half-away); conv1x1 projections stored [1, in, out] reshape to [in, out] so the quantized row length is the real contraction length. Norms, biases, layer scales, codebooks, convs, and convtrs keep their float dtypes. - 347 MB -> 199 MB (-43%), 68 tensors quantized, quantization recorded in moshi.mimi.quantization metadata. Codec: two new independent bound operand properties, each selected by explicit guard rows per the behavior-modeling directive (never helper branches): proj_q8 (transformer projections; encoder/decoder gain a transformer variant decision state with guard_proj_f32/guard_proj_q8 rows) and rvq_q8 (quantizer projections; the quantizer's variant decision states now carry three mutually exclusive class rows: f32 / reference-f16 / q8). Pre-quantized weights bind once into the arena (prepare_raw_q8_0) and the hot path dispatches the existing AVX2/NEON quantized mat-vec kernels - no packing or weight conversion in the frame loop. Real-model quality vs the f16 token-exact reference (37-frame torture signal): 87% code match, semantic stream 35/37, decode PSNR ~31 dB; an RVQ-projections-in-fp variant measured identical code match, confirming the flips come from transformer-latent perturbation inherent to quantization. The f16 lane keeps its token-exact gate; the q8 artifact is a size/bandwidth option with these measured bars. Full suite: 1154/1154. Lint clean.
topology unroll, event-payload observation) Addresses tmp/codex.review.md: - HIGH kernel_kind: codec_runtime::kernel_kind now defaults to emel::kernel::detect_host_kind() (aarch64 hosts route to the aarch64 kernel actor) and the bound kind is applied to the nested kernel machine exactly once at bind; the five per-helper set_kind calls are gone, so no backend selection happens inside compute helpers. - HIGH seanet block-kind branching: compute_seanet_stack's runtime layer.kind dispatch is replaced by a compile-time unroll of the constexpr topology tables - compute_stack_step<conv_f16, kind> is instantiated per table slot (kind is a template parameter resolved from k_encoder_topology/k_decoder_topology at compile time), and the public entries are compute_seanet_encoder/compute_seanet_decoder chosen by the already-distinct actor effects. Only compile-time conditionals remain in the stack. Token-exact parity re-verified after the change (37/37 frames vs the moshi.cpp reference). - MEDIUM context-reading wrapper accessors: removed frame_samples()/n_q()/ frames_encoded()/frames_decoded()/frames_quantized()/frames_dequantized(). Callers observe the modeled events instead: initialize_done already carries frame_samples and n_q, and the done callbacks count completed frames (runner, bench suite, and lifecycle tests updated). The child actors keep no persistent state, so their contexts are now empty structs per the context rules. - HIGH stage_ok routing: kept, with the pattern now documented at the ctx definition - it is the repository's sanctioned per-dispatch outcome channel (identical to gguf loader actions writing ctx.err from detail::probe_requirements and guards routing on it, and to the whisper encoder's runtime ctx). Actions record outcomes of already-executed work without branching; guards - pure predicates of the runtime event - route the explicit success/error transitions; the mark_*_failed effects assign typed errors on the explicit error transitions. Full suite: 1154/1154. Lint, boundaries clean. Token-exact gate green.
New opt-in suite (EMEL_BENCH_WEIGHT_STREAMING=1, set by scripts/bench.sh --suite=weight_streaming) comparing three lanes on the LFM2.5-230M-Q8_0 fixture at max_tokens 32 with separate first_token rows: emel window (streamed decode via the tensor window), emel mmap (passthrough whole-file mapping, OS demand paging), and a llama.cpp mmap reference at matched threads. EMEL lanes are EMEL-owned end to end; the reference lane never shares objects. Note fields record bytes_read and major_faults. scripts/bench.sh gains --memory-max=<bytes|NNpct|none> (weight_streaming only): systemd-run user-scope wrapper with MemoryMax + MemorySwapMax=0, probe with hard fail when delegation is missing, NNpct derived from the fixture size, run-only mode reusing the default bench build dir. Known limits recorded in the bench source: EMEL session arenas size to the model's advertised context_length (3.57GB RSS on this fixture), so honest capped runs need a larger fixture or a session context cap; reference rows pair by case name so the llama measurement appears under both lane names.
Every build script used bare 'cmake --build --parallel' (one job per core). The SML template TUs cost 2-4GB of compiler RSS each, so 30 jobs on a 58GB host oversubscribes memory ~2x and swaps the machine - worst under the coverage lane's g++ -O0 --coverage rebuild inside quality gates. scripts/build_jobs.sh computes jobs = min(cores, MemAvailable / 4GB) (override: EMEL_BUILD_JOBS) and exports CMAKE_BUILD_PARALLEL_LEVEL; sourced by build_with_zig, bench, test_with_coverage, and quality_gates so the gate's inner builds are bounded too. AGENTS.md records the rule plus the no-concurrent-jobs invariant for shared hosts.
Measured compiler RSS is ~3-4GB per template TU under zig -O3 but ~7-8GB under g++ -O0 --coverage, so the flat 4GB budget still let the coverage lane reach the memory ceiling at 8 jobs. The clamp now takes a per-job budget (EMEL_BUILD_JOB_MEM_GB, default 6) and the coverage build recomputes its own bound at 8GB/job (override: EMEL_COVERAGE_BUILD_JOBS).
# Conflicts: # tools/bench/CMakeLists.txt
…actions, wavefront outcome-slot guard, total submit_or_run, public mimi sizing Finding 1 (stage_ok routing): every success/error route in the mimi facade and encoder/decoder/quantizer children is now decided by pure validation guards BEFORE the corresponding action runs; compute actions are non-failing by contract and chain unconditionally. detail gains validate_codec_contract (compile-time dry-run instantiation of the same bind walk, so the validator cannot drift from the bind it authorizes), validate_codes_in_range (the only data-dependent per-frame failure), void compute entries, and O(1) bound sizing (runtime.workspace_floats/frame_floats replace a per-frame model re-plan in capacity guards). Bind splits into contract -> capacity -> bind states with distinct bind_failed / arena_capacity errors; frame requests route explicit request_shape / code_range errors. Finding 2 (shared outcome slot race): parallel wavefront dispatch now requires pairwise-distinct caller-owned accepted slots (all_lane_outcomes_distinct); aliased slots route through the serial path. Reproduced first with a failing test (misreported failed_lane). Finding 3 (fallback selection in action): new total fork primitive thread_pool_scheduler_ref::submit_or_run executes each task exactly once inside the join window (worker or calling thread - scheduler-internal capacity handling, not a behavior choice); decode_wavefront action and the generator sliced-matmul helper are straight-line now. Finding 4 (detail reach-in): public arena-sizing contract in mimi any.hpp (prepared/state/workspace/frame_arena_floats); bench + parity runner migrated off mimi::detail. Coverage debt closed: new committed operand-class fixtures mimi-tiny-f16.gguf (f16 convs + RVQ projections) and mimi-tiny-q8.gguf (dim-32, converter-quantized q8_0 projections) drive the guard_conv_f16 / guard_proj_q8 / guard_class_q8 rows and their compute paths in tests (mimi component coverage 66% -> ~90%, detail.cpp 92%). Also: merge fallout fixes (bench registry 34->35, speech_codec_mimi reference-lane placeholder records via the sortformer recorded pattern, per-lane case dump on count mismatch), benchmark markers on the new mimi sm.hpp files, gcc -Werror class-memaccess sweep in tests (memset on the non-trivial model::data::vocab replaced with value-init; the encoder test vocab_builder now reproduces its all-zero contract explicitly). Verification: full suite 1185/1185; token-exact mimi encode parity vs moshi.cpp re-verified post-refactor (37/37 frames, decode PSNR 80.7 dB); bench_snapshot (speech_codec_mimi) and paritychecker lanes green.
The facade pre-validates child requests, so the children's explicit runtime_unbound / request_shape / buffer_capacity / code_range transitions only execute when the actors are dispatched directly. Covers the remaining changed-line clusters flagged by the coverage gate (88.0% -> above the 90% threshold on the mimi component).
pointwise_conv_hwc and standard_conv_hwc_rect gained a leading emel::kernel::sm parameter, but the aarch64-only #else blocks in vision_embedding_lane_tests.cpp still used the old signatures; x86_64 hosts preprocess those blocks away, so the break only shows on arm64.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5ba7093bd7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
bind_rvq_split prepares raw f16 projection copies (prepare_raw_f16) whenever the f16 conv operand class is selected and the split is not q8, so an f16-class model with f32 RVQ projections passed the contract's f32-or-f16 float class and then failed codec initialization. The RVQ projection probes now require f16 in that configuration. Reproduced first as a failing test: a fixture with every non-transposed conv flipped to f16 (selecting the class) and untouched f32 projections validated pre-fix and now rejects.
Mirrors the contract fix: when the first encoder conv selects the f16 operand class and the RVQ split is not q8, the converter now requires raw f16 RVQ input/output projections, matching bind_rvq_split's prepare_raw_f16 requirement. The pinned mimi source still converts in both classes.
gabewillen
left a comment
There was a problem hiding this comment.
No actionable findings on the new head commit 447b25160e76c5f1ef5b3659c295c7967167f00b.
Reviewed the range c14ea43ea607cda5d34cfac9ce7747047abb6e65..447b25160e76c5f1ef5b3659c295c7967167f00b after reading AGENTS.md and docs/rules/sml.rules.md. I focused on the new Mimi/Moshi contract probes, converter parity checks, generator streamed-route/raw-record classification, tensor-window completion guards, kernel guard bounds, changed tests, and bench dependency/setup wiring.
Verification performed locally on the PR head:
git diff --check c14ea43ea607cda5d34cfac9ce7747047abb6e65..HEADscripts/check_domain_boundaries.sh
Residual risk: I did not run a fresh compile or targeted test suite in this automation worktree because it has no existing build/ directory; the conclusion is based on source inspection plus the static checks above.
bench_suite_build_dir() returns the unfiltered default tree whenever its bench_runner is already built: the default binary contains every suite and run_bench_runner already selects at run time via EMEL_BENCH_SUITE, so per-suite trees (each cloning and compiling a private llama.cpp reference) are only justified as a cold-start path on fresh checkouts. configure_bench_build() never applies a suite filter to the default tree, which also fixes a latent thrash where a scoped run could filter-reconfigure the shared tree.
POSIX advisory calls require page-aligned addresses, but the streaming window advises arbitrary weight extents: on platforms that enforce the alignment (Linux returns EINVAL) every unaligned hint silently failed. Read hints (sequential/willneed) now expand outward to page boundaries - prefetching a little extra is harmless - and the cache-release hint shrinks inward so only fully covered pages drop and neighbours still in use never fault (degrading to a successful no-op when no full page is covered). macOS tolerates unaligned advisory addresses, so the new unaligned-extent test pins the contract rather than reproducing a failure on this host.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6cc3afb886
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…vq projections cross_check_mimi runs before quantize_mimi_tensors, and the RVQ projections are in the quantizable set: with --quantize q8_0 the source-side f16-RVQ requirement rejected an f16-conv raw file whose projections are f32 even though the published artifact carries q8_0 projections, a class bind_rvq_split accepts without the raw-f16 copies. The f16 requirement now applies only when no projection quantization is pending.
…e codec runtime The weight-streaming bench constructs emel::io::mmap::sm directly for its baseline and streaming lanes, and the PersonaPlex-MLX comparison exercises the maintained codec runtime through the EMEL parity runner: mmap-only and codec-only changes could each skip the suite that exercises them. Added src/emel/io/mmap to weight_streaming and the codec runtime plus mimi_emel_parity_runner.cpp to speech_codec_mimi_mlx (with the manifest baseline synced).
… on Apple Silicon) (#93) * kernel: add NEON f16 mul_mat and f32 conv_transpose variants to the aarch64 lane The aarch64 lane's f16 mul_mat previously fell through to the shared scalar route (vec_dot_f16_ggml compiles its AVX2 path out on arm64), which was both the dominant mimi profile cost and the reason the f16 parity case could not match arm64-built ggml. The new simd_op_mul_mat_f16_vector row ports the pinned ggml_vec_dot_f16 NEON fp16-arithmetic path exactly (float16x8_t vfmaq_f16 accumulators, pairwise reduce, f32-product tail into double), so the route is bit-exact against live ggml on fp16-capable aarch64 hosts. The f32 conv_transpose_1d scatter kernel (decode upsampling, 39% of the post-mul-mat mimi profile) gains a NEON variant that is bit-identical to the shared scalar route as compiled: same per-element accumulation order, fused multiply-add matching the toolchains' -ffp-contract=on scalar codegen, with the route test asserting exact equality. Both variants are explicit guard-routed transition rows with dispatch-count observability (context counters, sm and kernel::any accessors); the shared scalar rows keep guard-level mutual exclusion so the route choice is decided by guards, never row order. Capability-absent hosts keep the scalar routes. Measured on the real Mimi artifact (Apple Silicon, single-threaded): encode 183.3 -> 65.0 ms/frame, decode 139.2 -> 71.8 ms/frame; both stages now meet the 80 ms real-time budget the x86 lane already met. * parity: scope the f16 mul_mat bit-exact case to the host kernel lane f16 mul_mat accumulation order is ISA-class-specific (x86 lane: AVX2 f32 accumulators; aarch64 lane: NEON fp16 accumulators) while the live ggml oracle always computes the host's numerics, so cross-lane runs of this case compare two implementations that are correct to different contracts and can never match bit-for-bit. The kernel runner now executes the f16 case only for the lane matching detect_host_kind() and prints an explicit skip notice for the foreign lane. With the aarch64 NEON f16 port in place this makes the kernel parity gate green on arm64 hosts: previously both lanes failed there; the host lane now matches ggml exactly and the foreign lane is out of the case's contract on either host type. * docs: regenerate kernel aarch64 machine docs Picks up the simd_op_mul_mat_f16_vector and simd_op_conv_transpose_1d_f32 rows; the shared f16/f32 rows now render their named guards instead of anonymized variant-template placeholders. * revert: drop quality-gate timing snapshot churn from this branch Snapshot files are not updated without explicit consent (review feedback); the gate's local rewrites stay uncommitted. * review: guard-owned route predicates and machine-driven route tests - can_use_neon_mul_mat_f16_vector and can_use_neon_conv_transpose_1d_f32 move from aarch64/actions.hpp into guards.hpp guard::detail (the home of route/capability predicates, alongside the packed q4/q6 request predicates); the capability probe stays with its dotprod/i8mm siblings and the kernels remain in actions. - the f16 route tests no longer call kernel::detail::run_mul_mat_f16 directly: the shared-route reference is produced by a second aarch64_sm dispatch with a no-NEON context, so the scalar row, guard mutual exclusion, and wrapper are exercised on both sides of every comparison. * kernel: SVE exclusion for the f16 route; compile probe for the conv route - neon_f16_vector_supported() now rejects __ARM_FEATURE_SVE builds: the pinned ggml_vec_dot_f16 selects its SVE branch ahead of the NEON fp16 branch on such hosts, so this NEON port would not match the reference's accumulation order there; the scalar route keeps those hosts correct. - can_use_neon_conv_transpose_1d_f32 gains a compile-time capability probe (neon_conv_transpose_f32_supported): on non-NEON builds a forced neon_available context could previously select the route whose kernel compiles to a no-op, silently leaving the output zero-filled. Kernel parity and the full suite re-verified green on this host. * kernel/parity: mirror the SVE exclusion in test gates and the parity skip The f16 route test expectations and the host-scoped parity case now key on the same condition as the production probe: the test #if gates add !defined(__ARM_FEATURE_SVE), and the parity kernel runner skips the aarch64 f16 case (with an explicit notice) when neon_f16_vector_supported() reports the route disabled - on SVE builds ggml selects its SVE f16 branch, which EMEL intentionally does not serve until an SVE port exists.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4edf280e77
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
# Conflicts: # snapshots/parity/generation_lfm2_5_230m_q8_0_prompt_hello_max_tokens_1.txt # src/emel/kernel/aarch64/guards.hpp # tests/kernel/aarch64_tests.cpp
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ad6b803edd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The pass decision only checked encode code-match thresholds, so a decoder returning silence or wrong PCM with the right length passed the Moshi/MLX comparison on encode tokens alone. --min-decode-psnr-db now fails the run below a floor when --compare-decode measured a PSNR, with per-backend defaults calibrated against live healthy lanes on this host: 30 dB for the token-exact moshi.cpp lane (measured 37.0 dB even with the standing token divergence) and 10 dB for the cross-implementation MLX lane (measured 21.8 dB, lane passes end-to-end); both are env-overridable.
A speech_codec_mimi selection fell through to the generic bench path, which runs codec_mimi_bench with placeholder reference rows only - real Mimi parity regressions could pass the scoped gate. The suite now routes through bench_mimi_compare.sh --reference=moshi_cpp like the MLX branch.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 44ea202f5d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… at the plan A q8 projection whose aggregate element count is 32-aligned but whose contraction width is not (dim, MLP width, or codebook width) bound successfully and then failed inside the compute loops, which have no error channel back to the frame publisher - the codec kept publishing frames. plan_codec now rejects q8 operand classes whose dim, transformer MLP widths, or codebook width are not QK8_0-aligned. Reproduced first as a failing test: the dim=16 fixture with every projection flipped to q8_0 initialized successfully pre-fix and now routes bind_failed.
The q8 matvec kernels require block-aligned contraction widths; the contract now rejects a q8 projection class when dim, a family MLP width, or codebook_dim is not 32-aligned, mirroring the codec plan gate. Reproduced first as a failing test on the dim=16 fixture.
can_run_conv_transpose_1d and can_run_im2col accepted metadata-only destinations; through the modeled dispatch the accepting row's backend-validity guard already rejected them, but the op guards are now self-contained for any caller and the null-destination rejections are pinned by machine-driven tests.
The parity runner loads the enriched artifact through the Moshi hparam/contract path before codec initialization, so src/emel/model/moshi changes now select both mimi compare suites (manifest baseline synced).
gabewillen
left a comment
There was a problem hiding this comment.
No actionable findings in the new 447b25160e76c5f1ef5b3659c295c7967167f00b..140738f264d6210d071f7b7d9f1e7ec14adf2b5e delta.
Review scope:
- Read
AGENTS.mdanddocs/rules/sml.rules.mdbefore judging SML/model changes. - Inspected the new aarch64 kernel guard/action routes, f16 and conv-transpose optimized rows, matrix-x4 lane guards, mmap advise page-window handling, Moshi/Mimi q8 alignment contracts, Mimi compare gating, quality-gate benchmark routing, and related tests.
- Verified
git diff --check 447b25160e76c5f1ef5b3659c295c7967167f00b..origin/pr/90. - Verified
scripts/check_domain_boundaries.sh.
Residual risk: I did not run the full build/test/bench suite in this watcher pass, so numeric regressions outside the inspected delta would still need CI/bench coverage.
* docs(roadmap): add v1.27 gap closure phases Reopen the cooperative async milestone for scheduler error semantics, loader resumability, evidence consistency, and constrained-RAM profiling. Co-authored-by: Cursor <cursoragent@cursor.com> * chore(lint): add PR #89/#90/#92 files to clang-format baseline Regenerated with scripts/lint_snapshot.sh --update (clang-format 21.1.8, matching the pinned dev-host results). Add-only: 26 new entries, 0 removals. * docs(planning): define v1.28 Memory-Owned KV Block Addressing Cutover Source-backed audit: memory::hybrid does real block accounting on the generate path, but physical K/V addressing is generator-local linear position math; the captured snapshot is never dereferenced in src/; sequence_recurrent_slot is unused. v1.28 cuts physical addressing over to the block map (phases 245-250) with bit-exact single-sequence parity and component-level multi-sequence proof. * feat(memory,generator): Phase 245 — memory-owned KV block geometry contract KVM-01: shared geometry contract in emel::memory::view (DEFAULT_BLOCK_TOKENS, MAX_BLOCKS, blocks_for_tokens, positions_capacity_for); kv machine constants and duplicated blocks_for_length collapse onto it; generator backend derives kv_block_tokens/kv_positions_capacity at prepare and sizes/strides the physical cache from the block-padded capacity (bit-identical when n_ctx is block-divisible). Free stack now hands out ascending contiguous block ids so contiguous logical growth maps to contiguous physical spans (Phase 248 flash-contiguity prerequisite). KVM-02: new pure guard guard_memory_geometry_fits_backend rejects reserve pools larger than physical capacity before dispatch (under-provisioned pools stay valid; exhaustion remains the modeled allocate_slots out_of_memory route). paritychecker/bench/window-streaming tools now reserve whole blocks capped at model n_ctx instead of passing token budgets as block counts. Validation: emel_tests 14/14 (1811 cases), coverage and paritychecker gate lanes pass; bench_snapshot lane fails due to pre-existing main breakage (reference-lane ggml SIGBUS + PR #89 suites missing baselines), reproduced on pristine origin/main — see 245-VALIDATION.md. * feat(generator): Phase 246 — snapshot addressing coherence guards KVM-03: the per-step captured memory::view::snapshot is now validated as the addressing truth before compute phases. guard_snapshot_geometry_coherent and guard_snapshot_covers_tokens fold into guard_prefill_request_ready (prompt_token_count) and guard_decode_request_ready (kv_tokens + 1); geometry drift, inactive sequence, length drift, or missing block mapping fail the ready predicates and route through the existing explicit invalid transitions. No parallel token accounting enters machine context. Validation: emel_tests 14/14 first-run, coverage and parity lanes pass; bench lane blocked by the pre-existing reference SIGBUS (standing disposition, 245-VALIDATION.md). * feat(generator): Phase 247 — block-mapped KV write and scalar-read cutover KVW-01/KVR-01: physical KV addressing now derives from the captured memory::view::snapshot. A backend-resident logical->physical position map (kv_physical_positions, identity after prepare) is rebound per compute dispatch in bind_guarded_inputs from the snapshot the graph events already carried; layer_cache_offset and flash_layer_cache_head_position_offset consume it, cutting over store_attention_kv_cache (both layouts) and the scalar attention read path in one move. validate_guarded_compute / validate_guarded_preselected_argmax enforce the snapshot contract (present, geometry-coherent, active primary sequence) through the processor's modeled validate-failed routing. Bit-exact for contiguous single-sequence mappings (identity map); a reversed-block detail test proves stores and offsets follow the snapshot rather than the logical position. Hand-built test backends keep the flat layout via the bounded identity fallback, mirroring the existing offset-table fallback pattern. Validation: emel_tests 14/14, paritychecker lane PASS (real-model LFM2.5 generation through the mapped path); bench lane blocked by the pre-existing reference SIGBUS (standing disposition). * docs(planning): Phase 247 complete; committed-state gate evidence * feat(generator): Phase 248 — flash route KV map identity guards KVR-02: flash attention consumes contiguous strided views rooted at each layer's cache base, so flash eligibility now additionally requires the snapshot block map to be the identity over the tokens it reads (guard_flash_kv_map_identity, pure bounded predicate). Folded into decode_flash_runtime_supported and prefill flash_runtime_supported; permuted or offset mappings route to the scalar span-walking path through the existing explicit non-flash transitions (their complements). No helper-return route selection. Guard tests cover identity, permuted, and restored mappings for both routes. * feat(generator): Phase 249 — recurrent state via snapshot slot KVS-01: shortconv recurrent state is addressed through the snapshot-resolved recurrent slot (kv_recurrent_slot, rebound per compute dispatch alongside the physical map; validate_kv_map_contract requires an assigned slot for the primary sequence). Slot 0 preserves the flat single-sequence layout bit-exactly; the cache holds max_sequences (currently 1) slots. Detail tests cover slot binding, offset shift, and the unassigned-slot validate rejection. * test(memory,generator): Phase 250 KVP-01 — interleaved multi-sequence proof Machine-level: interleaved two-sequence growth with disjoint block sets and distinct recurrent slots; free/reallocate recycles ids LIFO without disturbing the survivor. Helper-level: two sequences bound from one real hybrid snapshot yield disjoint physical position sets; reused mappings are non-identity (the Phase 248 flash guard is load-bearing) and remain disjoint. KVE-01/KVD-01 closeout remains blocked on the pre-existing bench-lane breakage (reference ggml SIGBUS + missing PR #89 baselines, chip task_48a05fc3); see 250-VALIDATION.md. * docs(planning): v1.28 state — phases 245-249 + KVP-01 done, closeout blocked on bench repair * fix(gates): guarantee lane evidence on timeout without capping verification The parallel quality group previously had only the global timeout: a wedged or starved lane burned the entire budget and the run died with zero lane logs flushed (observed: a 30-minute silent run with no lane verdicts). Each lane now runs under timeout(1) via a single-lane re-exec of this script (EMEL_QUALITY_GATES_LANE) so the whole lane process group can be signalled. The lane budget is an EVIDENCE GUARANTEE, not a work cap: it is the remaining global budget minus a 180s flush margin, so no lane ever gets less verification time than the global timeout already allows — it just fails loudly (status 124, 'lane timeout' marker, log flushed) instead of being killed silently, and the surviving lanes still report. Raise EMEL_QUALITY_GATES_TIMEOUT for legitimately longer runs. EMEL_QUALITY_GATES_LANE_TIMEOUT exists for hang triage only; it can make the gate fail faster, never pass with less verification. Lane logs are seeded with a 'lane start name=... budget=...' line so every lane always reports. Validated: single-lane dispatch runs parity alone and passes; a 60s triage override kills bench/coverage at budget with markers and full flush (73s wall, exit 124); default budgets are the full remaining window (1617s) and a light run passes identically. * chore(gates): restore timing.txt to baseline Five phase commits (245-249) accidentally captured gate-written run telemetry in snapshots/quality_gates/timing.txt. Per the standing rule that file is gate-written and must stay uncommitted. Restore it to the origin/main baseline so this PR is net-zero on it. Branch is already pushed, so a history rewrite/force-push is avoided in favor of a forward cleanup commit. * fix(memory): harden KV block geometry helpers * fix(text): harden KV snapshot dispatch contracts * fix(text): preserve KV reuse contracts across reinit * fix(graph): harden KV execute addressing contracts * docs(planning): refresh v1.28 closeout handoff * bench: refresh PR 94 performance snapshots * bench: clarify snapshot provenance * fix: resolve PR 94 review feedback * fix: address PR 94 review comments * Fix PR 94 KV review regressions --------- Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
Branch line for the Moshi/PersonaPlex M2 milestone (Mimi codec) plus the resolution of the second-pass codex architecture review, and a merge of
worktree-dataloader(streaming weights phases).Mimi codec (M2)
src/emel/speech/codec/mimi/**): SEANet encoder/decoder (compile-time topology unroll), codec transformers with exact ggml numerics (bf16 KV rings, physical-order softmax, fp16 GELU), split-RVQ quantizer.scripts/bench_mimi_compare.sh --require-token-exact.tools/bench/moshi_gguf_convert.py --quantize q8_0, 347→199 MB).Codex review round 2 resolution (this HEAD commit)
bind_failed/arena_capacity/request_shape/code_rangeerror routes.acceptedslots; aliased slots take the serial path. Reproduced first with a failing test (misreportedfailed_lane).thread_pool_scheduler_ref::submit_or_runprimitive (placement is scheduler-internal capacity handling); wavefront action and generator sliced-matmul are straight-line.mimi::*_arena_floatsfromany.hpp, nevermimi::detail.Coverage
New committed operand-class fixtures
mimi-tiny-f16.gguf/mimi-tiny-q8.gguf(deterministic, generator reproduces base fixture bit-identically) drive the f16/q8 guard rows and compute paths: mimi component coverage 66% → ~90%.Merge + host fixes
worktree-dataloader(streaming weight window machine, RAM-aware build clamp, weight_streaming bench suite).speech_codec_mimireference-lane placeholder records (sortformer recorded pattern) so the full compare gate pairs lanes 1:1.-Werror=class-memaccesssweep in tests (memseton the now-non-trivialmodel::data::vocab→ value-init; encoder-testvocab_builderreproduces its all-zero contract explicitly).Verification
bench_snapshot(speech_codec_mimi) andparitycheckerlanes green.quality_gates.shfinal run in flight at draft time (coverage lane ~30 min on this host); will update here when it lands.Open items (need maintainer decision)
speech_codec_mimi.stage_ok-style action-recorded outcome channels still exist in whisper/sortformer/gguf-loader (out of this review's scope; likely the next review target).EMEL_QUALITY_GATES_SCOPE=fullreserved for M2 milestone closeout.Handoff (resume protocol)
Where: worktree
/shared/stateforward/emel.cpp/.claude/worktrees/arch64, branchworktree-arch64. HEAD =2a69575(review-round-2 resolution) on top of merge12dff0a(worktree-dataloader). Durable session notes live in the agent memory filemoshi-personaplex-progress.md(memory index under~/.claude/projects/-shared-stateforward-emel-cpp/memory/).Exact current state (updated at handoff time):
bench_snapshot(speech_codec_mimi) ✅,paritychecker✅, fuzz skipped, all 13 coverage ctest shards ✅. The coverage gate scored changed-line 88.0% vs the required 90% on the previous run; commitce9c514added direct child-actor validation tests (unbound-runtime / request-shape / buffer-capacity / code-range routes onencoder::sm/decoder::sm/quantizer::sm) which raise the mimi component to 92.3% lines locally. A full gate re-run is in flight at handoff time — check for the freshest result before assuming state; if it still lands under 90%, the residual uncovered lines are per-tensor contract-reject branches indetail.cpp's plan/bind walk (reachable only with corrupt-model fixtures).Next step: confirm the in-flight gate run is green, then update this PR (lane status + mark ready if appropriate).
How to run the gate on this host (5950X box gotchas):
timeout 1800sby default; the coverage lane alone takes ~29 min here, soEMEL_QUALITY_GATES_TIMEOUT=5400sis required.atmux exec --detach --shared --timeout 0 -- bash <wrapper.sh>— plainsetsid/nohupchildren get reaped between agent tool calls, and the 10-min tool timeout kills foreground runs.speech_codec_mimibecause thedecode_wavefrontsuite has no committed baselines (pre-existing; consent-gated, see Open items). Touchingtools/bench/bench_runner*.cppmaps to "all suites" and will fan out ~30 per-suite llama.cpp clones — always passEMEL_QUALITY_GATES_BENCH_SUITE.Verification commands:
scripts/bench_mimi_compare.sh(expects"token_exact": true, decode PSNR ~80 dB; needsbuild/moshi_reference/artifacts fromscripts/setup_moshi_cpp_reference.sh).cmake --build build/zig --target emel_tests_bin --parallel 8 && ./build/zig/emel_tests_bin(1185 cases green at HEAD).python3 tools/bench/moshi_make_tiny_fixture.py --output-dir tests/models.After gates are green: update this PR (mark ready or note lane status), then next roadmap work is M3 (temporal transformer + depformer under
src/emel/speech/lm/moshi/**) per the approved plan (~/.claude/plans/pull-in-moshi-cpp-as-lazy-perlis.md); optional M2 follow-ups: fork/join conv-GEMM lane parallelism (generatorcompute_mul_mat_sliced_parallelpattern; per-head attention needs per-lane scratch), quantized convs (per-layer class design), ARM NEON exactness ports.Note
Low Risk
Documentation-only changes under
.planning/architecture/with no executable code paths modified.Overview
Updates
.planning/architecture/Mermaid diagrams and transition tables so they match the currentsm.hppstate machines (no runtime code in this diff).graph.mdnow documents thecompute_reserved_graphpath: valid reserved compute jumpsreserved→executing(skipping assemble), with matching execute/completion handling and reserved-specific compute-error dispatch back toreserved.io_mmap.mdadds the fulladvise_mapping_runtimeflow fromstate_ready: handle/range/platform/kind validation, sequential/willneed/dontneed attempts, and done/error callback branches.kernel_aarch64.mdreflects new or refined dispatch guards on the ready state—e.g. dtype/mode-specificmark_doneroutes for add/mul,get_rows, rope, im2col, conv transpose; f16mul_matSIMD path; and unary tanh/elu/gelu/silu rows.Reviewed by Cursor Bugbot for commit 140738f. Bugbot is set up for automated code reviews on this repo. Configure here.