Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 28 additions & 14 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -279,28 +279,46 @@ add_test(NAME serve_context_limit_classify COMMAND bash ${CMAKE_SOURCE_DIR}/test
# creates. #1583 added one name for a target defined inside if(ONEBIT_NPU), which CI does not configure -- and ninja
# rejects the whole command line before building anything, so `onebit` stopped being compiled for every PR. Reads the
# two files, no build and no submodules; --self-test drives it.
add_test(NAME ci_targets COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/ci/ci_targets_check.py --check --root ${CMAKE_SOURCE_DIR})
add_test(NAME ci_targets_self COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/ci/ci_targets_check.py --self-test)
# engine#1864: `find_package(Python3)` used to be at :761, long after the first `${Python3_EXECUTABLE}` users above, so those
# registrations carried an EMPTY interpreter and ctest executed each script directly -- which passes only while the file keeps
# its exec bit (a mode-only rewrite of tools/ci/hrx_build_scope.py turned that row into BAD_COMMAND). Find the interpreter
# first and register every Python test through one place: it runs the script THROUGH the interpreter, and on a machine
# without one the test is dropped with a status line instead of a .py being handed to the kernel as a program.
find_package(Python3 COMPONENTS Interpreter)
function(add_python_test name)
if(Python3_Interpreter_FOUND)
add_test(NAME ${name} COMMAND ${Python3_EXECUTABLE} ${ARGN})
else()
message(STATUS "ctest: not registering ${name} (no Python3 interpreter)")
endif()
endfunction()
# engine#1864: the ordering rule itself, checked on the file (no configure, no build): every ${Python3_EXECUTABLE} use has
# to follow the find_package above. The nine that did not ran through their exec bit, and a mode-only rewrite of one
# script turned the row into BAD_COMMAND.
add_python_test(python_test_order_check ${CMAKE_SOURCE_DIR}/tests/python_test_order_check.py --check --root ${CMAKE_SOURCE_DIR})
add_python_test(python_test_order_check_self ${CMAKE_SOURCE_DIR}/tests/python_test_order_check.py --self-test)
add_python_test(ci_targets ${CMAKE_SOURCE_DIR}/tools/ci/ci_targets_check.py --check --root ${CMAKE_SOURCE_DIR})
add_python_test(ci_targets_self ${CMAKE_SOURCE_DIR}/tools/ci/ci_targets_check.py --self-test)
# engine#1820: the other half of ci_targets_check -- a standalone shell test that nothing references cannot fail.
# `need` is every tests/*.sh, `have` is every file that mentions its basename somewhere that can run it, and
# tools/ci/unreferenced_tests.txt carries the deliberate exclusions WITH their reasons, so the list can shrink.
add_test(NAME tests_referenced COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/ci/tests_referenced_check.py --check --root ${CMAKE_SOURCE_DIR})
add_test(NAME tests_referenced_self COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/ci/tests_referenced_check.py --self-test)
add_python_test(tests_referenced ${CMAKE_SOURCE_DIR}/tools/ci/tests_referenced_check.py --check --root ${CMAKE_SOURCE_DIR})
add_python_test(tests_referenced_self ${CMAKE_SOURCE_DIR}/tools/ci/tests_referenced_check.py --self-test)
# engine#1777: the release row's own arm, which merged unregistered -- this sweep is what found it (engine#1820).
add_test(NAME release_check_hrx_init_reason COMMAND bash ${CMAKE_SOURCE_DIR}/tests/release_check_hrx_init_reason_test.sh ${CMAKE_SOURCE_DIR}/os/mini/release-check.sh)
# engine#1615: every process holding the GPU/NPU device must belong to a live gpu-hold/npu-hold ticket. Three
# orphans of that shape landed in two days (51 GiB of GTT for 14 h; an NPU server 70 min past a 6-min ticket;
# then two lanes each starting an HRX server outside the token within one half hour). The ancestry test is the
# check; the two permanent services are exempt by name. --self-test drives the decision, no device needed.
add_test(NAME device_holders COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/device_holders.py --self-test)
add_python_test(device_holders ${CMAKE_SOURCE_DIR}/tools/device_holders.py --self-test)
# engine #1668: the bench preflight must pin the load mode, because `-lm none` is +17.5 % prefill at -1.6 % decode for +604 MiB of
# GTT. The script existed with a test that nothing ran; a test nobody runs is a comment, so the loader/flag assertions are registered
# here (the test fakes the box, so it needs no device and no ticket).
add_test(NAME bench_preflight COMMAND bash ${CMAKE_SOURCE_DIR}/tools/tests/test-bench-preflight.sh)
# engine#1702: builds a per-layer MoE expert placement table from a moe_trace, and refuses a prefill-only trace because
# placement is a decode lever (5.4-6.9 % on batched prefill against dedup's 90-94 %). --self-test drives it on synthetic
# traces with a known answer; no model, no device.
add_test(NAME moe_placement COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/moe_placement.py --self-test)
add_python_test(moe_placement ${CMAKE_SOURCE_DIR}/tools/moe_placement.py --self-test)
# engine #1279: the version a package is built with (scripts/pack-version.sh) -- a release tag as
# it stands, a candidate mapped into the ISO week of its own date with a suffix that sorts below that
# release, and the ordering a candidate needs: previous release < candidate < its release. The
Expand Down Expand Up @@ -701,15 +719,12 @@ add_test(NAME route_log COMMAND route_log_test)
# case is an artefact someone would actually push, and the conservative direction -- "full" -- is the
# one every uncertain case must land on, because the build being skipped is the one that catches a
# broken HRX pin. Stdlib only: no git needed for the decision itself.
add_test(NAME hrx_build_scope
COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/ci/hrx_build_scope.py --self-test)
add_test(NAME copyright_check_untracked
COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tests/copyright_check_untracked_test.py)
add_python_test(hrx_build_scope ${CMAKE_SOURCE_DIR}/tools/ci/hrx_build_scope.py --self-test)
add_python_test(copyright_check_untracked ${CMAKE_SOURCE_DIR}/tests/copyright_check_untracked_test.py)
# engine#1517: the prefill flash-attention ratio is measured in adjacent pairs and only quoted when the pairs agree, so a
# loaded box yields VOID instead of a number. The self-test is the estimator's own gate and needs no GPU: it accepts
# agreement, refuses disagreement, and proves a dropped run cannot shift an arm.
add_test(NAME fa_ratio_estimator
COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/fa_ratio.py --self-test)
add_python_test(fa_ratio_estimator ${CMAKE_SOURCE_DIR}/tools/fa_ratio.py --self-test)
add_dependencies(onebit route_log_test)
# CI builds `--target onebit` plus a fixed list in .github/workflows/ci.yml; building this check with onebit
# keeps the laya_models ctest from reporting "Not Run" without a workflow change.
Expand Down Expand Up @@ -757,8 +772,7 @@ if(ONEBIT_LAYA_ROUTE_MODEL)
endif()

# The registry against the reviewed not-an-alias list (docs/arch-gaps.md) and the committed pins:
# no checkouts or network.
find_package(Python3 COMPONENTS Interpreter)
# no checkouts or network. (The interpreter is found once, at :287: engine#1864.)
if(Python3_Interpreter_FOUND)
add_test(NAME registry_gaps COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/registry_build.py --check-gaps)
# pin the guard's firing behavior: the committed registry always passes --check-gaps, so
Expand Down
123 changes: 123 additions & 0 deletions tests/python_test_order_check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/usr/bin/env python3
# Copyright 2026 bong-water-water-bong
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Copyright 2026 The 1bit-MONSTER Authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""engine#1864: a Python test must be registered AFTER find_package(Python3).

`add_test(... COMMAND ${Python3_EXECUTABLE} script.py ...)` before the find_package expands the interpreter to the empty
string, so `CTestTestfile.cmake` holds the script as the program. ctest then runs it through its exec bit -- and a
mode-only rewrite (tools/ci/hrx_build_scope.py, 100755 -> 100644) turns the row into BAD_COMMAND with nothing visibly
wrong in the source. Nine registrations were in that state.

The rule is a file-order rule, so it is checked here on the file, with no configure and no build: every
`${Python3_EXECUTABLE}` use in CMakeLists.txt must come after the first `find_package(Python3`. `add_python_test(...)`
satisfies it by construction, which is the other half of the fix.
"""

import argparse
import pathlib
import re
import sys

USE = re.compile(r"\$\{Python3_EXECUTABLE\}")
FIND = re.compile(r"^\s*find_package\(\s*Python3\b", re.MULTILINE)


def _strip_comments(text: str) -> str:
"""CMake comments out, line numbers preserved: the fix's own comment names the variable it forbids."""
return "\n".join(re.sub(r"#.*$", "", line) for line in text.split("\n"))


def offenders(text: str):
"""Line numbers of Python3_EXECUTABLE uses that precede the first find_package(Python3)."""
text = _strip_comments(text)
finds = list(FIND.finditer(text))
if not finds:
# No find_package at all: every use is unbound. Report them all rather than pass silently.
first = None
else:
first = finds[0].start()
out = []
for m in USE.finditer(text):
if first is None or m.start() < first:
out.append(text.count("\n", 0, m.start()) + 1)
return out


def check(root: pathlib.Path) -> int:
bad = 0
for cmake in sorted(root.rglob("CMakeLists.txt")):
if any(part in {"build", ".git", "third_party"} for part in cmake.parts):
continue
text = cmake.read_text(encoding="utf-8", errors="replace")
lines = offenders(text)
for ln in lines:
print(f"FAIL {cmake.relative_to(root)}:{ln}: ${{Python3_EXECUTABLE}} used before find_package(Python3)")
bad += 1
if bad:
print(f"FAIL {bad} registration(s) run a script through its exec bit instead of through the interpreter")
return 1
print("ok: every ${Python3_EXECUTABLE} use follows find_package(Python3)")
return 0


def self_test() -> int:
after = "find_package(Python3 COMPONENTS Interpreter)\nadd_test(NAME a COMMAND ${Python3_EXECUTABLE} s.py)\n"
before = "add_test(NAME a COMMAND ${Python3_EXECUTABLE} s.py)\nfind_package(Python3 COMPONENTS Interpreter)\n"
none = "add_test(NAME a COMMAND ${Python3_EXECUTABLE} s.py)\n"
commented = "# ${Python3_EXECUTABLE} in a comment is prose, not a use\nadd_test(NAME a COMMAND ${Python3_EXECUTABLE} s.py)\n"
helper = "find_package(Python3 COMPONENTS Interpreter)\nfunction(add_python_test n)\n add_test(NAME ${n} COMMAND ${Python3_EXECUTABLE} ${ARGN})\nendfunction()\nadd_python_test(a s.py)\n"
cases = [
(after, [], "a use after the find_package is fine"),
(before, [1], "a use before it is an offender"),
(none, [1], "with no find_package every use is unbound"),
(helper, [], "the helper's own use comes after the find_package"),
(commented, [2], "a comment mentioning the variable is not a use"),
]
bad = 0
for text, want, why in cases:
got = offenders(text)
if got != want:
print(f"FAIL self-test: {why}: want {want}, got {got}")
bad += 1
print("self-test ok" if not bad else f"self-test FAILED ({bad})")
return 1 if bad else 0


def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--self-test", action="store_true")
ap.add_argument("--check", action="store_true")
ap.add_argument("--root", default=".")
a = ap.parse_args()
if a.self_test:
return self_test()
if a.check:
return check(pathlib.Path(a.root).resolve())
ap.print_help()
return 2


if __name__ == "__main__":
sys.exit(main())
Loading