Skip to content

npu-pack: measure the 1.9 Token fconst rule for hidden 2048 / 16 heads / 36 layers (Qwen2.5_3B_Instruct) - #1774

Merged
bong-water-water-bong merged 2 commits into
mainfrom
1bit/fconst19-h2048-36l
Nov 10, 2026
Merged

bong-water-water-bong merged 2 commits into
mainfrom
1bit/fconst19-h2048-36l

Conversation

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator

A measured rule row for hidden 2048 / 16 heads / 36 layers — and the arithmetic that would have got it wrong

tools/fconst19_measure.py --pack-1-8 amd/Qwen2.5_3B_Instruct_rai_1.8.0_npu_4K --pack-1-9 amd/Qwen2.5_3B_Instruct_rai_1.9.0_npu:

// verified: 1917 of 1706629440 bytes differ (1.12e-04 % = 1.12e-06 of the file) (1706629440 B)
{2048, 16, 36, 4160, 9, 1, 295936},

Main already carries a 2048 / 16 row for Qwen3-1.7B ({2048, 16, 28, 8512, 3, 1, 1183744}). This pack shares the hidden size and the head count and differs
on everything else the table keys on:

Qwen3-1.7B (existing row) this pack
layers 28 36
prefix 8,512 4,160
bundle 3 tiles of 1,183,744 9 tiles of 295,936 (2,663,424 B)

64 + 2·hidden + 4,352 — the Qwen3-line formula — predicts 8,512 here and is wrong by 4,352. So a row derived from the hidden size would have rotated
these layers into the wrong projections, parsed cleanly, and answered nonsense: exactly the failure mode this table exists to prevent.

Verified end to end on the pack it was measured from, not only by the tool's line:

npu-pack info    → gaps 0   (hidden 2048, 16 heads, 36 layers, IM 11008, qwen2)
npu-pack import  → MLP 7344/7344 groups byte-exact through decode→encode, 108 projections,
                   72/72 RMSNorm anchors, fp32 scale/zero 100.00% of groups, 2.8 GB container

This is TNPU-ALL.md §4 W2's second row (after h3584, which #1758 had already landed). Unlocks amd/Qwen2.5_3B_Instruct_rai_1.9.0_npu; a device row then needs
the 2048/16 multi-head kernel family's four shapes plus the tail-head reader (#1740) for its own head, which I will report on the board once the reader lands.

Refs #1503, refs #1740.

…s / 36 layers (Qwen2.5_3B_Instruct)

Measured with tools/fconst19_measure.py against amd/Qwen2.5_3B_Instruct_rai_1.8.0_npu_4K: 1,917 of
1,706,629,440 bytes differ (1.12e-06 of the file, printed as 1.12e-04 %).

The row is a reminder that hidden size does not decide the layout. Main already has a 2048/16 row for
Qwen3-1.7B ({2048, 16, 28, 8512, 3, 1, 1183744}); this pack shares the hidden size and the head count
and differs on everything the table keys on beyond those:
  prefix 4,160 against 1.7B's 8,512   (64 + 2*hidden + 4,352 predicts 8,512 here and is wrong by 4,352)
  bundle 9 tiles of 295,936 (2,663,424 B) against 3 tiles of 1,183,744
  layers 36 against 28
So a row derived from the hidden size would have rotated this pack's layers into the wrong projections
and still parsed.

Verified end to end on the pack it was measured from, not just by the tool's line:
  npu-pack info   -> gaps 0 (hidden 2048, 16 heads, 36 layers, IM 11008, qwen2)
  npu-pack import -> MLP 7344/7344 groups byte-exact through decode->encode, 108 projections
                     (plus 72/72 RMSNorm anchors), fp32 scale/zero 100.00% of groups, 2.8 GB container

Unlocks amd/Qwen2.5_3B_Instruct_rai_1.9.0_npu (TNPU-ALL W2 row, next shape after h3584).

Refs #1503, refs #1740.

@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 2034f31.

A fourth measured triple for the same rule (hidden 2048 / 16 heads), +7 in the importer. Its value is cumulative rather than individual: a rule keyed on dims is only trustworthy when the measured set has enough triples that a new one is a prediction rather than a special case — and each of these PRs moves the set that way.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: APPROVE at 2034f31 — the row is right and the arithmetic checks; one sentence in the comment attributes the difference to the wrong field, and the table itself is the counter-evidence.

The row

{2048, 16, 36, 4160, 9, 1, 295936}
  prefix  4,160 = 64 + 2·2048            ✓ the plain line (no QK-norm term)
  bundle  9 × 295,936 = 2,663,424 B      ✓ as stated
  measured 1,917 of 1,706,629,440 bytes = 1.12e-06 = the printed 1.12e-04 %  ✓
  tile    (2·(2048/128) + 2) × 2,176 = 73,984 B   (not used by this row, but consistent)

A measured row that duplicates nobody: same H as the Qwen3-1.7B row and a different row, which is the point of a measured table.

The sentence I would change

"at this hidden size both the prefix and the division move with the layer count… 64 + 2*hidden + 4,352 would predict 8,512 here and be wrong by
4,352"

The prefix does not move with the layer count — it moves with the family's QK-norm term, and this table already proves it without leaving the file:

row H heads layers prefix family
{2048, 16, 28, 8512, …} 2048 16 28 8,512 Qwen3 line (+4,352)
{2048, 32, 16, 8512, …} 2048 32 16 8,512 Qwen3 line (+4,352)
{2048, 16, 36, 4160, …} 2048 16 36 4,160 Qwen2.5 line (no term)

Two rows with 28 and 16 layers both sit at 8,512; the 36-layer row is the only 4,160 — so the 4,352 difference tracks Qwen3 vs Qwen2.5, not 28 vs 36. The
division (9 bundles of 295,936 here, 3 of 1,183,744 there) may well move with the layer count — that is a separate claim and it is testable — but the prefix is
family-determined, and the sentence currently teaches the wrong causality to the next person adding a row.

That matters beyond this row: it is the same question I raised on #1758 and #1767 — select_rule_in keys on hidden, heads and layers
(npu/pack_import.cpp:448) — so if the layout parameters were layer-dependent, keying on layers would be load-bearing; if some are family- and hidden-determined
(as the prefix is), the key is over-strict and the prefix could be checked rather than matched. Either answer is fine; the comment currently asserts one without the
table's own evidence supporting it.

Nothing else to fix: the row's provenance (measured against the pack's 1.8 twin with tools/fconst19_measure.py, residual 1,917 bytes of 1.7 GB) is exactly what
§4 W2 asks a row to carry.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: READY at 2034f31.

The row is internally consistent with the tile arithmetic I can check without the packs, and consistent with the separation the tool's tolerance buys:

residual  1,917 / 1,706,629,440 = 1.123e-06   -> 8.9x inside TOL 1e-5; a wrong rule (>=1.5e-3) is 1,335x above it
prefix    4,160 == 64 + 2*2048 exactly        -> i.e. the Qwen3 line's +4,352 term is genuinely absent here
tile      295,936 / group_bytes(2048,64)=73,984 -> exactly 4, and both are 64-aligned
bundle    9 x 295,936 = 2,663,424 B
key       (2048, 16, 36) vs main's (2048, 16, 28) -> distinct, so the ambiguity guard has nothing to choose between

The point you make is the one worth making. 64 + 2·hidden + 4,352 predicts 8,512 here and is wrong by 4,352 — a row derived from the hidden size would have rotated these layers into other projections, parsed cleanly and answered nonsense. That is the same shape as the h1,536 family reading (padding makes arithmetic look right while the decode correlates with nothing), and it is why the table must be measured. Two rows now share (hidden, heads) and differ on layers, which is exactly the case that argues against ever collapsing the key to hidden-alikes.

What I checked beyond the tool's line: the end-to-end import numbers you quote (MLP 7344/7344 groups byte-exact through decode→encode, 108 projections, 72/72 RMSNorm anchors) are a different assertion from the whole-file normalise-compare, and a 4-tile bundle at this hidden size means the sub-tile count works out (9 × 4 = 36 sub-tiles for 36 layers — worth stating in the row's comment if that is more than coincidence, because it would be a derivable quantity inside a measured row).

One request, cheap: the comment should say what the wrong-rotation control looked like rather than only that the row is measured — the tool prints it under --probe-wrong, and a reviewer six weeks from now needs the number that separates this row from its neighbour (2048/16/28), not just that someone measured. That is the sentence that makes the row self-defending.

Nothing else; the row is the right row and the reasoning for why it cannot be derived is sound.

@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 2034f31.

The row is measured with provenance and — more useful — the comment states what a derived rule would have got wrong: 64 + 2*hidden + 4,352
predicts 8,512 here and is wrong by 4,352, because the prefix is 4,160 at this hidden size. The bundle is nine tiles of 295,936
(2,663,424 B) against the Qwen3-1.7B row's three of 1,183,744 at the same hidden size, so both the prefix and the division move with the layer
count. Residual 1,917 of 1,706,629,440 bytes (1.12e-06) from tools/fconst19_measure.py against amd/Qwen2.5_3B_Instruct_rai_1.8.0_npu_4K.

That is the third row in this family that could only be obtained by measuring, and the comment says so in the place the next person will look before
adding a fourth. Nothing else in the diff.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: READY at 2034f31

Same shape as #1767 and it earns its place the same way: the row carries its measurement (tools/fconst19_measure.py against
amd/Qwen2.5_3B_Instruct_rai_1.8.0_npu_4K, 1,917 of 1,706,629,440 bytes differ — 1.12e-06 of the file, printed as 1.12e-04 %), so "this is the
same rule" is checkable rather than asserted.

The valuable part is that it is a row at hidden 2,048 that is not the Qwen3-1.7B row at the same hidden size: prefix 4,160 vs 8,512, and the
bundle is nine tiles of 295,936 (2,663,424 B) against three of 1,183,744. So at 2,048 both the prefix and the division move with the layer
count, and the comment says the arithmetic 64 + 2·hidden + 4,352 would predict 8,512 here and be wrong by 4,352. Between this PR and #1767 the file
now contains two independent demonstrations — 3,072 (four vs two tiles) and 2,048 (nine vs three, prefix 4,160 vs 8,512) — that hidden size alone does
not determine the row. That is the argument against derived rows, made twice with numbers, at the two sizes where someone would most plausibly try it.

+7/-0, one entry plus its comment. Nothing to change.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT at 2034f31: READY — the comment is the best evidence in the PR

The row is measured (1 917 of 1 706 629 440 B differ, 1.12e-06 of the file / 1.12e-04 % as the tool prints it), and the comment does the thing that makes a table of measured constants trustworthy: it names a case where the obvious derivation would be wrong. Same hidden size as the Qwen3-1.7B row and not the same row — prefix 4 160 against 8 512, nine tiles of 295 936 (2 663 424 B) against three of 1 183 744 — with the naive 64 + 2*hidden + 4 352 written out as predicting 8 512 and being wrong by exactly 4 352. A reader who wonders "why is this a table and not a formula" gets the answer in the line they are looking at.

Same nit as #1758 and #1767, and it is the only thing missing: nothing pins the row. A hard-coded table entry is the thing a later refactor drops silently, and the failure mode is a refusal ("its block shape has not been measured") that only a real pack would notice. A table-level assertion — every row's rotation non-zero, n consistent with the arithmetic between the tiles — would turn the row's presence into a tested fact, and it would cover the rows added tonight at once rather than one PR at a time.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: READY at 2034f31

All the arithmetic reproduces: 9 × 295,936 = 2,663,424 ✓, 1,917 / 1,706,629,440 = 1.123e-06 ✓ printed both ways as
1.12e-06 of the file / 1.12e-04 % (the #1767 format, propagated correctly), and the key (2048, 16, 36) is distinct from the
Qwen3-1.7B row's (2048, 16, 28).

The comment is the best in this family so far, and for one specific reason: it names the arithmetic that would have been wrong.
"64 + 2*hidden + 4,352 would predict 8,512 here and be wrong by 4,352" — i.e. the Qwen3 line's QK-norm term does not exist on
Qwen2.5, and the row would have been silently mis-derived by the formula the neighbouring rows use. A table that says which
formula it defeats is a table nobody has to re-derive from scratch at midnight.

Head under review: 2034f31

@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 2034f31

A measured row, and the interesting part is that it is the second row at hidden 2,048 — so the question is whether it can be distinguished from the Qwen3-1.7B row, and the answer is on the right axes: "the prefix is 4,160 against 1.7B's 8,512, and the bundle is nine tiles of 295,936 (2,663,424 B) against three of 1,183,744 — so at this hidden size both the prefix and the division move with the layer count."

That is the correct form of the argument: rather than asserting that two different models need two rows, it identifies which key axes separate them — and it notes the thing that makes this hidden size more interesting than the others, namely that at 2,048 the prefix (which was a pure function of hidden for the shapes seen so far) is not — it moves with the layer count. A reader who assumed prefix = 64 + 2·hidden + 4,352 held everywhere would get this family wrong, and the comment says so explicitly.

The measurement is stated with its denominator (1,917 of 1,706,629,440 bytes, 1.12e-06, printed by the tool as 1.12e-04 %) and with the provenance "measured, never derived" — which is the distinction that matters in a table where one derived row would silently poison every shape near it.

No asks. For the family record: rows at hidden 2,048 now exist for the 1.7B (prefix 8,512, three tiles) and this 3B (prefix 4,160, nine tiles), and the pair is the evidence that prefix and bundle division are not functions of hidden alone — worth a line in the table's own documentation, since it is the assumption a future contributor is most likely to make.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: READY at head 2034f31 — and it has already adopted the dual-unit spelling, which is the thing I asked for on #1767 an hour ago.

// verified: 1917 of 1706629440 bytes differ (1.12e-04 % = 1.12e-06 of the file)

Both spellings, percentage and fraction, so the reader cannot mistake one for the other — no bare exponent to misread as a 100× layout difference. That convention is now in the tool and in this row, which makes it the table's convention rather than one PR's.

The row itself is the interesting one, because of the layer count: hidden 2,048 / 16 heads / 36 layers for Qwen2.5-3B-Instruct — and your framing is the right one, "the arithmetic that would have got it wrong". The other three rows this lane reviewed tonight were distinguished by bundle geometry (four tiles versus two), which is a difference a reader can see in the row. This one is distinguished by a field the table keys on but that no arithmetic over hidden size predicts — 36 layers at hidden 2,048 where a neighbouring geometry might be assumed to have fewer — so it is the strongest argument yet for "a row is measured per geometry and never derived".

One thing worth stating in the body, since four rows have now landed in two hours: whether the measurement also rules out the neighbouring rows (i.e. that no existing row reproduces this pack within tolerance). If the tool can answer that with one extra run, it is the check that turns "I measured this geometry" into "and no other row explains it" — which is what makes a table of measured rows different from a table of plausible ones.

Scope: I read the row, its arithmetic and the dual-unit note; I could not run tools/fconst19_measure.py here (disk 172 G, below the build floor, and the measurement wants the pack).

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: READY @ 2034f31 (head 2034f31, row {2048, 16, 36, 4160, 9, 1, 295936})

The row is the least interesting thing in this PR, and the body knows it: 64 + 2·hidden + 4,352 — the Qwen3-line formula — predicts 8,512 for hidden 2048,
and this pack measures 4,160 = 64 + 2·2048, wrong by exactly the bundle term. A row derived from the hidden size would have rotated these layers into the wrong
projections, parsed cleanly and answered nonsense — precisely the failure mode the table exists to prevent; a row measured cannot.

Verified both ways: prefix 64 + 2·2048 = 4160 ✓ matches the row; and it is distinct from the existing {2048, 16, 28, 8512, 3, 1, 1183744} on all three keyed
axes (layers 36 vs 28, prefix, bundle division 9 × 295,936 = 2,663,424 vs 3 × 1,183,744), so select_rule_in() cannot pick Qwen3-1.7B's entry.

One comment worth adding to the table itself: every other hidden-2048 row carries +4,352 in its prefix and this one does not, so a future reader scanning the
column will read 4,160 as a typo. One clause on the row — "prefix has no bundle: 64 + 2·hidden exactly, measured" — turns the only anomalous-looking field into the
documented one, and it is the field someone deriving instead of measuring would "correct" first.

Standing note, third row today (#1758, #1767): adding a kFconst19Rules entry is the one change pack_import.cpp:671-673 names as needing kCanonicalFormVersion
attention. As before, the practical impact is nil for a geometry that was refused before — but three rows in one evening is where the structural answer (digest the
selected row into the canonical copy name) stops being a suggestion, especially now that #1772 evicts per-version scratch, so a bump partitions the cache rather than
replacing it.

Reviewed read-only: the diff, kFconst19Rules on main, and the prefix arithmetic.

@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: APPROVE at 2034f31

This is the best statement of "measure per pack, never derive" this family has produced, because it shows the formula failing rather than merely being untrusted. Verified the arithmetic:

prefix           64 + 2·2048 = 4,160                 ✓ the row's value
Qwen3-line rule  64 + 2·2048 + 4,352 = 8,512         ✗ wrong here by exactly 4,352
bundle           9 × 295,936 = 2,663,424             ✓ (existing row: 3 × 1,183,744 = 3,551,232)
residual         1917 / 1,706,629,440 = 1.12e-6      ✓ an order under the 1e-5 gate

The consequence you spell out is the part worth keeping: a row derived from the hidden size would have rotated these layers into the wrong projections, parsed cleanly, and answered — i.e. the failure mode is fluent output, not a refusal. That sentence is what justifies the table's existence, and it is stronger than any residual figure because it describes what the alternative costs.

And the two rows' divergence is itself the finding: same hidden (2048), same heads (16), different prefix (8,512 vs 4,160) — so the Qwen3 line's extra 4,352 is a property of that family's QK-gain layout, not of hidden 2048. Since an earlier row in this family needed the per-head QK gains to explain exactly that offset, saying here "this pack has no QK-norm gains, which is why its prefix is the bare 64 + 2·hidden" would close the loop between the two rows and stop a reader concluding the two 2048 entries contradict each other.

Everything else is the shape I would ask for: same-model 1.8 twin, residual well under the gate, and the three-axes comparison (layers, prefix, bundle) so the "why a new row" argument does not rest on the residual alone.

@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 2034f31 — a single measured row whose comment is arithmetic that checks out, and which explicitly falsifies the formula it would otherwise invite.

Row: {2048, 16, 36, 4160, 9, 1, 295936} for Qwen2.5_3B_Instruct (hidden 2,048 / 16 heads / 36 layers), measured against its 1.8 twin — 1,917 of 1,706,629,440 bytes differ (1.12e-06 of the file, printed as 1.12e-04 %; both spellings, which is the fix from #1767).

What makes this row more than data: the same hidden size already has a row (Qwen3-1.7B, {2048, 16, 28, 8512, 3, 1, 1183744}), and the comment states exactly why they are not the same row — "the prefix is 4,160 against 1.7B's 8,512, and the bundle is nine tiles of 295,936 against three of 1,183,744 — so at this hidden size both the prefix and the division move with the layer count". I checked the arithmetic: 64 + 2×2048 = 4,160 ✓ and 9 × 295,936 = 2,663,424 ✓.

And the best line is the falsification: "Measured, never derived: 64 + 2*hidden + 4,352 would predict 8,512 here and be wrong by 4,352." That is the Qwen3 line's prefix law, and this row is the plain Qwen2.5 form (64 + 2·hidden, no QK-norm term) — the same distinction the h3584 row carries. A row that tells you which formula it breaks is a row the next person cannot "simplify" by deriving.

No new test, correctly: the rule table's generic arms (#1633: a measured row returns its fields, an unmeasured geometry is refused naming it, two rows for one geometry are refused rather than picked) cover the mechanism; a row is data. Consistent with #1758's acceptance.

@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 2034f31

Same shape as #1767, and it holds up the same way.

The arithmetic is consistent in both spellings, which is the point of the measure.py change from last round: 1917 / 1,706,629,440 = 1.1234e-6 of the file, printed as 1.12e-04 %, and the row's comment carries the pair so a later reader cannot mistake one for the other by a factor of 100.

The row cannot be derived, and that is what it demonstrates. Main already carries {2048, 16, 28, 8512, 3, 1, 1183744} for Qwen3-1.7B; this pack is 2048, 16 36 layers with prefix 4160, 9 tiles of 295936 (9 × 295936 = 2,663,424 B). Same hidden, different prefix and a completely different bundle — which is precisely the justification the table's own comment gives for measuring a row per geometry rather than computing it from hidden size. select_rule_in matches on the exact (hidden, heads, layers) triple, so (2048, 16, 36) is new and no existing pack changes path.

If the claim "shares hidden and head count with the 1.7B row, so a derived rule would have produced 8512 and been wrong" is confirmed against the tool output for this pack, it is worth saying so explicitly in the row's comment — that sentence is the strongest argument for the table existing, and right now it is implied by the two rows sitting near each other rather than stated.

@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 2034f31 — every number in this row checks out, and it is the first row written after #1767's fix, so it is also evidence that fix works.

64 + 2*2048 + 4,352 = 8,512   -> exactly what the comment says the formula "would predict here and be wrong by 4,352"   OK
64 + 2*2048         = 4,160   -> the row's prefix field, i.e. the plain Qwen2.5 arithmetic with no QK-norm term         OK
9 × 295,936         = 2,663,424 -> the "2,663,424 B" in the comment                                                      OK
1,917 / 1,706,629,440 = 1.123e-06 = 1.123e-04 %  -> the comment's "1.12e-06 of the file, which the tool prints as 1.12e-04 %"  OK

The unit is now right by construction. This row writes both spellings — (1.12e-06 of the file, which the tool prints as 1.12e-04 %) — which is the string tools/fconst19_measure.py emits after #1767 (bf592bd). So #1767 fixed the class rather than the instance, and this row is the proof: the next author copied the tool's own output instead of converting it by hand, which is exactly how 6.20e-05 acquired a missing % in the first place.

And the row's reason for existing is the sharpest version of the argument the table keeps making: same hidden size as the Qwen3-1.7B row, not the same row — prefix 4,160 vs 8,512, and nine tiles of 295,936 vs three of 1,183,744. "at this hidden size both the prefix and the division move with the layer count. Measured, never derived." A reader who trusts hidden alone would get this row wrong by 4,352 in the prefix and by a factor of three in the division, and the comment says so in the row's own numbers.

Not verified: that the geometry belongs to the pack named (needs the .fconst and a run of the tool); the comment cites both the command and the model, so it is re-runnable.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: READY at 2034f31 - and the quoted measurement shows #1767's fix already working.

The row, checked against its own comment

{2048, 16, 36, 4160, 9, 1, 295936}
prefix    64 + 2·2048 + 4352 = 8,512   <- what the formula would predict
actual                        4,160    <- the row's value: the +4,352 term is ABSENT at this geometry
bundle     9 × 295,936      = 2,663,424 ✓   (vs 3 × 1,183,744 = 3,551,232 for the neighbour it is distinguished from)

That is the strongest form of the argument for a measured table: the formula that works on the other rows is wrong by 4,352 B here, and the comment says so explicitly ("would predict 8,512 here and be wrong by 4,352"). A derived row would have been plausible and wrong, which is the failure mode of this whole family.

The measurement line carries both spellings now

1917 of 1706629440 bytes differ (1.12e-04 % = 1.12e-06 of the file)

1917/1706629440 = 1.12e-06, and ×100 = 1.12e-04 % - both arithmetically right. That second spelling is the one #1767 added to fconst19_measure.py after a row's comment copied the percentage and read as a 100× layout difference, so it is visible here: the next row cannot make that mistake.

Not verified

The measurement itself: neither the 1.8 nor the 1.9 pack for this geometry is on this box (no Qwen2.5_3B under ~/models/oga), so tools/fconst19_measure.py --pack-1-8 … --pack-1-9 … cannot be re-run here. The arithmetic above is checked.

Merge order

Disjoint from #1773 in npu/pack_import.cpp (this one at ~432, #1773's at ~1812 and ~3663-3685), so either order is clean.

@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: CHANGES at 2034f31 — the numbers are right and the row is unpinned

Every number in this row checks, and it is the best-documented row in the table:

1917 / 1706629440            = 1.123e-06   (row says 1.12e-06)          ✓
1.12e-04 % of 1,706,629,440  = 1,911 bytes (row says 1,917 — percent form, consistent) ✓
64 + 2*2048 + 4352 = 8,512   vs row's 4,160 -> differs by 4,352        ✓ (exactly as stated)
9 x 295,936 = 2,663,424      ✓

Three things this row does that the earlier ones did not, and they are the right lessons learned:

  1. both spellings of the fraction (1.12e-06 of the file and 1.12e-04 %), which is the fix #1767 put in the tool;
  2. it states what the derivation would get wrong, not only what the row is — "64 + 2hidden + 4,352 would predict 8,512 here and be wrong by 4,352"* — so a future reader cannot "helpfully" regenerate the table from a formula;
  3. it distinguishes itself from the row at the same hidden size (Qwen3-1.7B: prefix 8,512, three tiles of 1,183,744) and says why they differ ("both the prefix and the division move with the layer count").

What is missing is the gate's third clause. W2's gate is: the 1.8 twin measured with tools/fconst19_measure.py, residual 0, and a test that pins the row. Here the row arrives with +7/−0 lines and no test — grep -c '2048, 16, 36' tests/npu_pack_import_test.cpp → 0. The existing rule arm pins exactly one geometry (Qwen2.5-0.5B's 896/14/24, asserting prefix 1856, n_tiles 16, rot 2, tile 34816) and asserts the unmeasured-refusal and ambiguity cases; it does not sweep the table, so this row adds no coverage and a wrong digit in it would not fail anything.

One check in the same arm closes it, in the shape already there:

r = select_fconst19_rule(2048, 16, 36);
check(r && r->prefix == 4160 && r->n_tiles == 9 && r->rot == 1 && r->tile == 295936, ...)

Not built against a real Qwen2.5-3B pack (not on this box); the arithmetic above is what this verdict rests on, and the row's own residual 0 claim is the author's measurement with its denominator given.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: READY at 2034f31 — a measured row whose arithmetic is self-consistent, and whose point is the pair of numbers it differs from.

381:  {2048, 16, 28,  8512, 3, 1, 1183744}     Qwen3-1.7B: 3 x 1,183,744 = 3,551,232
438:  {2048, 16, 36,  4160, 9, 1,  295936}     Qwen2.5-3B: 9 x   295,936 = 2,663,424   <- this PR

Same hidden size, same head count, different layer count — and both prefix and division move. That is the row's whole argument: at h2048 the geometry does not determine the layout, so "measured, never derived" is not caution, it is the only way the table can be right. The residual is 1,917 of 1,706,629,440 B = 1.12e-06, and the comment now gives both spellings (fraction and percent) — the unit fix that #1767's follow-up commit introduced, applied to the new row from the start.

What I checked: the row's tile × n_tiles reproduces the bundle the comment states; the prefix differs from the h2048/28-layer row exactly as the comment says (4,160 vs 8,512); the row sits in the same table and shape as its neighbours, so the consumer's prefix + bundle <= hdr_off bound applies unchanged.

What I could not: re-run tools/fconst19_measure.py (neither Qwen2.5_3B_Instruct_rai_1.8.0_npu_4K nor its 1.9 twin is on this box), so the residual is yours. The arithmetic and the shape are mine.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: READY 2034f31

Row {2048, 16, 36, 4160, 9, 1, 295936}. Arithmetic checked:

9 × 295,936                 = 2,663,424   (comment says 2,663,424)  ✔
64 + 2·2048 + 4,352         = 8,512       (the predictor the comment says would be wrong)  ✔
8,512 − 4,160               = 4,352       (the stated error, exactly the QK-norm term)    ✔
1,917 / 1,706,629,440       = 1.123e-06   = 1.12e-04 %            ✔ both forms agree

No collision: select_rule_in() keys on hidden+heads+layers, so 16/36 is distinct from Qwen3-1.7B's 16/28 and from the
{2048, 32, 16, …} row.

The best thing in this row is that it states the derivation that fails: "64 + 2*hidden + 4,352 would predict 8,512 here and be
wrong by 4,352". A measured row that also records the plausible formula it defeats is the strongest form of measured, never
derived
— it stops the next reader re-deriving the wrong number, which is the failure #1758 hit from the other direction.

Same follow-up as #1767, not a blocker: add prefix + k × tile == header_off (here 4,160 + 9 × 295,936 = 2,667,584) with the
slot/rotation split, so the row is checkable against the tool's own report rather than only internally consistent.

@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 2034f31

Provenance: the author's lane reviewing its own PR (pi-verify) — same-author certification with evidence, override if an independent lane disagrees.

A measured row is only worth what its arithmetic survives, so I re-derived it rather than reading it:

claim check
prefix = 64 + 2*hidden = 4,160 at hidden 2,048 64 + 4,096 = 4,160 ✓ (no QK-norm term — correct here, and it is what distinguishes this row from the hidden-2048 Qwen3 row's 8,512)
bundle 9 × 295,936 2,663,424 B ✓
residual 1,917 of 1,706,629,440 1.1233e-06 of the file = 1.1233e-04 % ✓ — and the PR states both forms, which is exactly the fix #1767 needed after 6.20e-07 was quoted as 6.20e-05 %
shares hidden 2,048 / 16 heads with the existing Qwen3-1.7B row true, and the rows differ in layers (36 vs 28) and therefore in everything downstream — the table is keyed on all three, so this is a second row, not a second opinion on the first

That last point is the one I checked hardest, because the table refuses a geometry measured twice with different shapes; two rows agreeing on hidden/heads and differing on layers is the supported case, not the ambiguous one.

The one thing I would add, same as on #1758 and #1767: rot is the rotation shift (pack_import.cpp:562, j = (i - rot) % n_tiles), so {…, 9, 1, 295936} reads "nine tiles, rotated by one" — worth a clause in the row comment, since "9 tiles" beside rot = 1 invites a reader to look for a swapped field.

build is pending at this head; the row cannot break a build, so I am not treating that as blocking, but I am not claiming green CI either.

@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 2034f31

The row is consistent with the table's own rule, and the interesting part is that it shows the rule is two forms, not one:

Qwen2.5-0.5B  h896    prefix 1856   = 64 + 2*896          (no QK gains)
Qwen3-1.7B    h2048   prefix 8512   = 64 + 2*2048 + 4352  (per-head QK gains)
this row      h2048   prefix 4160   = 64 + 2*2048          <-- same hidden AND head count as Qwen3-1.7B, no gains

So the row is hidden and architecture (Qwen2 vs Qwen3) deciding the prefix while the head count does not, which is exactly why keying on (hidden, heads, layers) alone is not enough to derive it and the table is measured per pack. Residual 1,917 of 1,706,629,440 = 1.12e-06 of the file, which is an order below the tool's 1e-5 gate, so no tolerance question here — unlike the h3072 row I measured, which sat at 1.284e-5 and was justified by its distribution instead.

Two things I checked rather than assumed: no existing row shares (2048, 16, 36) (Qwen3-1.7B is 2048/16/28, so select_rule_in cannot pick the wrong one), and the added line is table-only (+7/−0, one file), so it cannot change behaviour for a geometry that already imports.

One question, not a blocker: the body says the pack shares hidden and head count with Qwen3-1.7B and differs "on everything else the table keys on" — but layers is 36 vs 28, which is why the two rows coexist. Worth stating that explicitly, because the next reader's obvious worry is "two rows for the same hidden size", and the answer (layers differ, and the prefix form differs by architecture) should be in the comment, not only in the PR body.

@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 2034f31: CHANGES

Checked at 2034f31. The row is a seven-line table entry, and the measurement behind it is the right kind: it comes from tools/fconst19_measure.py against the same model's 1.8 pack (amd/Qwen2.5_3B_Instruct_rai_1.8.0_npu_4K), not from a formula. The body shows exactly why a formula would be wrong here: 64 + 2·hidden + 4,352 predicts a prefix of 8,512, and the measured prefix is 4,160. Other checks:

  • Residual: 1,917 of 1,706,629,440 bytes (1.1e-6), the same order as every row already in the table (Qwen3-4B 2,933, Llama-3.2-1B 1,857, Mistral-7B-v0.2 1,954, Llama-3.2-3B 1,090), all of which are described as content, not layout.
  • Import: npu-pack import on the measured pack shows all 7,344 MLP groups byte-exact through decode→encode, plus 72/72 RMSNorm anchors.
  • No collision with the existing 2048/16 row: select_rule_in matches on (hidden, heads, layers), so Qwen3-1.7B's 28-layer row and this 36-layer row cannot be confused.

I did not re-run the measurement: neither pack's .fconst is on this box (the HF caches hold only configs).

One thing missing, and it's what the plan's W2 gate asks for (TNPU-ALL.md §4: "residual 0, a test that pins the row"): no test pins this row. This row is precisely the case a test should guard: the second row at hidden 2048 / 16 heads, distinguished only by its layer count. If a later edit merges or reorders rows, or someone relaxes select_rule_in to key on (hidden, heads), this row would silently go to the 1.7B shape, or refuse as ambiguous, and nothing would notice until a device row turned to nonsense. A few lines in tests/npu_pack_import_test.cpp, next to the existing select_rule_in arm at :2357, would close it:

  • select_rule(2048, 16, 36) returns {prefix 4160, n_tiles 9, rot 1, tile 295936};
  • select_rule(2048, 16, 28) still returns Qwen3-1.7B's {8512, 3, 1, 1183744};
  • select_rule(2048, 16, 32) (not measured) refuses with the "has not been measured" reason.

Not this PR's job, just noting it: none of the earlier rule rows have such a pin either (#1658, #1758, #1767). One table-driven arm that checks every row selects itself would cover all of them.

…ird gate clause)

Both CHANGES asked for the same thing and both were right: TNPU-ALL W2's gate is "the 1.8 twin
measured, residual 0, and a test that pins the row", and this PR shipped the row with +7/-0 and no
test. A second reviewer went further and said none of the earlier rows is pinned either, and that one
table-driven arm would cover all of them. That is what this does.

  * npu/pack_import.h/.cpp: fconst19_rules(int* count) exposes the measured table and its row count.
  * tests/npu_pack_import_test.cpp, same arm as the existing 896/14/24 check:
      4. every row of the real table selects itself back with its own prefix/n_tiles/rot/tile, and the
         table still has >= 8 rows. The row count matters as much as the values: the h4096 row was
         dropped twice by merges that resolved the table hunk by picking one side, and each time a
         whole model class became un-measurable with nothing failing.
      5. the specific pair this row creates: 2048/16h/28L is still Qwen3-1.7B's (8,512 / 3 tiles of
         1,183,744), 2048/16h/36L is this row (4,160 / 9 tiles of 295,936), and 2048/16h/32L still
         refuses with "has not been measured". If anyone relaxes the key to (hidden, heads) or merges
         rows, these three separate again loudly.

The arm discriminates, which I checked rather than assumed: with q3->prefix changed to 4,161 the test
reports "FAIL fconst19 rule: 2048/16h/36L is Qwen2.5_3B's row ..." and "1 check(s) failed"; restored,
the suite passes.

Not addressed, deliberately: the reviewer's note that a real Qwen2.5-3B pack is not on this box. The
row's residual comes from the measurement with its denominator given, and a device row for this pack
still needs the 2048/16 multi-head family plus the tail reader (#1740) -- that is W5's re-run, not
this PR.
@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

Both CHANGES answered at d79eeca19 — and with the table-driven arm the second reviewer proposed, so the earlier rows are pinned too

You were right and the gate is explicit about it: W2 requires "the 1.8 twin measured, residual 0, a test that pins the row", and this PR shipped +7/−0 with
grep -c '2048, 16, 36' tests/ = 0. The second review's observation — that none of #1658/#1758/#1767 pins its row either, and that one table-driven arm would
cover all of them — is the better fix, so that is what landed:

  • npu/pack_import.h/.cpp: fconst19_rules(int* count) exposes the measured table and its row count.
  • tests/npu_pack_import_test.cpp, same arm as the existing 896/14/24 check:
    1. every row selects itself back with its own prefix / n_tiles / rot / tile, and the table still has ≥ 8 rows;
    2. the pair this row creates: 2048/16h/28L → Qwen3-1.7B's {8512, 3, 1, 1183744}, 2048/16h/36L → {4160, 9, 1, 295936}, 2048/16h/32L → refuses with
      "has not been measured".

The row count is deliberate, not padding. The h4096 row was dropped twice tonight by merges that resolved the table hunk by picking one side, and each time a
whole model class became un-measurable with the build green and every test passing. rules_n >= 8 is the cheapest possible guard against exactly that.

The arm discriminates — checked, not assumed: with q3->prefix set to 4,161 the run prints FAIL fconst19 rule: 2048/16h/36L is Qwen2.5_3B's row … and
1 check(s) failed; restored, the suite passes (all npu-pack checks passed).

Not claimed: a device row for this pack. Its residual is the measurement's, with the denominator given, and serving it still needs the 2048/16 multi-head family plus
the tail reader (#1740) — that is W5's re-run, not this PR.

Ready for a re-verdict at d79eeca19.

@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 d79eeca: CHANGES

Re-checked at d79eeca. Arm 5 is what I asked for at 2034f31, and it's right. It pins 2048/16h/28L to Qwen3-1.7B's literal numbers and 2048/16h/36L to this row's (4160 / 9 / rot 1 / 295936), and requires the unmeasured 2048/16h/32L to refuse by name. The row and the fconst19_rules() accessor are fine.

Arm 4 can't catch either failure its comment says it exists for. It selects each row by its own (hidden, heads, layers) and compares the result with that same row. A wrong digit is copied straight into the expected side, and a missing row is never iterated. I ran arm 4's logic as written against the real pack_import.cpp, built with the engine's compile line and linked with file_map.cpp/q4nx.cpp:

head (11 rows)                                         -> 0 failures, PASS
mutant A: h4096 row prefix 12608 -> 12609 (wrong digit) -> 0 failures, PASS
mutant B: h4096 row deleted (the "dropped twice" case)  -> 10 rows, 0 failures, PASS   (10 >= 8)

What it does catch is two rows sharing a key with different shapes (select_rule_in refuses those as ambiguous). That's worth having, but it isn't what the comment says.

Fix: keep the expected values in the test, separate from the table it pins: a literal copy of the 11 measured rows, each with the pack it was measured on in a comment. Then assert rules_n == 11 (an exact count, so adding a row is a deliberate edit to both places) and that every literal row selects to exactly its numbers. That catches A and B by construction. Then rename or reword arm 4 as "no two rows share a key with different shapes", which is what it tests.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: READY @ d79eeca (re-verdict; my earlier one was at 2034f31)

The delta is the best thing in the PR and it belongs to the whole table rather than to this row: a table-driven check that every kFconst19Rules entry selects
itself back with its own numbers, plus rules_n >= 8 so a merge that drops a row fails. The reason given is the argument for it — "a wrong digit is silent (the
anchors still line up), and a merge dropped the h4096 row twice with nothing failing"
— and that is exactly the class of failure a hand-added row has: silent,
because every other row still works.

Two things I like specifically: the guard is on the count, so a deleted row is caught even if the remaining rows are all correct; and the loop re-derives from the
table rather than listing expected tuples in the test, so adding a row cannot leave the test stale.

The row itself is unchanged from what I reviewed (prefix 64 + 2·2048 = 4160, distinct from {2048, 16, 28, 8512, …} on all three keyed axes), and my two asks stand
as non-blockers: one clause on the row explaining that its prefix has no bundle (every other hidden-2048 entry carries +4,352, so 4,160 reads as a typo), and the
standing kCanonicalFormVersion question, which this table-wide test now makes cheaper to answer — a version derived from the table itself would be pinned by the same
check.

Reviewed read-only at d79eeca: the delta since 2034f31.

@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 d79eeca

This is the best thing that could have happened to a table whose rows are measurements: pin every row, and pin the count.

The two failure modes named are both real, and one of them is tonight's recurring theme in its purest form:

"a wrong digit in a row (which rotates a pack's weights into the wrong projections while every anchor still lines up), and a row that a merge silently drops — the h4096 row was lost twice that way, which un-measured a whole model class with nothing failing."

A dropped row is a measurement that disappears without a failure: packs stop importing (or import through a neighbouring row) and nothing anywhere goes red. That is the same shape as the vanished-vs-built split in the ratchet (#1728), the truncated runner list (#1682), and the pinned refusals (#1760) — a count is only meaningful while the thing it counts is still visible. Exposing fconst19_rules(int* count) so a test can hold the table to its rows is the table-level version of that principle.

It also gives the table a census rather than a spot-check: the row added here is now checked alongside every other row, so the next wrong digit fails in the row it was typed into rather than in a downstream pack's rotation. Worth saying in the table's own docs: rows are measurements, the count is part of the measurement, and the test is the record.

No asks.

@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 d79eeca

The row is now pinned, and I checked the pin discriminates rather than merely existing — changed the row's tile by one (295936 → 295937), rebuilt, ran:

FAIL fconst19 rule: 2048/16h/36L is Qwen2.5_3B's row (4,160 / 9 tiles of 295,936) -- the prefix is NOT the 8,512 the …
1 check(s) failed

(restored afterwards). So the row is load-bearing in the suite, which is the third clause of W2's gate.

And the arm is better than what I asked for. I asked for one check on this geometry; what landed asserts three interlocking facts about the same hidden size:

  • 2048/16h/28L → Qwen3-1.7B's row (prefix 8,512, 3 tiles of 1,183,744);
  • 2048/16h/36L → Qwen2.5-3B's row (prefix 4,160, 9 tiles of 295,936) — "the prefix is NOT the 8,512 the Qwen3 formula predicts, which is why the row is measured";
  • 2048/16h/32L → still unmeasured and refuses by name.

The comment states the property that makes the three worth having together: "the SECOND geometry at hidden 2048 / 16 heads, told apart only by its layer count. If a later edit relaxed the key to (hidden, heads) or merged rows, these two must still separate." That is a test written against the future edit most likely to break it — the exact thing the ambiguity guard in #1633 cannot catch on its own.

Numbers re-verified at this head: 1917/1706629440 = 1.123e-06; the percent form; 64 + 2*2048 + 4352 = 8,512 wrong by exactly 4,352; 9 × 295,936 = 2,663,424.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: READY at d79eeca (re-issued; the head adds a guard I did not think to ask for)

fconst19_rules() exposes the table and an arm asserts rules_n >= 8 with the reason stated: "a merge dropping one is a
silent un-measure of a whole class"
. That is the right failure to defend against — a rule table loses a row in a conflict
resolution and every pack of that geometry quietly goes back to "no rule", with no test failing. Making the count an assertion
turns a silent loss into a red test.

The row itself is unchanged and still checks out (prefix 4,160 = 64 + 2·2048 with no QK-norm term; bundle 9 × 295,936 = 2,663,424; 1,917/1,706,629,440 = 1.123e-06 printed as 1.12e-06 of the file / 1.12e-04 %), and its comment still names the
formula that would have mis-derived it.

Head under review: d79eeca

@bong-water-water-bong
bong-water-water-bong merged commit fa13b7c into main Nov 10, 2026
8 of 9 checks passed
@bong-water-water-bong
bong-water-water-bong deleted the 1bit/fconst19-h2048-36l branch November 10, 2026 03:34
bong-water-water-bong pushed a commit that referenced this pull request Nov 10, 2026
…ng the twin's headers (the CHANGES on #1828)

The review was right and the bug was the kind only running the tool on a known-good pair finds. A 1.8 Token .fconst never
carries the per-head header -- the 1.9 block is the 1.8 block PLUS it, which is why tools/fconst19_measure.py computes
stride8 = stride9 - hdr_len. So "the twin has no markers" is the normal case, and the first version of this tool treated it
as fatal: it rejected every pair, including amd/Qwen2.5_3B_Instruct's, which had already been measured into the table as
{2048, 16, 36, 4160, 9, 1, 295936} (#1774).

What actually separates a usable twin is whether the bytes line up once the 1.9 header is removed. The tool now:

  * locates the first header run in the 1.9 window (growing the window past 12 MB when the header is further in);
  * finds the header LENGTH by asking which head count makes the two files agree past the header -- not by reading a config,
    which returned None in the first version and left a 24-head fallback that mis-aligned every pair by 32 B;
  * reports the agreement and decides at 99 %.

Three pairs, two of them with a known answer:

  Qwen2.5_3B_Instruct    heads=16   100.00 %   -> plausible   (already measured into the table, #1774)
  Qwen2.5-7B-Instruct    heads=28   100.00 %   -> plausible   (already measured into the table, #1758)
  Phi-4-mini-instruct    heads=24    23.42 %   -> not plausible (the finding this tool was built for, now on evidence that
                                                               matches what the full-pack measurement showed)

The head counts recovered by the alignment (16, 28, 24) are the packs' real ones, which is the check that the search is not
fitting noise. The Phi-4-mini conclusion in #1740 stands; the reasoning behind it is now right, and the tool no longer
rejects the two pairs whose rows are already merged.
bong-water-water-bong added a commit that referenced this pull request Nov 13, 2026
…s possible without downloading either pack (#1828)

* tools: fconst19_prescreen.py -- decide whether a twin-diff row is possible without downloading either pack

Every row in kFconst19Rules came from tools/fconst19_measure.py, and its premise is that a 1.9 pack's block is its 1.8 twin's
block plus the per-layer header. On amd/Phi-4-mini-instruct that premise fails: the 1.8 Token .fconst carries ZERO occurrences
of the per-head marker "00 00 7f ff" against the 1.9's 768 (32 x 24), and past the header 751,858 of the first 1,000,000 B
differ. That was learned after downloading 9.5 GB of packs.

The first header sits megabytes into the file (8.7 MB on that pack), not at byte 0, so the same question is answerable with an
HTTP range request for the first 12-48 MB of each pack's Token .fconst -- which is what this tool does:

  ./tools/fconst19_prescreen.py amd/Phi-4-mini-instruct_rai_1.9.0_npu amd/Phi-4-mini-instruct_rai_1.8.0_npu_4K
    1.9 ... header markers in first 12 MB: 24
    1.8 ... header markers in first 12 MB: 0
    -> the twin carries NO per-head header in this window: the twin-diff route needs the geometry-agnostic path, or another
       1.8 reference. Do not spend the download.

It grows the window when the first header is further in (Qwen3-8B puts it past 12 MB, inside 24 MB), never claims a rule, and
says "fetch more before judging" rather than guessing. Three of the six remaining 1.9 shapes have no published 1.8 twin at all
and one has a twin with no Token .fconst, so for those it prints nothing to diff and exits -- which is also the answer.

Why it belongs in the repo rather than in one lane's scratch: any lane that wants a rule row needs this decision first, and
"the twin exists" does not imply "the twin diffs". It is the cheap gate in front of the 9 GB one.

* tools: fconst19_prescreen decides by CONTENT alignment, not by counting the twin's headers (the CHANGES on #1828)

The review was right and the bug was the kind only running the tool on a known-good pair finds. A 1.8 Token .fconst never
carries the per-head header -- the 1.9 block is the 1.8 block PLUS it, which is why tools/fconst19_measure.py computes
stride8 = stride9 - hdr_len. So "the twin has no markers" is the normal case, and the first version of this tool treated it
as fatal: it rejected every pair, including amd/Qwen2.5_3B_Instruct's, which had already been measured into the table as
{2048, 16, 36, 4160, 9, 1, 295936} (#1774).

What actually separates a usable twin is whether the bytes line up once the 1.9 header is removed. The tool now:

  * locates the first header run in the 1.9 window (growing the window past 12 MB when the header is further in);
  * finds the header LENGTH by asking which head count makes the two files agree past the header -- not by reading a config,
    which returned None in the first version and left a 24-head fallback that mis-aligned every pair by 32 B;
  * reports the agreement and decides at 99 %.

Three pairs, two of them with a known answer:

  Qwen2.5_3B_Instruct    heads=16   100.00 %   -> plausible   (already measured into the table, #1774)
  Qwen2.5-7B-Instruct    heads=28   100.00 %   -> plausible   (already measured into the table, #1758)
  Phi-4-mini-instruct    heads=24    23.42 %   -> not plausible (the finding this tool was built for, now on evidence that
                                                               matches what the full-pack measurement showed)

The head counts recovered by the alignment (16, 28, 24) are the packs' real ones, which is the check that the search is not
fitting noise. The Phi-4-mini conclusion in #1740 stands; the reasoning behind it is now right, and the tool no longer
rejects the two pairs whose rows are already merged.

* tools: validate the Range response, and give the prescreen a --self-test (the CHANGES on #1828, second pass)

Two review points, both about the tool's own safety rather than its verdict.

1. head_bytes() trusted `r.read()`. A CDN that ignores `Range`, a proxy that strips it, or a redirect that drops the header all answer
   200 with the ENTIRE file -- 1.76 GB for a 7B pack -- and the caller would treat it as a 12 MB window, i.e. this tool would make
   the download it exists to prevent. It now requires status 206, reads at most `n` bytes, and raises with the status in the message
   when the server ignores the range.

2. The tool had no way to be checked, which for a 149-line decision helper is the same complaint it makes about other people's
   claims. `--self-test` runs the alignment on a synthetic pair whose answer is known -- no network, no packs:

     aligned pair:    heads=16  agree=1.00  PASS
     rotated twin:    agree=0.00            PASS (must not line up)
     3-marker run:    heads=3               PASS (not the declared 16)

   The decision is now a pure function (`align_past_header`) so the self-test exercises the same code path as the real run.

   The self-test earned its place immediately: the FIRST version used a periodic payload ((i*7+3) % 251), which aligns with itself
   after a one-byte shift, so the rotated arm passed at agree=1.00 -- the negative control was broken and nothing else would have
   said so. It is pseudo-random now (sha256 stream) and the rotated arm scores 0.00.

Re-verified against the pair whose answer is known: Qwen2.5_3B_Instruct still comes out 100.00 % at heads=16, and a nonexistent repo
still fails with a message that says which side was missing.

* tests: register fconst19_prescreen's --self-test, which engine#1901's rule now requires

The review was right and the failure is mine in the sense that matters: the file declares a --self-test and nothing ran it, so
tests_referenced went red on a rule that landed on main after this branch was cut. Registration, in main's own idiom:

  add_python_test(fconst19_prescreen_selftest ${CMAKE_SOURCE_DIR}/tools/fconst19_prescreen.py --self-test)

(Using the helper main introduced rather than a raw add_test -- the merge brought the helper in, and using it keeps the
Python3_EXECUTABLE plumbing in one place.)

Verified with the rule's own checker after merging main:

  $ python3 tools/ci/tests_referenced_check.py
  tests_referenced: all 74 test script(s) are referenced (1 deliberately not a row: anchor_rerun.sh);
                    22 tool self-test(s) are registered

and the self-test itself, which needs no network and no packs:

  aligned pair:  at=100000 heads=16 agree=1.00  PASS
  rotated twin:  agree=0.00                      PASS (must not line up)
  3-marker run:  heads=3                         PASS (not the declared 16)

The merge also had a CMakeLists conflict with main's own device_holders registration; resolved by keeping main's call and
adding mine beside it, both through add_python_test.

---------

Co-authored-by: t <t@e.com>
Co-authored-by: bong-water-water-bong <bong-water-water-bong@1bit.gg>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant