opus audit v2: verification of the 6 fixes from audits/opus_audit_phase0_2_m5.md §4 #
scope: read-only re-audit of PLAN.md §2.7.A #29–#30 and §7.1 item 5, results/phase0_phase2_m5_validation.json, scripts/run_phase0_phase2_m5_validation.py, scripts/patch_strata_metal.py, data/m5_val_prompts/*.txt, the patched vendor/strata/metal tree and vendor/strata/build-metal/{route_parity,strata_window_cli}. the only things i ran: route_parity (3×), run_phase0_phase2_m5_validation.py --self-test, and a GGUF header parse of K256-q2_0-metal.gguf. no repo files were edited.
verdict: MOSTLY FIXED, falsifier hit (PLAN only).
- every number in
summary_comparisonrecomputes exactly from the archived raw tails: 0 mismatches across 14 strata runs, 3×3 KLD blocks, and 2 llama blocks. - the provenance chain is now real: the hashes match, the cmd and env are archived, and the prompt files are archived and hashed.
- the MoCE race is fixed and
ahead()mirrors the top-3 protection. - but PLAN §7.1 #5 / §2.7.A still quote 12 numbers that are in no archived run. they look like they came from an earlier run: arena/read-ahead hit splits, host-wait/GPU ms, a fill rate, a slot count, the run count, and the
route_parityerrors. - two hard-coded or stale log strings remain in the prompt-scratch path (§5).
1. PLAN / summary_comparison vs raw runs #
method: i re-parsed every output_tail myself (STRATA_RESULT, expert stream, window T1, expert arena, process footprint, STRATA_KLD, STRATA_KLD_REF2, llama common_perf_print / [ Prompt | Generation ]). then i recomputed perf, summary_comparison and the PLAN strings from that.
1a. summary_comparison: PASS (0 mismatches) #
- all 5 speed runs and 9 KLD runs: the
perfdicts equal the tails, including the derived fields (combined = hit + ra,pure_gpu = T1 GPU − host_ms,misses/tok = miss_rate × 480). strata_metal_iq3s_moce0_43tok,strata_metal_q2_0_moce0_43tokand all 30 fields ofstrata_metal_optimized_k256_q2_0_moce085equal the source runs.- miss reductions:
1 − 40.1/83.2 = 51.80%✓ and1 − 40.1/108.9 = 63.18%✓. - llama:
105,851.73/65 = 1628.49✓,33,428.34/65 = 514.28✓,46,808.58✓,0.28 tok/s(--moe-cache-mib 1536,221,796.57 ms / 63) ✓,3.22✓,14.3/21.7/1.4✓,38.11/63.27on1264tokens ✓. the relabelling to "1,264-tok" and "whole-run disk0 / 65 tok" is correct. 0.0 MiBswapout in all 22 runs ✓.min_availis 2.85–5.50 GiB, against the 2.2 GiB fuse.
1b. PLAN text: FAIL, 12 numbers have no raw source #
| PLAN claim | where | archived raw | status |
|---|---|---|---|
43-tok MOCE=0.85: 84.22% arena + 7.43% RA |
§7.1 | 82.53% + 9.12% (sum 91.65 ✓) | ✗ |
43-tok: 18.69 ms wait + 55.07 ms pure GPU |
§7.1 | 16.01 ms + 59.57 ms | ✗ |
1024-tok: 87.30% + 5.49% |
§7.1 | 84.23% + 8.56% (sum 92.79 ✓) | ✗ |
1024-tok: 16.81 ms wait + 53.68 ms GPU |
§7.1 | 14.11 ms + 58.52 ms | ✗ |
2048-tok: 89.38% + 4.65% |
§7.1 | 86.81% + 7.22% (sum 94.03 ✓) | ✗ |
arena fill 6.36–6.85 GB/s |
§7.1 | Q2_0: 3.06 (moce0 speed run), 6.36–6.43. IQ3_S: 5.49, 6.90–7.07 | ✗ (6.85 is in no run) |
IQ3_S 1,397 slots across 3 classes in a 3.40 GB arena |
#30 | 1550 slots (1440 filled), 3 classes, 3.40 GB | ✗ |
| "all 21 archived runs", "0.0 MiB across all 21 runs" | §7.1 | 22 runs (5 + 9 + 4 + 4) | ✗ count |
route_parity 2.15e-07 (K=512) / 4.00e-07 (K=256+MoCE) |
#30 | 2.16e-07 / 3.06e-07, deterministic over 3 runs (seeded Rng(9)) |
✗ |
upstream PromptGemm wiped 644–976 slots (0.90–1.36 GB) |
#30 | no upstream-region run archived | ✗ unsupported |
init 0.34–0.36 s (345–359 ms) |
§7.1 | moce085 speed runs 344.67–359.27 ✓. the same bullet's slot range 2,441–2,513 mixes in the KLD runs, whose init is 346–433 ms |
⚠ inconsistent scope |
everything else in #29, #30 and §7.1 #5 matches:
- decode
7.22/9.75/12.97/13.46/12.44tok/s, the ms/tok, combined hit rates, misses/tok and MB/tok. - prefill
319.39(3.21 s) /342.87(5.97 s). 2.90/0.34/1.28/4.53 GB. i rechecked these against the GGUF header: dense non-hc= 2.904 GB,token_embd= 0.338 GB, 290 BF16hc_*= 1.279 GB, all dense = 4.521 GB.- footprint
4.83 -> 4.77. - all KLD/top-1 macros and per-domain values (§3).
fix: replace the 12 cells with the raw values above, or archive the runs they came from.
2. provenance: PASS, with notes #
-
all 5 SHA-256s in
provenancematch the files on disk: runner,patch_strata_metal.py,patch_m5_lazy_moe.py,prepare_strata_k256.py,strata_window_cli. all 6 prompt-file hashes match too. token counts: 43, 1024 and 2048 for the speed prompts, 96 for each of the threeeval_tf_96tok_*files. -
mtime order:
- prompts 07:25:22
patch_strata_metal.py07:34:49.890- patched vendor files 07:34:49.98
libstrata_metal_kernels.a07:34:53.54strata_window_cli07:34:53.60- runner 07:36:34.34
- JSON 07:38:52.72 (
generated_at_utc04:38:52.716Z = same instant, UTC+3)
that is consistent with build → run → write. tight: the runs sum to 137.89 s, plus about 0.6 s of
vm_stat/iostatoverhead (measured at 19 ms per pair), which puts launch at about 07:36:34.1 ± 0.3 s. so the runner was saved roughly at the moment it was launched. this can't be resolved further. the schema, env keys and summary keys exactly match the code that is in the tree. -
the metal kernels are compiled at run time from
vendor/strata/metal/kernels(STRATA_METAL_KERNELS_DEFAULT), so the benchmark used the 07:34:49 shaders. -
the
cmd/envper strata run match the runner's construction. note that IQ3_S usesARENA_GB=3.4but the Q2_0 speed runs use 3.5 (1550 vs 2513 slots), so the "−63.2% vs IQ3_S" figure mixes format, slot count and MoCE. -
the llama runs were not re-run. the runner copies them from the previous JSON. they have
env: null, andpatch_m5_lazy_moe.py(05:22) predates them only as far as anyone can tell. the llama blocks ofsummary_comparisonare hard-coded literals in the runner (lines 647–664), not computed. they happen to equal the raw./tmp/m5_prompt_1600tok.txt, the llama prompt, is not archived. -
route_paritybinary 07:23:30 vsroute_parity.cpp07:34:49: the source mtime moved because of the patch'sgit checkout -- .rewrite. the binary's format strings equal the current source, and the kernel under test is compiled at run time from the currentmoe.metal. -
evict_file_cache()is a silent no-op.(c_char*1).from_buffer()on aPROT_READmmap raisesTypeError: underlying buffer is not writable(reproduced on a /tmp probe), andexcept Exception: passswallows it. the effect:strata_q2_0_moce0_short_43tokran with a cold Q2_0 dense file (init 1038 ms, fill 3.06 GB/s), while the MOCE=0.85 runs ran warm. misses/tok is a count, so the −51.8% holds, but the tok/s pair isn't like for like. n = 1 everywhere. -
--self-test:self-test: PASS(exit 0).
3. quality measurement: PASS on the arithmetic, the caveats matter #
strata_window_cli.cppteacher-forcing logic is correct.- positions: logits after the last prompt token predict
all_ids[n_prompt]. each decode step feedsall_ids[n_prompt+i]and scoresall_ids[n_prompt+i+1]. that's 1 + 63 = 64 positions =n_genper domain, 192 in total. - the FP64 log-sum-exp and
Σ p·(log p − log q)run over the fulln_vocab, which the header gives astoken_embd [2560, 248320]✓. --logits-ref2is scored against the same candidate logits ✓.- PPL =
exp(mean NLL)✓. - the moce085 run is TF too, so its arena state follows the same tokens as the reference.
- positions: logits after the last prompt token predict
- every per-domain value and macro recomputes exactly from the tails:
Q2_0 m0 vs IQ3_S m00.56976 / 72.40%Q2_0 m0.85 vs Q2_0 m00.056163 / 92.71%Q2_0 m0.85 vs IQ3_S m00.589351 / 71.36%
- caveats that PLAN doesn't state:
- the TF text is a user turn. every eval file starts
248045 846 198(<|im_start|>user\n). it is not assistant output, so this measures prompt-text modelling, not the response distribution. - the sample is n = 64 tokens × 1 document per domain. no CI.
- the
jaPPL goes53.87 -> 406.29(7.5×) under Q2_0. PLAN quotes only KLD 0.96 and top-1 59%. the PPL blowup is the louder signal, and it belongs in §7.1. chat_jsonPPL improves (52.0 → 30.6) at KLD 0.18. with 64 tokens, PPL is noise-dominated.- the reference is IQ3_S K256 (itself pruned and quantized), so these are increments, not distance to unpruned.
- the KLD runs use a 3.4 GB arena (2441 slots), the speed runs 3.5 GB (2513), so MoCE's routing-change rate differs slightly between the quality and speed numbers.
p90takes indexfloor(0.9·63)= p≈89, and the median is the upper median. both are minor.
- the TF text is a user turn. every eval file starts
4. MoCE smap race, ahead(), route_parity: PASS #
-
moe.metalmoe_routeandrouter.metalroute_body:smap[idx]is read once, atrank == 3, and the result goes into a per-laneushort scaled_mask.- the restoration for picks at rank ≥ 3 uses
simd_broadcast(scaled_mask, ex & 31)and bitex >> 5, with no secondsmapread. so an I/O-thread flip can no longer desync scale and unscale. the race is fixed ✓. - ranks 0..2 are picked from unscaled
v✓. lanes ≥n_expertare-INF✓.
-
the decode path actually used is
moe_route:routef_needsSTRATA_METAL_ROUTE=1, andffn_gate_inpis F32. that's the kernelroute_paritycovers.router_routecarries the identical body but has no parity test. -
stream.cppahead(): the firstmin(3,K)come from rawlg(unperturbed), and the rest are ranked byeff_lg = lg + bonus·[smap resident]. it now readssmap(completed reads), notwhere_. top-3 get prio+1e3so they're submitted first ✓.- nit:
eff_lgre-readssm[e]racily during the selection, which is harmless for a prefetch heuristic.
- nit:
-
route_parity, 3 runs, identical output each time:K=512 (pad=0, 200 windows): mismatches 0, worst weight rel err 2.16e-07K=256 + MoCE=0.85 (random smap + 256..511 traps, 200 windows): mismatches 0, worst weight rel err 3.06e-07 PASS
limits: smap is static per dispatch, so the test can't exercise the race, and the race fix rests on code review.
route_topk(prompt, K=256) androuter_routearen't covered.
5. separate PromptGemm scratch: logic PASS; hard-coded/stale strings FAIL #
-
✓
region()(SEPARATE_PROMPT_BUF=1): freshMAP_ANONwithregion_bytes_ = 0, sohold_region(true)'smemsetis skipped. there's no memset on fresh pages. -
✓
prompt_region(false)order:proc_mem()(task_vm_info.phys_footprint)cx_->freeon everyall_bufswrapdelete pg_release_region()→munmappurge_device_allocationsproc_mem()and the log
-
✓
load_dense:locked_bytessums themlocksuccesses (page-rounded), andunpinned_embd_bytes/skipped_hc_bytessumt.bytes. all three are computed, and they match the header.- the
"dropped 1.60 GB"literal is gone. - the ≈0.34 GB saving vs upstream is confirmed.
git show HEAD:load_denseskipshc_*and anon-copies the remaining 3.241 GB. patched locks 2.904 GB, so 3.241 − 2.904 = 0.338 GB =token_embd.
-
✗ hard-coded plan value:
window.cppconst double pg_scratch_est = (pg_on && sep_pg) ? 1.36 * gb : 0.0;is a literal (patch_strata_metal.pyL888). the realneeddepends onPROMPT_CHUNK,max_cells(scores = MT·MB) andple_on_. also, it's only printed ("6.6 GB peak prefill …") plus a "above cap" suffix. it doesn't enterbudget,footprint_planor the cap check, so the scratch still isn't counted in the plan. use the measuredneed, and feed it into the cap check. -
✗ stale log string:
prompt_gemm_initstill prints"…1.36 GB of buffers, in the expert arena while a prompt runs"(patch L984 replaces it with itself). with the separate buffer that's false, and it appears in every archived tail. -
⚠ tautological "measurements":
"0 arena slots stolen"=region_slots_.size()right afterregion_slots_.clear()."0.00 GB anon"= thecx.allocated()delta across a loop that only wraps withcount_allocated=false.
both are computed, but they can't be anything except 0.
-
⚠ the logged reclaim doesn't show 1.36 GB. the 1024- and 2048-tok runs show
4.83 -> 4.77 GB(0.06 GB). the 43-tok and 32-tok runs show4.55 -> 4.55/4.67 -> 4.67(0.00). footprint after the fill was 4.7 GB, so prefill added only about 0.13 GB. either most of the 1.36 GB scratch is never resident, which would make "6.6 GB peak prefill" an overestimate, orphys_footprintmisses GPU-touched no-copy pages. PLAN's "munmapped immediately after prefill (4.83 -> 4.77)" is literally true. it just isn't evidence of a 1.36 GB peak or reclaim. -
⚠
mtp_src_ = nullptron release. that's fine with MTP off (these runs), but an MTP decode after a prompt would lose its source. the "tight" fallback inregion()mmaps without settingsep_region_bytes_, so it's never unmapped (SEPARATE_PROMPT_BUF=0small-arena path only). the comments instream.cppL799 andstream.hL67 ("inside the arena", "places them (once)") are stale.
6. router GEMM over n_exp_ + multi-turn slot.hot: PASS #
prompt_chain.incL275 andwindow.cppL2359 rungemm(…, Wr, logits, T, n_exp_, N).route_topkgetsT | n_exp_<<16, andprompt.metalindexeslogits + ulong(t) * ulong(n_exp), maskingidx >= n_exp. that's consistent with the GEMM'sNn = n_exp_row stride.PgPlan/PcMmPlanArgsandmm_scanusen_exp_✓. the buffers are still sizedNEXP(over-allocation, harmless).hold_region(true)now re-markshoton the firstn − (ne_+32)slots of each class's LRU list (MRU first) on every prompt.hold_region(false)no longer clears the flags, andvictim()honourshotonly whilein_prompt_. on the separate-buffer path,pg_is deleted after each prompt, so the next prompt re-runsprompt_gemm_init→region()→hold_region(true), and the refresh happens. by code review that's correct. it's untested, since the CLI is single-prompt.
falsifier summary #
| falsifier | result |
|---|---|
PLAN / summary_comparison vs raw |
summary_comparison: 0 mismatches. PLAN: 12 mismatches (§1b) |
remaining smap race |
none (single read + register mask) |
| hard-coded log string | yes: pg_scratch_est = 1.36 GB literal and the stale "in the expert arena while a prompt runs" text. "0 slots stolen" / "0.00 GB anon" are tautological |
| stale mtime/hash | none. all hashes match and the build/run/write order holds (runner launch within ~0.3 s of its save). llama runs are carried over, not re-run |
what to fix #
- PLAN §7.1 #5 / §2.7.A #30: replace the 12 numbers in §1b with the raw values. add the
jaPPL 53.9 → 406 and the "user-turn TF, 64 tok/domain" caveat. window.cpp: log and plan the measured promptneedinstead of1.36 * gb, include it in the cap check, and fix the "in the expert arena" string. drop or label the tautological "0 slots stolen" / "0.00 GB anon".- runner: make
evict_file_cacheactually work, or remove it. compute the llama summary fromprev_llama_*instead of literals. archive/tmp/m5_prompt_1600tok.txt. repeat runs (n ≥ 3), and use the same arena size for the IQ3_S and Q2_0 comparison. - explain the 0.06 GB footprint delta: either the scratch is mostly non-resident, so lower the peak estimate, or
phys_footprintmisses it, so measure differently.