Conversation
|
Important Review skippedToo many files! This PR contains 1468 files, which is 1368 over the limit of 100. To get a review, narrow the scope: Upgrade to a paid plan to raise the limit. Usage-priced reviews support at most 300 files. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (12)
📒 Files selected for processing (1701)
You can disable this status message by setting the Warning Billing warning: we have not been able to collect payment for this subscription for more than 72 hours. Please update the payment method or pay any pending invoices in Billing to avoid service interruption. |
| } | ||
| store.mu.Lock() | ||
| defer store.mu.Unlock() | ||
| return scanAgentRun(store.connection.QueryRow(runSelect+" WHERE id = ?", id), "Run") |
| } | ||
| store.mu.Lock() | ||
| defer store.mu.Unlock() | ||
| runResult := scanAgentRun(store.connection.QueryRow(runSelect+" WHERE id = ?", runID), "Continuation") |
| } | ||
|
|
||
| func queryAgentLogs(connection *sql.DB, suffix string, arguments ...any) ([]work.LogChunk, error) { | ||
| rows, err := connection.Query("SELECT run_id, sequence, stream, text, created_at FROM agent_log_chunks "+suffix, arguments...) |
| pli.astype(np.float32).tofile(os.path.join(OUT, "pli.f32")) | ||
| layer_out.tofile(os.path.join(OUT, "layer_out.f32")) | ||
| attn_res.tofile(os.path.join(OUT, "attn_res.f32")) | ||
| json.dump({"ids": IDS, "T": T, "H": H, "NL": NL, "PLID": PLID}, open(os.path.join(OUT, "manifest.json"), "w")) |
| layer_out[li] = h | ||
| print(f"layer {li:2d} {'S' if is_sliding else 'G'}{'' if has_kv else ' shared->' + str(prev[li])}: |h| max {np.abs(h).max():.3f}") | ||
|
|
||
| os.makedirs(OUT, exist_ok=True) |
| # SDPA, scale 1.0, causal (+ sliding window), GQA broadcast kv head | ||
| o = np.zeros((T, NH, hd), dtype=np.float64) | ||
| gqa = NH // nkv | ||
| for hh in range(NH): |
| attn_res = np.zeros((NL, T, H), dtype=np.float32) | ||
| kv_bank = {} | ||
|
|
||
| for li in range(NL): |
| by_type = {} | ||
| for i in range(M): | ||
| by_type[LTYPES[i]] = i | ||
| for j in range(M, NL): |
| } | ||
| s.mu.Lock() | ||
| defer s.mu.Unlock() | ||
| item, err := scanItem(s.conn().QueryRow(itemSelect+" WHERE id = ?", id)) |
| if count == 0 { | ||
| return core.Fail(datasetNotFoundErr("tui.duckDatasetStore.DatasetArchive", "dataset", id)) | ||
| } | ||
| d, err := scanDataset(s.conn().QueryRow(datasetSelect+" WHERE id = ?", id)) |
| } | ||
| s.mu.Lock() | ||
| defer s.mu.Unlock() | ||
| d, err := scanDataset(s.conn().QueryRow(datasetSelect+" WHERE slug = ?", slug)) |
| } | ||
| s.mu.Lock() | ||
| defer s.mu.Unlock() | ||
| d, err := scanDataset(s.conn().QueryRow(datasetSelect+" WHERE id = ?", id)) |
| // can observe or claim the same seq value. | ||
| func (s *duckDatasetStore) nextSeqLocked(table string) (int64, error) { | ||
| var next int64 | ||
| if err := s.conn().QueryRow("SELECT COALESCE(MAX(seq), 0) + 1 FROM " + table).Scan(&next); err != nil { |
`lem serve --capture <slug>` and `lem ssd --dataset <slug>` tee completed turns / sampled traces into a lem data dataset, stamped with a path-derived model fingerprint. Both taps stay entirely CLI-side: neither go/serving nor go/train exposes a completion hook (ServeConfig has no OnComplete field; RunSSDCommand returns only an error), so serve's tap is a captureTextModel inference.TextModel decorator injected via serving.ServeConfig.Loader — mirroring go/serving/welfare_guard.go's decorator shape one layer up, including the captureSchedulerModel variant that keeps capture live under `-scheduler` (the same Unwrap/SchedulerModel bypass bug class welfare_guard.go's own doc comment documents and fixes). ssd's tap reads back the ssd-captures.jsonl sidecar train.RunSSDCommand already writes and lands each row as a KindTrace item via a small local dedupe-then-append helper (go/dataset exports no dedicated trace ingest path; KindTrace is never welfare-screened either way). Both taps are OFF by default (no store touched without the flag) and log-and-continue on a capture failure — proven directly: a --capture pointing at a missing dataset fails the serve boot closed before any listener binds; a failing store still lets every token stream through via a fake-store unit test. Receipts: cli main package 273 tests pass after this commit (588 across all 3 cli-module packages); go build/vet/gofmt clean.
…tor has_sinks lane
Rung 1 of the gpt-oss serving ladder (#37): every gpt_oss layer's self_attn.sinks
(bf16 [heads] — verified [64] BF16 in the real gpt-oss-20b-MLX-4bit shard header)
now loads through the neutral assembler and dispatches through the MLX
sdpa_vector kernels' has_sinks(25) function-constant lane.
Binding contract, read from the PINNED kernel source (external/mlx @ v0.32.0,
mlx/backend/metal/kernels/sdpa_vector.h — the exact source of the shipped
metallib; no lthn patch touches sdpa):
- sdpa_vector: sinks buffer(16) + num_q_heads buffer(17), indexed
sinks[q_batch_head_idx % num_q_heads]
- sdpa_vector_2pass_1: sinks buffer(18), head idx from the grid, seeded ONLY
in block 0; pass 2 unchanged (sink mass rides block 0's
sums/maxs)
- semantics: seeds the online softmax max=sink, sum=1 — one extra softmax
column per head contributing denominator mass, never value mass.
Semantics cross-checked against both lineage references, fetched 2026-07-19:
- transformers modeling_gpt_oss.py eager_attention_forward:
cat([attn_weights, sinks]) -> softmax -> drop the last column;
sinks = nn.Parameter([num_attention_heads])
- mlx-lm gpt_oss.py: scaled_dot_product_attention(..., sinks=self.sinks) —
the checkpoint's own lineage drives exactly this kernel lane.
Wiring: WeightNames.Sinks ("" default; gptoss overrides ".self_attn.sinks") ->
Assemble loads RAW (never the NormBiasOne fold) -> LoadedLayer.Sinks ->
Decode/QuantizedLayerWeights.Sinks -> archLayerBufs.sinks -> the attention
halves' new trailing `sinks bufView` -> encSDPADecodeSinksAt routes the
has_sinks pipeline variants (own PSO cache keys; the plain caches untouched).
Lane policy (correct-first): a sinks session declines the paged-KV pool
(lthn_paged_* kernels have no sinks lane) and the batched attention fold
(multi-query kernels ditto — doubly guarded: gpt_oss has no qNorm so the fold
was already ineligible); decode + batched per-row prefill run the linear-cache
sdpa_vector lane end to end. Paged/multiQ sinks are named perf follow-ups.
Gates:
- host oracle: softmaxWithSinkF32 + sdpaHostRefWithSinks, byte-gated against
the LITERAL concat-softmax-drop reference + a hand-computed case
(expectations independently re-derived in python before commit)
- emit ABI: recording-sink tests prove sinks bind at 16/17 (single) / 18
(pass 1) AND that the plain emitters bind NOTHING there (the non-sinks
regression, host-side, no GPU needed)
- GPU parity: SDPAWithSinks / SDPA2PassWithSinks vs the host oracle + a
must-differ-from-plain-SDPA check (engine/metal's TestMain runs them at the
orchestrator's metallib gate; skipped cleanly without it, as designed)
- done-gate: go build -tags metal_runtime ./... OK; go vet OK;
go test -count=1 -tags metal_runtime ./model/... ./engine/metal/ . —
4664 passed, 0 failures (3 new assemble sinks tests + gptoss weights-name
assertions included)
Arch() still refuses: the o_proj/router/expert biases (rung 2) and the YaRN
attention_factor (rung 3) remain unconsumed.
Co-Authored-By: Virgil <virgil@lethean.io>
…per-expert gate/up/down biases
Rung 2 of the gpt-oss serving ladder (#37): every additive bias beyond BQ/BK/BV
that the checkpoint ships (all BF16 in the real gpt-oss-20b-MLX-4bit shard
header, read 2026-07-19: o_proj.bias [2880], mlp.router.bias [32],
mlp.experts.{gate,up,down}_proj.bias [32,2880]) now has a consumer.
References (fetched 2026-07-19):
- mlx-lm gpt_oss.py: router = nn.Linear(hidden, num_local_experts, bias=True)
-> the router bias is INSIDE the logits the top-k reads (bias before top-k);
SwitchGLU(..., bias=True) -> per-expert projection biases;
o_proj bias via attention_bias=true (transformers modeling_gpt_oss.py:
nn.Linear(..., bias=config.attention_bias) on o_proj).
BO: QuantizedLayerWeights/DecodeLayerWeights gain BO (mapped from L.O.Bias —
LoadLinear had already captured it); both projectors gain bO and biasView now
answers projO. Every existing arch loads no o_proj.bias -> zero bufView ->
encProjBias no-ops -> dispatch stream byte-identical (gated by
TestProjector_BiasViewProjO_Good; TestProjector_ProjectOBias_Good proves
biased == bias-free + AddBF16(BO) byte-for-byte on GPU).
Router + experts: MoEQuantLayerWeights gains the gpt_oss block (ClampedSwiGLU
marker + SwigluLimit + RouterBias + ExpGate/Up/DownBias), mapped by moeToQuant
ONLY under Activation "gpt_oss_clamped_swiglu" (model.Arch gains SwigluLimit;
gptoss.buildArch declares it, 7.0 default per transformers' GptOssConfig).
encGptOssMoEHalf (new arch_gptoss_moe.go) decodes the layer: PreFFNorm -> host
router logits + bias -> softmax -> top-k -> renormalise (gptOssRouterTopK,
factored + unit-tested: the fixture bias FLIPS the selection, proving
bias-before-top-k; nil bias == zero bias) -> ONE MoEExpertsQuantClampedSiLU
dispatch -> residual. MoEExpertsQuantClampedSiLU gains gateBias/upBias/downBias
(per-expert slices added right after each matvec — gate/up BEFORE the clamp,
down before the router-weighted combine), gated byte-for-byte against the
composed biased reference (TestMoEExpertsQuantClampedSiLU_Biases_Good); nil
biases skip the adds — the pre-bias encode stream, and the existing composed-
reference test still passes on the nil form. MoEExpertsQuant (gemma GELU) and
MoEExpertsQuantSiLU (qwen) untouched entirely.
Routing safety: the ClampedSwiGLU marker intercepts in stepToken BEFORE the
qwen/gemma MoE branches; sharedEncodeEligible and batchedMoEUsable both decline
clamped layers (host half breaks the cb; the batched block encodes the gemma
dual-branch shape), so gpt_oss can never silently ride a wrong MoE lane.
moeToQuant regression: a silu/gelu arch maps ZERO gpt_oss fields even when its
Linears carry .bias tensors (TestGptOssMoE_MoeToQuant_Ugly).
Done-gate: go build -tags metal_runtime ./... OK; go vet OK; go test -count=1
-tags metal_runtime ./model/... ./engine/metal/ . — 4664 passed, 0 failures.
Arch() still refuses: the YaRN attention_factor (rung 3) remains unconsumed.
Co-Authored-By: Virgil <virgil@lethean.io>
Wires the judge:<name> half of `lem data score`, replacing Task 6's
placeholder refusal with a real end-to-end driver.
- judges/ at the repo root: 3 default templates (quality, factuality,
refusal-correctness), each 0-100, plus README.md documenting the
minimal front-matter + {{prompt}}/{{response}} format.
- cli/judgetemplate.go: front-matter parsing, MIN-MAX range parsing,
placeholder rendering, and the strict bare-number score parser
(rejects prose, out-of-range values, and NaN/Inf — ParseFloat
accepts both and a NaN comparison is always false, so this needed an
explicit finite check). Resolution order is a pure function
(resolveJudgeTemplateFrom) so override-wins is directly testable
against two dirs, with the real production paths (~/.lem/judges/ via
a new tui.OpenJudgesDir, the in-repo default via a bounded upward
walk anchored on go.work+judges/) wired in separately.
- cli/tui/paths.go: appPaths.Judges + OpenJudgesDir, following
OpenDatasetStore's resolve-then-ensure shape (Task 5's paths
contract, no --home override).
- cli/judgedriver.go: newJudgeDispatcher loads the --model checkpoint
ONCE via inference.LoadModel (never per item), resolves/caches
templates by name, and implements go/dataset's JudgeDispatcher
seam — render, greedy generate (temp 0, bounded max-tokens) via
TextModel.Chat, thinking-channel strip, strict parse, Score with the
judge model's fingerprint. The pure core
(newJudgeDispatcherFromModel) takes an already-loaded TextModel so
it's testable against a stub with no GPU.
- cli/data.go: `--kind judge:<name>` requires `--model`; the model
loads only when there's at least one item to score; a malformed
judge reply is a loud per-item stderr line, never a silent 0.
Tests: template resolution order (override wins, in-repo fallback,
empty-dir fallthrough), render placeholder filling, parse Good/Bad/Ugly
(in-range / out-of-range / non-numeric garbage incl. NaN), the bounded
repo-root walk (found / bound-too-small / anchor-without-judges-dir),
an integration check that the real shipped judges/*.md parse cleanly,
the stub-model dispatcher (good path, template caching, unknown
template, generation error, malformed item content, unscorable kind,
and three malformed-output Ugly cases), and the verb's
refuse-without-model / skip-load-on-empty-dataset / honest
load-failure cases.
Done-gate (cli/): go build ./... clean, go vet ./... clean,
go test -count=1 ./... — 644 passed, 0 failed, 3 packages.
Ticks Task 9's three boxes in
docs/superpowers/plans/2026-07-19-lem-dataset-loop.md.
Co-Authored-By: Virgil <virgil@lethean.io>
…() resolves, gpt-oss serves
Rung 3 of the gpt-oss serving ladder (#37): the last named gap. The
application point, verified against BOTH lineage references fetched
2026-07-19 (cited verbatim in buildArch's comment):
- transformers modeling_gpt_oss.py GptOssRotaryEmbedding.forward:
"cos = emb.cos() * self.attention_scaling; sin = emb.sin() *
self.attention_scaling" with attention_scaling = attention_factor
default 0.1*ln(factor)+1 (modeling_rope_utils _compute_yarn_parameters)
and self.scaling = head_dim**-0.5
- mlx-lm rope_utils.py YarnRoPE.__call__ (the checkpoint's own lineage):
"x[..., : self.dims] = self.mscale * x[..., : self.dims]" before
mx.fast.rope — the same factor on the pre-rope input (rotation is
linear, the two are identical)
Both q AND k emerge scaled by mscale -> the attention logits carry mscale².
gpt_oss is FULL-rotary (rotaryDim == headDim), so folding mscale² into the
SDPA scale is algebraically EXACT: AttnScale = mscale²/sqrt(headDim)
(factor 32 -> mscale 1.34657 -> 0.22665755, confirmed on the real
checkpoint). Sinks stay outside the fold (the kernel's scale multiplies q
only; the sink seeds the softmax raw) — exactly the reference. Non-YaRN
configs keep the plain 1/sqrt(headDim) (regression:
TestConfig_Arch_NonYarnScale_Good + the qwen35 AttnScale anchor in
TestNonYaRNArch_RopeFreqs_Unchanged — the fold lives entirely inside
gptoss.buildArch).
Arch() now returns buildArch() — the refusal is LIFTED (all three rungs
consumed: sinks rung 1 / biases rung 2 / attention_factor here). Docs,
example and every refusal-pinning test flipped to pin the resolution
instead; model-side smoke against the REAL gpt-oss-20b-MLX-4bit checkpoint:
Arch resolves (24 layers / 32 experts / AttnScale 0.22665755 / clamped
limit 7), all 24 layers load [64]-bf16 sinks, q/o/router/expert biases all
captured at exactly the shard-header byte sizes, embed 4-bit gs=64 untied.
Live gate extended per the brief: live_generate_test.go (darwin/arm64 +
metallib + local checkpoint; test-only import of engine/metal) loads
through the full registered path (native.LoadDir -> quant arch session on
the linear-KV sinks lane) and asserts a REAL greedy generation: few-shot
capital prompt must contain "Paris", plus a second non-degenerate
continuation (>=8 tokens, >=3 distinct ids, non-empty text). The
orchestrator runs it at merge with the GPU.
Done-gate: go build -tags metal_runtime ./... OK; go vet OK; go test
-count=1 -tags metal_runtime ./model/... ./engine/metal/ . — 4665 passed,
0 failures (TestLive_RealCheckpoint_ParseAndBoundary ran live against the
local real checkpoint and passed).
Co-Authored-By: Virgil <virgil@lethean.io>
Fifth panelID, `Data`, beside Chat/Work/Models/Service — the human review surface for the dataset loop, per the approved design's "Review surface (TUI)" decision. Follows Work panel's list+detail+palette+overlay shape throughout; every write goes through dataset.Store (OpenDatasetStore's duckDatasetStore in production), never raw DuckDB. - **List** (datapanel.go): items ACROSS datasets — Store.Items requires one DatasetID per call, so a cross-dataset view merges one call per matching dataset, re-sorted here. Filters (dataset/status/kind/source/ score) via a tiny grammar (parseDataFilterExpr) mirroring cli/data.go's --filter clauses plus dataset=<slug>; sort toggles date/score in place. j/k + bubbles' own filter idiom, matching Work. - **Detail**: content via the existing Glamour path (markdown.go, same renderer Chat uses); full score breakdown (every Score row + its payload pretty-printed, generic across lek/hostility/sycophancy/judge:* — no hardcoded schema); lineage (parent via Item.ParentItemID, children by scanning the dataset — Store has no "children of X" query); welfare flags (reviewer == auto:welfare); review history via the new ReviewHistoryStore optional capability, falling back to ReviewLatest when the connected store doesn't expose it (dataset.MemoryStore). - **Actions** (dataoverlay.go for the overlay seams): approve/reject (direct, no overlay — friction scales with blast radius); quarantine- clear and tag (dataNoteOverlay, note/label required to submit); edit- as-derived (dataItemEditor, two textareas, Ctrl+S saves — creates the derived Item, archives the original via the new ItemArchiver optional capability, approves the child, exactly as go/dataset's Item doc comment specifies); bulk-apply-to-current-filter (dataBulkOverlay, a two-phase arm/confirm mirroring changeAcceptanceOverlay — "no confirm, no writes" proven at the panel, overlay, and full key-driven app level). Palette mirrors every action (data.* commands, the agentcap pattern via dataCapability/dataWorkspaceCommandsForContext); unavailable actions render their reason rather than hiding. - **Two go/dataset gaps closed CLI-side, not in go/** (Task 9's lane owns go/; ItemArchive and full review history were never in Store's shipped contract): ItemArchiver and ReviewHistoryStore, small optional interfaces on duckDatasetStore discovered by type assertion — this repo's own "separate interface, never extend the base one" idiom. "tag" has no dedicated field in the domain model either, so it rides the Review note channel, status preserved, documented as such. - **`lem data review [slug]`** (cli/data.go, diff isolated to this one verb): tui.RunDataReview opens the real interactive program focused on Data, pre-filtered to slug via connectWorkspace's new resources. DatasetStore (best-effort opened in openWorkspaceWithContext, its own datasets.duckdb — a store problem degrades to a warning, never blocks Chat/Work, matching State/Preferences' own precedent). Kept the fallback message: runDataReviewTUI is an injectable seam (default tui.RunDataReview) because tea.NewProgram's WithAltScreen opens /dev/tty directly regardless of the stdout/stderr passed in — calling the real thing from `go test` would hang or open a live session on any box with a controlling terminal, so tests drive the seam, never the real program (matching this codebase's existing precedent: Run's own interactive branch has zero direct test coverage either). - Found and fixed a real bug while wiring this: connectWorkspace's activateManagedSession(..., true) unconditionally forced activePanel back to Chat, silently discarding RunDataReview's Data focus. Fixed generally (preserve any non-Chat activePanel requested before connect survives the session-activation reset) — a no-op for every existing caller, all of which already start on Chat. Tests: panel state machine (construction, selection-preserved-across- refresh, sort toggle, filter set/round-trip via SetFilterExpr/FilterExpr, parseDataFilterExpr Good/Bad/Ugly); every action incl. the note-required guards (QuarantineClear/Tag reject blank input, proven to write nothing); EditAsDerived Good (real duckDatasetStore) and Bad (MemoryStore lacks ItemArchiver — refuses loudly, zero mutation); BulkApply Good/Bad (edit- as-derived has no bulk form; a rejected bulk call proven to write nothing); Capabilities Good/Bad (honest availability matrix); render snapshots per the layout-test idiom (structural + ansi.Strip'd substring checks + the lipgloss.Width overflow bound, at two widths). The explicit bulk-confirm-gate proof: dataBulkOverlay's own two-phase Confirm() unit test, plus TestApp_DataPanelBulkConfirmGate driving real key messages end-to-end (open → esc → no write; open → one enter arms → no write; second enter → writes). Plus app wiring (attachData incl. the nil-store honest-unavailable path, route/panelView dispatch, every hotkey flow), palette wiring (TestDataCommandPalette_Good), and bootstrap wiring (TestOpenWorkspace_DatasetStoreOpensAndCloses / ...FailureDegrades...). Receipts: go build ./... clean; go vet ./... clean; go test -count=1 ./... — 649 passed, 0 failed, 3 skipped, across all 3 cli-module packages (588 pre-existing + 61 new; zero regressions). Plan: docs/superpowers/plans/2026-07-19-lem-dataset-loop.md Task 8 boxes ticked. Co-Authored-By: Virgil <virgil@lethean.io>
…an complete (Task 10) The capture -> score -> review -> export loop closes its plan: - docs/cmd-lem.md: the \`data\` verb family (subcommands, the enforced loop rules, judge templates), serve --capture and ssd --dataset flag rows, verbs-at-a-glance entry. - cli/tui/README.md: the fifth Data panel row + its key idiom (lowercase acts on the selection, uppercase bulks across the filter behind a count confirmation). - Design doc synced with the Task-5 learning: raw SQL over go-orm's DuckDB lane (gaps tracked as #45), behaviour pinned by the dual-store conformance table. - Plan Task 10 ticked with the honest coverage receipts: go/dataset 96.7% (176 tests, bar 95%); cli/tui 73.1% (360 tests, below-bar recorded); cli suite 705 passed. Co-Authored-By: Virgil <virgil@lethean.io>
| if count == 0 { | ||
| return core.Fail(datasetNotFoundErr("tui.duckDatasetStore.ItemArchive", "item", id)) | ||
| } | ||
| item, err := scanItem(s.conn().QueryRow(itemSelect+" WHERE id = ?", id)) |
…/V rows MeasureReal runs the existing Q_mse codec (b=2/3/4 plus the live cache's K4/V3 mixed config) over real captured K/V rows through the same measureOne/CodecReport machinery MeasureCodecs drives, so a real-kv row is scored identically to the synthetic sweep. SaveRealKVRows is LoadRealKVRows' write-side companion, for committing a capture fixture. RFC #41 slice S3 (evidence before the 3.5-bit live-cache default). Co-Authored-By: Virgil <virgil@lethean.io>
DumpKVRows reads a resident cache-owning layer's post-RoPE K/V rows back to host float32, one row per (attention head, cached token) — the granularity TurboQuant's codec operates over. It reuses CaptureKV's own accessors (stateLayerViews, nativeKVLayerCaptureWindow, stateBlockLayerBytes, nativeKVTokenRowsToLayerSlab, nativeKVLayerSlabHeads) rather than re-deriving the cache geometry; read-only, issues no GPU work of its own. RFC #41 slice S3. Co-Authored-By: Virgil <virgil@lethean.io>
…4 e2b)
TestTurboQuantRealKVCaptureReceipt (LEM_TQ_CAPTURE=1) loads the actual
gemma-4 e2b-4bit checkpoint, decodes a real prompt to session position 691,
taps every distinct global-attention cache-owning layer via DumpKVRows,
measures each with turboquant.MeasureReal, and writes the small committed
CI fixture (testdata/real_kv_{keys,values}.bin, 32 rows/side, ~128 KB) that
go/kv/turboquant's TestMeasureReal_Ugly now exercises instead of skipping.
This checkpoint has only 3 distinct-cache global-attention layers (4, 9,
14 of 35), not the nominal 7 full_attention-typed layers: gemma4's
num_kv_shared_layers=20 routes layers 19/24/29/34 onto layer 14's cache
(model.DeriveLayers), so a 4th distinct sample does not exist on this
architecture. RFC #41 slice S3.
Co-Authored-By: Virgil <virgil@lethean.io>
…-4 e2b Real K/V relative-MSE (the paper's metric) sits within -0.5% to +1.5% of the published Gaussian-oracle constant at b=2, and +14% to +16% (b=3) / +4% to +8% (b=4) above it. K and V differ from each other by at most 3.7% at any sampled layer/bit width, sign-inconsistent across the 3 layers measured — the data does not support K4/V3's asymmetric bit allocation on relative-MSE grounds. RFC #41 slice S3. Co-Authored-By: Virgil <virgil@lethean.io>
…1 S3)
The decode cache for qualifying GLOBAL attention owners now holds TurboQuant
codes — packed Lloyd-Max centroid indices in a rotated basis + one f32 norm
per row per head (the kv/turboquant Q_mse wire format; turboquant_device.go
stays the format authority) — with the decode SDPA reading codes directly.
Mode contract (fixed): -kv-cache turboquant (bare = 3.5), :4, :3.5 (K4/V3),
:3, :2; SupportedCacheModes reports [native, turboquant]; off (empty/native)
is byte-identical to today (existing suite is the proof).
Kernels (kernels/lthn_tq_kv.metal, template instantiations 128/256/512 with
kBits/vBits as function constants 27/28, blocks fc 26 as MLX):
- lthn_tq_kv_store_bf16_b{2,3,4}: bf16 staging row -> per-head codes + γ
(one threadgroup per head, the q8 store's ICB rebind shape at binds 3/4)
- lthn_tq_rot_rows_bf16 / lthn_tq_unrot_rows_bf16: Π·x / Πᵀ·x over bf16 rows
— q pre-rotated once per step per layer, output unrotated once (the
O(output) fold; nothing O(n·d²) inside the KV scan)
- lthn_sdpa_vector_tq_bf16_{D} + lthn_sdpa_vector_2pass_1_tq_bf16_{D}: the
q8 pair's structure verbatim with code unpack + centroid lookup + row-γ
loads; pass 2 stays MLX's unchanged merge
Recorded-ICB lane: TQ owners land K/V into fixed staging, two store ops
rebind per token (prepareStepRebind), the SDPA reads codes via rot->sdpa[->
pass2]->unrot; layerOpStarts carries the extra ops (total() gains nTQOps).
Plumbing: LoadConfig.CacheMode + WithCacheMode; serve/generate pass
-kv-cache into the load; metal parses (parseTurboQuantCacheMode) and refuses
unknown modes loudly.
v1 declines (each tested): paged KV, MTP pairing, composed/hybrid/mamba2,
MoE + attention-sinks archs, no-qualifying-layer, batched dense pass (falls
back to the TQ-aware per-token replay), prompt reuse (whole prefill), KV
snapshot / -state sleep (stateLayerViews chokepoint), laneSet, submit-ahead
peer (recordPeerICB nil -> serial chained tail).
Receipts:
- kernel gate: store parity vs kv/turboquant.EncodeQMSE + SDPA vs f64 oracle
on dequantised rows at hd 128/256/512 × modes (4,4)/(4,3)/(3,3)/(2,2) ×
kv {1,2}, single-pass AND 2-pass: max |Δ| ≤ 0.0041 in 33/36 cases, worst
0.0369 (hd=512 k4v4) — asserted band 0.08 (~2× worst measured)
- session gate: TQ vs native stepwise hidden cosine min 0.999182 over 8
steps on the synthetic gemma4; K code cache < half the bf16 cache
- metallib rebuilt via task metallib:kernels; cli/lthn_kernels.metallib.gz
refreshed
Co-Authored-By: Virgil <virgil@lethean.io>
…2E gates + example (#41 S3) The bring-up bug: the recorded arch ICB is built with maxKernelBufferBindCount=16 (bind indices 0..15) and the TQ pass-1 bound vCentroids at index 16 — a SILENT no-op under ICB recording, so the kernel read garbage as the V centroid table. Encoder paths carry no bind cap, which is why every encoder-driven gate was tight while the live 2-pass session read 30/64 agreement at |logit Δ| 32. Isolated by op-level bisection: a minimal [rot, pass1] ICB was byte-identical to the encoder; adding pass-2's consumption exposed the corrupted V-side partials. Fix: repack the 2-pass ABI — kCentroids -> 6 (the MLX ABI's free slot), vCentroids -> 15; max bind index now 15 on every TQ kernel. The emit ABI test pins bind 16 EMPTY so the cap can never silently eat a bind again. Receipts (real gemma-4 e2b-4bit, greedy, teacher-forced 64 steps): - 2-pass lane (maxLen 2048): top-1 agreement 62/64, max |logit Δ| 6.31 - single-pass lane (maxLen 512): 62/64, 6.76 — same codec band - retrieval smoke: fact planted 1047 tokens back retrieved exactly (7412) through the code caches over an 1107-token per-token-replay prefill - minimal-ICB isolation after the fix: |icb - encoder| = 0.000000 - example (the house acceptance check): examples/pkg/kvcache-turboquant prints native 173.2 tok/s @ 14336 B/token vs turboquant:3.5 109.2 tok/s @ 3192 B/token (4.5x smaller global-layer KV), coherent continuations - CLI: bin/lem generate -kv-cache turboquant:4 answers correctly at 104.3 tok/s decode; turboquant:9 refuses loudly naming the served modes cli/lthn_kernels.metallib.gz refreshed (task metallib:kernels). Co-Authored-By: Virgil <virgil@lethean.io>
The host test/probe driver allocated nine device buffers per call and dropped the handles (+1 retained IOAccelerator memory each) — the kernel gate's 38 GPU cases leaked ~MBs per run. Collect every device.NewBuffer* handle and release on exit; the resident Π/centroid/γ uploads stay shared (process memo / residency registry, exactly as before). Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Virgil <virgil@lethean.io>
Swap guarded `.Value.(T)` scalar assertions for the v0.12 typed getters (`.String()`/`.Bytes()`) across go/dataset — ingest.go, export.go, score.go. Every adopted site was already gated by an `.OK` check immediately above, so this is behaviour-preserving: same value on the success path, same zero-value contract on failure. Non-scalar assertions (`[]Item`, `Item`, `[]Score`) are Cast[T] territory, pre-existing since v0.11, left untouched. Co-Authored-By: Virgil <virgil@lethean.io>
Swap guarded `.Value.(T)` scalar assertions for the v0.12 typed getters (`.String()`/`.Bytes()`/`.Duration()`) across go/serving — welfare_guard, serve_multimodel_config, backend_http, admin, chathistory, mlservice, pipeline, policy, provider/openai. Every adopted site was already gated by an `.OK` check (or, for parseConfigDuration, the check plus a same-package producer whose success path only ever stores a time.Duration Value), so behaviour is unchanged on every reachable path. Left alone: provider/openai/content.go's base64-decode fallback (Value may legitimately be []byte OR string — no single getter covers an either/or without collapsing the distinct error messages), and backend.go's ContextAssembler read (a public, externally-implementable interface — .String()'s Sprint(Value) fallback on a wrong-typed OK value isn't verifiable across every implementer, unlike the internal-only sites). Co-Authored-By: Virgil <virgil@lethean.io>
Swap guarded `.Value.(T)` scalar assertions for `.String()`/ `.Bytes()` across the quant snapshot writers (gptq, awq, nf4, fp8, mlxaffine, autoround, jang, codebook) — the safetensors-header, sidecar-copy, and config-write paths shared near-identically across the quant family. Every site was already gated by an `.OK` check (or, for the `samePath` helpers, a short-circuited `a.OK && b.OK`) immediately guarding the assertion, so behaviour is unchanged. Co-Authored-By: Virgil <virgil@lethean.io>
Swap guarded `.Value.(T)` scalar assertions for `.String()`/ `.Bytes()`/`.Int()` across modelmgmt's ollama, consolidate, helpers, publish, gguf, and ebook_model. The package-local `readAll` helper (helpers.go) always wraps its success Value as `[]byte` by construction, so every one of its guarded call sites (ollama.go, publish.go) adopts safely; the remaining sites were already gated by an `.OK` check with a same-package producer whose success path is verified to store the asserted scalar type. Co-Authored-By: Virgil <virgil@lethean.io>
Swap guarded `.Value.(T)` scalar assertions for `.String()`/ `.Bytes()` across model/merge — merge_copy's samePath helpers (core.PathAbs is confirmed to always store a string Value on success), merge.go's output-path resolution, and merge_tensors.go's provenance write. All sites were already gated by an `.OK` check. Co-Authored-By: Virgil <virgil@lethean.io>
Capture tap + MeasureReal + committed 32-row real-E2B fixture + the distortion receipt: real K/V matches the paper oracle at b=2, runs +14-16% above at b=3 and +4-8% at b=4; K/V asymmetry ≤3.7% and sign-inconsistent — K4/V3 is not supported by MSE alone, the needle receipts decide the 3.5 default. Co-Authored-By: Virgil <virgil@lethean.io>
… cache (lane/tqkv) -kv-cache turboquant[:2|:3|:3.5|:4] honoured end-to-end (serve + generate + library WithCacheMode): rotate_quant on append, TQ sdpa_vector single-pass + 2-pass reads (rotation-invariant scores, O(output) unrotate fold), per-layer prefill dequant scratch. v1 scope dense archs; MoE / hybrid-recurrent / sinks / paged / MTP / state-sleep refuse loudly with tests. Live gate on e2b-4bit: top-1 62/64, max |logit Δ| 6.31 vs native over 64 teacher-forced steps. Co-Authored-By: Virgil <virgil@lethean.io>
…d vocab sweep instead of K per-row matvecs; LTHN_MTP_ROWS_HEAD=0 keeps the per-row forensics escape (#53) Co-Authored-By: Virgil <virgil@lethean.io>
Sweeps go/ Go comments matching date-stamped or personally-attributed narrative (campaign dates, "per <name>", quoted decisions, handover references) down to the terse technical constraint the code can't show itself. Zero behaviour change — comments and blank lines only; string literals, test fixtures, and real doc/import path citations are untouched. Co-Authored-By: Virgil <virgil@lethean.io>
… preserved, history stays in git; 34 residual grep hits are string data, real import paths, or dated doc filenames (justified in the lane report) Co-Authored-By: Virgil <virgil@lethean.io>
… root causes TestRealCheckpointGPU_OLMoEArgmaxParis_Good stays wrong after the MoE activation fix (#63): mlx-community/OLMoE-1B-7B-0125-Instruct-4bit still diverges from mlx-lm's greedy ids. This lane's oracle-vs-capture instrument (mirroring capture_hidden_qwen3_oracle_test.go's pattern) pins down why, per-layer, against an independent mlx-lm extraction of the same checkpoint at the same prompt ids. Layer 0 already diverges (+41% post-block; the attn/mlp bisection splits it +63% attention / +100% MLP-MoE, both growing with depth). Two independent, compounding defects fully explain it: - Attention: OLMoE's q_norm/k_norm are [2048]=[n_heads*head_dim]-shaped (ONE RMSNorm over the whole projected vector, per mlx_lm's own Attention.__call__), but engine/metal's QK-norm kernels (qknorm_rope.go/attention.go's encRMSNormRowsBF16) are hard-contracted to gemma4's per-head [head_dim]-shaped shared weight — the kernel silently reads only the first 128 of the checkpoint's 2048 q_norm/k_norm elements and applies them per-head instead of as one whole-vector reduction. - Router: OLMoE's router softmaxes over all 64 experts THEN gathers the top-8 (no forced renormalisation, since this checkpoint's norm_topk_prob is false), but engine/metal/router.go's shared device/host router (moe_block.go's only router call site, used identically by gemma4, mixtral, dbrx, olmoe, granitemoe) top-k SELECTS first and softmaxes only over the K winners — always renormalising combine weights to sum 1, correct for gemma4, wrong here. model.Arch.NormaliseMoETopK is declared by every MoE arch's config.go but never read anywhere in router.go or moe_block.go. Cross-checked: the capture's own argmax (417) matches the production ArchSession's first wrong generated token exactly, on both the ICB and plain decode routes, so the tap is faithful to ordinary decode. Not fixed here: defect 1's kernel is attention wiring (in-fence) but is consulted from many call sites (decode_forward_arch.go's four halves, the ICB recorder's separate setQKNormRope, train_real_layer.go) that would all need a new whole-vector-norm branch, verified provably inert for gemma4/ qwenmoe at each site. Defect 2 lives in router.go, which is neither moe_block.go nor attention wiring — outside this lane's file fence entirely. Fixing only one would not flip the receipt regardless, since both actively corrupt every layer; the full citation trail is the handoff. Co-Authored-By: Virgil <virgil@lethean.io>
…tion tables vs mlx-lm; both defects diagnosed to the line (whole-vector QK-norm misread as per-head; router softmax order inverted, NormaliseMoETopK grep-dead) Co-Authored-By: Virgil <virgil@lethean.io>
…e local checkpoint made them run soft-red in every default suite; red must mean regression Co-Authored-By: Virgil <virgil@lethean.io>
…ify's next round reuses the K-row head's argmax instead of a full-vocab head pass + host rescan Co-Authored-By: Virgil <virgil@lethean.io>
…ers fold; =0 is the forensics lane Co-Authored-By: Virgil <virgil@lethean.io>
…aim dissolved by A/B, KV-mode matrix, TQ deep-prefill RSS defect Co-Authored-By: Virgil <virgil@lethean.io>
…ginal counting-bench method; the number is prompt-class-elastic, prose parity is the frontier Co-Authored-By: Virgil <virgil@lethean.io>
… hub cache — community snapshots pair by default (bf16 first, refs/main-resolved, trailing-slash safe) Co-Authored-By: Virgil <virgil@lethean.io>
OLMoE's q_norm/k_norm weights are whole-vector (heads*headDim, one RMSNorm reduction over the full concatenated projection before the head split) rather than gemma4/mixtral's per-head (headDim, one shared weight normed independently per head). Every consumer applied the per-head kernel unconditionally, silently reading only the first headDim of a whole-vector weight and broadcasting that wrong slice across every head. qkNormGranularity (qknorm_rope.go) classifies a loaded weight's length at load time; a whole-vector layer's projector is wrapped (qkNormWideProjector) so the correct single-row RMSNorm runs immediately after the Q/K matmul, at the exact point every consumer already runs the per-head norm — plain/paged/shared-KV decode, the batched-dense prefill fold, and the q8 KV landing all pick this up with no changes of their own, since a wide layer leaves archLayerBufs.qNorm/kNorm the zero bufView and their existing nil-buf skip fires correctly. A weight whose length matches neither shape is now a load error, never a silent truncation. train_real_layer.go/train_backward.go carry the same granularity split for the host f32 training forward/backward. The ICB recorder (ineligible for any MoE layer, hence for OLMoE, hence provably unreachable today) is documented rather than extended, to avoid unverified changes to hot recording code no gate exercises. Receipt: TestForwardCaptureHiddensOLMoEAllLayersVsRealOracle and TestForwardCaptureHiddensOLMoEEmbedVsRealOracle both green (capture_hidden_olmoe_oracle_test.go); existing QK-norm regression tests (qknorm_rope_test.go, TestDecodeQKNorm) byte-unchanged. Co-Authored-By: Virgil <virgil@lethean.io>
…ht order OLMoE's router softmaxes over ALL experts first, then gathers the top-K probabilities without renormalising them to sum to one (norm_topk_prob=false); the engine always selected top-K first and softmaxed only over those K, which sums to 1 unconditionally. That order is the mathematically identical, cheaper form of softmax-over-all-then-renormalise-the-gathered-K, so it stays exactly correct for a NormaliseMoETopK=true arch (gemma4/mixtral) — but wrong whenever the checkpoint declares false. model.Arch.NormaliseMoETopK — declared by every MoE arch's config parser, previously read nowhere — now reaches the router via a new MoELayerWeights.NormaliseTopK/MoEQuantLayerWeights.NormaliseTopK field, set at load (moeLoadedToBF16, moeToQuant) the same way UsesSiLU/arch.Activation already is. Top-K selection is unchanged (a monotonic transform of the raw scores); only the weight computation branches on the policy (softmaxAllThenGatherInto vs the existing softmaxAt). The device (GPU topK kernel) lane declines to the host path whenever the policy is false, since a fixed kernel can only implement the always-renormalise order; quantMoEDeviceRouterBuffersUsable is the single keystone predicate this reaches through, so every call site that gates on it (decode_forward_arch.go's shared-encode eligibility, fully-encoded lane, and break-out flow; moe_batch.go) picks up the correct fallback with no changes of their own. moeRouterQuantDeviceTopKNoCopyWithBufferInPool's signature is frozen (mtp_rows_moe.go calls it directly): it hardcodes true internally, so the MTP verify lane — which predates this fix and has never routed a NormaliseMoETopK=false arch — stays byte-identical. Receipt: TestRealCheckpointGPU_OLMoEArgmaxParis_Good now reproduces mlx-lm's greedy continuation exactly. Existing router/MoE regression tests (TestMoERouter's explicit sum-to-1 assertion, TestMoEBlock, TestMoEBlockQuant, TestRouterFusedMatchesChain, TestQuantMoEDeviceRouterBuffersUsableWidthSweep) and the real gemma-4-26B-A4B checkpoint (TestRealMoE26BHostProfile, TestRealMoE26BFamilyGPUProfile) all pass byte/behaviour-unchanged. Co-Authored-By: Virgil <virgil@lethean.io>
… zoo MoE real-checkpoint parity writeup capture_hidden_olmoe_oracle_test.go's three tests skipped behind LTHN_OLMOE_ORACLE=1 while the QK-norm and router defects were open; they now run unconditionally (requireNativeRuntime + checkpoint presence only), per the plan the file's own header already documented. Two of three are green: TestForwardCaptureHiddensOLMoEAllLayersVsRealOracle (every layer, both the ICB-default and ICB-disabled routes) and TestForwardCaptureHiddensOLMoEEmbedVsRealOracle. TestForwardCaptureHiddensOLMoEAttnMLPBisectionVsRealOracle still fails. Its own oracleOLMoEAttnSumAbs/oracleOLMoEMLPSumAbs reference table does not self-consistently match what capturedAttnHiddens/capturedMLPResHiddens are documented — and, by cross-checking capturedMLPResHiddens against the independently validated per-layer oracle above (which it matches to within rounding), now confirmed — to capture: residual-inclusive values. This predates the fix and sits in the bisection's own extraction, not in the engine; a correct replacement pair needs a fresh mlx-lm capture this lane has no access to re-derive, so the file documents the discrepancy precisely rather than guessing new constants. docs/zoo-moe-real-checkpoint-parity.md described the GELU-vs-SiLU expert-combine defect (#63), already fixed before this lane started and confirmed engaged rather than residual by this file's own diagnosis. Rewritten to state the two mechanisms this lane actually fixed (QK-norm granularity, router combine-weight order) and the now-passing receipt. Co-Authored-By: Virgil <virgil@lethean.io>
…ght order Co-Authored-By: Virgil <virgil@lethean.io>
…ttn = x+Wo·attn, mlp = post-block (doubles as the capture-identity check); all four OLMoE receipts green Co-Authored-By: Virgil <virgil@lethean.io>
…enormalise order the engine now honours (#65); restores the concurrent MoE device lane Co-Authored-By: Virgil <virgil@lethean.io>
…ead as gemma GELU on all layers (#67) Co-Authored-By: Virgil <virgil@lethean.io>
…ding at the store; encSiLUGateMulBF16 prefers it, composed chain stays the fallback (#67) Co-Authored-By: Virgil <virgil@lethean.io>
…racle row at its raw post-block value (hidden_states' final entry is post-norm), header states both mechanisms Co-Authored-By: Virgil <virgil@lethean.io>
…nce — both byte-agree with the fused encoder path (#67) Co-Authored-By: Virgil <virgil@lethean.io>
…ntom context row fixed #67 (target hidden fidelity) is now landed — re-measured DFlash's z-lab accept-rate against it. TestSpeculativeModel_DFlashZLab_RealPairedGenerate moves from the documented 0.00 to a real, non-zero rate for the first time. Extended the receipt into a distribution: new TestSpeculativeModel_DFlashZLab_AcceptRateSurvey drives the real z-lab/Qwen3-4B-DFlash-b16 + Qwen/Qwen3-4B pair over ~200 draft/verify rounds across 8 diverse prompts and reports the accepted-per-round histogram, not just an aggregate. Bisected before trusting the number: target hidden capture at all 5 aux layers sits within ±0.25% of the transformers oracle (all-layer, not spot checked); the drafter's own forward maths still holds its 0.02 real-checkpoint oracle band. Both clean. Found a third, in-lane bug by reading the checkpoint's own spec_generate/modeling_dflash.py directly: its target_hidden context always stops strictly BEFORE the anchor token (extract_context_feature slices [:acceptance_length+1], never including the newly-committed anchor); the anchor enters the forward solely via the block's own position-0 noise embedding, RoPE'd at its own absolute index per apply_rotary_pos_emb's q-tail-slice. The live glue instead extracted hidden states for the anchor too (ExtractAuxHiddensAllRaw over the full running sequence) and passed that larger count straight through as ctxLen — a phantom context row plus a one-position RoPE offset on every block. Fixed at the seam (zLabDFlashProposer.ProposeBlock): trim the anchor's row and decrement ctxLen once, before the forward call. No change to DFlashZLabForward's RoPE maths (already correct given a right-sized ctxLen) or to any source closure's contract. Paired receipt, same 8 prompts, 48 tokens each, losslessness holding both ways: before: rounds=204 proposed=3060 accepted=190 mean=0.931/round rate=6.21% after: rounds=196 proposed=2940 accepted=197 mean=1.005/round rate=6.70% Real, aggregate improvement (+7.9%), wins 5 of 8 prompts individually. But still well under a healthy bar (>=2 accepted/round) with both remaining candidate fault classes (capture fidelity, forward maths) independently clean — DFlashEngineProbe stays false. Honest open item banked in docs/design-dflash-forward.md §7c rather than guessed at further. Co-Authored-By: Virgil <virgil@lethean.io>
… RoPE fix at the proposer seam Co-Authored-By: Virgil <virgil@lethean.io>
…rds once per K, replays as ONE execute
The verify-tail lane's named follow-up: record the fold's interior layers
WHOLE (attention + tail) into one ICB and replay them with a single
executeCommands per verify block, between the live edge layers. The
staged-sliding blocker resolves by per-pass machinery outside the recorded
commands: dedicated host-rewritten length buffers for the SDPA live lengths,
setICBKernelBufferAtCommandIndexFast rebinds for the pos-dependent cache
rows (global basePos rows, sliding pos%window slots, q8 code+scale rows),
and re-pointed PLE-slab binds. Shape phases (direct→staged landing, the
2-pass knee) live in the validity key; a flip re-records the width once.
Edges stay live so the pass's I/O behaviour is untouched and recordings
survive K wobble. Default ON; LTHN_VERIFY_STACK_ICB=0 kills; the banked
per-layer tail lane keeps priority whenever LTHN_VERIFY_ICB enables it.
MoE/TQ/bidirectional/prefill/sinks/SiLU/deep-2-pass decline to the live
fold. Record==live via the shared emit* bodies; any unrecordable op fails
the whole recording.
Receipts (e2b-4bit + bf16 assistant, K=6, 512 tokens, same prompt):
- byte-identity: synthetic sliding+global fixture — hiddens AND KV cache
bytes equal to the live fold across 8 blocks, K in {5,2,6}, a phase flip
and wrap-crossing replays (engagement counter 4); real pair — 96 tokens
identical to LTHN_VERIFY_STACK_ICB=0, replays proven >0
- interior records ~656 commands, 33/33 layers; replays 11/12 probe blocks
- traced GPU per verify pass 9.4ms live -> 8.3ms replay (interior segment
7.6ms); verify-forward wall 10.4-11.2 -> 10.0-10.9ms after the sibling
fence relaxations (ropeK/vnorm ride the Q-rope fence, storeV rides
storeK's, up rides gate's)
- decode tok/s FLAT: ON 171.0/172.8/171.5 vs OFF 173.1/172.7/171.3 — the
verify fold is not encode-bound at this shape; the wall is intrinsic op
time + the serial chain + ~2ms host wrapper outside the fold. The lane
ships for the GPU cut and freed host encode; the next lever is op-count
fusion inside the interior, not execute granularity.
Co-Authored-By: Virgil <virgil@lethean.io>
… as one execute, byte-identical, default-on; verify fold proven not encode-bound Co-Authored-By: Virgil <virgil@lethean.io>
…intermittent byte divergence (~1 in 3, same signature) under the default suite; synthetic parity stays always-on force-armed Co-Authored-By: Virgil <virgil@lethean.io>
…engine's own re-engagement bistability, proven live-vs-live (lane disabled both arms, 4/10, both directions, KV bytes clean); reproducer + rowhash/all-barriers instruments banked, key hardened over every per-row identity Co-Authored-By: Virgil <virgil@lethean.io>
…e no-q8 configuration of record, bf16-force stays a dev instrument Co-Authored-By: Virgil <virgil@lethean.io>
…ells were lane-contention artefacts and do not reproduce; bf16 ≈ q8 on E2B at both depths, TQ demoted to capacity-mode-only Co-Authored-By: Virgil <virgil@lethean.io>
|


No description provided.