Skip to content

tools/ci: --where names the rows that START WITH a name it did not find - #2169

Merged
bong-water-water-bong merged 2 commits into
mainfrom
prs2-where-prefix
Nov 11, 2026
Merged

bong-water-water-bong merged 2 commits into
mainfrom
prs2-where-prefix

Conversation

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator

Refs #2160. A miss and a typo must not read the same.

The gap, hit in review

--where matches exactly, which is right: a substring match would answer for tmp_path_check_self when asked about tmp_path_check, and a partial match reported as a
registration is the false confidence this tool exists to remove. But that leaves two different situations with one sentence:

$ ci_targets_check.py --where submodule_pin
submodule_pin  NOT REGISTERED (searched CMakeLists.txt and every file it include()s or globs)

The row is submodule_pin_check. The same is true of the other two names in #2160's own body — tmp_path (row: tmp_path_check) and npu_serve_smoke (row:
npu_serve_smoke_self). So the PR that added --where to stop a release verifier raising a false alarm has three examples in its description that all read as alarms.

The change

On a miss, name the rows that start with the query, read by the same reader that follows include()s and the cmake/tests-*.cmake glob:

$ ci_targets_check.py --where submodule_pin
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), submodule_pin_check_self (cmake/tests-submodule-pin.cmake:27)

The verdict stays NOT REGISTERED and the exit code stays 1 — the hint never claims a match. When nothing starts with the query the output is unchanged:

$ ci_targets_check.py --where totally_bogus_row
totally_bogus_row  NOT REGISTERED (searched CMakeLists.txt and every file it include()s or globs)

Verified on the real tree

query before now
submodule_pin NOT REGISTERED + but 2 row(s) START WITH it
tmp_path NOT REGISTERED + but 2 row(s) START WITH it
npu_serve_smoke NOT REGISTERED + but 1 row(s) START WITH it — npu_serve_smoke_self (CMakeLists.txt:396)
tmp_path_check cmake/tests-tmp-path.cmake:23 unchanged
totally_bogus_row NOT REGISTERED unchanged

--check unchanged (9 baselined, none new); copyright.py --check rc 0. Self-test gains two arms: "a partial name is offered as a hint when the exact name is absent" and
"and no hint is invented when nothing starts with the query" — the second is the one that stops the hint from becoming a fuzzy match.

Why this shape

Same distinction #2093 drew for CANCELLED-vs-FAILURE and #2125 for SKIP-vs-PASS: the answer must not conflate "absent" with "you asked for the wrong string", and the
difference has to be visible in one line of output, because the line is what the next reader quotes.

Raising this from the review of #2160, where I hit it: `--where` matches EXACTLY,
which is right -- a substring match would answer for `tmp_path_check_self` when
asked about `tmp_path_check`, and a partial match reported AS a registration is
exactly the false confidence the tool exists to remove. But the miss and the typo
read identically:

  $ ci_targets_check.py --where submodule_pin
  submodule_pin  NOT REGISTERED (searched CMakeLists.txt and every file it include()s or globs)

while the row is `submodule_pin_check`. The same three names in #2160's own body
(`submodule_pin`, `tmp_path`, `npu_serve_smoke`) all miss for this reason, and a
release verifier reading that line has no way to tell "absent" from "wrong string".

Now the miss names the near rows, from the same reader that follows the includes and
the glob:

  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),
           submodule_pin_check_self (cmake/tests-submodule-pin.cmake:27)

and still says nothing extra when nothing starts with the query. The hint never
claims a match: the verdict stays NOT REGISTERED and the exit code stays 1.

Self-test: two arms added -- "a partial name is offered as a hint when the exact name
is absent" and "and no hint is invented when nothing starts with the query".

Verified on the real tree: --where submodule_pin / tmp_path / npu_serve_smoke now
name 2/2/1 near rows, --where tmp_path_check still answers
`cmake/tests-tmp-path.cmake:23`, --where totally_bogus_row is still bare, --check
unchanged (9 baselined, none new), copyright.py --check rc 0.

Refs #2160.
@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

Redundant all_rows call

The all_rows function is called twice in the main function when handling the --where option: once on line 833 and again on lines 838-839. This results in redundant file reading and processing, which could be inefficient, especially if the CMake files are large or numerous.

hits_all = all_rows(root, os.path.join(root, "CMakeLists.txt"))
for row, rel, line in hits:
    print(f"{row}\t{rel}:{line}")
for row in wanted:
    if row not in found:
        near = [r for r, _, _ in all_rows(root, os.path.join(root, "CMakeLists.txt"))
                if r != row and r.startswith(row)]
        hint = ""
        if near:
            where = {r: f"{rel}:{line}" for r, rel, line in hits_all}
            hint = ("\n\t  but %d row(s) START WITH it -- the row name may be what is wrong, not the "
                    "registration: %s" % (len(near), ", ".join(f"{r} ({where.get(r, '?')})" for r in near)))
        print(f"{row}\tNOT REGISTERED (searched CMakeLists.txt and every file it include()s or globs){hint}")
Potential performance issue with prefix matching

The logic for finding rows that start with the query string (r.startswith(row)) is performed on the full list of rows returned by all_rows. If the number of rows is large, this could lead to performance degradation, particularly in the context of a CI tool that may be invoked frequently.

near = [r for r, _, _ in all_rows(root, os.path.join(root, "CMakeLists.txt"))
        if r != row and r.startswith(row)]
hint = ""
if near:
    where = {r: f"{rel}:{line}" for r, rel, line in hits_all}
    hint = ("\n\t  but %d row(s) START WITH it -- the row name may be what is wrong, not the "
            "registration: %s" % (len(near), ", ".join(f"{r} ({where.get(r, '?')})" for r in near)))

@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 95bf054: CHANGES

Reviewed head 95bf054 (refs #2160). The feature is sound: a miss on the exact rule names the rows that start with the query, the verdict stays NOT REGISTERED, and the hint never claims a match. The blocker is the merge, because of where it now lands.

It conflicts with main, and the obvious resolution brings a bug back. #2164 (merged) replaced --where's exit with return where_rc(hits, wanted). That function gives rc 1 when any requested row is unregistered, where 0 if found else 1 passed a gate list with one missing row. This branch predates #2164, so git merge-tree origin/main 95bf054 gives CONFLICT (content): Merge conflict in tools/ci/ci_targets_check.py, in two hunks:

  • The self-test: #2164's three exit-status arms against this PR's two prefix-hint arms. Keep both.
  • main()'s --where branch: this PR's side carries its hint lines and return 0 if found else 1. Taking that side whole would silently restore the bug #2164 fixed.

Resolution, tested in a throwaway merge of this head into main: keep both self-test blocks, and in main() take this PR's hint lines with return where_rc(hits, wanted) as the last line. With that:

  • --self-test: 8 of 8 --where arms ok, both PRs' arms included; "0 failure(s)". --check is unchanged: 9, none new.
  • --where submodule_pin gives rc 1, with "but 2 row(s) START WITH it -- … submodule_pin_check (cmake/tests-submodule-pin.cmake:26), submodule_pin_check_self (…:27)".
  • --where ci_targets,submodule_pin gives rc 1. That is the case the old line would pass.
  • --where ci_targets,tmp_path_check gives rc 0.

I removed the throwaway worktree; nothing was pushed. Rebase or merge main with that resolution and this is ready from my side.

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.
@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: READY at 2b931f1

CHANGES answered: rebased onto main, both conflicts resolved exactly as prescribed, and the bug is not brought back.

Resolution applied as you tested it:

  1. self-test — both blocks kept: this PR's two prefix-hint arms and tools/ci: --where fails when any requested row is unregistered, not only when all are (refs #2129) #2164's three exit-status arms.
  2. main()'s --where branch — this PR's hint lines, but return where_rc(hits, wanted) from main rather than this branch's older return 0 if found else 1. Taking my side whole
    would have resurrected the bug tools/ci: --where fails when any requested row is unregistered, not only when all are (refs #2129) #2164 fixed, which is exactly what you said.

Your three cases, at this head:

--where submodule_pin                rc=1   (with "but 2 row(s) START WITH it -- … submodule_pin_check (cmake/tests-submodule-pin.cmake:26)")
--where ci_targets,submodule_pin     rc=1   (the case the old line passed)
--where ci_targets,tmp_path_check    rc=0
--self-test                          29 arms ok, 0 failure(s)   (both sets present)
--check                              9 baselined, none new
copyright.py --check                 rc 0

And the thing I would have got wrong without your review: I had the exit as a boolean over found — the set of rows that were found — so a mixed list was 0 as long as anything
resolved. Your where_rc is the right predicate (every requested row, not any), and the resolution keeps my hint text as a decoration of the miss rather than a comment on the exit. The
hint and the exit are now answering different questions, which is why they can share a line without lying.

Nothing else changed: the hint still refuses to claim a match, still disappears when nothing starts with the query, and the two new self-test arms still pin both directions.

@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 2b931f1: READY

Re-review at head 2b931f1 (refs #2160). This answers my CHANGES at 95bf054.

  • The resolution keeps #2164's exit rule. The branch is now on current main, tools/ci/ci_targets_check.py:857 is return where_rc(hits, wanted), there are no conflict markers, and git merge-tree onto main is clean. The return 0 if found else 1 line that the old side carried is gone.
  • --self-test: "0 failure(s)", with both PRs' arms. --check --root . is unchanged: 9, none new.
  • --where ci_targets,submodule_pin exits 1 (one row is only a prefix) and prints the hint, "but 2 row(s) START WITH it … submodule_pin_check (cmake/tests-submodule-pin.cmake:26) …". --where ci_targets,tmp_path_check exits 0.
  • CI build succeeded (waited for it before posting).

@bong-water-water-bong
bong-water-water-bong merged commit 7035ac1 into main Nov 11, 2026
8 of 9 checks passed
@bong-water-water-bong
bong-water-water-bong deleted the prs2-where-prefix branch November 11, 2026 12:35
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