Skip to content

test(dependency-check): fix the assertion that left main red - #522

Merged
ProtocolWarden merged 1 commit into
mainfrom
fix/depcheck-version-assert
Aug 19, 2026
Merged

test(dependency-check): fix the assertion that left main red#522
ProtocolWarden merged 1 commit into
mainfrom
fix/depcheck-version-assert

Conversation

@ProtocolWarden

Copy link
Copy Markdown
Owner

Main is red. tests/test_dependency_check.py::test_board_status_reports_version_and_health fails on 6f0a55e4.

The test is mine, from #521, and the assertion was wrong — not the code:

normalize_version("13.0.5+gitea-1.22.0")   # -> "13.0.5+gitea-1.22.0", not "13.0.5"

That helper strips a leading tool name ("codex-cli 0.117.0""0.117.0"), not a build suffix. Keeping the suffix is the better behaviour anyway: +gitea-1.22.0 is how an operator tells which Gitea API generation their Forgejo speaks — exactly what a dependency report exists to surface.

How it reached main

Two things lined up:

  1. I put the gate run and the git push in one script, so the push didn't wait on the result. Gate first, read, then push — the ordering was the mistake, not the assertion.
  2. tests/test_dependency_check.py is not in any CI job. CI runs tests/unit, tests/test_pr_review_watcher.py, tests/integration/reviewer, and tests/integration/observer. So CI was green, the reviewer's verdict was SUCCESS, and feat(board): delete the Plane adapter — the migration is complete #521 merged with a red test in an un-gated suite — while I was fixing it on the branch, which by then belonged to a closed PR.

This is the un-gated-suite gap I flagged in #512 landing for real, rather than hypothetically. Roughly 1,830 tests sit outside the gate; this one was new and still invisible.

Verification

tests/test_dependency_check.py: 1 failed, 10 passed → 11 passed.

🤖 Generated with Claude Code

…returns

My own test from the previous commit was wrong, not the code: it expected
normalize_version("13.0.5+gitea-1.22.0") to yield "13.0.5". That helper strips
a leading tool name ("codex-cli 0.117.0" -> "0.117.0"), not a build suffix.

Keeping the suffix is the better behaviour anyway — "+gitea-1.22.0" is how an
operator tells which Gitea API generation their Forgejo speaks, which is
exactly what a dependency report exists to surface.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ProtocolWarden
ProtocolWarden merged commit e0f4418 into main Aug 19, 2026
25 checks passed
@ProtocolWarden
ProtocolWarden deleted the fix/depcheck-version-assert branch August 19, 2026 11:58
ProtocolWarden added a commit that referenced this pull request Aug 19, 2026
…524)

The Plane -> Forgejo migration ran off direct operator requests and was never
tracked in the backlog, so nothing in `.console/` tells a future session it
happened or why the codebase looks the way it does now.

Adds the Done entry (with the recon finding that reshaped it: Plane was never
live on this host, so the planned drain was vacuous) and the two items it left
open:

* **CI runs ~1,830 fewer tests than exist.** No longer hypothetical — #521
  merged a NEW failing test because `tests/test_dependency_check.py` is in no CI
  job, and main was red until #522. #513 was the same story a week earlier.
  Recorded with the 6 currently-failing tests that make switching the gate on a
  decision rather than a chore, and the sensible order: fix those 6, then add
  the suites in the PR that proves them green.

* **`audit` on Forgejo Actions** — the last line of the PR-adapter spec, blocked
  on an operator installing a runner. Everything upstream is done.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
ProtocolWarden added a commit that referenced this pull request Aug 19, 2026
… it (#525)

* ci: gate the ~1,830 tests that had no job, and fix the 6 that blocked it

Two dedicated jobs already exist for single files that rotted unnoticed
(tests/test_pr_review_watcher.py, tests/integration/reviewer) — each added
AFTER that suite had drifted. This generalises the fix instead of waiting for
the next one.

What the gap cost, concretely: #509 shipped a regression that broke
tests/maintenance/, found a week later by hand in #513. #521 merged a brand new
failing test in tests/test_dependency_check.py — CI green, reviewer verdict
SUCCESS, main red until #522. tests/test_proposer_entrypoint.py had been
failing since the board-seam migration weeks earlier and nothing noticed.

Switching the gate on required fixing 6 failures, and they were not what they
looked like:

FOUR WERE BAD MOCKS, NOT BUGS. They raised FileNotFoundError("message") — with
no errno. pathlib's predicates swallow only ignorable errnos (ENOENT, ENOTDIR,
EBADF, ELOOP), so an errno-less error escapes is_file()/is_dir(), which a real
vanished path never does. Verified identically on 3.11 and 3.12: deleting a
directory mid-scan makes glob() return []. The mocks were testing CPython's
exception plumbing, not the collectors' guards. They now raise the way the OS
does. My first attempt "fixed" production by guarding the walk against
deletion — defending against something that cannot happen — and is reverted.

ONE WAS A REAL GAP THE BAD MOCK WAS HIDING. EACCES and EIO are NOT ignorable,
so a log directory that becomes unreadable (rather than deleted) does raise
straight out of the walk and takes the collector with it. latest_matching_file
now guards the walk for OSError, with the distinction written down, because
"return None when nothing is discoverable" is its contract.

ONE WAS A REAL PRODUCTION BUG. custodian_sweep._emit answered zero-findings
before its dry-run branch could run, so that branch was unreachable and a dry
run reported "skipped-zero-findings" — the past tense, for work it had not
done. Two tests in the same file asserted opposite labels for the same call;
the module's own would-comment / would-create convention and the shadowed
branch both say `would-` was intended.

ONE WAS A STALE PATCH TARGET: proposer.main.PlaneClient stopped existing at the
board migration. Patched at the seam now.

Verified: tests/unit 8623 passed, the new job's exact command 1830 passed, both
0 failed. ruff clean, ty at the 13-diagnostic baseline, custodian doctor OK,
audit clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(observer): walk dependency reports with iterdir, not glob

The new test-rest job went red on its first CI run — which is the job doing its
job. Three failures, all in dependency_drift, none reproducible on 3.12:

CPython 3.11's glob() stats every matched path through exists(); 3.12's does
not. Two of the tests counted Path.stat calls to prove the collector does not
re-stat after discovery — a fair question, but the counter was also counting
the interpreter's probing. The third needed one unreadable run directory to be
skipped while the rest are still read.

My first attempt made it worse: wrapping the walk in list(glob(...)) meant a
single bad entry aborted discovery, turning "skip run1, use run2" into
not_available. glob() is a generator, so the first error closes it — per-entry
recovery inside it is not possible at all.

_latest_dependency_report now walks with iterdir(), which stats nothing:

  * one unreadable entry is skipped, not fatal (EACCES/EIO are NOT among the
    errnos pathlib swallows, unlike ENOENT/ENOTDIR/EBADF/ELOOP)
  * the counting assertions see only the collector's own stat calls, on either
    interpreter, so the test-side glob patching I added is removed as both
    unnecessary and ineffective — it still called the real glob()

Verified on both: 3.12 locally 1830 passed, 3.11 in a python:3.11-slim
container 1828 passed with the 3 fixed. The container also reports 2 failures
CI does not (test_resolve_repos_root_falls_back_to_checkout_layout,
test_loader_reads_latest_snapshot_with_bounded_history) — it mounts a flat
worktree with no sibling checkouts, which is what those two probe. CI is the
authority for CI.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant