Repository navigation
tests: the plans checked in under configs/plans/ are loaded by a gate (engine#799) - #2233
Conversation
… (engine#799)
`docs/npu-plan.md` says four plans are checked in "one per model directory on the build box", and that
`tools/npu_plan.py <dir> --check` proves a directory's copy still matches. Both true - and the second needs the
model directory, which CI has not. So the shipped plans had **no gate at all**: `git grep configs/plans` found
them mentioned in two docs and read by nothing, and a hand edit or a generator change could leave one refused by
`Plan::load()` with the first evidence being a lane loading it on the box.
$ (driving the four through the same loader the forward uses)
configs/plans/bonsai2-27b-NPU-b8.plan.json LOADS (layers=64)
configs/plans/bonsai2-27b-NPU.plan.json LOADS (layers=64)
configs/plans/bonsai2-27b-pb16i.plan.json LOADS (layers=64)
configs/plans/Qwen3-0.6B.plan.json LOADS (layers=28)
They are all valid today - which is the reason to pin them, not a reason to skip it.
The test loads each shipped plan through `Plan::load()`, so the refusal vocabulary is the engine's own rather than a
JSON schema written twice: a format bump is refused by name
plan: configs/plans/Qwen3-0.6B.plan.json format is "1bit-npu-plan/2", this engine reads "1bit-npu-plan/1"
and it also asserts `plan.format == kFormat`, so a future format bump has to touch this test instead of silently
accepting yesterday's plans. It needs no model, no device and no pack.
An empty or wrong directory FAILS rather than passing over zero plans - the vacuous green this test exists to
prevent. Verified both arms: a bumped format fails with the sentence above (rc 1), an empty directory fails (rc 1),
the real directory passes (rc 0), and through ctest in a real configure (`Test #239 npu_plan_shipped`, 100% passed).
Registered through cmake/tests-*.cmake (#1979's glob), so no CMakeLists.txt hunk.
What it does NOT prove: that a plan still matches its model directory (that is `--check`, and it needs the pack),
or that a plan is right - only that it is one the engine can read.
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT at 855163d: READY
A checked-in plan that is not loaded by anything is the same defect as a test that runs nowhere — the file exists, looks authoritative, and nothing would notice if it stopped parsing or named a directory that is gone. npu_plan_shipped_test closes that: the plans under configs/plans/ are loaded through the same reader the runtime uses, so a plan that drifts from the schema fails here rather than at serve time.
cmake/tests-plan-shipped.cmake puts the registration in a family file, which is the current convention (#1696's pattern) and keeps CMakeLists.txt from growing another block for one row.
The linking is also right: nlohmann_json only, no onebit_npu, so the arm tests the plan parser rather than dragging in the forward — which is what makes it runnable everywhere, including CI without a device.
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT: READY at 855163d
Built it, ran it (9 arms), then broke one plan to watch the gate catch it — which is the whole question for a gate over checked-in data.
$ ./npu_plan_shipped_test
ok the shipped plans directory holds at least one .json (configs/plans)
ok Qwen3-0.6B.plan.json: loads through Plan::load() with 28 layer(s)
ok Qwen3-0.6B.plan.json: carries the format this build reads
ok bonsai2-27b-NPU-b8.plan.json: loads through Plan::load() with 64 layer(s)
… npu_plan_shipped: ok
$ (format: "bogus-9" in Qwen3-0.6B.plan.json)
FAIL Qwen3-0.6B.plan.json: REFUSED by Plan::load(): plan: configs/plans/Qwen3-0.6B.plan.json format is "bogus-9", this engin…
FAILED
The failure names the file, the value, and what the engine reads — which is what makes this gate usable on a stale plan rather than just red.
The finding that motivates it is the one I would have missed: "git grep configs/plans finds them named in two docs and read by nothing". Four plans, documented as "one per model directory on the build box", and no gate — so a plan can drift from Plan::load() for as long as nobody
runs tools/npu_plan.py <dir> by hand, and the first symptom is a model that fails to load on a box where the plan is right but the format moved.
Two details that make it a good gate:
the shipped plans directory holds at least one .json— the empty-set arm. A gate over a directory that has been emptied or moved would otherwise pass with zero checks, which is the failure
mode of half the enumerations in this repo.- both arms per plan: "loads through
Plan::load()" and "carries the format this build reads" — the second is the one that catches a format bump, and it is separate because a plan can load and
still be the wrong vintage.
One note, not a change: the arms are generated per file in the directory, so a new plan is covered automatically but a deleted one only shrinks the list — if the count matters (four, per the doc), an
arm pinning >= 4 would make a disappearance as loud as a corruption. The "at least one" arm catches the empty case, which is the important half.
Not run: tools/npu_plan.py against the plans (no device needed for Plan::load(), but the tool's path is out of scope here).
|
VERDICT: READY at The gap is stated as an impossibility, which is the honest form
|
docs/npu-plan.mdsays four plans are checked in "one per model directory on the build box", and thattools/npu_plan.py <dir> --checkproves a directory's copy still matches. Both are true — and the second needs the model directory, which CI has not.So the shipped plans had no gate at all:
git grep configs/plansfinds them named in two docs and read by nothing. A hand edit, or a change to the generator, could leave one refused byPlan::load()and the first evidence would be a lane loading it on the box.They are all valid today — which is the reason to pin them
What the test does
Loads each one through
Plan::load(), so the refusal vocabulary is the engine's own rather than a JSON schema written twice. A format bump is refused by name:and it also asserts
plan.format == kFormat, so a future format bump has to touch this test instead of silently accepting yesterday's plans.An empty or wrong directory FAILS rather than passing over zero plans — the vacuous green this test exists to prevent.
Verified both arms, plus the real path
Registered through
cmake/tests-*.cmake(#1979's glob), so noCMakeLists.txthunk. Ratchets unmoved:ci_targets_check9 (baseline 9, none new),tmp_path_check44 sites none new/stale, copyright clean.What it does not prove
That a plan still matches its model directory (that is
--check, and it needs the pack), or that a plan is right — only that it is one the engine can read. Stated in the test's own header so the next reader does not over-read a green row.