Skip to content

Enumerated conformance table: derive (qtype × op × backend) proof obligations from the dispatch registry — the test half of #3418 #3945

Closed as not planned

Description

@noahgift

Downstream of #3421 Phase 1, and the other half of #3418. Alfredo's concept ticket asks for the data table (llama.cpp's ggml_type_traits[]); this asks for the test matrix derived from it, so that admitting a quant type automatically creates its proof obligations instead of an author remembering N sites.

#3418 already states the problem in exactly these terms:

"'does architecture X work' is not actually one question — it's architectures × quant_types × backends × call_sites, and today most of that matrix is untested."

That sentence is the specification. What is missing is the thing that enumerates it.

Why now: the 0.69.1 release paid for its absence, measured

Every item below is from the night of 2026-09-23 on release/0.69.1-batch-2.

  1. The GPU-eligibility whitelist is recorded in NINE places. b9435c6b6 is titled "the whitelist is recorded in SIX places and I updated one" — and undercounted: it missed crates/apr-cli/contracts/apr-model-capability-v1.yaml, the include_str!'d packaged mirror, which held the release branch red for hours. dtype.rs itself is the eighth. The ninth is crates/aprender-serve/src/infer/tests_11.rs:357.
  2. The ninth was invisible to three separate audits, and the reason generalises: it asserts is_legacy_gguf_quant(30) (BF16), and no BF16 change had happened — so a whitelist record stays latent until the type it names changes, and a sweep that looks for breakage cannot find it. It will now redden the in-flight BF16 work at the worst moment.
  3. dtype.rs calls itself "Single source of truth for the GPU-eligibility whitelist" and contradicted itself — prose listed ten types and explicitly said Q5_1(7) … gated to CPU; the expression permitted thirteen, including 7, 20 and 21. Wrong in both directions: a reader concluded IQ3_S still needed work (it did not) and that Q5_1 was unsupported (it was permitted). That comment is what produced a wrong type number in a kernel assignment.
  4. A capability string conflates two crates. "IQ also fails the CPU dequant path" is true of aprender-core (which is why tensor_contract cannot inspect those tensors) and false of aprender-serve (which decodes all four). One string, two crates, and an estimate was wrong until someone checked per-crate.
  5. Six-plus bespoke per-type contracts already exist — q2k-dequant-parity-v1, q3k-dequant-correctness-v1, q5k-dequant-correctness-v1, bf16-dequant-v1, quant-roundtrip-fidelity-v1, … — each hand-written for one type. That is the duplication ARCH: quant-type dispatch is duplicated across ~30 files with no single source of truth — propose a dedicated consolidation release #3418 describes, in the contract layer rather than the code layer.

What competitors do, since #3418 already reaches for llama.cpp

how the kernel matrix is produced
llama.cpp test-backend-ops auto-enumerates (op × quant type × shape), runs backend vs CPU, compares by NMSE against a threshold. Plus test-quantize-fns for round-trip bounds, and perplexity delta as the regression backstop
PyTorch OpInfo — a declarative op registry; the generic suites (dtypes, devices, gradients) are derived from it rather than written per op
vLLM pytest kernels vs PyTorch eager (rtol/atol), plus greedy-output equality vs HF transformers
TensorRT-LLM per-kernel unit tests, with MMLU/perplexity accuracy as the acceptance gate

test-backend-ops walks every type the backend claims and tests each. Structurally, findings 1–3 above cannot happen in that design.

Where we are already ahead, and must not lose it

Our kernel bar is planted faults proven RED first (gemv_entry_name_tests_3477.rs:116; the contract's "never moved on a kernel's existence alone"). test-backend-ops has no fault-injection step, and neither does vLLM's kernel suite. Our CRUX judge (crux_inference_judge.py, #3739) also refuses to pass vacuously — no comparator answered, control ALL_WRONG, no control declared — which most differential harnesses cannot do.

So this is not "adopt llama.cpp's testing". It is: keep the discrimination bar, replace the hand-picked matrix with an enumerated one.

Proposal

Once #3421 Phase 1 lands quant_type_traits(), derive a conformance table from it:

  • Enumerate (qtype × op × backend × shape) from the registry, not from a hand-written list. A type admitted to the whitelist without its conformance rows is a build failure.
  • Per-format tolerance, declared in the registry. This is a correction to our own current standard: we are claiming EXACT (0 ULP / 0.000e0). That is achievable for BF16, where widening is a pure 16-bit shift, and not generally achievable for GEMV, whose reduction order differs from the CPU's — which is precisely why llama.cpp uses NMSE thresholds. Each type should declare its bar, or we will eventually assert bit-exactness where it is physically unavailable and then either weaken the gate or block a correct kernel.
  • Generate, do not maintain, the support table. Docs: publish a GPU-vs-CPU model architecture support table (no user-facing doc exists today) #3077 (Alfredo: publish a GPU-vs-CPU model architecture support table) becomes a rendering of the enumeration rather than a hand-kept document — and Docs: publish a GPU-vs-CPU model architecture support table (no user-facing doc exists today) #3077 stops being able to drift.
  • Subsume the per-type contracts in finding 5 as rows, rather than leaving six hand-written siblings.
  • Keep the mutation requirement per row, so an enumerated matrix cannot become a large vacuous one. An enumerated table that has never gone red is a bigger lie than a small one.

Precondition, and a correction to #3421

#3421 marks Phase 0 [x] complete and it is not. PR #3420 is OPEN, contracts/quant-dispatch-completeness-v1.yaml is not on main (it exists only on that branch, commit 1d7dcc5e9), and there are zero qdc_ tests in the tree. Verified on release/0.69.1-batch-2.

That is worth stating plainly because the five findings above are what #3418 predicted would keep happening, and its own foundation is sitting in an unmerged PR. Landing #3420 is the cheapest available step toward all of this.

Scope: 0.70.0 or the Inference dispatch & architecture consolidation milestone alongside #3423 — not the 0.69.1 train.

Activity

  1. added this to the 0.74.0 milestone on Sep 23, 2026
  2. noahgift commented on Sep 23, 2026

    @noahgift
    MemberAuthor

    milestone → 0.74.0 per docs/roadmaps/milestone-triage-2026-09-23.md (#4024), operator approval 2026-09-23 (relayed by aprender-cf). Reason: qtype x op x backend obligations derived from dispatch: one quant dispatch (#4001)

  3. noahgift commented on Sep 23, 2026

    @noahgift
    MemberAuthor

    Test half: #3968. Cop ruling (A) 2026-09-23: a census-driven device harness (every held (type, k, n), GPU vs CPU decoder, condition-aware bound, planted fault per type) plus a guard over (type, shape class). The guard lands with the harness's first green receipt on both hosts. Census: 163 held (type, k, n) across 17 whitelisted types; details in #3968.

  4. added
    kind:triageEpic, tracker, decision or hygiene work (derived rule, #4159)
    on Sep 24, 2026
  5. noahgift commented on Sep 25, 2026

    @noahgift
    MemberAuthor

    Parked by APR-EPIC-001: over S2 budget (rank 37/38). Reopen = pull. Applied by aprender-d1: claude+agy both said close, apr shadow row recorded (handoff/close-quorum-2026-09-25.json).

  6. modified the milestones: 0.74.0, backlog on Sep 25, 2026
  7. added
    parkedClosed over epic budget (APR-EPIC-001 rule 5). Reopen = pull.
    on Sep 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind:triageEpic, tracker, decision or hygiene work (derived rule, #4159)parkedClosed over epic budget (APR-EPIC-001 rule 5). Reopen = pull.

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions