Skip to content

spec(MODEL-MM-GLM53-FLASH): GLM-5.3-Flash is an architecture no oracle implements and no device here can hold (#1998) - #2001

Open
localai-bot wants to merge 3 commits into
mainfrom
row/MODEL-MM-GLM53-FLASH
Open

spec(MODEL-MM-GLM53-FLASH): GLM-5.3-Flash is an architecture no oracle implements and no device here can hold (#1998)#2001
localai-bot wants to merge 3 commits into
mainfrom
row/MODEL-MM-GLM53-FLASH

Conversation

@localai-bot

Copy link
Copy Markdown
Collaborator

zai-org/GLM-5.3-Flash was published 2026-08-26 and declares
Glm5NextForConditionalGeneration / model_type: glm5_next. Nothing in this
tree matched it. This lands the row's records and its spec; no product code.

The name collides with work that is already blocked, and that misreading is the
expensive one. .agents/model-matrix.md already carries a row labelled "GLM-5":
MODEL-TEXT-deepseek-v2-glm-moe-dsa-for-causal-lm, BLOCKED at 753.9B, which is
DeepSeek-V3.2 verbatim. glm5_next is a different model_type, a different
parameter count, a different attention topology, and it has a vision tower. New
row, not a revival.

vLLM implements nothing, at either end of the pin. Read live 2026-08-26:
git grep "Glm5\|glm5_next" returns zero hits at 555967922 and zero at
origin/main = c71f6f8a81, whose vllm/models/ package holds common,
deepseek_v32, deepseek_v4, dots3_note, inkling, kimi_k3 and
minimax_m3. That is absence from vLLM main, not staleness in our pin, so
advancing the pin — 348 commits of reconciliation — reaches nothing here. What
exists upstream is vllm#53906, opened the same day, open and mergeable: false,
and an unmerged pull request is not a revision. It is inadmissible as an oracle
and is cited in the spec only as evidence of upstream shape. SGLang is the same
picture with one trap worth recording: its GLM-5.3-Flash cookbook merged while
its implementation PR stayed open, so the model card links a recipe SGLang
main cannot run. llama.cpp has no glm5_next either.

So the only admissible oracle is transformers, and the release is bounded rather
than assumed: modeling_glm5_next.py is HTTP 200 at v5.16.1 and 404 at
v5.16.0 and v5.15.1, making 5.16.1 the first release carrying the
architecture. The MODEL-MM-QWEN4-EXP lane pins 5.16.0 and this one pins
5.16.1, one day apart, because Qwen4Exp merged before the 5.16.0 cut and
Glm5Next after it. Two lanes, two releases, which is what a lane pin is for.

Most of the model is already here, and the survey moved three conclusions.

Two of the three obvious reuses are wrong in one place each, in ways a token
gate cannot see.
The KDA forget gate branches on safe_gate_lower_bound; the
checkpoint sets gate_lower_bound: -5.0, so it takes the bounded branch,
-5.0 * sigmoid(exp(A_log) * (f_b(f_a(x)) + dt_bias)), where our kimi_kda.cpp
implements Kimi-Linear's -exp(A_log) * softplus(g + dt_bias). Different
functions of the same inputs, both smooth, both negative, both fluent, and the
sign of decay_rate differs too. And the mHC head collapse is
hidden_streams.mean(dim=2), an unweighted mean whose own docstring says
"Unlike DeepSeek-V4", where our HcHeadCollapse is the V4 weighted-gated
collapse — the checkpoint carries no hc_head.* tensors at all, which settles
it. Both get a red-first wave test whose failure against the wrong reuse is the
deliverable.

The text stack has no rotary embedding anywhere, which is easy to get wrong
in the other direction. qk_rope_head_dim: 0, mla_use_nope: true, no
rope_theta, no rope_scaling; the reference deletes the inherited
rope_parameters field and passes position_embeddings=None to every layer.
indexer_rope_interleave: true is a vestigial flag the indexer override
ignores, so implementing it because the config names one is implementing a bug.
Position comes only from the KDA decay and the short convs. NoPE does buy one
thing: MLA weight absorption becomes trivially valid, since there is no rope
slice to keep out of it. It also blocks: MlaBlockDims::Validate refuses
qk_rope_head_dim == 0 today, and Kimi-Linear is not the same case — it sets
mla_use_nope while keeping qk_rope_head_dim: 64, so the rope slice still
occupies the cache row.

The k-pool indexer is unobservable at or below 2048 tokens. With
index_topk: 2048 a shorter context selects every candidate, the selection is
the identity, the pooling is invisible, and any short-prompt gate passes over a
broken indexer. That is now a stated requirement in ## Gates rather than a
note. The pooling itself is learned and per channel — 128 independent 4-way
softmaxes over a learned [4,128] intra-pool position embedding, pools aligned
to the first valid token so the grid is batch-dependent, expanded back to raw
indices and widened to 2051 by an unscored ragged tail.

Nothing fits, and no GGUF exists. Measured by HTTP RANGE over all 62
safetensors headers, payload never fetched: 76,108 tensors, 321,322,735,872 real
parameters, routed experts 311.65B = 97.0%. Against ~119.63 GiB on GB10 the
published FP8 is 305.78 GiB, BF16 598.53, and the smallest, an NVFP4 requant, is
181.32 — 1.52x over. All four repositories named *-GGUF contain zero .gguf
files. gateable = no on memory, and the consequence is the scoping result: no
oracle can execute this model on any device this project reaches, so no
end-to-end token gate exists or can exist here. That is recorded as visible debt
rather than waived, and what replaces it is a tiny-shape CPU reference oracle
instantiated from the pinned transformers — a real oracle for the numerics, and
explicitly not oracle gateability for the model.

The developer set the W7 target as a low GGUF quant that fits the DGX. The
arithmetic, with experts at the named type and the other 3% at Q6_K and bits per
weight taken from our own reader's block traits: Q8_0 318.0 GiB, Q6_K 245.5,
Q4_K 170.6, IQ3_XXS 118.1 which leaves ~1.5 GiB and is not a margin, Q2_K 102.6
with ~17 GiB left, IQ2_XXS 82.3. Q2_K is the recommendation and the reason is
producibility, not quality: i-quants need an importance matrix, an importance
matrix needs a forward pass, a forward pass needs 181 GiB, and the dependency is
circular on this fleet. K-quants need none. Since llama.cpp has no glm5_next
the converter is ours to author, with no reference GGUF to diff against and no
llama.cpp floor for the arm.

The MODEL row ratchet moves 378 -> 379 with its justification appended in the
existing log format, re-derived off the matrix rather than carried forward. One
row and not three, which is the arithmetic the new test exists to hold: the open
vllm#53906 would register Glm5NextForCausalLM,
Glm5NextForConditionalGeneration and Glm5NextMTPModel, so the IndexTTS-2.5
and dots3-note two-row shape is the tempting read and it does not apply. None of
the three is registered at any vLLM revision, and the only architecture a
published artifact declares is Glm5NextForConditionalGeneration; the MTP head
is layers.45 inside the same checkpoint, which the transformers reference
discards outright. The at-the-pin static invariants (324/373/356/310/261) are
unchanged, because the Upstream cell carries no pinned module/class target.

Two anchors in engine-matrix.md are repaired in the same change. Inserting the
new test into tests/scripts/test_agent_record.py shifted
ENG-RECORD-ANCHOR-RATCHET's two citations of that same file by 45 lines — the
rot that row exists to measure, produced by an edit to the very file it cites.
Rot goes 39 -> 37.

Evidence. check-agent-record.py OK at ENGINE=173 MODEL=379 QUANT=84 KERNEL=58
BACKEND=87 ANCHOR-ROT=37; check-model-checklist.py OK;
tests/scripts/test_agent_record.py 124 passed. The new test was mutation-proved
three ways, each restored byte-for-byte and re-verified green: renaming the row
reds it, adding a -for-causal-lm sibling to "match" the upstream PR reds it,
and leaving the ratchet at 378 reds it. The third mutation initially read as a
false red after restore because scripts/__pycache__ still held the mutant's
bytecode; it was re-run with the caches cleared on both sides.

Scoping only. No product code lands under this pull request, and the eight
implementation waves are dispatchable from the committed spec — W0 to W2 and W4
CPU-gateable, W3 and W5 to W8 needing a GPU, W8 unscheduled because there is no
denominator.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: Claude:claude-fable-5 [Claude Code]

mudler added 2 commits August 26, 2026 16:59
…e implements and no device here can hold (#1998)

`zai-org/GLM-5.3-Flash` was published 2026-08-26 and declares
`Glm5NextForConditionalGeneration` / `model_type: glm5_next`. Nothing in this
tree matched it. This lands the row's records and its spec; no product code.

The name collides with work that is already blocked, and that misreading is the
expensive one. `.agents/model-matrix.md` already carries a row labelled "GLM-5":
`MODEL-TEXT-deepseek-v2-glm-moe-dsa-for-causal-lm`, `BLOCKED` at 753.9B, which is
DeepSeek-V3.2 verbatim. `glm5_next` is a different model_type, a different
parameter count, a different attention topology, and it has a vision tower. New
row, not a revival.

**vLLM implements nothing, at either end of the pin.** Read live 2026-08-26:
`git grep "Glm5\|glm5_next"` returns zero hits at `555967922` and zero at
`origin/main` = `c71f6f8a81`, whose `vllm/models/` package holds `common`,
`deepseek_v32`, `deepseek_v4`, `dots3_note`, `inkling`, `kimi_k3` and
`minimax_m3`. That is absence from vLLM `main`, not staleness in our pin, so
advancing the pin — 348 commits of reconciliation — reaches nothing here. What
exists upstream is vllm#53906, opened the same day, open and `mergeable: false`,
and an unmerged pull request is not a revision. It is inadmissible as an oracle
and is cited in the spec only as evidence of upstream shape. SGLang is the same
picture with one trap worth recording: its GLM-5.3-Flash *cookbook* merged while
its implementation PR stayed open, so the model card links a recipe SGLang
`main` cannot run. llama.cpp has no `glm5_next` either.

So the only admissible oracle is transformers, and the release is bounded rather
than assumed: `modeling_glm5_next.py` is HTTP 200 at `v5.16.1` and 404 at
`v5.16.0` and `v5.15.1`, making 5.16.1 the first release carrying the
architecture. The `MODEL-MM-QWEN4-EXP` lane pins 5.16.0 and this one pins
5.16.1, one day apart, because `Qwen4Exp` merged before the 5.16.0 cut and
`Glm5Next` after it. Two lanes, two releases, which is what a lane pin is for.

Most of the model is already here, and the survey moved three conclusions.

**Two of the three obvious reuses are wrong in one place each, in ways a token
gate cannot see.** The KDA forget gate branches on `safe_gate_lower_bound`; the
checkpoint sets `gate_lower_bound: -5.0`, so it takes the bounded branch,
`-5.0 * sigmoid(exp(A_log) * (f_b(f_a(x)) + dt_bias))`, where our `kimi_kda.cpp`
implements Kimi-Linear's `-exp(A_log) * softplus(g + dt_bias)`. Different
functions of the same inputs, both smooth, both negative, both fluent, and the
sign of `decay_rate` differs too. And the mHC head collapse is
`hidden_streams.mean(dim=2)`, an unweighted mean whose own docstring says
"Unlike DeepSeek-V4", where our `HcHeadCollapse` is the V4 weighted-gated
collapse — the checkpoint carries no `hc_head.*` tensors at all, which settles
it. Both get a red-first wave test whose failure against the wrong reuse is the
deliverable.

**The text stack has no rotary embedding anywhere**, which is easy to get wrong
in the other direction. `qk_rope_head_dim: 0`, `mla_use_nope: true`, no
`rope_theta`, no `rope_scaling`; the reference deletes the inherited
`rope_parameters` field and passes `position_embeddings=None` to every layer.
`indexer_rope_interleave: true` is a vestigial flag the indexer override
ignores, so implementing it because the config names one is implementing a bug.
Position comes only from the KDA decay and the short convs. NoPE does buy one
thing: MLA weight absorption becomes trivially valid, since there is no rope
slice to keep out of it. It also blocks: `MlaBlockDims::Validate` refuses
`qk_rope_head_dim == 0` today, and Kimi-Linear is not the same case — it sets
`mla_use_nope` while keeping `qk_rope_head_dim: 64`, so the rope slice still
occupies the cache row.

**The k-pool indexer is unobservable at or below 2048 tokens.** With
`index_topk: 2048` a shorter context selects every candidate, the selection is
the identity, the pooling is invisible, and any short-prompt gate passes over a
broken indexer. That is now a stated requirement in `## Gates` rather than a
note. The pooling itself is learned and per channel — 128 independent 4-way
softmaxes over a learned `[4,128]` intra-pool position embedding, pools aligned
to the first valid token so the grid is batch-dependent, expanded back to raw
indices and widened to 2051 by an unscored ragged tail.

**Nothing fits, and no GGUF exists.** Measured by HTTP RANGE over all 62
safetensors headers, payload never fetched: 76,108 tensors, 321,322,735,872 real
parameters, routed experts 311.65B = 97.0%. Against ~119.63 GiB on GB10 the
published FP8 is 305.78 GiB, BF16 598.53, and the smallest, an NVFP4 requant, is
181.32 — 1.52x over. All four repositories named `*-GGUF` contain zero `.gguf`
files. `gateable = no` on memory, and the consequence is the scoping result: no
oracle can execute this model on any device this project reaches, so no
end-to-end token gate exists or can exist here. That is recorded as visible debt
rather than waived, and what replaces it is a tiny-shape CPU reference oracle
instantiated from the pinned transformers — a real oracle for the numerics, and
explicitly not oracle gateability for the model.

The developer set the W7 target as a low GGUF quant that fits the DGX. The
arithmetic, with experts at the named type and the other 3% at Q6_K and bits per
weight taken from our own reader's block traits: Q8_0 318.0 GiB, Q6_K 245.5,
Q4_K 170.6, IQ3_XXS 118.1 which leaves ~1.5 GiB and is not a margin, Q2_K 102.6
with ~17 GiB left, IQ2_XXS 82.3. Q2_K is the recommendation and the reason is
producibility, not quality: i-quants need an importance matrix, an importance
matrix needs a forward pass, a forward pass needs 181 GiB, and the dependency is
circular on this fleet. K-quants need none. Since llama.cpp has no `glm5_next`
the converter is ours to author, with no reference GGUF to diff against and no
llama.cpp floor for the arm.

The `MODEL` row ratchet moves 378 -> 379 with its justification appended in the
existing log format, re-derived off the matrix rather than carried forward. One
row and not three, which is the arithmetic the new test exists to hold: the open
vllm#53906 would register `Glm5NextForCausalLM`,
`Glm5NextForConditionalGeneration` and `Glm5NextMTPModel`, so the IndexTTS-2.5
and dots3-note two-row shape is the tempting read and it does not apply. None of
the three is registered at any vLLM revision, and the only architecture a
published artifact declares is `Glm5NextForConditionalGeneration`; the MTP head
is `layers.45` inside the same checkpoint, which the transformers reference
discards outright. The at-the-pin static invariants (324/373/356/310/261) are
unchanged, because the Upstream cell carries no pinned module/class target.

Two anchors in `engine-matrix.md` are repaired in the same change. Inserting the
new test into `tests/scripts/test_agent_record.py` shifted
`ENG-RECORD-ANCHOR-RATCHET`'s two citations of that same file by 45 lines — the
rot that row exists to measure, produced by an edit to the very file it cites.
Rot goes 39 -> 37.

Evidence. `check-agent-record.py` OK at ENGINE=173 MODEL=379 QUANT=84 KERNEL=58
BACKEND=87 ANCHOR-ROT=37; `check-model-checklist.py` OK;
`tests/scripts/test_agent_record.py` 124 passed. The new test was mutation-proved
three ways, each restored byte-for-byte and re-verified green: renaming the row
reds it, adding a `-for-causal-lm` sibling to "match" the upstream PR reds it,
and leaving the ratchet at 378 reds it. The third mutation initially read as a
false red after restore because `scripts/__pycache__` still held the mutant's
bytecode; it was re-run with the caches cleared on both sides.

Scoping only. No product code lands under this pull request, and the eight
implementation waves are dispatchable from the committed spec — W0 to W2 and W4
CPU-gateable, W3 and W5 to W8 needing a GPU, W8 unscheduled because there is no
denominator.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: Claude:claude-fable-5 [Claude Code]
`.agents/issue-index.md` conflicted. It was resolved by taking
`origin/main`'s file whole and re-appending this branch's single added row
(#1998) at the end, rather than accepting the automatic three-way merge git
offered. AGENTS.md requires exactly that for a keyed record: take the complete
target-branch version, apply the scoped edit again, and verify unrelated keys
are byte-for-byte equal. A clean automerge of this file is the failure mode,
not the success case, because it has previously duplicated a row and silently
dropped a tail row.

Verified after the resolution: 730 rows on `origin/main` plus this branch's one
row is 731; no duplicate row key; the added row is last.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: Claude:claude-fable-5 [Claude Code]
`origin/main` moved again while this branch's CI ran, and GitHub reported a
conflict that does not exist locally: `.gitattributes` sets
`.agents/issue-index.md merge=union` and the forge ignores that driver, so two
branches appending to the same append-only file read as conflicting.

This is the second re-merge this branch has needed for the same reason, and the
cost is a full CI re-run each time, because CI builds the merge commit rather
than the pull request head.

`.agents/issue-index.md` was resolved by taking `origin/main`'s file whole and
re-appending this branch's single row (#1998), derived from the diff rather than
from the file's tail. The automatic three-way merge was discarded unread: a
clean automerge of a keyed record is the failure mode here, not the success
case.

Verified after the resolution: 743 rows on `origin/main` plus this branch's one
is 744; no duplicate row key; the added row is last.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: Claude:claude-fable-5 [Claude Code]
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