feat(ENG-RESIDENCY-CONFIG): the device budget is a config key, and --offload-config reaches vllm-cli and the pooling server (#1127, #1135) - #1216
Merged
Conversation
…nd which of the three unreached entry points get the document (#1127, #1135) W1 left two entry-point gaps and one knob outside the config surface it built. W2 closes both issues in one change, because they edit the same two files: `server_main.cpp`'s argument block and `weight_residency.cpp`'s parser. The budget key (#1127). `VT_DEVICE_WEIGHT_BUDGET_BYTES` becomes `vllm_cpp.device_fit.weight_budget_bytes` on the same terms as its five siblings: the environment still wins, a misspelling anywhere in the new level is refused by name, and an absent field still means unchanged. It is the only key here whose legal range includes zero, because `0` is the documented spelling of "suppress the device-fit refusal", so it parses through its own non-negative helper rather than the positive-only one `slots` and `slot_bytes` use. The three entry points (#1135), decided rather than plumbed. `vllm-cli` gets `--offload-config`, which reaches the C ABI field that already parses both halves. The server's pooling path gets both halves, because it builds `EngineParams` and calls the same loader. The transcription-only path gets NEITHER, and that is the honest answer: `ParakeetTranscriber::FromDir` builds no `EngineParams` and calls no `LoadedEngine`, so no field of either half has a reader on that path. It refuses a non-empty document at startup and names the missing seam, which is #1195. The pooling block still drops six other `EngineParams` fields, `device` among them; that is #1196. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [Claude Code]
…offload-config reaches vllm-cli and the pooling server (#1127, #1135) Two of W1's own `## Owed` entries, closed together because they edit the same two files: `server_main.cpp`'s argument block and `weight_residency.cpp`'s parser. Splitting them would have put two branches on both. ## The budget as a config key (#1127) `VT_DEVICE_WEIGHT_BUDGET_BYTES` is the escape hatch for the load-time device-fit refusal that landed in #1132, and it was the odd one out once mmap, prefault, expert_stream, slots and slot_bytes had all become keys under `vllm_cpp`. It joins them as `vllm_cpp.device_fit.weight_budget_bytes`, on the same terms: environment variable > config > device probe, an absent field means unchanged, and a misspelling anywhere in the new level is refused at startup by name. `device_fit` is an OBJECT rather than a scalar sibling of `mmap` and `expert_stream` for two reasons. `vllm_cpp` maps a name to an object today and the parser's `ExtObject` walk assumes it, so one scalar would make the level heterogeneous. And the device-fit check is a third knob family rather than a member of either existing one. ZERO is legal here and nowhere else in the struct. `CheckDeviceWeightFit` reads a zero budget as UNKNOWN and decides nothing, so `0` is the documented spelling of "suppress the refusal", exactly as `VT_DEVICE_WEIGHT_BUDGET_BYTES=0` already means. `slots` and `slot_bytes` are sizes and keep refusing a zero. The budget therefore parses through its own `ExtNonNegativeInt`, and a negative value is still refused. `DeviceWeightBudgetBytes` keeps its name and its callers and delegates to `ResolveDeviceWeightBudgetBytes`, which is now the sole reader of the variable. That is what keeps the install-time override announcement from drifting away from what the resolver does with a value: `0` wins and is announced, while a signed, spaced or garbage value is ignored and falls through — to the config now, where it used to fall through to the probe. ## The three entry points (#1135), decided rather than plumbed The server parses `--offload-config` ONCE, ahead of the architecture branch. `vllm-cli` gets the flag. It is a thin ABI client and the ABI field already parses both halves, so this is one assignment and both tiers arrive, the mirrored `uva`/`prefetch` refusal included. The pooling/embedding path gets both halves. It builds `EngineParams` and calls the same `LoadedEngine::FromModelDir`, which installs the residency document and the weight offloader ahead of every path and weight operation, so nothing about pooling makes either half inapplicable. The transcription-only path gets NEITHER, and REFUSES a non-empty document at startup. `ParakeetTranscriber::FromDir` builds no `EngineParams` and calls no `LoadedEngine`, so that path runs no `SetWeightResidencyConfig`, no `CreateWeightOffloader`, no GGUF mapping and no expert slot store: no field of either half has a reader on it. AGENTS.md says to refuse an unimplemented arm with a message that names the missing part, and a warning would leave a server running while it holds a placement instruction it does not follow, which is the failure #1135 was filed about. The wiring is owed as #1195. Also found and recorded: the pooling block drops six other `EngineParams` fields, `device` among them, so `vllm-server --device cuda` on an embedding model runs the accelerator-first probe (#1196). Fixed in flow: five `docs/USAGE.md` command lines named `./build/vllm-server` or `./build/vllm-cli`, and both binaries are built under `build/examples/` (#1206). ## Gate Red first for the budget key: with the resolver stubbed, `test_weight_residency_config` rc 1, 24 cases / 7 failed; with the implementation, rc 0, 24 cases, 315 assertions. Twelve mutations, each applied alone with the file's sha256 printed before and after, the build's exit status beside every result, and a non-zero case count required: all twelve built and all twelve were killed, including the three call-site deletions and the reachability mutation that removes `SetWeightResidencyConfig`. Full gate `ctest --test-dir build -j 6` rc 0, 100% tests passed, 0 failed out of 516. No build hit ENOSPC. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [Claude Code]
Records only on the incoming side: a new spec, an engine-matrix row, an issue-index append and a checker change. No source file overlaps this branch. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [Claude Code]
Incoming: the environment-agnostic campaign spec, its bring-up script and gates, and a docs/USAGE.md section. The only file both sides touch is docs/USAGE.md, and the two edits are in different sections. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [Claude Code]
Incoming: vt::QuantFp8Group and its gates. The one shared file is tests/CMakeLists.txt, where the two additions are in different blocks. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [Claude Code]
Incoming: a records-only change to AGENTS.md, .agents/environment.md and the issue index. No source, test or build file overlaps this branch, so the gate this branch ran on the previous merge still describes the tree it produces. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [Claude Code]
`origin/main` advanced to 65d6cda while this branch's review repair was being written: the gcc 16 build lane, the ROCm attention-backend selection, and `vt::MatmulFp8BlockScaled`. Sixty-five files on the incoming side, mostly additive. Four files are edited on both sides — `CMakeLists.txt`, `tests/CMakeLists.txt`, `include/vllm.h` and `.agents/issue-index.md` — and git reported no conflict in any of them. `.agents/specs/expert-streaming.md` is the one to watch, because open PR #1200 edits its `## Owed` table two rows above this branch's #1127 row; #1200 has not landed yet, so this merge does not meet it. If it lands first, the next merge takes the target-branch version of that file whole and re-applies the one scoped row, as AGENTS.md requires for a keyed record — never the automatic three-way result. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [Claude Code]
… the vllm-cli gate SKIPS, and #1206 is three lines not five Review repair for #1216. Every behavioural attack the reviewer ran came back clean, so nothing about what the code DOES changes here. What it says about itself does. ## `include/vllm.h` still described the pre-#1127 schema AGENTS.md names one file as the place a shipped capability is exposed, and the `vllm_cpp` block in it was written before the sixth key existed. It omitted `device_fit.weight_budget_bytes` from the schema, omitted `VT_DEVICE_WEIGHT_BUDGET_BYTES` from the precedence list, and its refusal list said "a non-positive `slots` or `slot_bytes`" without ever saying that `weight_budget_bytes` refuses a NEGATIVE while ACCEPTING `0` — the single asymmetry this wave exists to introduce. That is sharper than ordinary drift because `vllm-cli`, the wave's own new entry point, is a pure ABI client: it passes exactly the document the header called invalid, and the loader accepted it. `grep -rn device_fit include/ src/capi/` returned nothing at all. All three statements are now there, and the zero gets its own paragraph rather than a clause. ## A test that claimed to SKIP actually FAILED `cmake -DVLLM_CPP_BUILD_TESTS=ON -DVLLM_CPP_BUILD_EXAMPLES=OFF` is a legal configuration. There `VLLM_CLI_BINARY` is undefined, the file defines it as `""`, and all four cases ran `REQUIRE(std::string(kCliBinary) != "")` — four FAILED cases, not a skip, on a build that simply did not include the binary. The comment in CMakeLists.txt said "SKIPPED". No CI job hits that combination today, so it was latent rather than red, and it is still a verdict about the configuration wearing the shape of a verdict about the code. The tree already had the idiom: `vllm_cpp_add_test` sets `SKIP_RETURN_CODE 77` on every test, and `test_voxtral_e2e` exits 77 when its preconditions are absent. So the four `REQUIRE`s become one `RequireCliBinary()` that exits 77, CTest reports **Skipped**, and both comments now say what happens and why. Returning early instead would have printed doctest's `assertions: 0 ... Status: SUCCESS!`, which is the #463 trap and the reason the 77 convention exists. ## #1206 said five command lines; it was three The fix was always complete and correct — `grep -c 'build/vllm-' docs/USAGE.md` is 0 at head. Only the count was wrong, and it was never counted: 3 at this branch's base `fd64c76ee`, 3 at the merge base `5af6e763`, at lines 2354, 3835 and 3848. Corrected in `.agents/issue-index.md`, in this spec's `## Work breakdown` W2c, in the pull request body, and on GitHub issue #1206. The index row is append-only and cannot be corrected after the merge, which is why it is corrected while the pull request is open. The body of `f19b66cfc` carries the same wrong number and is not rewritten. This repository squash-merges with `squash_merge_commit_message = PR_BODY`, so that body never reaches `main`; the pull request body is the message that lands, and it is corrected. Rebasing four merge commits to edit a discarded message would cost the branch its merge bases for nothing. ## A refusal message docs/USAGE.md quotes, that the parser stopped printing W2 added `device_fit` to the `vllm_cpp` level, so `RejectUnknownKeys` now enumerates three names. The sample output in `docs/USAGE.md` still read `(expected one of: mmap expert_stream)`, which is a message the code no longer produces — and it is quoted in the section whose whole point is that a typo is named rather than ignored. Found by `scripts/check-doc-checkpoint.py`, which refused this commit for touching `include/vllm.h` and `CMakeLists.txt` without touching `docs/USAGE.md`; the gate was right, and looking for what it was owed found this. No separate issue: the defect was introduced by this unlanded pull request and is repaired inside it. ## The sixth knob invalidated six "five" statements `weight_residency.h:62` said the latch covers "TWO of the five knobs" twelve lines above a list this same wave rewrote to name THREE things that do not freeze; `:261` and `weight_residency.cpp:618` called the copy "five optionals" for a struct with six; `:312` and `:315` banner "The five knobs ... five functions" over six resolvers; and `test_serve_residency_config.cpp:58` said the install line reports "all five fields". `weight_residency.h:92` and `weight_residency.cpp:325` are historical and relative respectively, and stay. `test_gguf_device_fit_reach.cpp:321` said "These two ... they set NO variable at all" and three cases follow, the third of which sets one deliberately. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [Claude Code]
…, and the spec says which mutation reds which case The second half of the #1216 review repair: one behaviour change, argued below, and the evidence the first half owed. ## A negative budget through the public setter switched the guard OFF `ResolveDeviceWeightBudgetBytes` casts a configured `int64_t` to `size_t` and its comment justified that by saying the parser had already refused a negative. That is true of every production caller and false of the type's other door: `SetWeightResidencyConfig` is declared in a public header and takes the STRUCT, so a hand-built `WeightResidencyConfig{.device_weight_budget_bytes = -1}` reaches the process-global having run no parser at all, and `-1` resolves to `SIZE_MAX` — an effectively infinite budget that turns the load-time device-fit refusal off in silence. That is precisely the "a budget the operator believes is set, met as an out-of-memory kill rather than as an error" failure the refusal's own text names. So the trust is made true rather than narrated. `RejectOutOfRangeFields` runs before the lock and before the latch check, and it repeats the parser's three range rules at this door: a non-positive `slots` or `slot_bytes`, and a negative budget. `0` still installs, because it is this field's suppression spelling and a guard that refused it would delete the escape hatch the key exists to give. The two sizes were unguarded here too, and they are in for the same reason: two doors into one struct should state one rule. Red first, whole binary: `test_weight_residency_config` rc 1, 25 cases / 1 failed, 324 assertions / 7 failed, with the failing message logged as `ACCEPTED (no throw)`. With the guard, rc 0, 25 cases, 324 assertions. The case count moving 24 to 25 is the check that the case was added rather than silently skipped. ## The spec attributed three cases' red to one mutation; it takes three `## Evidence` said "the three `test_gguf_device_fit_reach` cases were written AFTER the resolver, so their red is M7". M7 kills ONE of them. Measured with whole binaries and the failing case names read off the doctest output: M7 kills the config-key case alone, M12 kills the config-key case and the ZERO case, and M4 kills the precedence case alone. Each of the three is now recorded with the mutation that reds it and the ones that do not, and why. The ZERO case also gets the sentence the spec was missing. Its "no refusal" half is VACUOUS on that fixture: the fake staging platform probes 0 and `CheckDeviceWeightFit` reads a zero budget as UNKNOWN, so no refusal fires whether the configured zero arrives or not. Its one discriminating assertion is the read-back, which is exactly why M12 is the only mutation of the three that kills it. The file's own comment said so; the spec did not. ## Two results reported as one run, and an A/B that measured itself The pull request body gave "100% tests passed, 0 failed out of 516" and, two paragraphs later, "3 failures against this branch's 2". Different runs, different instruments, different lanes: `test_cpu_x86_llamacpp_floor` is not a ctest test at all — `ctest -N | grep -i floor` matches nothing — it is `tests/scripts/test_cpu_x86_llamacpp_floor.py`, run by `ci.yml:210` and `scripts/agent-preflight.sh:145`. The concurrent A/B is withdrawn rather than repeated. It is self-poisoning: each arm becomes the other's contention and the failure lands on whichever loses the race, which is why the review's rerun put the failure on the CONTROL arm. Two things that do not race replace it. The three files the harness reads are byte-identical on this branch and on `origin/main`. And a single-arm sweep on this branch alone gives rc 1 at load 172 to 194, where the harness's own quiet gate fires `NO_QUIET_WINDOW after 15s` and the run takes 114.7 s, against rc 0 at load 53 to 49, `Ran 10 tests in 3.338s / OK`. ## Gate Full build rc 0, ENOSPC 0. `ctest --test-dir build -j 6` rc 0: 100% tests passed, 0 failed out of 523, 466.09 s. Five repair mutations, each applied alone with its sha256 printed on both sides, the build's exit status beside every result and a non-zero case count required; the restore is `cp` plus `touch` plus a rebuild, never `cp -p`, because a preserved mtime makes ninja skip the rebuild and a stale mutated binary then produces a kill it has not earned. One of the five came back INVALID rather than green — reverting only the four `RequireCliBinary()` calls leaves `SkipGate` unused and `-Werror=unused-function` refuses the build — and it is recorded as INVALID, because a mutation that fails to build reads exactly like a passing test when only the suite's exit code is printed. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [Claude Code]
`origin/main` advanced to c20018f while the review repair's gate was running: the CUDA-graph dedup device record, and `GATE-SYMBOL-ANCHORS`, which replaces `file:line` citations with symbol citations and adds a checker for them. Three files are edited on both sides. `tests/vllm/entrypoints/test_gguf_device_fit_reach.cpp` takes an anchor rewrite at line 62 on the incoming side and this branch's "These two / three cases" correction at line 321; git reported no conflict and the two hunks are 250 lines apart. `docs/USAGE.md` and `.agents/issue-index.md` likewise merge without a conflict. `.agents/specs/expert-streaming.md` is untouched on the incoming side, so the #1127 `## Owed` row this branch edits still needs no manual reconciliation; PR #1200, which edits that table two rows above, is still open. The full gate is rerun on the merged tree rather than inherited from the pre-merge run, because a clean merge is not a merge that builds. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [Claude Code]
… the spec records both runs `origin/main` advanced to c20018f while the review repair's gate was running, so the gate ran twice and `## Evidence` now carries both rather than the first one alone. A clean merge is not a merge that builds, and the second run is the one the branch stands on. Both are the declared recipe on the same host. On `65d6cdaed`: build rc 0, ENOSPC 0, ctest rc 0, 100% tests passed, 0 failed out of 523, 466.09 s. Merged onto `c20018f8d`: build rc 0, ENOSPC 0, ctest rc 0, 100% tests passed, 0 failed out of 523, 587.09 s. The second is slower for contention only — the box's 1-minute load average was above 200 for much of it and `test_ltx2_video` alone took 542.97 s against 461.46 s — so the difference is the box, not the tree, and the row says so rather than leaving a reader to wonder. `scripts/check-symbol-anchors.py`, which `origin/main` added in that interval, reports OK on this branch: 618 citations, 93 in-repo checked, 93 fresh, 0 stale. `scripts/agent-preflight.sh` is rc 0 with no failing gate. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [Claude Code]
`origin/main` advanced to 7271639 between this branch's gate and its push. The one incoming commit is `FIX-GATE-COMMANDS-PROSE-PIN` (#1229), which keys `ENG-CUDAGRAPH-DEDUP`'s credited device leg on structure rather than on a sentence — and it is the fix for a red this branch's own preflight hit and did not cause. Recorded because the shape matters: `scripts/agent-preflight.sh` on this branch failed `test_check_gate_commands` with `assertIn("Device byte-identity A/B (owed", spec)`, and the spec at HEAD is byte-identical to the spec on `origin/main` (`eebe438b1` on both sides), so the assertion was measuring `origin/main`, not this change. Merging is the whole repair; nothing on this branch needed to change. It touches four record and checker files and no product code, so the rebuild is the two checkers' test lane rather than the tree. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [Claude Code]
…rries the gate-commands repair `origin/main` moved twice while this branch's gate ran, so `## Evidence` now carries three runs rather than one. The last is the one the branch stands on. Merged onto `727163997`: build rc 0 with `ninja: no work to do`, ENOSPC 0, ctest rc 0, 100% tests passed, 0 failed out of 523, 2218.79 s. That commit changes only records and checkers, so its binaries ARE the previous run's binaries — the gate was rerun anyway rather than argued from that. Also recorded: `scripts/agent-preflight.sh` was rc 1 before this merge, on `test_check_gate_commands`. The assertion it failed reads `.agents/specs/eng-cudagraph-dedup.md`, which is byte-identical on this branch and on `origin/main` (`eebe438b1` on both sides), so it was measuring `origin/main` rather than this change — and `origin/main`'s own `FIX-GATE-COMMANDS-PROSE-PIN` (#1229) is the repair. Merging it was the whole fix, and the row says so rather than leaving a reader to reconstruct why a green branch had a red preflight. The three wall times, 466.09 s / 587.09 s / 2218.79 s, are contention and not the tree: three worktrees on this host ran `test_ltx2_video` at the same time and it alone took 461.46 s, 542.97 s and 2147.17 s across the three runs. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [Claude Code]
…ependent floor harness The sweep now has three runs on ONE tree, and the verdict tracks the box rather than the branch: rc 1 at load 172-194, rc 1 again at load 92-107 with the same `NO_QUIET_WINDOW` signature, and rc 0 at load 49-53. The middle point was taken because `scripts/agent-preflight.sh` went rc 1 again while this branch sat unchanged, and it is rc 1 exactly when this harness is. That is what the withdrawn concurrent A/B could never show. Two arms racing each other put the failure on whichever loses; one arm at three loads puts it on the load. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [Claude Code]
The base moved while W2 was under review and repair, and #1200 landed edits to `.agents/specs/expert-streaming.md` two rows above this row's own entry. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [Claude Code] # Conflicts: # .agents/specs/expert-streaming.md
Second base move during this row's landing. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [Claude Code] # Conflicts: # docs/USAGE.md
…ious commit The previous commit pushed `docs/USAGE.md` with conflict markers still in it. A per-key resolver asserted that both sides had changed `--speculative-config`, exited, and the commit was chained after it without checking that the resolution had actually succeeded — so the marker text was staged and pushed. Nothing reached `main`: the pull request is unmerged, so this is repaired forward rather than by rewriting the pushed history. Both rows are now resolved by key. `--offload-config` takes this row's rewrite, which is what the row exists to do. `--speculative-config` takes main's version: it is a strict superset carrying the DSpark block-size guard from #1243, and this branch's copy is the older text that arrived here through an earlier merge rather than an edit of its own. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [Claude Code]
localai-bot
pushed a commit
that referenced
this pull request
Aug 18, 2026
…, and it was re-appended by hand `origin/main` advanced two commits (#1216, #1237) while this reconcile was being written. Neither touches `.agents/model-matrix.md`, `docs/STATUS.md`, `docs/BENCHMARKS.md` or `.agents/specs/nemotron-h-model.md`, so the scoped edit did not have to be rewritten a second time. `.agents/issue-index.md` did overlap: main gained three rows and the union driver interleaved them, putting this branch's two rows before main's new ones and destroying the prefix property that makes the file an append-only log. GitHub does not run that driver anyway. So the auto-merge was DISCARDED, main's file taken whole, and only the rows whose KEY main lacks re-appended: #1074 and #1080. Asserted: main's blob is a strict BYTE prefix of the result (346246 of 349242 bytes), 369 rows, zero duplicate keys. The delta against `cdfade6ab` is byte-for-byte the same five files it was against `b626be75a`. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [claude-code]
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.
Two of
ENG-RESIDENCY-CONFIG's own## Owedentries, closed together becausethey edit the same two files:
server_main.cpp's argument block andweight_residency.cpp's parser. Splitting them would have put two branches onboth.
The device budget becomes a config key (#1127)
VT_DEVICE_WEIGHT_BUDGET_BYTESis the escape hatch for the load-time device-fitrefusal that landed in #1132, and it was the odd one out once
mmap,prefault,expert_stream,slotsandslot_byteshad all become keys undervllm_cpp.It joins them:
--offload-config '{"vllm_cpp":{"device_fit":{"weight_budget_bytes":68719476736}}}'Same terms as its five siblings. Environment variable > config > device probe,
pinned by a test in both directions. An absent field means unchanged, at the
parse and at the install, pinned by two DIFFERENT partial documents in one
process — the shape that caught #1133 H2, because a second document that restates
the first's field cannot show a dropped field. A misspelling anywhere in the new
level is refused at startup by name, with a case per spelling
(
device_fitt,device-fit,weight_budget_byte,device_weight_budget_bytes).device_fitis an object, not a scalar sibling ofmmapandexpert_stream. Two reasons.vllm_cppmaps a name to an OBJECT today and theparser's
ExtObjectwalk assumes it, so one scalar would make the levelheterogeneous for one field. And the device-fit check is a third knob FAMILY
rather than a member of either existing one; the field name drops the family
prefix, which is the transformation
VT_GGUF_MMAP→mmap.enabledandVT_MOE_EXPERT_STREAM_SLOTS→expert_stream.slotsalready use.ZERO is legal here and nowhere else in the struct.
CheckDeviceWeightFitreads a zero budget as UNKNOWN and decides nothing, so
0is the documentedspelling of "suppress the refusal and get the late failure back" — exactly what
VT_DEVICE_WEIGHT_BUDGET_BYTES=0already means.slotsandslot_bytesaresizes and keep refusing a zero, because a slot count that silently became 64 is a
cache the operator does not have. So the budget parses through its own
ExtNonNegativeInt, a negative value is refused, and the message says "must notbe negative" rather than "must be positive", because the second sentence would be
false about a value the parser accepts.
DeviceWeightBudgetByteskeeps its name and its callers and delegates toResolveDeviceWeightBudgetBytes, now the sole reader of the variable. That iswhat stops the install-time override announcement from drifting away from what
the resolver does with a value:
0wins and is announced, while a signed, spacedor garbage value is ignored and falls through — to the config now, where it used
to fall through to the probe. A run with no config therefore resolves
byte-for-byte as before.
Three entry points, decided rather than plumbed (#1135)
The server parses
--offload-configONCE, ahead of the architecture branch.vllm-cligets the flag. It is a thin ABI client andvllm_model_params.offload_configalready parses both halves, so this is oneassignment and both tiers arrive — the mirrored
uva/prefetchhalf included,refusal and all. The gate runs the built binary and reads the install line off
its stderr, because a test that called the ABI would re-prove the ABI and would
have passed on the day the flag was missing.
The pooling/embedding path gets both halves. It builds
EngineParamsandcalls the same
LoadedEngine::FromModelDir, which installs the residencydocument and the weight offloader ahead of every path and weight operation, so
nothing about pooling makes either half inapplicable. Before this, both were
dropped there in silence.
The transcription-only path gets NEITHER, and refuses a non-empty document at
startup.
ParakeetTranscriber::FromDirbuilds noEngineParamsand calls noLoadedEngine, so that path runs noSetWeightResidencyConfig, noCreateWeightOffloader, no GGUF mapping and no expert slot store: there is nofield of either half that any code on it could read. Wiring it means giving the
transcription stack a loader seam, which is larger than #1135. AGENTS.md says to
refuse an unimplemented arm with a message that names the missing part, and a
warning would leave a server running while it holds a placement instruction it
does not follow — the failure #1135 was filed about. The wiring is owed as #1195
and listed under
## Owed.The review repair
A fresh review executed every behavioural attack and all came back clean, so
nothing about what the code DOES changed. What it said about itself did.
include/vllm.hstill described the pre-#1127 schema, in the one fileAGENTS.md names as the place a shipped capability is exposed. It omitted
device_fit.weight_budget_bytesfrom the schema block, omittedVT_DEVICE_WEIGHT_BUDGET_BYTESfrom the precedence list, and its refusal listsaid "a non-positive
slotsorslot_bytes" while never saying thatweight_budget_bytesrefuses a NEGATIVE and ACCEPTS0— the single asymmetrythis wave exists to introduce. Measured:
git grep device_fit aed3aa5e9 -- include/vllm.h src/capi/matches nothing, whileinclude/vllm/config/weight_residency.hhas seven hits at the same commit, so thekey existed everywhere except the one file that is the public surface. That is
sharper than ordinary drift, because
vllm-cli— this wave's own new entry point —is a pure ABI client passing exactly the document the header called invalid, and
the loader accepted it. All three statements are there now.
A test that claimed to SKIP actually FAILED.
cmake -DVLLM_CPP_BUILD_TESTS=ON -DVLLM_CPP_BUILD_EXAMPLES=OFFis a legalconfiguration; there
VLLM_CLI_BINARYis undefined, the file defines it as"",and all four cases ran
REQUIRE(std::string(kCliBinary) != "")— four FAILEDcases on a build that simply did not include the binary. No CI job hits that
combination today, so it was latent rather than red. The tree already had the
idiom:
vllm_cpp_add_testsetsSKIP_RETURN_CODE 77on every test. The fourREQUIREs become oneRequireCliBinary()that exits 77, CTest reportsSkipped, and both CMake comments now say what happens. Returning early
instead would have printed doctest's
assertions: 0 ... Status: SUCCESS!, whichis the #463 trap the 77 convention exists for. The repaired shape also cannot be
half-reverted: dropping only the calls leaves
SkipGateunused and-Werror=unused-functionrefuses the build, which is how the first attempt atthe proving mutation came back INVALID rather than green.
The setter now refuses what the parser refuses.
SetWeightResidencyConfigis declared in a public header and takes the struct, soa hand-built config reaches the process-global having run no parser — and
ResolveDeviceWeightBudgetBytescasts the configuredint64_ttosize_t, so aninstalled
-1resolved to SIZE_MAX: an effectively infinite budget that switchedthe device-fit guard OFF silently, which is the exact failure that guard's own
refusal text names.
0still installs, because it is the suppression spelling.docs/USAGE.mdquoted a refusal message the parser had stopped printing. W2added
device_fitto thevllm_cpplevel, soRejectUnknownKeysenumeratesthree names; the sample output still read
(expected one of: mmap expert_stream),in the section whose subject is that a typo is named rather than ignored. Found by
scripts/check-doc-checkpoint.pyrefusing the repair commit — the gate was owed areal edit and this was it. No separate issue: the defect was introduced by this
unlanded pull request and is repaired inside it.
The counts were wrong and are corrected: #1206 below, six "five" statements
the sixth knob invalidated (
weight_residency.h:62,:261,:312,:315,weight_residency.cpp:618,test_serve_residency_config.cpp:58), a "These two"above three cases, and the spec's attribution of three
test_gguf_device_fit_reachcases to a single mutation when it takes three.Filed in flow
Owned by
ARCH-ONE-SURFACE, listed under## Owed.EngineParamsfields,deviceamong them, so
vllm-server --device cudaon an embedding model runs theaccelerator-first probe. Same shape as --offload-config does not reach three entry points: vllm-cli, and the server's pooling and transcription paths #1135 over a wider set, predates this
row, owned by
SERVE-POOLING-ENDPOINTS, listed under## Owed.docs/USAGE.mdcommand lines named./build/vllm-serveror./build/vllm-cli, and both binaries are built underbuild/examples/. Fixedin this flow. The issue, the index row, this body and the spec first said FIVE;
the number was never counted.
grep -c 'build/vllm-' docs/USAGE.mdis 3 at thisbranch's base
fd64c76eeand at the merge base5af6e763(lines 2354, 3835,3848), and 0 at head. The FIX was always complete; only the count was wrong, and
every place is corrected — the append-only index row while this pull request is
still open, because after the merge it cannot be.
Gate
Every number below names the instrument that produced it, because two of them were
previously reported as one run and they are not the same lane.
Red first for the budget key (
./build/tests/test_weight_residency_config,whole binary). With
ResolveDeviceWeightBudgetBytesstubbed to return the probe:rc 1, 24 cases / 7 failed, 271 assertions / 15 failed — the seven are exactly
the seven cases this adds. With the implementation: rc 0, 24 cases, 315
assertions.
Red first for the setter guard, same binary, on the repair: rc 1, 25 cases
/ 1 failed, 324 assertions / 7 failed, the failing message logged as
ACCEPTED (no throw); with the guard, rc 0, 25 cases, 324 assertions. Thesuite's case count moves 24 → 25, which is the check that the case was added rather
than silently skipped.
Mutations. Each applied alone from a pristine byte copy, with the file's sha256
printed before and after so a never-applied edit cannot read as a pass, the build's
exit status beside every result so a non-building mutation is INVALID rather than a
pass, a NON-ZERO doctest case count required, the LAST
test cases:line taken, andthe tree restored by byte copy plus
touchplus a rebuild —cp -ppreservesthe mtime, ninja then skips the rebuild, and a stale mutated binary produces a kill
it has not earned. The twelve original mutations include the three call-site
deletions and the reachability mutation that removes
SetWeightResidencyConfig. Therepair adds five, three of them to establish WHICH mutation reds WHICH of the three
test_gguf_device_fit_reachcases — the spec had attributed all three to one, and itis M7 for the config-key case, M12 alone for the zero case and M4 alone for the
precedence case. One of the five came back INVALID rather than green and is recorded
as such. Both tables are in the spec's
## Evidence.Full ctest gate, twice, because
origin/mainmoved while the first wasrunning. Both are the declared recipe,
cmake -S . -B build -G Ninjawith no buildtype so asserts stay live. On
65d6cdaed: build rc 0, ENOSPC 0,ctest --test-dir build -j 6rc 0, 100% tests passed, 0 failed out of 523,466.09 s. Merged onto
c20018f8dand rerun: build rc 0, ENOSPC 0, ctest rc0, 100% tests passed, 0 failed out of 523, 587.09 s. The second is the one
that counts, because a clean merge is not a merge that builds. It is slower for
contention only — the box's load average was above 200 for much of it.
test_modelopt_mixed_precision_checkpointandtest_voxtral_e2eare Skipped inboth, as they are on this host. The count is 523 rather than the 516 recorded
earlier because
origin/mainadded test binaries in between.scripts/check-symbol-anchors.py, which arrived in that interval, reports OK with618 citations and 0 stale, and
scripts/agent-preflight.shis rc 0 with no failinggate.
tests/scripts/test_cpu_x86_llamacpp_floor.pyis a DIFFERENT instrument and isnot one of those tests. It is a Python harness contract run by
ci.yml:210andscripts/agent-preflight.sh:145;ctest -N | grep -i floormatches nothing. Itfails on this box under load, and the isolation showing the change is not the cause
is NOT the concurrent A/B this body previously reported. That A/B was
self-poisoning: each arm is the other's contention and the failure lands on
whichever loses the race, which is why a rerun put the failure on the control arm
and inverted the result. The 3-versus-2 claim is withdrawn. What isolates it is
two things that do not race. The three files the harness reads are byte-identical on
this branch and on
origin/main(358927d17,bd7a51925,94f8509c4on bothsides). And a SINGLE-arm sweep on this branch alone, three runs on one tree: rc
1 at load 172→194, where the harness's own quiet gate fires
NO_QUIET_WINDOW after 15sand the run takes 114.7 s; rc 1 again at load92→107, same gate, 86.0 s; and rc 0 at load 53→49,
Ran 10 tests in 3.338s / OK.scripts/agent-preflight.shis rc 1 exactly when this harness is, and rc 0when it is not. All of it is in the spec's
## Evidence.A doctest filter trap, recorded because it cost a reading. Two case names here
contain a comma and
--test-case=splits its argument on commas, so filtering toone of them ran 0 cases and printed
Status: SUCCESS!. Every result above comesfrom running a whole binary and reading its case count.
Closes #1127. Closes #1135. Closes #1206.
FOLLOWING_AGENTS_PROTOCOL
Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]