Skip to content

gpu, gpu-gates: the nemotron_h resident bytes count every buffer, one owner for the zero-context refusal, the serve gate's checks return their status - #277

Merged
midagedev merged 3 commits into
mainfrom
nemo7fold5
Oct 15, 2026
Merged

midagedev merged 3 commits into
mainfrom
nemo7fold5

Conversation

@midagedev

@midagedev midagedev commented Oct 15, 2026 •

Copy link
Copy Markdown
Owner

Follow-up to #259: the three findings of Shingler's review of #259 at 2b2b19d, which landed after the merge.

What it changes.

  • Body::resident_bytes counts the Mamba-2 scratch (Mamba2Scratch::device_bytes: part and done) and the gemv
    ids (KGemvKernels::device_bytes: one). The load record's resident_bytes read 3,904 bytes short on Nemotron
    3 Nano 4B [derived in the review].

  • Body::load no longer refuses a context of 0 itself: GpuModel::load_blocks refuses it before the body loads, so
    the branch could not run (R14).

  • gate_nemotron_serve's check functions return their status (Result<bool, _> or a pair) instead of taking
    ok: &mut bool (R24). The clauses and their order are the same.

  • Review fold (Shingler on 0e9e581): the Qwen bodies' resident totals (body35.rs, body.rs) count the same
    K-gemv ids (self.k.q35 … kgemv.device_bytes()), the undercount this PR fixes for Nemotron.

  • Review fold 2 (Shingler on f0f9170): the GLM and MiMo bodies count the same ids of their K-block kernels
    (KBlockKernels::device_bytes, through the now public KGemvKernels::device_bytes).

No kernel, launch or engine output moves.

What I ran

Head: see the SHA in the push request. Pre-review CLEAN at 421fbaa.

Head 0e9e581 on main 3898696, through the box queue (BLOOMERY_BOX_QUEUE=1 tools/gate-batch.sh check lint fmt-check gate-gpu-mamba2 gate-gpu-nemotron-e2e gate-gpu-nemotron-serve); the box's cards, as on #259:
NVIDIA GeForce RTX 3090, 615.71.09 and NVIDIA RTX A6000, 615.71.09.

$ BLOOMERY_BOX_ENV='BLOOMERY_GATE_CARD=a6000' just gate-gpu-nemotron-e2e
logits_near_mainlines: cosine 0.999816 / 0.999886 / 0.999858 / 0.999685 (floor 0.999), every clause PASS
gpu-gate.sh: gate_nemotron_e2e ran 13 s (exit 0)

$ BLOOMERY_BOX_ENV='BLOOMERY_GATE_CARD=a6000' just gate-gpu-nemotron-serve
check plan_only_names_its_default / parallel_above_one_is_refused / load_and_listen / chat_is_200 /
      edit_resend_is_a_fresh_run / extension_keeps_the_held_sequence / completion_ids: PASS
load record: resident_bytes=8940614148
gpu-gate.sh: gate_nemotron_serve ran 23 s (exit 0)

$ BLOOMERY_BOX_ENV='BLOOMERY_GATE_CARD=3090' just gate-gpu-mamba2   # exit 0
$ just check / just lint / just fmt-check                           # rc 0; lint 41 `^warning:`, the ratchet's 41
$ just contrib-check --tier t0                                      # DONE tier=t0 total=83 red=0

On 421fbaa (main 2a47692, both folds): check, lint (41), fmt-check rc 0 through the box queue;
just contrib-check --tier t0 DONE total=83 red=0; gate-gpu-qwen35moe-e2e rc 0 on the same fold one rebase
earlier (0a6d6a1c, main df965c0).

Not run as FAIL-first: no gate pins resident_bytes to a derived figure; the count's change is the two
device_bytes terms above.

🤖 Generated with Claude Code

@github-actions github-actions Bot 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 15, 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 same K-gemv buffer undercount remains on the sibling Qwen paths.

Must fix

1. Include the K-gemv IDs in both Qwen resident totals

body35.rs:3195 and body.rs:1024 omit self.k.q35. Every Body35 load enables those kernels; Qwen3 enables them when its sites require them. A successful load allocates eight u32 IDs, but neither body total counts them. GpuModel::resident_bytes() sums these totals, so its result and the load records underreport by 32 bytes on those loads [derived]. This is the same defect this PR fixes for Nemotron.

Reuse the new owner now to avoid another accounting repair per model. Append this term to both linked resident_bytes sums:

            + self.k.q35.as_ref().map_or(0, |k| k.kgemv.device_bytes())

Non-blocking

⚠ Add a resident-byte regression check: gate_nemotron_serve.rs:344 checks load metadata but never checks resident_bytes. Removing either new accounting term leaves every clause green. Assert the recorded total against an independently derived allocation sum and show that the omitted-term mutant fails. Establishing that check now prevents this fix from regressing silently.

Checked

Duplicates: the two new byte-count methods cover different owned buffers. Dryer reported 0 pairs.
Complexity: crapper flagged no functions; the gate refactor adds no branches.
Silent failure: missing plan context, listen failures, log-read defaults and request errors reach a failed check or an error.
Tests: clauses unchanged. Returned failures remain false through the caller's &= accumulation and reach checks_failed; removing either accounting addition escapes the serve gate.
Gates: no pins, thresholds or cases changed. The common loader rejects zero context before the sole Nemotron body-load call.
Performance: changed accounting runs outside decode and prefill; no kernel or dispatch work changed.
Escape catalog: no patterns matched.

Notes

Dryer excluded gpu-gates; manual Grep covered the changed helpers.
The reported card runs omit the model-file identity required by CONTRIBUTING.md; GPU evidence is incomplete. No build or hardware gate ran locally.

Card check: needs-gpu. This pull request changes crates/gpu-gates/src/bin/gate_nemotron_serve.rs, crates/gpu/src/arch/nemotron_h/body.rs, crates/gpu/src/arch/nemotron_h/step.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)

@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 same K-gemv resident-byte omission remains on the GLM and MiMo paths.

Must fix

1. Count the K-gemv ids on the remaining model paths

Kind A. crates/gpu-deepseek41/src/block.rs:236 allocates a separate KGemvKernels for each loaded K-block kernel set. A GLM or MiMo file with a K-quant dense block reaches this allocation, but crates/gpu-glm5next/src/body.rs:2367 and crates/gpu-mimo2/src/body.rs:1210 omit it. Their load records omit eight u32 ids, or 32 bytes [derived] per loaded kernel set. BlockScratch::bytes() counts a separate one-id allocation. This is the same omission on sibling paths of this fix PR.
Closing this sibling path now avoids another correction of the same allocation.

In crates/gpu/src/site.rs, keep the existing documentation and expose the new owner across crates:

pub fn device_bytes(&self) -> usize {
    self.one.num_bytes()
}

Add this method inside the existing impl KBlockKernels in crates/gpu-deepseek41/src/block.rs:

/// Device bytes held beside the kernel modules.
pub fn device_bytes(&self) -> usize {
    self.gemv.device_bytes()
}

Replace GLM's ChainBody::resident_bytes:

fn resident_bytes(&self) -> usize {
    self.store_bytes()
        + self.scratch_bytes()
        + self.prompt.bytes()
        + self
            .taps
            .as_ref()
            .map_or(0, |t| t.iter().map(DeviceBuffer::num_bytes).sum())
        + self
            .nextn
            .as_deref()
            .map_or(0, |n| n.resident_bytes() + n.arena_bytes())
        + self.k.block.as_ref().map_or(0, KBlockKernels::device_bytes)
}

Replace MiMo's ChainBody::resident_bytes:

fn resident_bytes(&self) -> usize {
    self.store_bytes()
        + self.scratch_bytes()
        + self.prompt.bytes()
        + self
            .taps
            .as_ref()
            .map_or(0, |t| t.iter().map(DeviceBuffer::num_bytes).sum())
        + self.k.block.as_ref().map_or(0, KBlockKernels::device_bytes)
}

Non-blocking

⚠ Assert the corrected byte count: crates/gpu/src/arch/nemotron_h/step.rs:194 adds the Mamba scratch term, but gate_nemotron_e2e.rs:500 only prints the total. Deleting this term leaves its assertions green. Add an expected-byte assertion to the existing gate and show FAIL-first with the term removed; this prevents the same omission from returning.

Checked

Duplicates: the two new accounting methods sum their owners' buffers. Dryer reported 0 pairs.
Complexity: crapper flagged no function; the gate refactor preserves predicates and branch order.
Silent failure: a listen failure returns (None, false); run() combines returned statuses and rejects a failed check.
Tests: deleting the added Mamba byte term leaves the e2e gate's assertions unchanged; its only use of the total is printing.
Gates: no bands, thresholds or clauses removed or relaxed. GpuModel::load_blocks rejects zero context before invoking the body callback.
Escape catalog: no C1–C4 pattern matched.
Performance: accounting and gate code; no added work per token.

Notes

Static review only; no builds or GPU gates run here.
Dryer excluded gpu-gates from its scan.
The supplied GPU evidence omits the model file identity required by CONTRIBUTING.md.

Card check: needs-gpu. This pull request changes crates/gpu-gates/src/bin/gate_nemotron_serve.rs, crates/gpu/src/arch/nemotron_h/body.rs, crates/gpu/src/arch/nemotron_h/step.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 and others added 3 commits October 16, 2026 01:33
…mba-2 scratch and the gemv ids, the loader owns the zero-context refusal, the serve gate's checks return their status

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nt bytes count the K-block gemv ids

Co-Authored-By: Claude Opus 5.5 <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.

Verdict: CLEAN: No must-fix finding remains; recurrence coverage for resident-byte accounting is non-blocking.

Non-blocking

⚠ Guard the resident-byte correction against recurrence: crates/gpu/src/arch/nemotron_h/step.rs:194.
The Nemotron end-to-end gate only prints the byte total. The serve gate's load checks assert architecture, slots, layers and context, but not resident bytes.
Removing the Mamba scratch term or the new K-gemv term leaves these assertions unchanged. Extend the existing load clause with an independently derived total and show FAIL-first to protect this correction.

Checked

Duplicates: the 3 new byte-count methods count distinct owned buffers or delegate to their owner.
Complexity: no decision branches were added.
Silent failure: absent optional kernels contribute zero; missing context or records, failed requests and a missing listener reach gate failure.
Tests: static comparison confirms the 6 check-call conditions and their order are unchanged. Removing either Nemotron byte-count addition has no total assertion to fail.
Gates: no pins, thresholds or clauses moved or were removed.
Adversarial checks: ctx=0 is refused before Body::load; a failed check stays false after later passing checks; a listener failure returns a failed status before completion checks are skipped.
Performance: the changes affect host accounting and gate orchestration; decode and prefill launches, copies and reduction order are unchanged.
Escape catalog: no patterns matched.

Notes

CUDA gates were not run during validation. The reported GPU runs omit the resolved model-file path required by CONTRIBUTING.md.

Card check: needs-gpu. This pull request changes crates/gpu-deepseek41/src/block.rs, crates/gpu-gates/src/bin/gate_nemotron_serve.rs, crates/gpu-glm5next/src/body.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
midagedev merged commit 8ed083a into main Oct 15, 2026
7 of 8 checks passed
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 gpu-verified 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