Skip to content

gpu: ds41_ffn_handoff_9 and weighted_sum_card, the host tier's nine-slot pieces (Bolt offload) - #343

Closed
midagedev wants to merge 3 commits into
mainfrom
bolt-b1-handoff9-r2
Closed

midagedev wants to merge 3 commits into
mainfrom
bolt-b1-handoff9-r2

Conversation

@midagedev

@midagedev midagedev commented Oct 16, 2026 •

Copy link
Copy Markdown
Owner

What

The host tier's nine-slot pieces for Bolt offload (B1 of #328's offload row):

  • HandoffSlots::Nine and the ds41_ffn_handoff_9 entry: handoff_at's contract at nine slots, wired through enqueue_handoff; no _9_cols/_9_tier (Bolt's prompt uses the batch port, which needs no handoff launch).
  • weighted_sum_card: the routed combine over the card's slots — weighted_expert_sum's rule over the slots whose place sel is below n_card. A place at HOST is skipped with its weight and down row unread; a place in [n_card, HOST) raises FaultSite::ExpertId and NaNs every value of its token. weighted_expert_sum's loop is split into weighted_expert_sum_keep (#[inline(always)], a keep predicate the plain sum holds always true) so the two entries cannot drift apart.
  • Launcher enqueue_weighted_sum_card beside enqueue_weighted_sum.

Gates: gate_deepseek41_prefill's raise sites gain the 9 case (past ids at slots 4 and 8; the refused counts become 5, 7 and 11 — 9 became a built count). gate_hybrid's refusal arm holds the combine on synthetic inputs (it owns card_sel, the places writer): all-card places == weighted_sum bit for bit; HOST slots (their down rows NaN, unread by the contract) against the fused host transcription; a place in [n_card, HOST) faults and NaNs exactly its token. Measured: the device compiles both kernels' acc += w*down to an fma — the plain mul-then-add transcription failed the first run, the fused one is bit for bit.

Add-class proof

  • just ptx-compare ce1c310ff gate_e2e → rc 0 (job s1840) and just ptx-compare ce1c310ff generate_ds41 --features gpu,deepseek41 → added-only (rc 0): added 2: ds41_ffn_handoff_9 weighted_sum_card, removed none, changed none — weighted_sum's PTX does not move.
  • just gate-ptx-spill FAIL-first: generate_ds41 ds41_ffn_handoff_9 unpinned spill=0 jit_local=0 + weighted_sum_card unpinned (334 entries, 2 violations, FAIL) → pins 0/0 in tools/ref/ptx-shapes.tsv → entries=334 pinned=334 violations=0 PASS, gate_e2e entries=267 pinned=267 violations=0 PASS.
  • Unsafe ratchet PIN: gpu 1869→1874 blocks, 203→204 fns (the five new blocks and weighted_expert_sum_keep), dated line in tools/unsafe-ratchet.txt.

GPU Evidence

ws box, NVIDIA GeForce RTX 3090 (sm_86), driver 615.71.09, CUDA 13.4 (JIT cc 8.6). Base ce1c310, head 65c396b (= this PR). All runs through the box queue, lane 3090 (s1840 started before the any-lane note; later jobs any):

  • gate-gpu-lib job s1787 — gate-gpu-lib rc=0 251s try=1 lane=A tier=real
  • gate-gpu-ds41-prefill job s1791 — gate-gpu-ds41-prefill rc=0 839s try=1 lane=A tier=real (handoff9 clauses PASS: places/image PASS at inside and past ids; refuse 5/7/11 by name)
  • gate-gpu-hybrid job s1814 — refusal weighted_sum_card every slot a card slot: == weighted_sum bits true, rerun identical true, word clean PASS / HOST slots skipped, their rows unread (NaN): == the host transcription bits PASS / a place in [n_card, HOST): token NaN true, other tokens the transcription true, word "layer 2 site expert_id" PASS; refusal verdict PASS
  • gate-gpu-moe job s1811 — PASSED: gate_moe_fused fused 4-launch MoE routed half bit-identical to the 8-launch op path (h, Q8Blocks32, down, y, reruns, graph replays)
  • gate-ptx-spill job s1779 — lines above.
  • ptx-compare jobs s1840 (gate_e2e), s1850/s1864 (generate_ds41 base + here).

Mutants

tools/mutant-run.sh (logs kept by the round):

  • gate_hybrid, 3/3 killed by exactly their own clauses: keep-host (HOST terms summed → the NaN-rows clause), order-desc (descending order → the transcription clause; the all-card identity clause stays PASS, as designed), skip-not-fault ([n_card, HOST) skipped silently → the word/token clause). mutant-run: 3 mutants, 3 killed, 0 survived — PASS.
  • gate_deepseek41_prefill, place-id (a past id's place left as the id → the handoff9 places check): mutant-run: 1 mutants, 1 killed, 0 survived — PASS.

GPU Evidence (review fix, 2026-10-17)

ws box, NVIDIA GeForce RTX 3090 + RTX A6000 (sm_86), driver 615.71.09, CUDA 13.4 (JIT cc 8.6), ptxas 13.3.73. Base ce1c310, head 570ddb7 (= this PR after the review fix; commits 3054319 + 570ddb7 on the first-push 65c396b). All runs through the box queue, lane any.

ptx-spill FAIL-first, then green. The two new ds41_ffn_card_acc_9 rows pinned 4/4 first:

generate_ds41 ds41_ffn_card_acc_9 jit_local=0 pinned=4 BELOW
generate_ds41 ds41_ffn_card_acc_9 spill=0 pinned=4 BELOW
ptx-spill bin=generate_ds41 entries=334 pinned=334 nonzero=ds41_attn_seg_stage(spill=8,jit_local=8) violations=2 FAIL
gate_e2e ds41_ffn_card_acc_9 jit_local=0 pinned=4 BELOW
gate_e2e ds41_ffn_card_acc_9 spill=0 pinned=4 BELOW
ptx-spill bin=gate_e2e entries=267 pinned=267 nonzero=none violations=2 FAIL

pinned to the measured 0/0, rerun: ptx-spill bin=generate_ds41 entries=334 violations=0 PASS and ptx-spill bin=gate_e2e entries=267 violations=0 PASS. (The two spill jobs' attach ids were rotated by the queue daemon; the outputs above are verbatim from the runs' logs.)

Add-class proof, just ptx-compare ce1c310ff (job s2275 = gate_e2e, s2283 = generate_ds41 --features gpu,deepseek41; s2266 the base-side build), both rc 0:

added         2: ds41_ffn_card_acc_9 ds41_ffn_handoff_9
removed       none
changed       none
ptx-compare: added-only (rc 0)

weighted_sum_card (added by the first push, removed by the review fix) nets out of the table; nothing existing moved.

Gates. job s2286 gate-gpu-hybrid exit 0 — the reworked clauses:

refusal card_acc_9 every slot a card slot: == weighted_sum bits true, rerun identical true, word clean PASS
refusal card_acc_9 HOST slots skipped, their rows unread (NaN): == card_sum bits PASS
refusal card_acc_9 a place in [n_card, HOST) at n_card: token NaN true, other tokens the oracle true, word "layer 2 site expert_id; ..." PASS

job s2301 gate-gpu-ds41-prefill exit 0 (the clause whose 9-refusal the fix removed went FAIL-first on the first run — job s2290, card_acc of 9 slots: refused (ds41_ffn_card_acc_9: down holds 7200 words, 8100 needed); sums untouched true: FAIL — then [5, 7] + the dated reason):

gate_deepseek41_prefill: card_acc of 5 slots: refused (... built for 6, 8, 9 and 10); sums untouched true: PASS
gate_deepseek41_prefill: card_acc of 7 slots: refused (... built for 6, 8, 9 and 10); sums untouched true: PASS
PASSED: gate_deepseek41_prefill

job s2295 gate-gpu-lib exit 0 (the card-slots places test now loops SLOTS_9); job s2297 gate-gpu-moe exit 0.

Mutants (tools/mutant-run.sh --clean once, jobs s2336–s2377 = the four card_acc mutants + clean, s2310/s2321 = the handoff mutant + clean), every mutant killed by exactly its own clause, clean runs green:

mut-boundary rc=1 killed      (boundary clause: token NaN false, word none)
mut-keep-host rc=1 killed     (HOST clause: == card_sum bits FAIL)
mut-order-desc rc=1 killed    (identity clause: == weighted_sum bits false)
mut-skip-not-fault rc=1 killed (word/token clause)
mut-place-id rc=1 killed      (the handoff 9-clause places check)
mutant-run: 4 mutants, 4 killed, 0 survived ... clean runs 1 green — PASS
mutant-run: 1 mutants, 1 killed, 0 survived ... clean runs 1 green — PASS

The review's surviving place <= n_card mutant is dead (the sel_bad[E + 6] = n_card clause kills it).

This PR was written by a bot (GLM-5.3 agent in the Claude Code harness) under the lead's direction.

🤖 Generated with Claude Code

…lot pieces (Bolt offload)

`HandoffSlots::Nine` picks the new `ds41_ffn_handoff_9` entry (`handoff_at`'s contract at
nine slots; no `_9_cols` or `_9_tier`: Bolt's prompt uses the batch port, which needs no
handoff launch). `weighted_sum_card` is the routed combine over the card's slots:
`weighted_expert_sum`'s rule over the slots whose place is below `n_card`, the plain sum's
own expression, order and contraction, so with every slot on the card the two are bit for
bit equal; a place at HOST is skipped with its weight and down row unread, and a place in
`[n_card, HOST)` raises `FaultSite::ExpertId` and NaNs every value of its token.

elem.rs splits `weighted_expert_sum`'s loop into `weighted_expert_sum_keep`
(`#[inline(always)]`, a keep predicate the plain sum holds always true), so the two entries
cannot drift apart; `weighted_sum`'s PTX does not move (ptx-compare vs ce1c310: added
exactly the two entries, nothing changed).

Gates: gate_deepseek41_prefill's raise sites gain the 9 case (past ids at slots 4 and 8);
the refused counts become 5, 7 and 11 — PIN(2026-10-16): 9 became a built count.
gate_hybrid's refusal arm holds the combine: every slot a card slot == `weighted_sum` bit
for bit; HOST slots (their down rows NaN, unread by the contract) against the fused host
transcription — the device compiles both kernels' `acc += w*down` to an fma, measured (the
plain mul-then-add transcription failed the first run); a place in `[n_card, HOST)` raises
the layer's ExpertId and NaNs exactly its token. ptx-shapes.tsv pins both entries 0/0
(FAIL-first: unpinned red on exactly them, then green 334/334 and 267/267); the unsafe
ratchet rises by the five new blocks and `weighted_expert_sum_keep` (PIN in
tools/unsafe-ratchet.txt).

Co-Authored-By: Claude Code <noreply@anthropic.com>
@midagedev midagedev added gpu The card engine: crates/gpu*, crates/app needs-gpu Changes code a card must check, and carries no gate run on a card labels Oct 16, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Verdict: MUST_FIX: The card combine duplicates existing owners, and removed refusal cases lack a dated reason.

Must fix

1. Extend the existing card-combine owner

crates/gpu/src/elem.rs:1298 repeats crates/gpu/src/card_slots.rs:330: ascending FMA over card slots, unread HOST terms, and ExpertId plus token NaNs for invalid places. Its new launcher also repeats the existing CardAcc interface and validation (R14, R8).
Only the gate calls the new API, so consolidating it now avoids migrating engine callers later.
Add Nine to CardSlots and its of/n/entry/refusal/launcher dispatch. Remove weighted_sum_card, enqueue_weighted_sum_card and weighted_expert_sum_keep; restore weighted_expert_sum's original body. Add this entry in card_slots_kernels:

/// Sum the card's nine routed slots for each output value.
#[allow(clippy::too_many_arguments,
    reason = "kernel entry: flat device ABI (R8)")]
#[kernel]
#[launch_bounds(256)]
#[launch_contract(
    domain = 1, block = (256, 1, 1),
    requires = (
        w_pitch >= 9, down.len() >= 9 * n * m,
        w.len() >= w_pitch * m, sel.len() >= 9 * m,
        acc.len() >= n * m
    )
)]
pub fn ds41_ffn_card_acc_9(
    down: &[f32], w: &[f32], sel: &[u32],
    n: u32, m: u32, n_card: u32, w_pitch: u32,
    fault: FaultSink, mut acc: DisjointSlice<f32>,
) {
    let i = thread::index_1d().get();
    if i >= n as usize * m as usize { return; }
    // SAFETY: i < n*m; the launch contract bounds nine slots,
    // their down rows and weights at w_pitch >= 9.
    let v = unsafe {
        card_acc_at::<9>(
            down, w, sel, n as usize, n_card,
            w_pitch as usize, fault, i,
        )
    };
    // SAFETY: i < n*m <= acc.len(); thread i alone writes acc[i].
    unsafe { *acc.get_unchecked_mut(i) = v };
}

The new dispatch arm uses the existing cfg, n, m, n_card and w_pitch:

CardSlots::Nine => {
    let prep = mo.prepare_ds41_ffn_card_acc_9(cfg)?;
    mo.ds41_ffn_card_acc_9(
        stream, &prep, a.down, a.w, a.sel, n, m,
        n_card, w_pitch, a.fault, acc,
    )?;
}

Load CardSlotKernels once in the gate. Replace its four combine calls with enqueue_card_acc and CardAcc; for the first call:

let slots = bloomery_gpu::card_slots::CardSlotKernels::load(gpu.context())?;
slots.enqueue_card_acc(stream, &bloomery_gpu::card_slots::CardAcc {
    down: &down_dev, w: &w_dev, sel: &sel_dev,
    n: rows, m: M, n_card: n_card as usize,
    n_used: E, w_pitch: E, fault: gpu.layer_sink(R_LAYER)?,
}, &mut card)?;

This deletes the second launcher, predicate helper and fault/filter implementation. Recheck unchanged entries' PTX and the new entry's gates.

2. Reuse the host combine oracle

crates/gpu-gates/src/bin/gate_hybrid.rs:1383 repeats crates/runtime/src/combine.rs:62 (R14). Both own the same filter and ascending fused sum.
Using the owner now prevents the gate oracle from drifting when that contract changes. Replace sum_over:

let sum_over = |down: &[f32], sel: &[u32], t: usize, d: usize| {
    runtime::combine::card_sum::<E>(
        std::array::from_fn(|e| down[(t * E + e) * rows + d]),
        std::array::from_fn(|e| w[t * E + e]),
        std::array::from_fn(|e| sel[t * E + e] < n_card),
    )
};

3. Date the removed refusal clauses

crates/gpu-gates/src/bin/gate_deepseek41_prefill.rs:1344 and line 1384 remove the nine-slot refusal cases without the required dated reason.
Record the contract change now while its replacement coverage is in this diff. Add before the first changed refusal list:

// PIN(2026-10-16): handoff8/10 stop refusing 9; the built nine-slot entry is checked by handoff9_cases.

Non-blocking

⚠ Exercise the first invalid place: crates/gpu-gates/src/bin/gate_hybrid.rs:1489 uses n_card + 3. No new input equals n_card, so the production mutant place <= n_card passes every assertion. Covering this boundary now closes that gap with one line:

sel_bad[E + 6] = n_card;

Checked

Duplicates: 9 new named functions/constants checked; two dryer pairs read, both necessary entry wrappers over handoff_at. Other duplicates are listed above.
Complexity: refusal_arm 65→108 adds a combine stage; enqueue_handoff 22→26 adds one dispatch arm. Neither count alone is a finding.
Silent failure: 3 paths followed; bad ids raise ExpertId, HOST terms are skipped, invalid places raise ExpertId and NaN the token.
Tests: restoring nine-slot refusal or leaving past ids as places fails assertions. HOST summing, reversed order and silent invalid-place skipping have reported killed mutants; the boundary mutant survives.
Gates: unsafe ratchet has a dated PIN; removed refusal clauses need one.
Escapes: no catalog pattern matched. Hot path class: add, no engine caller; no added decode launches or allocations.

Notes

Static review only; GPU gates were not run here. The PR reports card/driver and gate results but omits nvidia-smi output and the model file from the required evidence list.

Card check: needs-gpu. This pull request changes crates/gpu-gates/src/bin/gate_deepseek41_prefill.rs, crates/gpu-gates/src/bin/gate_hybrid.rs, crates/gpu/src/elem.rs … and carries no gate run on a card (CONTRIBUTING's evidence list); a maintainer adds gpu-verified after one.

🔨 Shingler, bloomery's review bot: approves a clean pull request and requests changes on a must-fix (how it works)

[0, 3, 5, past, 9, 12, 300, past + 616],
[0.25, 0.125, 0.25, 0.125, 0.0625, 0.0625, 0.0625, 0.0625],
&[5, 7, 9],
&[5, 7],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Date why handoff8/10 remove the nine-slot refusal cases.

Suggested change
&[5, 7],
// PIN(2026-10-16): handoff8/10 stop refusing 9; the built nine-slot entry is checked by handoff9_cases.
&[5, 7],

Comment thread crates/gpu-gates/src/bin/gate_hybrid.rs Outdated
// every value NaN, the others the transcription.
gpu.clear_fault()?;
let mut sel_bad = sel_h.clone();
sel_bad[E + 6] = n_card + 3;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cover the first invalid place so changing the production comparison to <= fails this clause.

Suggested change
sel_bad[E + 6] = n_card + 3;
sel_bad[E + 6] = n_card;

The PR 343 review: a second card combine in elem.rs duplicates the card
slots' family owner. `CardSlots::Nine` now picks `ds41_ffn_card_acc_9`
(`card_acc_at`'s contract at nine slots) through `enqueue_card_acc`'s
existing `CardAcc` validation; `weighted_sum_card`,
`enqueue_weighted_sum_card` and the `weighted_expert_sum_keep` split are
deleted and `weighted_expert_sum` keeps its original body, so elem.rs is
byte for byte the base again.

gate_hybrid's combine clauses call `CardSlotKernels`/`CardAcc` and judge
against the shared oracle `runtime::combine::card_sum` (the hand
transcription deleted); the stray place is now `n_card` itself, the first
value in `[n_card, HOST)`, so the `place <= n_card` mutant fails the
clause. gate_deepseek41_prefill's handoff8/10 refusal lists keep the
dated reason for the nine-slot cases they stopped refusing.

ptx-shapes: `weighted_sum_card`'s rows out, `ds41_ffn_card_acc_9` in at
0/0 (FAIL-first red on exactly the two rows at a wrong pin); unsafe
ratchet gpu 1874 -> 1872 blocks, 204 -> 203 fns.

Co-Authored-By: Claude Code <noreply@anthropic.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Since the last review:

Verdict: MUST_FIX: The prefill gate still expects nine-slot card sums to be unsupported.

Must fix

1. Update the prefill gate's unsupported slot counts

crates/gpu/src/card_slots.rs:72 accepts nine slots. The existing sum refusal case still tests 9 through FfnBatchKernels, which delegates to this owner. Its down buffer has 7,200 values; nine slots require 8,100. The result is a buffer error named ds41_ffn_card_acc_9, so refused_by_name returns false and just gate-gpu-ds41-prefill fails.
Updating the caller now avoids shipping a failing verification path.

Replace the sum refusal loop header at line 1618 with:

// PIN(2026-10-16): nine-slot sums are covered by the card_slots gate; 11 remains unsupported.
for n_used in [5, 7, 11] {

Replace its description at line 1527 with:

/// - the sum refuses 5, 7 and 11 slots; the gather refuses 5, 7 and 9,
///   by name, nothing written;

Rerun just gate-gpu-ds41-prefill.

Non-blocking

⚠ Refresh the replacement kernel's evidence: crates/gpu/src/card_slots.rs:339 replaces weighted_sum_card, but the PR body reports runs at the earlier head with that deleted entry.
Attach the add/delete-class PTX comparison, spill gate FAIL-first, and current gate-gpu-lib, gate-gpu-hybrid and gate-gpu-ds41-prefill output.

Checked

Duplicates: the nine-slot entry reuses card_acc_at; the hybrid gate now uses runtime::combine::card_sum.
Complexity: the new entry delegates to the shared core; the launcher adds one dispatch arm.
Silent failure: empty extents and short buffers return shape errors; HOST terms stay unread; invalid places raise ExpertId and NaN their token.
Tests: source trace confirms the stale nine-slot refusal fails. The hardware test includes nine slots and checks HOST skipping, invalid-place faults and empty-card sums.
Gates: the handoff refusal reason has its PIN; the unsafe ratchet decreases with a PIN. No numeric band moves.
Escapes: no catalog pattern matched. The new entry has no engine caller; no decode launches, copies or allocations are added.

Notes

Static validation; GPU gates were not run here. The evidence also lacks the required nvidia-smi output and model file.

Card check: needs-gpu. This pull request changes crates/gpu-gates/src/bin/gate_deepseek41_prefill.rs, crates/gpu-gates/src/bin/gate_hybrid.rs, crates/gpu/src/card_slots.rs … and carries no gate run on a card (CONTRIBUTING's evidence list); a maintainer adds gpu-verified after one.

🔨 Shingler, bloomery's review bot: approves a clean pull request and requests changes on a must-fix (how it works)

The nine-slot entry is built, so the clause that refused 9 through
CardSlots now refuses only 5 and 7, with the dated reason; the nine-slot
entry itself is checked by gate_hybrid combine clauses and gate-gpu-lib
places test. The gather clause keeps refusing 9: its family has no
nine-slot entry.

Co-Authored-By: Claude Code <noreply@anthropic.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Since the last review:

Verdict: CLEAN: This increment removes the obsolete nine-slot refusal and records the dated reason.

Checked

Duplicates: no new functions, types or constants in this increment.
Complexity: the existing refusal loop loses one case; no new branching.
Silent failure: counts 5 and 7 return named Shape errors before launch; the gate checks refusal and untouched output.
Tests: static mutation reasoning at crates/gpu/src/card_slots.rs:74 shows accepting 7 as Six fails the refusal check. Removing Nine at line 72 makes the existing hybrid gate's nine-slot launch error.
Gates: the removed refusal has PIN(2026-10-16) and a reason. Existing hybrid and library gates check nine-slot success, HOST skipping and invalid-place faults. No numeric bands change.
Escapes: no catalog pattern matched. No ledger lessons are in force. This increment changes gate code only.

Notes

Static validation only. GPU gates and mutations were not executed.

Card check: needs-gpu. This pull request changes crates/gpu-gates/src/bin/gate_deepseek41_prefill.rs, crates/gpu-gates/src/bin/gate_hybrid.rs, crates/gpu/src/card_slots.rs … and carries no gate run on a card (CONTRIBUTING's evidence list); a maintainer adds gpu-verified after one.

🔨 Shingler, bloomery's review bot: approves a clean pull request and requests changes on a must-fix (how it works)

@midagedev

Copy link
Copy Markdown
Owner Author

Superseded by #391 (the same review-fixed content rebased onto origin/main; the only conflict was tools/unsafe-ratchet.txt, resolved by keeping main's PIN lines and adding one PIN(2026-10-17) for our measured delta). All five owning gates re-ran green there through --round-ledger; ptx-compare against origin/main is added-only (ds41_ffn_card_acc_9 + ds41_ffn_handoff_9).

This comment was written by a bot (GLM-5.3 agent in the Claude Code harness) under the lead's direction.

🤖 Generated with Claude Code

@midagedev

Copy link
Copy Markdown
Owner Author

Superseded by #391 (merged).

Written by a bot (Claude agent) for the maintainer.

@midagedev midagedev closed this Oct 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gpu The card engine: crates/gpu*, crates/app needs-gpu Changes code a card must check, and carries no gate run on a card

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant