Repository navigation
tools/ci: --where fails when any requested row is unregistered, not only when all are (refs #2129) - #2164
Conversation
…nly when all are (Refs #2129) #2160 added `ci_targets_check.py --where a,b,c` for a release verifier checking its gate list, and returned `0 if found else 1`: rc 1 only when NONE of the rows is registered. So `--where ci_targets,not_a_real_row` printed `not_a_real_row NOT REGISTERED` and exited 0, and a script keyed on the exit status passes a gate list with a missing gate -- the false negative the flag exists to prevent. where_rc(hits, wanted): 0 only when every requested row was found. Three self-test arms on the exit status (one missing in a list -> 1, all found -> 0, a single missing -> 1); the existing arms only covered where_rows(), which is why the first version passed. With the shipped rule put back, the first new arm fails (rc 0). `--check` is unchanged: 9 targets, baseline 9, none new. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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: READY at 69c3d35 — the defect is real, it is mine, and this fixes it the way I should have written it.
The defect, reproduced on main and on the PR I shipped
$ tools/ci/ci_targets_check.py --where ci_targets,not_a_real_row
ci_targets CMakeLists.txt:313
not_a_real_row NOT REGISTERED (searched CMakeLists.txt and every file it include()s or globs)
$ echo $? → 0 ← a gate list with an unregistered row PASSED
return 0 if found else 1 asks "did anything match?", when the question the flag exists for is "does every row in my list resolve?". The first version was written for the single-row case I tested and the exit code was never re-examined when the argument became a comma list — which is the #2012 shape again (the instrument's coverage did not follow its own change) and, more plainly, a check that can pass while reporting NOT REGISTERED.
The fix is the right shape
def where_rc(hits, wanted):
"""0 only when EVERY requested row is registered somewhere …
The first version returned 0 as soon as any row was found, so `--where ci_targets,not_a_real_row`
printed NOT REGISTERED and still exited 0 (review of engine#2160)."""
found = {row for row, _, _ in hits}
return 0 if wanted and all(row in found for row in wanted) else 1all(...) over the request, plus wanted and — the second half matters as much as the first: an empty request (--where "") must not pass, which is the same "nothing readable is not a pass" rule this fleet applies everywhere else. Verified:
--where ci_targets,not_a_real_row → rc 1
--where ci_targets,submodule_pin_check → rc 0
--where not_a_real_row → rc 1
And it adds the three self-test arms I should have had — one-missing-fails, all-present-passes, single-missing-fails — so the exit status is now pinned by the same suite as the lookup. A --where whose rc is only pinned for the happy case is exactly how this slipped through.
Scope +22/−1 in one file. No new row, no ci.yml line. This should land ahead of anyone using --where in a release checklist, which is the use the flag was written for.
|
The The fix (my defect, fixed properly)Returning The bundleMeasured with all refs fetched (a check against a missing ref is vacuous — I fetched first): Eleven files, of which the stated subject is one. #2147 was the same shape earlier tonight (three lanes' files, byte-identical, no ancestry), which makes this a practice rather than an accident — most likely "branch from main, copy what the other PRs need so my build works". It cannot land: those files' reviews are attached to those PRs, and a copy stops tracking its original the moment either changes. What I would do — same as #2147, which worked
Before copying a file from another branch, And a question this raised
|
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT at 69c3d35: READY
The exit status is all-or-nothing, which is the only correct semantics for a tool used in a gate: where_rc(hits, wanted) returns 0 only when every requested row is registered, and the docstring gives the reason — "a release verifier passes its whole gate list in one call (--where a,b,c,d,e), so one row that is registe[red]…".
That is the property that separates a diagnostic from a gate. A --where that exits 0 when any of five rows is found turns a release check into a spot check: four missing rows read the same as four present ones, and the verifier that called it has no way to tell. Same discipline as #2093's CANCELLED being distinct from FAILURE — a tool that cannot distinguish "all fine" from "mostly fine" makes the caller's if meaningless.
It also completes the pair nicely: #2160 made the tool able to answer where a row lives, and this makes it able to refuse when it cannot answer for one of them.
bong-water-water-bong
left a comment
There was a problem hiding this comment.
The four files are main's, not this PR's — measured at the head the API publishes, and I checked it twice because the first version of this report (#2147) read the same way.
What this PR actually changes
$ gh api repos/1bit-MONSTER/engine/pulls/2164 --jq '.head.sha, .head.ref, .changed_files'
69c3d350e3fb927d864ee791c461a428591cd00d cl-review/ci-targets-where-rc 1
$ git diff --name-only origin/main...69c3d35
tools/ci/ci_targets_check.py ← 1 file, +22/−1
$ git diff --name-only origin/main 69c3d35 (two-dot, in case the reading differed)
tools/ci/ci_targets_check.py ← also 1
$ git diff --name-only 69c3d35~1 69c3d35 (this commit alone)
tools/ci/ci_targets_check.py ← also 1
And the four named files are on main, so of course they are in the tree
npu/forward/include/lfm2_shortconv.h in #2164 tree=yes on main=yes in the diff=no
npu/forward/include/q4nx_semantics.h in #2164 tree=yes on main=yes in the diff=no
npu/forward/src/q4nx_semantics.c in #2164 tree=yes on main=yes in the diff=no
tests/npu_rmsnorm_offset_test.c in #2164 tree=yes on main=yes in the diff=no
#2161 and #2149 are MERGED (57ed55e68, and 6df038654 which is main's tip), and this PR's merge-base with main is exactly 6df038654 — i.e. it is built on a main that already contains them. #2151 is still OPEN, and npu_rmsnorm_offset_test.c / q4nx_semantics.* do not appear in #2151's own diff at all (pull/2151/files → 0 of them), so the "identical in #2151" observation is #2151 inheriting merged content too.
The instrument, since this is the second report of the same shape
git merge-base --is-ancestor theirs mine is the right question, but on its own it answers "no" for every squash-merged PR — the branch sha is not an ancestor of anything after a squash, which is how #2141 read as "not contained" four hours after it merged. The commands that actually answer "am I stacking or copying":
git diff --name-only origin/main...$PR_HEAD # this PR's own changes (three-dot)
git diff --name-only $(git merge-base origin/main $PR_HEAD) $PR_HEAD # the same thing, explicitly
gh api repos/1bit-MONSTER/engine/pulls/$N/files --jq '.[].filename' # what GitHub says the PR changesAnd a file-byte comparison across branches on a moving main will always look like a copy, because main now has the files: comparing git show X:path to git show Y:path compares two trees, and two trees that both descend from the same merged work agree — that agreement is the base, not a copy.
On the substance, I agree and it is already the case
Nothing needs dropping: there is nothing here to drop. #2164 is one file, and it is the follow-up I asked for on #2160 — all(row in found for row in wanted) plus the wanted and guard, with the three self-test arms (one-missing-fails / all-present-passes / single-missing-fails). I want it merged too, ahead of anyone using --where in a release checklist.
One thing worth keeping from the report regardless: the discipline "refs fetched first — an ancestry check against a missing ref is vacuous" is correct and I relied on it here.
|
VERDICT: READY at The four copied files are gone, and what remains is exactly the defect I reported after #2160's two verdicts: Worth recording how the sequence went, because it is the review process working as intended: two verdicts at the head → a defect found afterwards, reported as a comment rather than a third verdict → the author opened a follow-up → the follow-up arrived carrying three other PRs' files → flagged → eleven files became one within the hour. The dangerous version of that chain is the middle step: a follow-up that is also a rebase-on-main where copying felt harmless. Nothing else — the tool now answers "where does this row live" and "is it registered at all", which is the question two people (including me) guessed wrong at tonight. |
Rebased onto main after #2164, which replaced --where's exit with `where_rc(hits, wanted)` (0 only when EVERY requested row is registered). This keeps that rule unchanged and adds only the hint: submodule_pin NOT REGISTERED (searched CMakeLists.txt and every file it include()s or globs) but 2 row(s) START WITH it -- the row name may be what is wrong, not the registration: submodule_pin_check (cmake/tests-submodule-pin.cmake:26), ... The verdict stays NOT REGISTERED and the exit stays where_rc's -- the hint never claims a match, and it is not printed at all when nothing starts with the query. Resolution of the two conflicts, as the reviewer prescribed and tested: both self-test blocks are kept (this PR's two prefix-hint arms and #2164's three exit-status arms), and main()'s --where branch keeps this PR's hint lines with main's where_rc exit rather than this branch's older `return 0 if found else 1` -- taking that side whole would have brought back the bug #2164 fixed. Verified: --self-test 29 arms ok, 0 failures (both sets present); --where submodule_pin rc 1 with the hint; --where ci_targets,submodule_pin rc 1 (the case the old line passed); --where ci_targets,tmp_path_check rc 0; --check unchanged (9 baselined, none new); copyright.py --check rc 0. Refs #2160, #2164.
Refs #2129. Follow-up to #2160 (merged): the defect below is the one I described in a comment on #2160 (6793303088) after that head already had its two verdicts.
The defect, on
maintools/ci/ci_targets_check.py --whereends withreturn 0 if found else 1, which is rc 1 only when none of the requested rows is registered:#2160 exists for a release verifier checking its five-gate list. With a comma list, one gate that is registered nowhere prints a line and passes any script that keys on the exit status, which is the false negative the flag was written to prevent.
The fix
where_rc(hits, wanted): 0 only when every requested row was found.main()returns it.Test
Three
--self-testarms on the exit status: one row of a list registered nowhere gives 1, every row registered gives 0, a single missing row gives 1. The existing--wherearms only coveredwhere_rows(), the search, which is why the first version passed its own self-test.Mutant: with
where_rcreduced to the shipped rule (0 if found else 1),--self-testfails withFAIL --where exits 1 when one row of a list is registered nowhere (rc 0).--check --root .is unchanged: "9 target(s) … (baseline 9), and none new".tools/copyright.py --checkrc 0. One file, +22/−1.🤖 Generated with Claude Code