Commit Graph

16 Commits

Author SHA1 Message Date
Teknium
e1ec584b57 feat(ci): cap every AGENTS.md chain below the context budget it is truncated at
scripts/ci/check_agents_md_size.py (in scripts/check and lint.yml): root <= 12k, every
AGENTS.md plus its ancestors <= 30k (the joined root->cwd block on a 128k window, minus
the per-file labels), every area file <= _MAX_HINT_CHARS read from the source so the two
cannot drift. On origin/main it reports the root and all 11 root-to-area chains over.
2026-10-04 23:05:42 -07:00
Teknium
9a98bd0165 fix(code-health): case-collision test stages blobs, not files
test_ci_only_guards_run_in_scripts_check wrote pkg/Notes.md and pkg/NOTES.md to disk,
which a case-insensitive filesystem (Windows, macOS) holds as one file, so the fixture
could not build its own premise. Each path is now staged from a blob with
`git hash-object -w` + `git update-index --cacheinfo`, which is what --staged judges.
2026-10-04 22:35:16 -07:00
Teknium
4249e5226d fix(code-health): staged-health test ignores elapsed time
test_staged_health_ignores_unstaged_policy_and_engine compared two reports byte for
byte, elapsed "(0.1s)" included, so it flaked whenever the two runs straddled a tenth
of a second (seen on native Windows). The comparison now drops the elapsed time.
2026-10-04 22:35:16 -07:00
Teknium
51483660d3 fix(code-health): git hooks work with MSYS path conversion off
The hooks' judge() built its private index and tree under `mktemp -d`, a POSIX /c/...
path in Git Bash, and passed it to native git.exe and python.exe through GIT_INDEX_FILE,
--prefix and the checker path. Hermes' Windows terminal exports MSYS_NO_PATHCONV=1 and
MSYS2_ARG_CONV_EXCL=*, so those paths arrived unconverted and the hook died
("Unable to create '/c/.../index.lock'") before any check ran. judge() now hands native
tools the `cygpath -m` spelling when cygpath exists; elsewhere nothing changes.
2026-10-04 22:35:16 -07:00
Teknium
baa07694a8 feat(code-health): heuristic rules warn until a frozen replay shows precision
HX001, HX003, HX010, HX012 and PS-P05/P06 now print as advisory findings instead of
blocking. Reviewers' samples put them between ~12% and ~60% precision, and the plan
ships weak rules as warnings first. Promote one by flipping it to blocking with replay
evidence in the PR. The ENFORCEMENT comment now says where the switch is read from.
Tests that used PS-P05 as a stand-in blocking violation now use a blind except.
2026-10-04 21:29:39 -07:00
Teknium
7ceedd731a style(code-health): wrap the long lines added by the lane-C fixes
No behaviour change: line wrapping in the hook text, parse_switch docstring,
commit_or_none and the new tests; the test helpers lose an unused env parameter.
2026-10-04 21:29:39 -07:00
Teknium
f91534efb9 fix(code-health): each hooked candidate is judged by its own scripts/check
JoaoMarcos44 (inline scripts/check:40): the hooks began with
`[ -f "$repo/scripts/check" ] || exit 0`, before reading the pushed SHAs, so the
checked-out branch decided whether another revision was checked. Pushing an
invalid checker-containing branch while an older branch was checked out succeeded
without judging it.

Eligibility is now decided from the candidate tree: pre-push runs
`git cat-file -e <local_sha>:scripts/check` per pushed ref (a candidate that
predates the checker is skipped, deletions are still skipped), pre-commit does the
same for the index tree. An eligible candidate is checked out alone into a temp
dir (private index + checkout-index; the worktree, index and stash are untouched)
and judged by its own scripts/check with GIT_DIR pointing at the repo - with the
previous commit's snapshot-bound health job, implementation, job table, config and
policy all come from the judged artifact, whatever is checked out. pre-commit
exports an absolute GIT_INDEX_FILE because git may hand hooks a relative one.
2026-10-04 21:29:39 -07:00
Teknium
f472161acb fix(code-health): hooks prefer the repo virtualenv; scripts/check refuses Python < 3.11
unsupportedpastels M5: both hooks ran whatever python3 came first on PATH, but
scripts/check imports ruff_runner, which imports tomllib (3.11+, the project
minimum). With Ubuntu 22.04's python3 3.10 every hooked commit or push died with
"ModuleNotFoundError: No module named 'tomllib'".

The hooks now use the repo's virtualenv interpreter when there is one (.venv/ or
venv/, bin/python or Scripts/python.exe; this worktree first, then the main
checkout) and fall back to python3, then python. scripts/check checks
sys.version_info before importing the engine and exits 2 with a one-line message
naming the virtualenv instead of a traceback. Verified with a real CPython 3.10.21:
exit 2 and the message, where 96bb97a crashed in ruff_runner.
2026-10-04 21:29:39 -07:00
Teknium
f8501a9328 fix(code-health): --staged/--commit run the ratchet from the judged snapshot
F20 (andrexibiza): in --staged/--commit mode the guard jobs ran inside the
snapshot root with the snapshot's git env, but the health job ran in the real
worktree. Its source was pinned to the index tree, yet its engine and policy were
not: Measurer reads scripts/ci/profile_scope_patterns.json from the repo it runs
in, so with an identical `git write-tree`, editing only the unstaged P05
path_regex turned PS-P05 / exit 1 into "ok" / exit 0 and back.

The health job now runs like every other job: cwd = the snapshot root with the
snapshot env, so `python -m scripts.code_health` imports the snapshot's own engine
and reads the snapshot's policy files and ruff pin. The ruff job resolves its pin
from the same root. Unstaged edits to the policy file or the engine no longer move
the verdict, and they stay untouched in the worktree; plain runs are unchanged
(root is the worktree).
2026-10-04 21:29:39 -07:00
Teknium
f98585d5cc fix(code-health): scripts/check also runs CI's case-collision, lazy-deps and profile-archive guards
unsupportedpastels m4: scripts/check says it runs the lint checks CI runs, but CI
also runs scripts/check-case-collisions.py, scripts/ci/check_lazy_deps_imports.py
and scripts/ci/check_profile_archive_boundary.py in workflows of their own
(case-collision-check.yml, lazy-deps-guard.yml, profile-artifact-check.yml). A
case-colliding pair passed scripts/check and failed CI.

All three are deterministic and local (git ls-files / an os.walk of the checkout;
measured here: 0.2 s, ~7 s, 0.1 s on the full tree), so they run as ordinary guard
jobs - in the snapshot root for --staged/--commit like the other guards - and are
selectable with --only case-collisions / lazy-deps / profile-archives.
2026-10-04 21:29:39 -07:00
Teknium
a6274687fd fix(code-health): parse ENFORCEMENT with ast and read it from the main tip locally
unsupportedpastels m3: (a) the switch was found by a regex that accepted only the
exact `ENFORCEMENT = "..."` spelling, so `ENFORCEMENT: str = "off"` silently stayed
blocking; (b) local runs and both hooks read it from the merge-base with
origin/main, so a flip on main reached a branch only after a rebase, contrary to
"CI and local hooks alike".

(a) parse_switch() reads the module-level plain or annotated assignment with ast
(last one wins, as at runtime); missing, unparseable or unknown values are
blocking. (b) Without --base, the base is still the merge-base of the head (a
--head commit, else HEAD) but the switch comes from origin/main when it resolves,
falling back to the base. An explicit --base pins both (CI passes HEAD^1, the
target tip). scripts/check --commit now hands the commit itself to the ratchet so
it derives that commit's merge-base. The head under test never supplies the switch.
(c) A test pins enforcement() on this tree to config.ENFORCEMENT.
2026-10-04 21:29:39 -07:00
Teknium
b76c3facdf fix(code-health): profile regex rules match executable code, not prose
F21 (andrexibiza): PS-P05/PS-P06 ran their regexes over raw source lines, so a
comment such as `# Avoid env = os.environ.copy(); use the scoped builder.`, the same
sentence in a docstring, or a comment warning against `os.getenv("DISCORD_TOKEN")`
produced a blocking hit although nothing builds an env or reads a credential.

Before the regexes run, comment tokens (tokenize) and string statements (ast:
docstrings and bare string examples) are blanked in place, preserving every line
number and line break. Ordinary string literals inside code are kept, so the
env-key argument of `os.getenv("DISCORD_TOKEN")` still matches; the real
`env = os.environ.copy()` / `dict(os.environ)` / platform getenv stay flagged. If
tokenizing fails, the raw lines are used (more hits, never fewer).
2026-10-04 21:29:39 -07:00
Teknium
7ef5f0e1f9 fix(code-health): an allow comment may separate its rules with spaces
banditburai (inline report.py:36): `# health: allow BLE001 S110 -- boundary` waived
neither rule and reported "allow comment ignored: it needs a reason", although the
reason is there. _ALLOW accepts spaces in the rule list, but apply_allows split it
on commas only, so "BLE001 S110" was looked up as one rule name.

The rule list is now split on commas and whitespace, so `BLE001 S110`,
`BLE001, S110` and `BLE001,S110` all waive both rules. A reason is still required.
2026-10-04 21:29:39 -07:00
Teknium
f970c226f3 fix(code-health): a failing measurement tool exits 2, not with a traceback
unsupportedpastels m5: when the pinned TypeScript is not cached, ts_measure runs
`npm install`; a failed or timed-out install raised CalledProcessError /
TimeoutExpired, which cli.main did not catch (it caught RuntimeError only). The run
then died with a traceback and exit 1, which reads like a finding.

cli.main now reports those as a broken run: one `code health: measurement tooling
failed: ...` line on stderr and exit 2, like every other environment error.
2026-10-04 21:29:39 -07:00
Teknium
15274dfb41 fix(code-health): --json prints JSON on every return path
JoaoMarcos44 (inline cli.py:64): the ENFORCEMENT="off" and "no measured files
changed" branches returned before the --json formatter, so
`python -m scripts.code_health --base HEAD --head HEAD --json` succeeded with prose
on stdout and json.loads() raised.

Both early successes now print the empty findings list `[]` on stdout and move
the human explanation to stderr; findings and zero-finding measured diffs were
already JSON. Exit codes are unchanged on all four paths.
2026-10-04 21:29:39 -07:00
Teknium
ac40898e2d fix(code-health): reject unknown or empty --only selectors
F22 (andrexibiza): `scripts/check --only heath`, `--only ,` and `--only heath,rof`
filtered the job table down to nothing and reported "0 checks, ok" / exit 0, and
`--only health,rof` silently dropped the unknown name. A typo in a developer or
automation command could claim success without running the requested check.

The whole selector set is now validated before any job is built or dispatched:
an empty selection or any unknown name is a usage error (exit 2) that lists the
valid names. A valid selector still runs its check and keeps its status.
2026-10-04 21:29:39 -07:00