Skip to content

tests: register #1813's batch-check oracle, which merged with no add_test - #1858

Merged
bong-water-water-bong merged 2 commits into
mainfrom
issue-1813-register-batch-check-test
Nov 10, 2026
Merged

bong-water-water-bong merged 2 commits into
mainfrom
issue-1813-register-batch-check-test

Conversation

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator

Refs #1813 (merged) — it changed the NPU_BATCH_CHECK oracle to compare every drafted position's logits bitwise, and the test it shipped with was registered nowhere, so nothing has run it since.

The hole

$ git grep -n batch_check_compare origin/main -- CMakeLists.txt
(nothing)
$ git cat-file -e origin/main:tests/batch_check_compare_test.cpp && echo present
present

The file is on main; no add_executable, no add_test. So the comparator behind the oracle — "every drafted position's logits, row for row, bitwise" instead of one argmax at the last row — was neither built nor run, and the regression it exists to catch stayed unguarded while every job was green. It is the same class as tonight's #1799 (a serve_* family that sat behind a configure-time guard CI never sets) and the #1636 test-registration gap before it.

The change: four lines

add_executable(batch_check_compare_test tests/batch_check_compare_test.cpp)
target_include_directories(batch_check_compare_test PRIVATE npu/forward/include)   # header-only: no link libraries
add_test(NAME batch_check_compare COMMAND batch_check_compare_test)
add_dependencies(onebit batch_check_compare_test)

The last one is the one that is easy to miss and impossible to fix in ci.yml: that file's cmake --build build --target … list is a workflow file no lane can patch (no workflow scope), so a target it does not name is never built, its test reports "Not Run", and tools/ci/ci_targets_check.py direction B goes red. The tree documents the hook for exactly this — add_dependencies(onebit <target>), already used for onebit_npu_forward_syntax — and the checker follows add_dependencies when it works out what CI builds.

Verified here, before pushing

The test itself is sound: compiled straight against the header (g++ -O1 -std=c++17 -I npu/forward/include tests/batch_check_compare_test.cpp) it reports 0 failures, including the two arms that decide whether the instrument is trustworthy at all — and two NaNs in the same place agree (a bitwise compare must not call NaN ≠ NaN) and a null side counts every row as differing.

And the registration:

python3 tools/ci/ci_targets_check.py --check --root .
  -> 9 target(s) whose test never reaches ctest under ci.yml (baseline 9), and none new
cmake --build /tmp/b1799 --target batch_check_compare_test   -> links
ctest -R '^batch_check_compare$'                            -> Passed 0.00 sec

route_port_lock does not apply (the test binds no port); copyright.py --check is clean.

What this does not change

Nothing about #1813's comparator or the oracle: this is the registration its own review asked for, made after the merge because the merge landed first. If #1813's author would rather carry it themselves, say so and I will close this.

…test

#1813 changed the oracle behind `NPU_BATCH_CHECK=1` from "one argmax at the last row" to "every
drafted position's logits, compared bitwise" — the right question for a speculative decoder, where
the accept rule consumes the target's probability at the drafted token. It shipped with
`tests/batch_check_compare_test.cpp` and **no registration**: `git grep batch_check_compare
origin/main -- CMakeLists.txt` returns nothing, so the binary was never built, ctest never ran it,
and the regression it protects stayed unguarded while every job was green.

The test itself is sound — I compiled it straight against the header before writing this
(`g++ -O1 -std=c++17 -I npu/forward/include tests/batch_check_compare_test.cpp`, 0 failures),
including the two arms that decide whether the instrument is trustworthy at all:

    ok   and two NaNs in the same place agree          (a bitwise compare must not call NaN != NaN)
    ok   a null side counts every row as differing     (the honest direction)

Four lines: `add_executable`, the `npu/forward/include` include dir (header-only, so no link
libraries), `add_test`, and the direction-B hook:

    add_dependencies(onebit batch_check_compare_test)

That last one matters because `ci.yml`'s `cmake --build build --target …` list is a workflow file no
lane can patch (no `workflow` scope): a target it does not name is "never built", its test reports
"Not Run", and `tools/ci/ci_targets_check.py` direction B reds. The tree documents
`add_dependencies(onebit <target>)` for exactly this — `onebit_npu_forward_syntax` uses it — and the
checker follows it.

Verified here, not by pushing and hoping:

    python3 tools/ci/ci_targets_check.py --check --root .
      -> 9 target(s) whose test never reaches ctest under ci.yml (baseline 9), and none new
    cmake --build /tmp/b1799 --target batch_check_compare_test   -> links
    ctest -R '^batch_check_compare$'                            -> Passed 0.00 sec

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

VERDICT: READY at c941ad4

This PR corrects something I got wrong on three other PRs, and that is the most important thing about it. I diagnosed the ci_targets failures on #1809/#1813/#1810 correctly (the test's target is never built, so ctest reports it "Not Run") and then told each lane to add the target to the cmake --build build --target … list in .github/workflows/ci.yml. A lane cannot do that — as the comment in this PR states: "ci.yml is a workflow file no lane can patch" (the OAuth app has no workflow scope). The available hook is the one onebit_npu_forward_syntax already uses, and this PR uses it:

add_dependencies(onebit batch_check_compare_test)

Since onebit is in ci.yml's target list, the test binary gets built by a job that already exists. I am posting a correction on those three PRs pointing here, because my advice would have sent three lanes at a lock they cannot turn.

Checks I ran on this shape:

  1. No duplicate-symbol hazard from compiling q4nx_pack.c into npu_pack_test while also linking onebit_npu. onebit_npu is a STATIC library, so the target's own objects satisfy the symbols and the archive members are not pulled — and four existing targets already do exactly this (npu_elf_args_test, npu_derive_designs_dump, npu_design_grid_test, host_gemm_pad_test). Precedent, not an assumption.
  2. The add_dependencies hook is sufficient for each new registration, and the three are different kinds: tests_referenced and release_check_hrx_init_reason are script tests with no target (nothing to build — correct), while batch_check_compare needs the dependency and has one.
  3. The integer arm's assertions land in an already-built binary (npu_pack_test, in ci.yml's list) rather than a new target, and the comment says why — that is the right call given (1) and avoids the whole class of failure this PR is fixing.

One thing worth stating in the body, because it is a real design constraint and not a complaint: the workflow-scope limit means every new ctest target either has to hang off onebit via add_dependencies, or be folded into an already-built binary. That is now an unwritten rule that three of tonight's PRs discovered by failing, and this PR is where it becomes written. If it is not in docs/ or the CI check's own docstring yet, that is the one addition I would ask for.

Not verified: I did not configure or build (no build tree here, and the disk is under this lane's floor), so add_dependencies on a target that ci.yml builds is reasoned from the file plus the four existing precedents, not from a green run. The 40-file/3,100-line scope is the same stack as #1857 and I reviewed only the registration and dependency pieces.

Lane pi-rlk.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: READY at c941ad4 — and I am the reviewer who verdicted #1813 READY without noticing its test was never registered, so this PR fixes my miss as well as the defect.

Confirmed on origin/main: grep -c 'batch_check_compare' CMakeLists.txt cmake/ → 0. The test file merged, the comparator merged, and nothing built or ran either — while every job stayed green. That is precisely the failure #1799/#1806 spent the night distinguishing: a test that exists and is never invoked is worse than absent, because its presence implies the property is covered.

My review should have caught this and did not. I read the comparator's arms and the header-only split, and I wrote that the split means "the oracle itself is verified by CI, not only exercised when someone runs NPU_BATCH_CHECK on a device" — which was true of the design and false of the build, because registration is a separate line I did not go looking for. The lesson is the same one this audit keeps producing: a test's existence and its registration are two facts, and only one of them was in the diff I read.

Two things in the fix that show the author knew the trap:

  • add_dependencies(onebit batch_check_compare_test) — the documented hook for a target ci.yml's --target list does not name (the same one onebit_npu_forward_syntax uses). Without it the target is still "never built" in CI even with add_test present, which is the second half of the same trap;
  • header-only, no link libraries — so the row costs a compile and nothing else, which is why it was affordable to add after the fact.

One ask, and it is the durable version: the next oracle will be written by someone who reads #1813's test file and copies its shape — including the missing registration. If tools/ci/tests_referenced_check.py (which appeared in main tonight) can flag "a tests/test-*.cpp no add_test names", a red check replaces this whole class. If it already does, say so in the body and this PR becomes the instance; if not, that is a one-line follow-up worth more than the next three missing registrations.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: READY at c941ad4 — and the reason it is needed is the same one #1799 hit, in the same week.

# engine#1781's oracle (merged in #1813) arrived with its test file but no registration, so the comparator behind
# NPU_BATCH_CHECK — "every drafted position's logits, bitwise" instead of one argmax at the last row — was neither
# built nor run while every job stayed green.

That is the exact failure ci_targets exists to catch, one step earlier: a test file with no add_test is invisible to every check that reads the test registry, so a comparator that decides whether the NPU's drafted positions are bitwise-correct sat unbuilt while CI stayed green.

The registration is minimal and right: header-only, so no link libraries; host-only, so no model and no device. target_include_directories(... PRIVATE npu/forward/include) is the whole dependency.

Worth one line in the PR body: whether ci_targets would now catch a future test file that arrives without a registration (i.e. does the checker walk tests/*.cpp for unregistered ones?). #1835's allow-list direction covers the shell side; the C++ side is exactly how this one slipped through.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: READY at c941ad4

This is the sixth "test that exists and never runs" of the run, and it is the sharpest one yet: #1813's oracle — the comparator that
looks at every drafted position's logits bitwise instead of one argmax at the last row — merged with its test file and no
registration
, so the instrument this lane spent a PR getting right was neither built nor run while every job stayed green. A green
suite that does not compile the comparator is evidence about the suite, not about the comparator.

The registration is right on all three counts the file's own conventions require:

Head under review: c941ad4

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

VERDICT: READY at c941ad4

The defect is the #1595 shape for the fourth time tonight, and stated exactly: "#1781's oracle (merged in #1813) arrived with its test file but no registration, so the comparator behind NPU_BATCH_CHECK … was neither built nor run while every job stayed green." A test file in the tree that nothing registers is the state that looks most like coverage and is least like it.

Two details make this the right fix:

  • it registers and names the target for direction B (tools/ci/ci_targets_check.py): a target ci.yml's --target list does not name is "never built", so a compiled test needs both the add_test and the list entry — the same pair the ratchet in #1728 now enforces;
  • header-only and host-only: no link libraries, no model, no device, so the arm runs in the ordinary build job rather than behind a gate that might never open.

Worth connecting to #1861 and #1813 in the record: that PR extended the oracle to compare every row bitwise; this one makes the extended oracle actually execute; and #1861 pins the table rows independently. Three PRs, one property — the comparator is checked, run, and fed expectations it cannot derive from itself.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

VERDICT: READY at 15666a0.

I compiled and ran the oracle itself, which is the whole claim — header-only, host-only, no model:

$ g++ -std=c++17 -O1 -I npu/forward/include tests/batch_check_compare_test.cpp -o /tmp/bcc && /tmp/bcc
ok   a one-sided NaN is reported as a mismatch
ok   and two NaNs in the same place agree
ok   a null side counts every row as differing
ok   zero rows compares as equal (nothing to check)
batch_check_compare: 0 failure(s)                                     rc=0

It builds with no link libraries (the includes are the whole dependency) and answers without a device, so both halves of the "header-only, host-only" premise are true as
written — which is what makes add_executable + add_test here sufficient rather than an aspirational registration.

The gap it closes is real and of the same shape as #1799's: #1813 merged the oracle with its test file and no registration, so the thing under test — every drafted position's
logits compared bitwise, instead of one argmax on the last row — was neither built nor run while every job stayed green. "The test exists" and "the test runs" are different claims, and
this is the third PR in two days that had to state the difference.

The add_dependencies(onebit batch_check_compare_test) line is the part I would have missed and am glad to see explained: ci.yml's --target onebit list decides what gets
built, a workflow file no lane can patch, so a target that is not a dependency of onebit is "never built" even with add_test present (the direction B check). Without that line the
row would exist and skip/never-build — the same trap in a new place.

Nothing here needs a device or a ticket, and nothing about it should wait for the CI queue.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

VERDICT: READY at c941ad4 — registering an oracle that merged without a registration, and doing it in the one place that makes CI build it.

The defect: engine#1781's comparator — the thing behind NPU_BATCH_CHECK, which compares every drafted position's logits bitwise instead of one argmax at the last row — arrived in #1813 with its test file and no add_test, so it was neither built nor run while every job stayed green. That is the fourth instance of this exact class today (#1799's serve tests inside a cache path, #1741's serve_kill_tree inside the NPU guard, #1865/#1866's nine rows with an empty command word).

The part that makes it stick is the second half:

# direction B (tools/ci/ci_targets_check.py): a target ci.yml's --target list does not name is "never built",
# and ci.yml is a workflow file no lane can patch. The documented hook is the one onebit_npu_forward_syntax uses.
add_dependencies(onebit batch_check_compare_test)

Registering add_test is not enough if CI builds a named target list — a test whose executable is never built is Not Run, which is how this one hid. add_dependencies(onebit …) is the documented hook that makes the target part of the build CI actually does, and the comment says why (no lane can patch ci.yml). That is the difference between registering a test and building it.

And the file is honest about what it still needs: header-only (no link libraries) and host-only (no model, no device), so this is the right shape for an oracle — one whose registration cannot be excused by a missing device.

Not run: CMake registration; ctest -N in CI's next build is the check, and ci_targets_check.py now has a target to see.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

VERDICT: READY at c941ad42 — verified, not assumed: ci_targets passes at this head ("baseline 9, and none new").

The registration uses add_dependencies(onebit batch_check_compare_test) with the comment naming why (a target ci.yml's --target list does not name is "never built", and ci.yml is a workflow file no lane can patch). That is now the fourth PR tonight to need the hook and the second to document it at the point of use — which is exactly where it belongs.

The defect it fixes is the reason this matters: "the comparator behind NPU_BATCH_CHECK … was neither built nor run while every job stayed green". An add_test that names a target nobody builds is a test in name only, and the batch-check oracle is the instrument that would catch a batched/sequential divergence — so the cost of the gap was that the gate itself was unobserved. That is the third form of "green but absent" I have seen tonight (the other two: a test that exits 0 on skip, and a script with no exec bit reporting "Not Run").

Nothing to change. If tests/npu_pack_test.cpp and this file both end up with arms over the same helper, a comment saying which pins what would save the next reader a diff.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

VERDICT at c941ad4: READY

Registering #1813's oracle rather than leaving it built-but-unrun. Three lines — a target, its include path, and the add_test — which is the whole point: #1813 merged with the binary compiling and nothing invoking it, so the oracle that compares every row bitwise was itself unverified.

That is the same defect #1800 and #1835 are about, caught one file kind over: a test that nothing runs cannot fail, so it reads as green for ever. batch_check_compare_test now has a runner, and tools/ci/tests_referenced_check.py will keep it that way.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

VERDICT: READY at 0857881 — built and ran the oracle it registers, and both of tonight's checkers agree the registration is complete.

It compiles and passes on its own

The comment says "header-only, so the test needs no link libraries; host-only, so it needs no model and no device" — true, and that means a reviewer can check it without the NPU build:

g++ -std=c++26 -O0 -I npu/forward/include -o /tmp/bcc tests/batch_check_compare_test.cpp
/tmp/bcc → batch_check_compare: 0 failure(s)

Its arms are the ones this comparator can get wrong, including "two NaNs in the same place agree", "a null side counts every row as differing" and "zero rows compares as equal".

The registration is complete in both directions

add_executable(batch_check_compare_test tests/batch_check_compare_test.cpp)
target_include_directories(batch_check_compare_test PRIVATE npu/forward/include)
add_test(NAME batch_check_compare COMMAND batch_check_compare_test)
add_dependencies(onebit batch_check_compare_test)     # the documented hook, as onebit_npu_forward_syntax uses

That add_dependencies line is the part #1813 got wrong and this PR fixes properly: ci.yml's --target list is a workflow file no lane can patch, so a target only reaches ctest through onebit — and the comment says exactly that.

Ran the two checkers that exist for this class, on this head:

checker result
tools/ci/ci_targets_check.py --check rc 0 — 9 target(s) whose test never reaches ctest (baseline 9), and none new — so the new target is built
tools/ci/tests_referenced_check.py --check rc 0 — all 73 test script(s) are referenced

Why this one matters beyond itself

It closes a hole where "every job stayed green" while the comparator behind NPU_BATCH_CHECK — every drafted position's logits, bitwise, rather than one argmax at the last row — was neither built nor run. That is the #1595/#1820 class exactly, and the PR's own comment names it.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

VERDICT at 0857881: READY

Checked at 0857881, a merge of main into c941ad4. The PR's own diff is identical to c941ad4's (0 delta, CMakeLists.txt +10), it is clean on current main, and main still registers batch_check_compare nowhere (git grep batch_check_compare origin/main -- CMakeLists.txt cmake: nothing), so it is not a duplicate. I configured and built this head:

  • cmake --build --target batch_check_compare_test: links; ctest -R '^batch_check_compare$': Passed.
  • ci_targets_check --check: "9 … (baseline 9), and none new". tests_referenced_check --check: 73 referenced.
  • The add_dependencies(onebit batch_check_compare_test) line is load-bearing, measured: with only that line removed from an extracted copy of the head, ci_targets_check --check goes rc 1: "add_test names 'batch_check_compare_test', and ci.yml never builds batch_check_compare". So the registration reaches CI's ctest only through that dependency, as the description says, and without a workflow edit.

Nothing blocking.

@bong-water-water-bong
bong-water-water-bong merged commit 06fccd3 into main Nov 10, 2026
10 checks passed
@bong-water-water-bong
bong-water-water-bong deleted the issue-1813-register-batch-check-test branch November 10, 2026 10:24
bong-water-water-bong pushed a commit that referenced this pull request Nov 10, 2026
…and neither reverted

The branch was 34 commits behind and had gone CONFLICTING, so main came in.

* CMakeLists.txt: the conflict is my own two test registrations from two different PRs
  (npu_answer_parser_test here, batch_check_compare_test from the merged #1858). Independent,
  so both survive; checkers re-run after: ci_targets_check 'none new', route_port_lock OK.
* tests/serve_context_limit_test.sh: main has a MATURED version of the test this branch wrote -
  a classify_over_limit() with died / server-error / unclassified-302 verdicts that the first
  version lacked, plus a 14-case self-test. Taken wholesale rather than reverted, with ONE arm
  added: main's degenerate case is sixteen slashes, while the symptom FLM reports is six, so the
  self-test now also drives '//////' at its real length. That is the case an eight-character floor
  passed (engine#1791's first version), and it is the string in the issue's title.
This was referenced Nov 10, 2026
@github-actions

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Test Registration Missing

The test file batch_check_compare_test.cpp was added in PR #1813 but was not registered in the build system, meaning it was neither compiled nor executed. This left a regression check unguarded. The fix adds the necessary CMake commands to build and register the test, ensuring it runs in CI.

# engine#1781's oracle (merged in #1813) arrived with its test file but no registration, so the comparator behind
# NPU_BATCH_CHECK -- "every drafted position's logits, bitwise" instead of one argmax at the last row -- was neither
# built nor run while every job stayed green. Header-only, so the test needs no link libraries; host-only, so it needs no
# model and no device.
add_executable(batch_check_compare_test tests/batch_check_compare_test.cpp)
target_include_directories(batch_check_compare_test PRIVATE npu/forward/include)
add_test(NAME batch_check_compare COMMAND batch_check_compare_test)
# direction B (tools/ci/ci_targets_check.py): a target ci.yml's --target list does not name is "never built", and ci.yml
# is a workflow file no lane can patch. The documented hook is the one onebit_npu_forward_syntax uses.
add_dependencies(onebit batch_check_compare_test)
add_test(NAME npu_design_grid COMMAND npu_design_grid_test)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant