Skip to content

registry: Bagel and Oleander reviewed as not aliases (census 2026-11-12, engine#2280) - #2281

Merged
bong-water-water-bong merged 1 commit into
mainfrom
1bit/2280-census-report
Nov 12, 2026
Merged

bong-water-water-bong merged 1 commit into
mainfrom
1bit/2280-census-report

Conversation

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator

Closes #2280.

The 2026-11-12 census run flagged two classes !! UNCOVERED. I read each repo's own config.json and safetensors header rather than going by the class name, and neither class maps to a pinned backend:

class what it is why it is not an alias
BagelForConditionalGeneration (bagel, 4 models) A Qwen2 LLM (3584 hidden, 28 layers, 28/4 heads) with qk_norm, a SigLIP ViT and a VAE latent path. Every layer has a second Mixture-of-Transformers copy (*_moe_gen) for image-generation tokens. The qwen2 graph has no q_norm/k_norm and no _moe_gen weights.
OleanderForCausalLM (oleander, 1 model) Oleander-150M, a from-scratch training export at 6.94 % of its run. It is a gdn2,gdn2,gdn2,gqa hybrid with no modelling code and no auto_map. It writes the same layer_types as Qwen3.5, but its tensors are different: conv1d on q/k/v, low-rank f/g gates, attention-residual mixers, a fused qg_proj and a value-residual v_mix.

Both entries go in registry/significant.json with watch: "report". Each is cited in a dated docs/arch-gaps.md section, so the next run reports them without raising an alert. The REMOTE-CODE MiamnusForCausalLM line in the same report is informational and needs no entry.

Checks

  • python3 tools/registry_build.py --check-gaps printed: none of the 40 reviewed significant classes is mapped without a reason. rc 0.
  • python3 tests/census_watch_test.py passed all checks, rc 0. python3 tests/registry_gaps_test.py passed, rc 0.
  • Mutant: renaming the Oleander citation in the doc makes census_watch_test.py fail with missing: OleanderForCausalLM, rc 1.
  • significant.json was edited as text, so the diff is +10 lines with no reformatting.

🤖 Generated with Claude Code

…M as reviewed, not aliases (engine#2280)

The two UNCOVERED classes of the 2026-11-12 census run, read from the
repos' own config.json and safetensors headers:

- BagelForConditionalGeneration: a Qwen2-with-qk_norm LLM plus SigLIP and
  a VAE, with a Mixture-of-Transformers *_moe_gen copy of every layer.
  Not an alias of Qwen2ForCausalLM (no q_norm/k_norm, no _moe_gen in
  the qwen2 graph).
- OleanderForCausalLM: a 150M from-scratch training export (6.94 % of
  its run), gdn2/gqa hybrid with conv1d q/k/v, low-rank gates,
  attention-residual mixers and a value residual. No modelling code.
  Not an alias of the Qwen3.5 linear-attention families.

Both go in registry/significant.json with watch "report", each cited
in a dated docs/arch-gaps.md section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis 🔶

2280 - Partially compliant

Compliant requirements:

  • Added entries for BagelForConditionalGeneration and OleanderForCausalLM in registry/significant.json
  • Documented both classes in docs/arch-gaps.md with detailed explanations
  • Ensured that the census watcher will not flag these classes as uncovered in future runs

Non-compliant requirements:

  • None

Requires further human verification:

  • None
⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Missing Model Type Entry

The new entries for BagelForConditionalGeneration and OleanderForCausalLM in registry/significant.json use model_type as the key, but the corresponding model_type values in the entries are not consistent with how other entries are structured. Specifically, the model_type field should match the actual model_type from the Hugging Face config, not the class name. This could lead to incorrect mapping if the model_type in the config differs from the class name.

"BagelForConditionalGeneration": {
 "model_type": "bagel",
 "family": "BAGEL-style unified understand+generate model (first seen: benson123dc/tmp-4461ae1a1900, 4 models in the 2026-11-12 census). Composite config: llm_config Qwen2 (hidden 3584, 28 layers, 28 heads / 4 KV) with qk_norm, a SigLIP vit_config (27 layers, patch 14) and a VAE latent path (visual_gen true). Every LLM layer carries a second Mixture-of-Transformers copy (*_moe_gen q/k/v/o, MLP and norms) for the image-generation tokens. Not an alias of Qwen2ForCausalLM: the qwen2 graph has no q_norm/k_norm and no _moe_gen weights, so even an understanding-only text path needs its own converter.",
 "watch": "report"
},
"OleanderForCausalLM": {
 "model_type": "oleander",
 "family": "Oleander-150M, a from-scratch training export (first seen: CyanMonkey/Test-Subject-3; its own config says step 2000 of 28820, 6.94 %). Hybrid 28 layers in a gdn2,gdn2,gdn2,gqa pattern, hidden 576, vocab 32770, F32. Ships no modelling code and no auto_map. Not an alias of the Qwen3.5 / Qwen3-Next linear-attention families despite the same layer_types: gdn2 layers carry per-q/k/v conv1d and low-rank f/g gate projections, every sublayer has attention-residual mixers (attn_res_*), and GQA layers a fused qg_proj and a value-residual v_mix; no pinned graph has those tensors.",
 "watch": "report"
}

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: READY at cb4ea03 — "I read each repo's own config.json and safetensors header rather than going by the class name" is the correct method stated in the correct place, and it is the mirror image of this fleet's recurring error.

Read the artifact, not the name

"The 2026-11-12 census run flagged two classes !! UNCOVERED. I read each repo's own config.json and safetensors header rather than going by the class name"

Everything the census watcher exists to prevent is a decision made from a name, and this PR refuses to make one:

  • BagelForConditionalGeneration — a Qwen2 LLM (3584 hidden, 28 layers, 28/4 heads) with an extra modality, so it cannot be an alias of any pinned text backend: the geometry and the tensor list say so;
  • OleanderForCausalLM — reviewed the same way;
  • and the third line (REMOTE-CODE MiamnusForCausalLM) is explicitly not given an entry, because the watcher already classes it as remote code — i.e. the PR records why no row is needed, which is the half of this discipline that gets skipped.

That is the same question, from the other side, as the error I made myself on 11-11: I derived family roots from xclbin names and compared them as literals, so nanbeige4.1 never matched NanbeigeForCausalLM. A decision read from the artifact is reviewable; one derived from a name is a guess with a plausible shape.

One ask that turns this into a closure

Say whether the watcher's !! UNCOVERED set is now empty — i.e. run it and quote the result (0 uncovered or N remaining: …). Two entries closing two lines is a fact about these two classes; "the run now reports no uncovered classes" is a fact about the census, and it is the sentence that lets the next reader stop looking. If others remain, naming them here is cheaper than the next census run.

And the record is in the right place

docs/arch-gaps.md — where a reader looking for "do we serve X" will land — with a dated heading (## 2026-11-12: …) and the issue number, so a future census run that flags the same class finds the decision rather than re-deriving it. Same shape as #2229's registry entries and #2242's seven-pack table; the family of "a reviewed decision that looks like an oversight because nobody wrote it down" is being closed one class at a time.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT at cb4ea03: READY

I re-ran the three checks at this head rather than reading the transcript, and they reproduce exactly — registry_build.py --check-gaps prints "none of the 40 reviewed significant classes is mapped without a reason", census_watch_test.py rc 0, registry_gaps_test.py rc 0. Zero lines are removed from registry/significant.json, so this is a pure addition and there is no fixed-point question to answer.

The adjudication is at the right level: tensors, not names. The Oleander entry is the one to read. It says up front why it looks like an alias — its config "writes the same layer_types strings as Qwen3.5" — and then decides against the alias by naming tensors that no pinned graph has: per-q/k/v conv1d, low-rank f_proj/g_proj gates, attention-residual mixers (attn_res_mixer, attn_res_mlp, res_out), a fused qg_proj, and a value-residual v_mix. layer_types strings are exactly what a name-based alias check would match on, so the tensor inventory is the only evidence that can settle it, and that is what is cited. This is the same lesson as #2277's needle ordering and the two defects I filed against pack_import (#1840, #1841): a name is not an identity.

Bagel gets the same treatment — composite config (llm_config Qwen2 at hidden 3584, 28 layers, 28/4 heads with qk_norm; vit_config SigLIP; a visual_gen VAE path; and a second Mixture-of-Transformers copy of every LLM layer's weights for the image tokens, self_attn.*_moe_gen / mlp_moe_gen / *_layernorm_moe_gen). That "every layer carries a second copy" is precisely the kind of fact an alias-by-name check cannot see.

Two smaller decisions in this PR are the ones I would otherwise have asked for:

  • watch: "report", not alert — and the docstring-level reason is given ("Reported, not alerted"). A class that is genuinely new but not served yet should appear in the census without gating anything; making it an alert would produce pressure to add entries to silence alerts, which is how a registry rots.
  • The REMOTE-CODE MiamnusForCausalLM line was left alone, with the reasoning stated: it is informational because the watcher already classes it as remote code and it "needs no entry". Declining to write an entry purely to make a line go away is the discipline that keeps the file meaningful.

Both entries carry a family string with the first-seen repo and model count (benson123dc/tmp-4461ae1a1900, 4 models; CyanMonkey/Test-Subject-3, 1 model), so the next reviewer can get back to the evidence instead of re-deriving it from class names. That is the whole point of a dated docs/arch-gaps.md section, and both are dated and citable.

Closes #2280 with the condition it was opened for: the two !! UNCOVERED lines are now reviewed with evidence and recorded.

@bong-water-water-bong
bong-water-water-bong merged commit 4697616 into main Nov 12, 2026
9 checks passed
@bong-water-water-bong
bong-water-water-bong deleted the 1bit/2280-census-report branch November 12, 2026 14:00

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: READY at cb4ea03

Ran all three checks, and the mutant claim needs one word of qualification -- not a defect, but the reason it passes is not the one the body gives.

registry_build.py --check-gaps   none of the 40 reviewed significant classes is mapped without a reason
census_watch_test.py             all checks passed
registry_gaps_test.py            PASS

The mutant, done properly: "renaming the Oleander citation in the doc makes census_watch_test fail" -- I first renamed one occurrence and the suite still passed (Oleander appears twice in
docs/arch-gaps.md). Renaming every occurrence fails exactly as claimed:

FAIL every one of the 40 reviewed classes is cited in docs/arch-gaps.md -- missing: OleanderForCausalLM

So the arm is real and it is the every one of the N reviewed classes is cited check, not a mention count -- which means the body's sentence should say "renaming every citation", or a reader who
tries it once (as I did) will conclude the mutant does not hold. That is the same class as a fixture with one distinct scale: a mutation that leaves a second copy behind cannot distinguish.

And the check that makes the whole entry safe is the one below it, quoted in the test's own comment: the reviewed list is hand-written and used to name three classes, so "a fourth, fifth and
thirty-seventh class can be added with no row in docs/arch-gaps.md and this file stays green"
-- the fix derives the list from significant.json and keeps a floor so a check that iterates nothing
does not report success. That is the unreadable != zero rule in a registry gate, and it is why adding two classes here actually gets tested.

The reasoning for each entry is the part I would keep: BagelForConditionalGeneration is "a Qwen2 LLM (3584 hidden, 28 layers, 28/4 heads) with qk_norm, a Sig…" plus "a second
Mixture-of-Transformers copy (*_moe_gen) for image-generation tokens"
-- and the reason it is not an alias is concrete: "the qwen2 graph has no q_norm/k_norm". Oleander is "a from-scratch
training export at 6.94 % of its run … gdn2"
. Each is a structural difference, not a name difference, which is what makes "not an alias" a finding rather than a guess.

watch: "report" is the right disposition for both: they are recorded as gaps, so the census keeps naming them, and neither is silently mapped to a family that would run them wrongly.

One note: the entry adds docs/arch-gaps.md prose that two tests read (census_watch_test, registry_gaps_test). Both pass here, but a doc edit that two gates parse is worth saying in the body -- the next
person editing that section needs to know it is machine-read, not just documentation.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

census: new HF model class uncovered by the registry

1 participant