Repository navigation
Hook ABI v5 goldens for units, anatomy, mid and the S lens; population artifacts, bf16 norm fix, --dtype - #70
Merged
Merged
Conversation
…to the runtime contract
…rms are described
…e fit no-op proofs
…rowser's offline unit packs
…tention-patterns and unit-ablation golden builders
…ens, with their parity tests
…ties by identity
The validator reads each ranked list one deeper and refuses a returned set
or a k-th entry without the margin to the best excluded (lens reads, unit
reads, unitTop, footprints, anatomy units and pattern heads); reads move to
another k and record it. Probability lists rank by ln p. Near-tie runs are
declared as {path, key, groups} and compared entry by entry, matched by
identity, with order kept between runs; unit-activity peak rows without a
margin are skipped by index, float16 populations allow one ulp.
unitFind records each greedy pick against its runner-up. Generated nodes
decode distinct greedy tokens with every pick decisive; unit-activity refuses
unmargined listed peak rows outside the tie case and one-signed traced
neurons, and gains the authored case. unit-probes records per forward from
the tap ring, with a gated case on a gate-only unit and the gate scalars.
lens-reads adds S direction reads and a session without an S lens; slens
records the lowered 0.3 slens/<word> push; token-anatomy carries every
case's intermediates. tests/units pins the top shortcut in all four cases.
The python tolerance becomes the library's (1e-5 + 1e-4|x|): Linux CI differed from the M5 by up to 1e-5 on sites and logits. Writing, every margin also clears twice that tolerance, and the parity test rebuilds on the file's recorded choices (each read's k, a case's top, the anatomy's knobs, the gate thresholds), so a rebuild elsewhere never re-decides near a threshold. Unit-activity row margins compare at their peak's scale, and a tuned top also skips listing an unmargined peak row.
# Conflicts: # AGENTS.md # tests/browser/test_browser_parity.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Python goldens for drowse.ai's hook ABI v5 (units, token anatomy, the
midsite and the S lens on WebGPU), plus the small contract and engine changes the browser parity plan needs.Goldens
tests/support/browser_units.pyowns theunits-tiny-models-v1fixture: gemma3_text and qwen3, 4 layers, d = 64, d_ff = 96, 4/2 heads × 16. Every weight comes from a portable 32-bit integer generator, so drowse.ai can rebuild the tensors bit for bit, and every linear and the embedding is q4f32_1-exact (power-of-two group scales with a ±7 in each group). The module has onebuild_<golden>per file andwrite_goldens, which enforces the validator and the size caps. Regenerate withPYTHONPATH=. python -m tests.support.browser_units --write.New files under
tests/fixtures/browser/. There is one model file, plus one file per arch for each of: block-sites, unit-stats, unit-ablation, unit-probes, unit-activity, lens-reads, slens, token-anatomy, attention-patterns, unit-reads, unit-artifacts and neuron-push. That is 25 files, 1.85 MB in total, the largest 191 KB. The caps are 256 KiB per file and 2 MiB overall. No existing golden changes.unit-probes records one entry per forward (prefill and decode steps) from the unit tap's ring, with a gated case on a gate-only unit and the gate scalars the decode loop saw. unit-activity covers generated, sink, sink-population, authored (a user turn's prompt capture), two-spans, all-excluded, excluded-and-zero and segmented. lens-reads includes S direction reads (uncentred) and a session with no S lens. slens records the lowered
0.3 slens/<word>push, and token-anatomy carries each case's intermediates.Every value comes from drowse's own machinery:
tap_token, the real steering scope and decode loop,UnitHook/UnitOp,NodeReplayer(unit_activity,token_anatomy,_activityfor the hand-built forwards),UnitReader, the lens instrument's reads and the S embedding statistics.test_units_golden_matches_pythonrebuilds each golden from a fresh fixture and compares it within the file's own tolerance block. The model file must regenerate byte for byte, and its q4 round trip is asserted.The validator refuses non-finite values, a sink row that moves under unit ablation, an ablation that moves no logit, a saturated attention row, and every top-k boundary without a 1e-3 margin. Each ranked list (lens reads, unit reads,
unitTophits, footprint top-k, the anatomy's unit lists and pattern heads) is read again one deeper: a changed returned set or a k-th entry that ties the best excluded refuses, and a read moves to anotherk(recorded in the file) until its boundaries clear. Probability lists rank byln p, the logit gap their order rests on.unitFindrecords each greedy pick with its runner-up and refuses a pick without the margin. Every greedy decode pick must be decisive, generated nodes decode distinct tokens (greedy with a presence penalty), and unit activity refuses a listed or traced unit whose peak row has no margin (outside the declaredexcluded-and-zerocase) and a traced neuron that keeps one sign.Goldens hold across platforms: the
pythontolerance is the library's (1e-5 + 1e-4|x|). When writing, every margin also clears twice that tolerance, and the parity test rebuilds on the file's recorded choices (each read'sk, a case'stop, the anatomy's knobs, the gate thresholds;build_golden(..., replay=)), so a rebuild on another platform never re-decides near a threshold.A near tie inside a list does not refuse: it is a run in
declared_ties({path, key, groups}). The comparison matches a run's entries by identity and compares every field (ids, strings, values), with order kept between runs. Unit-activity peak rows without a margin are skipped by index, and float16 populations allow one ulp.Engine and contract
contracts.ts:StructuredHookProfileIdgainsstandard-v4andstandard-v4-residual.standard-v1–v3stay until drowse.ai's libraries are recompiled.CatalogInstrumentPack.kindis nowcore | jlens | slens | units | sae.UnitReader.population_artifacts(layer)returns, per layer, what the browser ships offline: the population scalars (Rrho/lse/lse_neg, Snorm/footprint_std), the contrast statistics (S fires pooled), the heads' OV contrast, the head-norm mean derivatives and the whitened write norms.null_basis()andhead_kept_ids()are now public, so drowse.ai's pack builder doesn't reach into privates._norm_specnow judges each convention relative to its gain. When both fit (every gain large), the module itself, called with a zero weight throughtorch.func.functional_call, answers the offset; the closer median is only the fallback. Before this, a bf16 module with gains of several hundred (gemma-3-270m's MLP output norms, up to about 1,650) failed the absolute offset gap even though1 + wwas clearly the better fit. The regression tests (bf16 gemma3_text1 + wand gemma4_text plain, large gains, and twelve all-large draws per arch) fail before this change.--dtype float32|bfloat16|float16on every model-loading verb. It reachesfrom_pretrained(dtype=)and themodel_source_fingerprintthat the lens-fit and manifold no-op proofs key on, so a bf16 fit is never proven as an fp32 one. The loaded model's stamp already carried the parameter dtype.Checks
pytest -q -m "not gpu and not perf" -n 8: 6022 passed, 7 skippedruff check .: cleanpyright: 0 errors (the two remaining warnings are pre-existing)scripts/generate_webui_types.py --check: currentcd webui && npm ci && npm run check && npm run build: Node 24.22.1, passes, no dist drift