feat(parity): L0-1b — apr parity --per-op names the first diverging op (1.5B: post_ffn_residual layer 26); the CPU Q8_K reference is the inaccurate side - #3032
Conversation
… binary c642576eecb62daa) — apr parity --json over 78 positions: qwen2.5-coder-1.5b min cosine 0.9508 at position 0 (|Δlogit|max 11.97), qwen2.5-coder-7b min 0.9986; under the horizon rule (min over >= 64 positions >= 0.98 [U]) 1.5B RED / 7B GREEN before any kernel edit (#3017) Pmat-Ticket: PMAT-1065
…est.sh -> evidence/models/supported.yaml, 18 models, every entry cites file:line; --check refuses a hand-typed entry; 6-row case table); C14 scripts/check_model_parity.sh --manifest (apr parity over >= 64 positions per manifest model, min cosine vs evidence/parity/thresholds.yaml — 0.98 [U] until item 5 measures it; UNMEASURED reported, README-cited unmeasured RED; SKIP_PARITY_GATE is an override that prints and refuses; 6-row case table over the lambda records: 1.5B RED, 7B GREEN, must-RED twin, < 64 positions refused) (#3017, PMAT-1065) Pmat-Ticket: PMAT-1065
…tree already does (cited), the five-whys hypothesis for the N-lane quorum; threshold basis = PARITY_GATE_COSINE_MIN (mod.rs:803), itself [U] Pmat-Ticket: PMAT-1065
…S (record corrected); the fused Q8_1 FFN is off by default (gpu_profile.rs:238), so the five-whys step 3 is refuted on default config and the 1.5B/7B asymmetry on the unfused path is the open question; the surviving zero-risk fix is REG-15's selected: line; lanes were one family (gap) Pmat-Ticket: PMAT-1065
…s its duplicate under driver v5.1) — receipt, record, scripts and manifest cite it Pmat-Ticket: PMAT-1065
…izon gate, the derived manifest, REG-15 admission); ci.yml guard-runner-labels runs the manifest case table + --check and C14's case table; every 0.65.2 (1.5B, cuda) dogfood receipt relabelled INVALID-CORRECTNESS citing #2971 (PMAT-1065) Pmat-Ticket: PMAT-1065
… a forced backend never downgrades — CliError::ParityFailed with its own code read at test time; unforced prints selected: cpu (reason: parity FAILED …); PASS prints selected: cuda …), override_line() for SKIP_PARITY_GATE, parse_gate_error over the load-time gate's message; 7 hermetic tests (worker-written, orchestrator-verified) (#2971, PMAT-1065) Pmat-Ticket: PMAT-1065
…oad failure: a parity-gate failure prints selected: cpu (reason: parity FAILED cosine=… threshold=…) when unforced (apr chat today) and refuses when forced (R-0b's --backend); apr compare prints the override line only when the user set SKIP_PARITY_GATE (diff-benchmark's silent set_var waits for its own decomposition — the file is over the complexity gate) (#2971, PMAT-1065) Pmat-Ticket: PMAT-1065
…pare override), the worker ledger, the cuda type-check on lambda, and the gaps (diff-benchmark decomposition, effective-config block, apr devices --model, dogfood C14, threshold measurement, gx10) Pmat-Ticket: PMAT-1065
…lsifier (FAILs the run if it ever passes), then check_model_parity.sh --manifest over the built binary: PASS when measured, FAIL on a measured failure or an override, REPORT with the reason on a host that holds no manifest model (the pre-publish proof is make fleet-verify ROW=release on lambda and gx10) (#2971, PMAT-1065) Pmat-Ticket: PMAT-1065
…e lambda 1.5B record must be RED and the 7B record GREEN under evidence/parity/thresholds.yaml (read by regex, no default), both over >= 64 positions; the full manifest runs only in dogfood, the release and R-8 (#2971, PMAT-1065) Pmat-Ticket: PMAT-1065
…ambda) sits at min cosine 0.9986 in all five runs and the known-bad pair (1.5B@lambda) at 0.9508 in all five (both deterministic, stdev 0.0); 0.98 lies between; [U] until the gx10 pair (#2971, PMAT-1065) Pmat-Ticket: PMAT-1065
…ositions,threshold,basis} — the load-time gate returns the cosine it measured, the CUDA model carries a ParityGateRecord (PASS | skipped under the SKIP_PARITY_GATE override | not-run) set by one admission helper, the report is never absent (not-run on cpu residency or a non-cuda build); shape test (#2971, PMAT-1065) Pmat-Ticket: PMAT-1065
…cs under --features cuda) Pmat-Ticket: PMAT-1065
…st targets (GREEN on a GPU-less host; the live manifest is the fleet-verify leg); receipt carries the v6 DONE-IF ledger Pmat-Ticket: PMAT-1065
…itations moved); accept.sh GREEN on this host (10/10 legs) Pmat-Ticket: PMAT-1065
…rive_model_manifest.sh --check must go RED in guard-runner-labels) and min_cosine 0.90 (the 1.5B sentinel must PASS and sentinel_1p5b_on_lambda_is_red must FAIL in workspace-test). REVERTED after the RED run ids are captured (I3) Pmat-Ticket: PMAT-1065
… row 7); UNMEASURED is a per-host REPORT and a host that measured nothing is not a pass (the fleet-level rule is R-5's); aliases of one file are measured once (longest name first); the case table judges under its own threshold fixture and writes the tracked twin only when absent; PAR-F-003's test is the admission level (R-0b owns backend_refusal_case_table); the manifest's admission rule is stated (#2971, PMAT-1065) Pmat-Ticket: PMAT-1065
…one() so the silent SKIP_PARITY_GATE set_var becomes the printed override (the file was over the complexity gate) (#2971, PMAT-1065) Pmat-Ticket: PMAT-1065
…to R-0b, two documented) in the receipt Pmat-Ticket: PMAT-1065
…ED line (SC2075); the round-1 guard job stopped at the bashrs step before reaching the manifest mutation Pmat-Ticket: PMAT-1065
…ade STALE (diff_benchmark_report.rs::run, error.rs::resolve_model_path, gguf/cuda/mod.rs::preload_and_verify are now under both thresholds) — the shrink-only ratchet demands the delete Pmat-Ticket: PMAT-1065
…t alias only resolves without --features cuda (cuda build of apr-cli was RED: E0107) Pmat-Ticket: PMAT-1065
…every SaveTensorStage on both forwards, admission bypassed internally), the bisection arms with their switches (FP8_PREFILL/FP8_DECODE, BATCHED_GRAPH, flash_decode_enabled, force_high_precision_ffn), the andon (#2971) Pmat-Ticket: PMAT-1065
… new I8 sentinel test (thresholds_demand_at_least_sixty_four_positions) must turn workspace-test RED; round-1 mutants (typed manifest entry, min_cosine 0.90) reverted — their RED is run 34049865821 (guard: manifest derivation step; workspace-test: sentinel_1p5b test) Pmat-Ticket: PMAT-1065
…sis I8); the I8 threshold test stays. Round-2 RED: run 34052968770 (workspace-test: thresholds_demand_at_least_sixty_four_positions, 3/3 tries); round-1 RED: run 34049865821 (guard: manifest derivation step; workspace-test: sentinel_1p5b) Pmat-Ticket: PMAT-1065
…e over every position (CPU tap on the reference forward, executor stage dump per phase, internal gate bypass recorded as skipped); step 1 arms + the layer-26 finding (docs/audits/l0-1b-arms.md): the CPU Q8_K reference is the inaccurate side on massive-activation tokens; forward_single_with_cache / single_cache_ffn_block decomposed (cognitive 55/69 -> 9/12), CPU dump tree bitwise identical (24,258 files) Pmat-Ticket: PMAT-1070
…rity-per-op-v1 (pv valid), accept.sh 6/6 on lambda Pmat-Ticket: PMAT-1070
…e, revert falsifier, speed n=3 [U]), gaps (gx10 twin, apr chat line, scratch/traced paths) Pmat-Ticket: PMAT-1070
…EQUIRED_TOP_LEVEL_KEYS 12 -> 13; the shape test was RED on the GREEN leg (run 34093549220) Pmat-Ticket: PMAT-1065
…e type is already must_use (clippy double_must_use under deny(clippy::all)) Pmat-Ticket: PMAT-1065
…s into guard-tree BSE-001 M2 split the old guard-runner-labels job into guard-tree (cargo-free, dispatched by scripts/guard_tree.sh) and guard-cargo. The four L0-1a steps (derive_model_manifest.sh --self-test/--check, check_model_parity.sh --self-test) are cargo-free by `grep -cE '(^|[^a-z_-])cargo '` == 0 on both scripts, so they re-anchor into guard-tree after check_row_pr_write_set.sh, the same neighbour they had before the split. Also drops unfused_test.json — a 0-byte file left at the repo root by the round-2 mutation run (193d626) and committed by accident. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018RouwmUL7vFfJyCx9qLEoH
…hold [U] lifted, the divergence is model-selected not device-selected Card items (iv) and (vi). `make fleet-verify` does not exist (BSE's G-11b), so the measurement was taken rather than waited on. gx10-a5b5, aarch64, NVIDIA GB10 (sm_121), driver 590.48.01, apr 0.65.2 (c04eda8) sha256 21d182d69505159c. Mechanism engaged, not intended: every run's stderr carries `[GH-480] Patched N backward branch(es) for sm_121 JIT workaround`, a path lambda's sm_89 build does not have. model positions<0.98 min cosine max|dlogit|@0 verdict qwen2.5-coder-1.5b-instruct-q4_k_m 1 0.950611 12.0087 RED qwen2.5-coder-7b-instruct-q4_k_m 0 0.998465 0.8032 GREEN n=5 per cell, stdev 0.0 in all four cells across both hosts. THE FINDING. Two GPU generations, two ISAs, two host architectures, one running a JIT workaround the other does not have — and the known-bad pair lands within 2.2e-4 of the same cosine (lambda 0.950827, gx10 0.950611) while the known-good pair on the same silicon is 0.9985+. The divergence is selected by the MODEL (hidden 1536/heads 12/kv 2 /GQA 6 vs 3584/28/4/7), not by the device. Every "an sm_89 kernel is wrong" or "the sm_121 JIT patch corrupts a branch" hypothesis is refuted before L0-1b dispatches a lane. It is asserted, not merely written down: the_two_hosts_agree_on_each_model_to_ within_a_thousandth goes RED if that stops holding. The driver's 0.9418 / 5.38 were guessed to be gx10's numbers by all three earlier lanes. They are not: gx10 measures 0.950611 / 12.0087. The source report's provenance stays [U]; the defect it names is confirmed on both required hosts. Item (iv) CLOSED, the [U] on evidence/parity/thresholds.yaml lifted: 0.98 now separates two measured known-good pairs from two measured known-bad pairs with 0.0185 of margin under the lower good floor, asserted at >= 0.01 on each side, because a gate that passes with no headroom is a finding (0.63.0 hansei) and a near-tie once inverted a whole diagnosis (#2359). Falsifiers added: check_model_parity.sh --self-test 7 -> 9 rows (both polarities on BOTH hosts); sentinel_tests 4 -> 8 (1.5B RED / 7B GREEN per host, cross-host agreement, threshold margin on both sides). Refs #2971, PMAT-1065 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018RouwmUL7vFfJyCx9qLEoH
…ps into guard-tree Same resolution as agent/L0-1: BSE-001 M2 split guard-runner-labels into guard-tree and guard-cargo, and the three L0-1a steps are cargo-free, so they re-anchor into guard-tree after check_row_pr_write_set.sh. Also drops the 0-byte unfused_test.json. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018RouwmUL7vFfJyCx9qLEoH
…ies is one file
check_hardcoded_paths.sh refused +25 shipped machine-specific paths — 24 of them
`"model": "/home/noah/models/…"` inside the apr parity --json output, one a hardcoded
cargo in accept.sh. That guard has no allowlist by design, and its own header sets the
precedent for evidence: redacting a host path "would delete the evidence and fabricate a
cleaner history".
Neither redaction nor an exemption was needed, because the path was never part of the
measurement.
* Every canonical record RE-TAKEN with the model named relatively (`cd ~/models &&
apr parity ./<model>.gguf …`), same pinned binaries (lambda c642576eecb62daa, gx10
21d182d69505159c), same prompt. The metrics array and every other key are
BYTE-IDENTICAL to the absolute-path run; only `model` differs — compared field by
field, not asserted.
* n5/ drops its ten JSONs per host. All five runs of each model were byte-identical to
each other AND to the canonical record — stdev 0 understates it, the whole file was
the same file — so five copies carried nothing their sha256 does not. DETERMINISM.md
records the hashes and the distinct-count; runs.log keeps the ten exit codes.
* accept.sh: CARGO="${CARGO:-$HOME/.cargo/bin/cargo}" — still never a bare `cargo`
(a shell function of that name overrides CARGO_TARGET_DIR), no longer a machine path.
Also `make readme-sync`: the CONTRACT_COUNT block stated 1815 and the merge tree carries
1816 (main's contracts/patterns/ratchet-verdict-d2-v1.yaml plus this row's
apr-gpu-cpu-parity-v1.yaml). That block is GENERATED, so it is an equality, not a ratchet.
check_hardcoded_paths.sh --full: delta +0. sentinel_tests 8/8. accept.sh 12/12.
Refs #2971, PMAT-1065
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018RouwmUL7vFfJyCx9qLEoH
…achine path check_hardcoded_paths.sh refused +25 shipped paths; the resolution was neither a redaction nor an exemption — the records were re-taken with the model named relatively (byte-identical metrics, same pinned binaries) and the n=5 series collapsed to its sha256, because all five runs were byte-identical to the canonical record. delta +0. Refs #2971, PMAT-1065 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018RouwmUL7vFfJyCx9qLEoH
…refusal proof never ran on main Found by asking of this row what R-0b's regenerated tree-reader ledger asked of its sibling: which of this PR's test targets does a workflow actually execute? $ grep -rc reg15_admission .github/workflows/ -> no match crates/apr-cli/tests/reg15_admission.rs is card item (i)'s falsifier — seven hermetic tests, among them forced_backend_over_a_failed_parity_gate_refuses_with_the_code_from_ error_rs, which is the whole claim of REG-15: a forced backend never silently downgrades. BSE-17's quick tier runs it on a PR that touches apr-cli, but the full tier and every push to main run `--lib` plus ONE explicit list of --test targets, and it was not on that list. Merged as it stood, nothing on main would ever have executed it again — the exact trap recorded for the beats line (a new test target is theater until it is added there). It joins that line beside cli_commands. Note the scale of the standing problem while passing: apr-cli carries 64 integration targets and the line names 7 of them (#2341). Refs #2971, PMAT-1065 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018RouwmUL7vFfJyCx9qLEoH
…taken portably from the pre-fix mutant build
check_hardcoded_paths.sh refused 11 shipped machine-specific paths. Seven were real
portability defects in the scripts — accept.sh, probe26.py, probe26b.py and sweep.sh
hardcoded ~/models, and sweep.sh reached into a SIBLING WORKTREE for
check_model_parity.sh's PROMPT. Now ${APR_MODELS_DIR:-$HOME/models} and a $ROOT derived
from the script's own location.
The other four were recorded `apr parity` outputs whose `model` field held the absolute
path, and two of them are the PRE-FIX table — the fix has since landed, so re-running was
not available. They were re-taken from the registered mutant instead (has_crushed_block
returning false, built --features cuda from this branch, sha256 0372f1cc846c0992; the
post-fix build of the same tree is 776cbbdb4306b5d8), with the model named relatively.
All four came back BIT-FOR-BIT identical — 283 rows and every other key, including
first_divergence post_ffn_residual layer 26 at min cosine 0.660150 @0, the row's central
finding. Only `model` differs.
That is worth more than the cleanup that prompted it: the step-0 evidence is not an
artifact a reader must trust, it is a FUNCTION of the committed tree, recoverable by
flipping one predicate. The source was restored immediately; `git status` on
quantize/mod.rs is clean.
check_hardcoded_paths --full: delta +0. check_no_claim_literals: PASS.
Refs #2971, PMAT-1082
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018RouwmUL7vFfJyCx9qLEoH
…ts n=5 series is one file
The same treatment the lambda records already had, applied to the gx10 twin this session
added: check_hardcoded_paths.sh counted 14 more, all `"model": "/home/noah/models/…"`
inside apr parity output.
* n5/ drops its ten JSONs. All five runs of each model were byte-identical to each other
AND to the canonical record — stdev 0 understates it, the whole file was the same file
— so five copies carried nothing their sha256 does not. DETERMINISM.md records the
hashes and the distinct-count; runs.log keeps the ten exit codes.
* The two canonical records and the two --per-op summaries were re-taken with the model
named relatively on the SAME binary (apr 0.65.2 (ecbd8e4), sha256 8cdb7c1a668127db).
Every metrics/rows array and every other key is byte-identical; only `model` differs,
compared field by field.
check_hardcoded_paths --full: delta +0 (from +14). sentinel_tests unchanged.
Refs #2971, PMAT-1082
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018RouwmUL7vFfJyCx9qLEoH
…tly extends L0-1a's
Three conflicts, all the same shape and all resolved to ours, because this branch is where
L0-1a's parity-gate API grew rather than a divergent take on it:
commands/mod.rs main lacks parity_per_op / parity_per_op_table — L0-1b's modules
cuda/mod.rs ParityGateRecord gains skipped_for_diagnosis() and load_time_skip()
-> Option<Self>; main carries L0-1a's earlier bool form
mod_parity_gate.rs admit_by_parity_gate takes Option<ParityGateRecord>, not bool
"Ours" is a claim until the callers agree, so both crates were compiled after the
resolution rather than eyeballed: `cargo check -p aprender-serve --lib` and
`cargo check -p apr-cli --lib` both clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018RouwmUL7vFfJyCx9qLEoH
Rebased onto the new
|
| file | main | here |
|---|---|---|
commands/mod.rs |
no parity_per_op* |
L0-1b's two modules |
cuda/mod.rs |
ParityGateRecord bool form |
skipped_for_diagnosis(), load_time_skip() -> Option<Self> |
mod_parity_gate.rs |
admit_by_parity_gate(bool) |
admit_by_parity_gate(Option<ParityGateRecord>) |
"Ours" is a claim until the callers agree, so both crates were compiled after the resolution rather than eyeballed: cargo check -p aprender-serve --lib and cargo check -p apr-cli --lib, both clean.
.pr/L0-1b/accept.sh — 6/6, hardware legs included:
ok A1 cargo test -p apr-cli --lib parity_per_op_table
ok A2 cargo test -p aprender-serve --lib per_op_tap
ok A3 pv validate contracts/apr-parity-per-op-v1.yaml
ok A4 docs/audits/l0-1b-arms.md non-empty
ok A5 apr parity <1.5B> --per-op → no diverging op, lm_head ≥ 0.98
ok A6 apr parity <7B> --per-op → no diverging op
Shared guards run pre-emptively rather than discovered one CI cycle at a time — claims ratchet, hardcoded paths (--full), competing harnesses, baseline ratchets, tree-reader registry: all 0.
Why this is the release
D-14 rescoped 0.66.0 to the CUDA parity fix and nothing else, and this PR is the fix. With it, C14 — the release criterion for 0.66's single claim — runs live and passes on lambda:
PASS qwen2.5-coder-1.5b-instruct: 78 positions, min cosine 0.9998 at position 36 >= 0.98
PASS qwen2.5-coder-0.5b-instruct: 78 positions, min cosine 0.9996 at position 0
PASS qwen2.5-coder-7b-instruct: 78 positions, min cosine 0.9996 at position 22
C14: measured=3 rc=0
Receipt: evidence/release/0.66.0/C14-live-lambda.md. The gx10 twin of the fix (GB10, sm_121, aarch64) is in evidence/parity/l0-1b/gx10/: 1.5B 0.950611 → 0.999583, 7B 0.998465 → 0.999782, first_divergence none on both.
…e T2 denominator The branch adds --per-op / --out / --threshold to `apr parity`, which is new CLI surface cited by docs/audits/surface_audit.csv, so check_dogfood_coverage.sh G2.1 freshness went red. Three rows added; then two things fell out of it. 1. in_dogfood_skill is `no`, not `yes`. The skill's Phase 2b sweep runs `"$APR" parity $MODEL` -- the bare subcommand. It does not pass a flag, so it does not exercise these three. Marking them `yes` would have moved coverage 143/833 (17.2%) -> 146/836 (17.5%) while covering nothing: the exact theatre G2.6 exists to stop, in the commit that touches G2.6. The column is self-declared and nothing verifies it, which is why it has to be declared against what the sweep actually runs. 2. The T2 pairing rule keys on the NUMBER, so growing the ledger invalidated the prose. `states_feature_ratio` matches a line only when the live feature denominator appears on it (the `feature...N/M` pattern needs the word before the digits, and these lines are written "143/833 features"). 833 -> 836 left four lines stating a cluster ratio with no feature ratio the guard could see. Re-derived in contracts/apr-dogfood-coverage-v1.yaml (references, description, baselines block, the T2 invariant, F-DOGCOV-009's prediction) and .claude/skills/apr-dogfood/SKILL.md. The description also mis-stated its own floor -- "Coverage is ALLOWED to be 17.2%. It is not allowed to become 17.1%" reads as a ratio floor. check_floors() ratchets COUNTS (total up, covered up, per-binary covered up) and never the ratio, and it has to: honestly adding ungated surface must be allowed to lower the ratio, because the only ways to hold a ratio while shipping three uncovered flags are to omit them from the ledger or to mark them gated. Corrected to say what the code enforces and why. Dogfood coverage for the three flags is owed and is 0.67 work, not 0.66. Verified: check_dogfood_coverage.sh rc=0 (G2.1/2.2/2.3/2.4/2.5/2.6 all PASS, 836 rows, 143 covered); --self-test rc=0, every registered mutation still RED; pv validate 0 errors. README count re-synced 1816 -> 1817 for FALSIFY-README-002. Refs #3032 Pmat-Ticket: PMAT-1070
…three uncited speed factors
Two guards went red on the merge, both for the same reason -- this branch changed
numbers that other files had recorded.
1. dogfood_baseline.py --check: the contract pins per_binary / per_band /
per_cluster totals, and the three new `apr parity` flag rows moved four of
them. Re-derived from the ledger, matching the script's own output exactly:
per_binary apr 370 -> 373 (covered 143)
per_band q7_8 9 -> 11 (covered 9, 100.0% -> 81.8%)
per_band q9_10 20 -> 21 (covered 20, 100.0% -> 95.2%)
per_cluster apr-lint-diag 68 -> 71 (covered 55, 80.9% -> 77.5%)
`--check` now prints CHECK PASSED.
2. check_perf_claims_cite_receipts.sh (PERF-010) reported three NEW uncited
speed comparisons in crates/aprender-serve/src/quantize/mod.rs. They are not
new: the identical text sits at 179/292/318 on origin/main and this branch's
+99 lines pushed it to 181/294/320. The baseline is file:line keyed, so a
pure shift reads as three arrivals and seven stale locations.
`--update` is the WRONG remedy and the guard says so: the ratchet is
per-entry, not per-count -- re-running it left the file smaller (243 -> 238)
and still RED, because an entry may only LEAVE. So the findings are fixed
instead:
"~3x faster than half::f16::from_bits().to_f32()" -> mechanism, no factor
"provides 2-4x speedup for Q4_K GEMV operations" -> mechanism, no factor
"Intel AVX-512 Guide: Contiguous loads 5x faster" -> vendor guidance, marked as not a measurement of this code
None of the three had a receipt, on this tree or any other. The op counts
under `# Performance` are structural and stay; "Expected speedup" stays too,
because a target needs no receipt.
Verified: dogfood_baseline.py --check PASSED; check_perf_claims_cite_receipts.sh
rc=0 (new: 0, dangling: 0, ratchet did not grow vs d6ed9ac);
check_dogfood_coverage.sh rc=0; cargo check -p aprender-serve --lib rc=0.
Refs #3032
Pmat-Ticket: PMAT-1070
…t the root — eight bashrs SEC/DET findings from #3032/BSE scripts, six shifted claim literals deleted (shrink-only ratchet), fresh PP-26 witness on lambda (c=1/4/8/16 PASS), C14 builds its own cuda apr on a GPU host, delegate agent-memory gitignored Pmat-Ticket: PMAT-1096 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BjhtNUSensCYpQb3mCYLod
Row L0-1b (#2971, PP-066 #2873) — steps 0, 1 and 2. Not armed yet: receipt is
status: partialuntil the gx10 twin is measured (fleet-verify).Ticket
PMAT-1070 (minted in #3025). Issue #2971 (P0, inst:A).
Claim
apr parity <gguf> --per-opnames the first op where the GPU-resident forward stops computing the function the CPU reference computes — per (stage, layer), over every prompt position (78 ≥ 64, I8), exit 0 with the table, the admission gate bypassed internally and recorded (neverSKIP_PARITY_GATE). On the 1.5B it namespost_ffn_residuallayer 26 (min cosine 0.660150 @pos 0) and itslm_headrow is the gate's own 0.9508; on the 7B it names nothing.RED test
Commit 71a25c2:
parity_per_op_tableunit tests (forward order; downstream red is never the answer) andper_op_taptests (selected stage only; unarmed writes and computes nothing; bypass thread-local). Live twin (POP-F-003):.pr/L0-1b/accept.shlegs A5/A6 on lambda.Acceptance
APR=<cuda build> bash .pr/L0-1b/accept.sh→ 6/6: table tests · tap tests ·pv validate· arms doc · 1.5B names layer 26 with lm_head within 1e-3 of 0.9508 · 7B clean.Step 1 arms (measured,
docs/audits/l0-1b-arms.md)graph off · FP8 decode off · FP8 all off · flash decode off · fused gate-up off · all off → 0.9508 @pos 0 in every arm; 7B 0.9986. No switchable GPU path is the mechanism.
The finding (measured; the receipt and the arms doc carry the tables)
Layers 0–25 agree at every op. At position 0 the residual carries a massive activation (dim 408 = −3664); the layer-26 FFN cancels it on CPU (ffn_out +3675.7 → residual 11.3) but not on GPU (4084.2 → 407).
ffn_norm@26is identical on both sides;ffn_swigl@26neurons 2908/7035 differ by +14 %/+7.5 %. A float64 recomputation from the dequantised weights (.pr/L0-1b/step0/probe26.py) gives −1142.0/618.4: the GPU is within 0.5 % of the truth; the CPU (−996.4/573.6) is 13 % off and is reproduced to three decimals by Q8-quantising the activation per 256 elements. The CPU Q8_K reference is the inaccurate side on massive-activation tokens.Step 2 — the fix (commit 361d685)
quantize::has_crushed_block(per 256-blockmax/second ≥ 8; basis: the measured criterion table — never on 77 ordinary positions × 28 layers, ≥ 20 on the first token's crushed blocks) sends that one matmul to the f32-activation kernel (quantize::direct_f32) throughmatvec_into_honeston the reference forward (QKV, o_proj, gate/up, down) and the fused gate+up driver.apr paritymin cosine--per-opfirst diverging op / lm_headapr paritymin cosineMutation
has_crushed_block → false→ the 1.5B table namespost_ffn_residuallayer 26 again, lm_head 0.950827,accept.shA5 RED; the mutant's CPU dump tree is bitwise identical to the pre-fix tree (24,258 files) — the routing refactor changes nothing by itself. Restored → 6/6.should_save→ tap test RED;has_crushed_block4 tests (the layer-26 block, an ordinary block, one-hot, all-zero).Contract
contracts/apr-parity-per-op-v1.yaml(kind: pattern; POP-OB-001..003 ↔ POP-F-001..003) —pv validatethroughscripts/pv_bin.sh: valid.Decomposition (hook-clean, verified)
forward_single_with_cache26/55 → 6/9 andsingle_cache_ffn_block21/69 → 6/12 (cyclomatic/cognitive), split into small helpers. Oracle: the per-op CPU dump tree over 78 positions — 24,258 files bitwise identical before/after; GPU tree identical; same first diverging op.Quorum
.pr/L0-1b/quorum.md— three families (gemini-3.1-pro, claude-sonnet-4-6, gpt-oss-120b): 3/3 endorse fixing the CPU side; lane 2's dissent ("per-32 matches the GPU" is falsified by the probe table) folded; the delegate's zero-code armDIRECT_FP32_GEMV=1measured 0.9508 → 0.999896 before the fix was written.Receipt
docs/audits/impl-PMAT-1070-receipt.md—status: partial(step 2 open).Writes
code:
crates/apr-cli/src/commands/{parity_per_op.rs,parity_per_op_table.rs,mod.rs,dispatch_analysis.rs},crates/apr-cli/src/extended_commands.rs,crates/aprender-serve/src/quantize/{mod.rs,direct_f32.rs,fused_gate_up.rs},crates/aprender-serve/src/inference_trace/gpu_stage_dump.rs(+gpu_stage_dump/per_op_tap.rs),crates/aprender-serve/src/cuda/executor/{stage_dump.rs,mod.rs,layers/phase_attention.rs,layers/indexed_ffn.rs},crates/aprender-serve/src/gguf/cuda/{mod.rs,mod_parity_gate.rs},crates/aprender-serve/src/gguf/inference/forward/ffn_block.rs· contracts:contracts/apr-parity-per-op-v1.yaml· receipt ·docs/audits/l0-1b-arms.md·.pr/L0-1b/**(plan, accept.sh, step0 evidence). No shared files.Fleet pin note: this branch sits on agent/L0-1 (#3026) and carries its cuda-feature fix (
gpu_profile_or_noneerror type).🤖 Generated with Claude Code