Skip to content

gate(ROCM): M4 for Qwen3.5-0.8B GDN -- the oracle-backed near-tie gate as the RED anchor of the forward-divergence fix - #559

Draft
VikashLoomba wants to merge 3 commits into
mudler:mainfrom
VikashLoomba:row/ROCM-M4-GDN-GATE
Draft

gate(ROCM): M4 for Qwen3.5-0.8B GDN -- the oracle-backed near-tie gate as the RED anchor of the forward-divergence fix#559
VikashLoomba wants to merge 3 commits into
mudler:mainfrom
VikashLoomba:row/ROCM-M4-GDN-GATE

Conversation

@VikashLoomba

@VikashLoomba VikashLoomba commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

M4 for Qwen3.5-0.8B (GDN) — the oracle-backed gate, committed as the RED anchor (issue #41)

Stacked on #549 (the 0.6B lane + oracle spec). This PR adds the second M4 gate: test_qwen35_paged_engine.cpp — the GDN sibling of the Qwen3-dense SACRED gate — plus its goldens, captured from the same pinned vLLM-ROCm oracle.

Verdict at landing: RED BY DESIGN — the gate tells the truth about the known 0.8B divergence

correctness gate: 3/16 prompts PASS  (STRICT: 0/16; near-tie-band: 3/16;
max gap 14.125 nats @ prompt[8] tok=8; 13 forward-divergent)
BACKEND PROOF — Qwen3.5 GDN ops on device type 5 with 0 declines
(kPagedAttention selections=1536, kGdnDecode selections=4320)
  • 13/16 prompts forward-divergent under the ratified 0.5-nat band; six prompts diverge at the FIRST TOKEN (gaps 0.375–1.188 nats) — over the band, so these are NOT bf16 near-ties
  • The oracle's K=10 capture is deterministic in every (prompt,pos) cell — the reference is stable; the divergence is ours
  • Backend proof is GREEN: all 15 dispatched GDN/full-attn ops selected with 0 declines — the divergence is numerical, not dispatch

This is the Qwen3.5-0.8B CPU/ROCm divergence remains open item from STATUS.md, now oracle-quantified. The earlier characterization localized the drift to the attention block (bf16-softmax amplification); this gate is the committed RED test that turns GREEN when the forward fix lands.

Change shape

  • NEW tests/parity/test_qwen35_paged_engine.cpp (checkpoint-gated via parity::HfSnapshot at the pinned HF revision 2fc06364...; check-snapshot-pins clean)
  • NEW goldens tests/parity/goldens/qwen35_greedy_0_8b/ (greedy + dist + our_ids + gaps + manifest.json recording the oracle identity)
  • tests/parity/hf_snapshot.h: the kQwen35_08BRevision pin + resolver, and a forward declaration fixing the call-before-declaration order hipcc rejects (the bug fix(build): main is RED — hf_snapshot.h calls HfSnapshot before it is declared (#551, #546) #555 fixes canonically on main; the forward decl is harmless either way)
  • tests/CMakeLists.txt registration

The 0.6B gate from #549 re-verified GREEN in this tree (16/16).


UPDATE 2026-08-12: the divergence this gate pinned is root-caused and fixed in #570 (AttnQkNormRopeGate ROCm dispatch keyed on source-dtype instead of output-dtype — bf16 src + f32 out mis-launched all-bf16). With the fix stacked, this gate is GREEN: 16/16 (15/16 strict, max gap 0.125 nats). The goldens in this PR are the pre-fix RED capture; #570 re-derives them from the fixed engine and re-teacher-forces the oracle.

@VikashLoomba VikashLoomba mentioned this pull request Aug 13, 2026
6 tasks
…lden lane in the Qwen3-0.6B near-tie gate

Issue mudler#41 M4 milestone. The oracle is upstream vLLM AT THE PIN (555967922,
runtime 0.23.1rc1.dev1511+g555967922 -- verified == the parity-pin block) built
from source as a ROCm wheel for gfx1100 in rocm/vllm-dev:base and committed as
the image vllm-rocm-oracle:555967922-gfx1100 (recipe: .agents/specs/rocm-m4-oracle.md).

Gate result on this box (4x RX 7900 XTX, ROCm 7.14, enforce_eager, batch=1,
flock ~/gpu.lock): oracle K=10 per-prompt greedy deterministic in every cell;
our ROCm engine 16/16 prompts PASS -- 11/16 strict token-exact vs base greedy,
5/16 near-tie band, max teacher-forced gap 0.125 nats, 0 forward-divergent,
125/125 assertions, backend proof all 8 Qwen3-dense ops selections>0 and
declines==0 on device 5. The p0 France/Italy flip is a literal 0.0000-nat tie
in the oracle's own logits (the Metal M3b signature, reproduced on ROCm).

Change shape: the parity gate's Metal/Tenstorrent device-golden lane gains the
kROCM arm (identical anchor+band logic, ROCm's own oracle-backed golden pair);
dgx base goldens byte-untouched; the *_rocm goldens are additive.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: pi:kimi-k3 [pi]
…e, committed as the RED anchor of the forward-divergence fix

Issue mudler#41 M4, second model. The GDN sibling of the Qwen3-dense gate:
test_qwen35_paged_engine drives the standard 16-prompt battery through the
full paged engine and holds our ROCm tokens against the pinned vLLM-ROCm
oracle (555967922 / 0.23.1rc1.dev1511+g555967922, same container as the 0.6B
lane) via the anchor + <=0.5-nat near-tie band, with the GDN backend proof
(all 15 dispatched ops selections>0 and declines==0).

VERDICT AT LANDING: RED BY DESIGN -- the gate FAILS 13/16 prompts
(0/16 strict, 3/16 near-tie band, max teacher-forced gap 14.125 nats;
first-token divergences on 6 prompts). This is the known 0.8B CPU/ROCm
divergence, now oracle-measured: a REAL forward divergence, not a
distributional near-tie. The oracle K=10 capture is deterministic in every
cell. Backend proof is GREEN (kPagedAttention 1,536 / kGdnDecode 4,320
selections, 0 declines) -- the divergence is numerical, not dispatch.

This commit is the RED test of the fix lifecycle: the gate goes GREEN when
the 0.8B forward lands. Goldens carry a manifest.json (oracle identity +
the real HF revision 2fc06364...); the gate resolves the checkpoint through
parity::HfSnapshot at that pinned revision (check-snapshot-pins clean).
hf_snapshot.h gains the kQwen35_08BRevision pin + resolver, and a forward
declaration fixing the call-before-declaration order hipcc rejects (mudler#555
carries the canonical main-side fix).

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: pi:kimi-k3 [pi]
…RED anchor at landing, 13/16 forward-divergent, max gap 14.125 nats)

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: pi:kimi-k3 [pi]
@localai-bot

Copy link
Copy Markdown
Collaborator

Reviewed as part of a sweep over the open external PRs. The measurement behind this is real — I recomputed the verdict independently from the committed goldens and got exactly your numbers: 13/16 fail, 3 pass, max gap 14125 mnats at (prompt 8, tok 8), 6 prompts differing at token 0. Golden provenance also checks out: greedy_ids.npy and our_ids.npy differ in 196 of 256 positions so they are not the same source, and the prompt token ids are distinctly Qwen3.5's rather than copied from the 0.6B lane. The manifest recording the oracle identity is a genuine improvement over the existing goldens, which record none.

Three things before this can land.

1. It would turn main's CPU CI red for every subsequent PR.

tests/parity/goldens/qwen35_greedy_0_8b/manifest.json declares "op": "qwen35_0_8b_greedy", and no runner is registered for it, so test_op_parity.cpp:1933 hits FATAL ERROR: no runner for op 'qwen35_0_8b_greedy' — add one before committing goldens. That takes down build-test-cpu and both sanitize-cpu jobs — all three are the same single ctest failure, not sanitizer diagnostics (no ASan report, no TSan race anywhere in the logs), and all three are green on main.

The guard is behaving correctly: the existing qwen3_greedy_0_6b/ goldens only avoid it by having no manifest at all. So please fix it by adding the runner arm next to the existing qwen3_5_mtp_head / gdn_packed_decode_bf16 precedents, or a PendingRunnerOps() entry — not by deleting the manifest, which is the best thing in this PR.

2. The gate does not fail safe by device.

const bool other_partial = metal || tenstorrent;kCPU and kCUDA set neither flag, so nothing returns and the gate proceeds to teacher-force a ROCm-captured anchor against whatever device is running, with the entire backend proof (OpRegistered, selections>0, declines==0) sitting inside if (rocm) and therefore skipped. On a CPU or CUDA box with that checkpoint cached you get either a hard REQUIRE "anchor drift" failure attributed to a CUDA regression that does not exist, or a green gate with no proof of which device ran. The only thing preventing this today is that the pinned revision is not cached on anyone else's box, which is luck rather than a fail-safe. Two lines fixes it: if (!rocm) { MESSAGE(...); std::exit(77); }.

Related, and cheap: the checkpoint-absent path at :118-123 returns, so doctest prints assertions: 0 | 0 passed | 0 failed and Status: SUCCESS! — indistinguishable in a log from a gate that loaded a model and matched an oracle. tests/CMakeLists.txt:34 already wires SKIP_RETURN_CODE 77 for every test and test_voxtral_e2e.cpp:55 has the canonical SkipGate() helper; this is issue #463's exact pattern.

3. The RED anchor does not have teeth against the defect it names.

The pass/fail decision is if (mn > kNearTieMnats) prompt_ok = false; where mn is read from the committed neartie_gap_mnats.npy. The engine's output enters only via the anchor REQUIRE(got == our_ids). So the committed RED is a property of a data file rather than of the code, and no forward fix can turn it green — the anchor REQUIRE fires first. #570 confirms this by replacing the goldens rather than passing the gate, which means the gate never had the chance to fail for the original defect.

The shape that works is to land the gate with GREEN goldens alongside #570, keeping the RED capture as recorded evidence in the spec and the parity ledger, where it already lives in full.

One more worth fixing while you are here: the anchor-drift message ends "— re-run qwen3-neartie-gap.py to refresh the gap golden". After #570, that REQUIRE is the only thing catching a reintroduction of the dtype-dispatch bug, and its failure text tells the next engineer to regenerate the golden. It should say a drift is a regression until proven otherwise.

Numbers to correct in the prose: the six token-0 divergences are 0.375/0.750/0.750/0.938/1.000/1.062 nats, so the max is 1.062 not 1.188, and only 5 of the 6 are over the 0.5-nat band. And worst_gap scans positions after the first over-band token, where the oracle is teacher-forced on an already-diverged prefix — the defensible headline is the gap at the first over-band position.

On CI: agent-record and pr-size are the unrebased-fork artifact (now fixed on our side in #619) and Windows is the known-broken arm — but build-test-cpu and both sanitizers are genuinely yours, per finding 1.

No AMD hardware here, so nothing was executed on ROCm; findings 1–3 are static, and the verdict arithmetic above came from your committed files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants