Skip to content

feat(backend): one engine-owned block relayout, and contract fixtures a downstream repo can run (#973.4) - #1102

Merged
michalharakal merged 1 commit into
developfrom
feature/1097-engine-owned-prepack
Aug 24, 2026
Merged

michalharakal merged 1 commit into
developfrom
feature/1097-engine-owned-prepack

Conversation

@michalharakal

Copy link
Copy Markdown
Contributor

Closes #1097 · #973 proposal items 3 and 6

The problem this removes

The census in #973 found the same permutation reimplemented in several places, drifting apart: an inlined Apertus relayout that had diverged from the shared packer it was copied from, three different conventions applied to the same GGUF K-quant tensor depending on which converter loaded it, and — the part that matters most — layout knowledge owned by the downstream repository, with the engine's own code naming GemmaMemSegConverter as responsible for honouring a kernel's layout.

One implementation, published

PackedWeights — prepackForMatmul(view) / toCanonical(view) for views, and toKernelOrder(bytes, …) / toCanonicalOrder(bytes, …) for a converter that holds bytes. This is the only sanctioned implementation of out[b * rows + o] = in[o * blocksPerRow + b].

It is idempotent by construction: prepacking an already-prepacked weight returns it unchanged. That is the direct answer to the double-transpose hazard #973 lists, where applying the old packed "transpose" twice silently produced a different matrix for a non-square block grid and nothing detected it.

blocksPerRow(encoding, inputDim) reads the geometry from the encoding's own descriptor instead of a caller's constant — one fewer place for a 32 to be written where a 256 belongs.

Fixtures that cross the repository boundary

PackedLayoutFixtures publishes canonical and kernel-order fixtures per format — in main, not a test source set, so the artifact a downstream repository already depends on carries them. disagreement(bytes, encoding, kernelOrder) returns null when the bytes agree, or names the first block that is in the wrong place.

This is the guardrail #973 asks for. A byte-layout change once shipped as a green-CI hotfix precisely because each repository's suite proved only its own convention: the engine built canonical fixtures, the downstream converter built kernel-native ones, and neither crossed the boundary. A downstream test asserting disagreement(myConverterOutput, Q4_K, kernelOrder = true) == null now runs against the same bytes the engine's own tests run against.

Every fixture is three blocks wide. At one block per row the two orders coincide, and a test built that way passes whichever convention the code happens to hold — that is the shape that hid #968.

Documentation

docs/design/memory/packed-weight-layout.md gains a section for downstream repositories, and the "prepack once, at load" rule with the reason its default is what it is: wiring the dispatcher's relayout on by default broke M1-A3 during #1095 by copying the whole weight per token. That regression is recorded, not smoothed over.

Gate

scripts/pr-gate.sh — all legs passed.

Keeps develop green by

Entirely additive: two new objects in an already-published module, one documentation file changed. No existing call site is touched — adopting PackedWeights downstream is a follow-up in that repository, which is exactly the point of publishing it.

🤖 Generated with Claude Code

… a downstream repo can run

Closes #1097 (#973, proposal items 3 and 6).

The census in #973 found the same permutation reimplemented in several
places and drifting — an inlined Apertus relayout that had diverged from
the shared packer it was copied from, three conventions applied to the same
GGUF K-quant tensor depending on the converter, and layout knowledge owned
by the wrong repository.

- `PackedWeights`: `prepackForMatmul` / `toCanonical` for views and
  `toKernelOrder` / `toCanonicalOrder` for a converter that holds bytes —
  the only sanctioned implementation of `out[b * rows + o] =
  in[o * blocksPerRow + b]`. Idempotent by construction: prepacking an
  already-prepacked weight returns it unchanged, unlike the transpose it
  replaces, whose double application silently produced a different matrix.
  `blocksPerRow(encoding, inputDim)` reads the geometry from the encoding's
  own descriptor rather than a caller's constant.
- `PackedLayoutFixtures`: canonical and kernel-order fixtures per format,
  in `main` rather than a test source set, so the artifact a downstream
  repository already depends on carries them. `disagreement(bytes,
  encoding, kernelOrder)` returns null when the bytes agree or names the
  first block in the wrong place. Every fixture is three blocks wide,
  because at one block per row the two orders coincide — the shape that hid
  #968.
- The normative doc gains the downstream section, the "prepack once, at
  load" rule with the M1-A3 regression that chose the dispatcher's default,
  and an updated status.

Tests: the byte relayout puts each block where the contract says and is its
own inverse; every covered format's fixture agrees with its own descriptor;
a disagreement names the block that moved; `prepackForMatmul` is idempotent
and preserves the decoded matrix; and it refuses what it cannot relayout.

Gate: scripts/pr-gate.sh — all legs passed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

📖 Documentation Preview

The documentation has been built successfully for this PR.

Generated Files:

  • Operator documentation: docs/modules/operators/_generated_/
  • JSON schema output: operators.json

Artifacts:

  • Download the documentation-preview-1102 artifact to view the complete documentation locally.

This comment will be updated automatically when the PR is updated.

@michalharakal
michalharakal merged commit 895c3e3 into develop Aug 24, 2026
19 checks passed
@michalharakal
michalharakal deleted the feature/1097-engine-owned-prepack branch August 24, 2026 18:36
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.

[973.4] Engine-owned prepack for downstream converters, and cross-repo contract fixtures

1 participant