Stop excluding tests by band, let tier C report instead of gate, and quote $PYTEST - #731
Stop excluding tests by band, let tier C report instead of gate, and quote $PYTEST#731lmoresi wants to merge 2 commits into
Conversation
1c6e6bd to
33c89de
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Critical test failures and unresolved Tier C, dependency, and option-handling issues remain.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Broadens CI coverage by re-enabling deferred test bands and reporting Tier C tests without gating.
Changes:
- Re-enables
test_06*,test_106*, andtest_107*. - Adds a non-gating Tier C reporting pass.
- Updates CI runtime rationale and removes redundant execution.
File summaries
| File | Summary |
|---|---|
scripts/test.sh |
Adjusts batching and Tier C handling. Review findings include two critical gating/dependency issues and three moderate issues involving collection scope, marker documentation, and PYTEST_ADDOPTS preservation. |
.github/workflows/build_uw3_and_test.yaml |
Updates CI runtime rationale and sharding documentation. |
Review details
Suppressed comments (1)
scripts/test.sh:269
- This command does not limit collection to Tier C: pytest collects/imports every test module under
tests/before applying-m tier_c. That reintroduces the monolithic run this script explicitly avoids and can trigger the import-time solves/side effects documented intests/conftest.py(including a 20+ minute collection), even when only a few Tier C tests execute. Run an explicit, collection-safe Tier C file set instead of passing the whole tree.
# answered with an explanation or a re-characterisation, never with a revert.
- Files reviewed: 2/2 changed files
- Comments generated: 4
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| # whole band was measured 2026-09-12 and passes; a band is not a unit of trust, | ||
| # and holding one back for a suspicion nobody recorded meant its level_1 files | ||
| # never ran at all. | ||
| $PYTEST tests/test_05*py tests/test_06*py tests/test_07*py || status=1 |
| # the deferred bands only 26 are level_3 or tier_c; 55 are level_1 AND tier_a — | ||
| # hardened, fast, and exactly what CI exists to run. test_1064 is the slow one | ||
| # and it is excluded by WHAT IT IS (tier_c) below, not by its number. | ||
| $PYTEST tests/test_106*py tests/test_107*py || status=1 |
| # unquoted at every call site, so bash would split "-m 'not tier_c'" into the | ||
| # words 'not and tier_c' and pytest would see a broken expression. pytest | ||
| # shlex-splits PYTEST_ADDOPTS, so the quoting survives. | ||
| export PYTEST_ADDOPTS="-m 'not tier_c'" |
| echo "Tier C characterisations (reported, not gating)" | ||
| echo "==========================================" | ||
| # Clear the exclusion above, or this pass would select nothing. | ||
| if env -u PYTEST_ADDOPTS pytest --config-file=tests/pytest.ini -m tier_c tests/; then |
…quote $PYTEST **The bands were never a cost decision.** `test_06*` was disabled as "potentially problematic" and stayed that way; `test_106*`/`test_107*` were held back pending "a triage/deselect decision" that nobody made. Measured 2026-09-12: those three bands hold 243 tests, of which only 26 are level_3 or tier_c. 55 are level_1 AND tier_a — hardened, fast, and exactly what CI exists to run. One slow test (test_1064) was quarantining its neighbours because they shared a number. They run now. The only failure among them was a test-side defect, fixed separately in #728. **This is affordable today.** The comment justifying the 120-minute cap measured the serial phase at ~55 min on 2026-08-15, before xdist. The five successful runs before 2026-09-12 spent 34, 35, 43, 44 and 48 minutes in "Run tests". Sharding across parallel jobs stays the durable fix if this tightens again — referenced in the workflow as "the CI-runtime issue" but never filed, now #730. **Tier C reports rather than gates.** A tier C failure demands an EXPLANATION, not a revert (Charter §8, TESTING-RELIABILITY-SYSTEM.md): these are characterisations that can fail because the code got BETTER. They are excluded from the batches that set $status and run in their own pass at the end, which is read but cannot fail the build. **$PYTEST is now an array.** It was a string expanded UNQUOTED at all 17 call sites, which made adding any argument containing a space unsafe: bash splits `-m 'not tier_c'` into the words `'not` and `tier_c'`, and pytest answers that by silently collecting NOTHING and exiting 0 — a green run that tested nothing: $ pytest -m "'not" "level_2'" tests/test_1070_free_surface_plume.py no tests collected in 0.00s # exit 0 The first version of this change dodged it through PYTEST_ADDOPTS, which pytest shlex-splits. Quoting the variable removes the hazard instead of routing around it, so the next argument someone adds is safe too. Verified by dry run that the marker arrives as a single argument, `ARG[not tier_c]`, in both the xdist and in-process branches. **Also drops a line that now runs twice.** `test_1072` was pulled forward out of test_107* by name because that band was not batched. The band runs as a whole now, so the named line is redundant; it is still covered, once. Verified by dry run with a stub pytest: every gating batch carries the exclusion as one argument, the previously-deferred bands appear, test_1072 appears once, and the tier C pass runs without the exclusion. Underworld development team with AI support from Claude Code
…re DEFERRED Rebased onto #723 so the two changes land consistently, which immediately surfaced an integration defect the guard itself caught: `globs_run_by` matched the literal `$PYTEST`, and this PR rewrites every call site to the array form `"${PYTEST[@]}"`. The guard therefore found NO globs and declared all 302 test files dark. It now matches both spellings. **DEFERRED is empty, and that is the point.** Every band that sat there — the test_06NN regression suite and test_106*/test_107* — is batched now. Nothing is excluded from CI by its number any more; a test that should not gate says so with `@pytest.mark.tier_c`, which is a property of the test rather than of where it falls in the numbering. **Dependencies, which the PR did not declare.** Copilot was right that this cannot land alone: - #728 fixes `test_1060_nitsche_freeslip`, whose bound is still `<1e-4` against an observed 1.0081e-4. Enabling `test_106*` without it makes this batch fail. - #729 puts the `tier_c` mark on the `test_1070` comparison and updates the tier definitions in `tests/pytest.ini` and the docs. Without it this PR enables `test_107*` while that comparison still gates, and the reporting pass contradicts a marker contract that still reads "development only, not for automation". Merge order is #728, #729, #723, then this. The PYTEST_ADDOPTS point in the same review was already addressed: the array landed in an amended commit the review had not seen. It also removes the objection behind it — an inherited PYTEST_ADDOPTS from the caller is no longer discarded, because the script no longer sets it. Verified: dry run shows the marker arriving as a single `ARG[not tier_c]`, the tier C pass running without it, and the guard passing with 302 reachable and 0 deferred. Underworld development team with AI support from Claude Code
33c89de to
5e613ce
Compare
|
Review points addressed. Dependencies, which this PR did not declare — correct, and now stated. It
Merge order: #728 → #729 → #723 → this. Retargeted onto #723 to make the PYTEST_ADDOPTS — already fixed in an amended commit the review had not seen. One thing the rebase found. Landing on #723 surfaced an integration defect
Verified: the marker arrives as a single |
Item 4 of the 2026-09 audit. Depends on nothing, but reads best after #729,
which defines what tier C means.
The bands were never a cost decision
test_06*was disabled as "potentially problematic" and stayed that way.test_106*/test_107*were held back pending "a triage/deselect decision" thatnobody made. Measured 2026-09-12, those three bands hold 243 tests, of which
only 26 are level_3 or tier_c. 55 are level_1 and tier_a — hardened, fast,
and exactly what CI exists to run.
One slow test (
test_1064) was quarantining its neighbours because they shareda number. They run now; the only failure among them was a test-side defect,
fixed separately in #728.
It is affordable today
The comment justifying the 120-minute cap measured the serial phase at ~55 min
on 2026-08-15, before xdist. The five successful runs before 2026-09-12 spent
34, 35, 43, 44 and 48 minutes in "Run tests". The deferred bands add ~22 min
single-process locally, considerably less under
-n 4.Sharding across parallel jobs stays the durable fix if this tightens again. It
was referenced in the workflow as "the CI-runtime issue" but never actually
filed — now #730, with these numbers.
Tier C reports rather than gates
A tier C failure demands an explanation, not a revert: these are
characterisations that can fail because the code got better. They are
excluded from the batches that set
$statusand run in their own pass at theend, which is read but cannot fail the build.
One trap worth flagging in review. The exclusion goes through
PYTEST_ADDOPTS, not appended to$PYTEST.$PYTESTis used unquoted atevery call site, so bash splits
-m 'not tier_c'into the words'notandtier_c'— and pytest then silently collects nothing and exits 0, reportinga green run that tested nothing. Verified:
pytest shlex-splits
PYTEST_ADDOPTS, so the quoting survives there. Thereporting pass clears it with
env -u, or it would select nothing itself.Also drops a line that now runs twice
test_1072was pulled forward out oftest_107*by name because that band wasnot batched. The band runs as a whole now, so the named line is redundant — it
is still covered, once.
Verified
Dry run with a stub
pytest: every gating batch carries the exclusion, all thepreviously-deferred bands appear,
test_1072appears exactly once, and the tierC pass runs with
PYTEST_ADDOPTSunset.Underworld development team with AI support from Claude Code