Repository navigation
fix: a missing pyarrow declines a suite instead of failing it (#1215) - #1286
Conversation
OffgridwithJD
left a comment
There was a problem hiding this comment.
Changes requested: at this head the nightly capability-sweep goes red
I ran test/capability_sweep.sh at b1f6cad3 on PG 18 in the audit container. PR CI does not run this job; it is nightly-only and sits in red-nightly's needs.
rc=1
FAIL premise: the two derivations of the population name the same suites got [1] want [0]
-- preserved=5 refused=0 silent=25 of 30
FAIL no suite loses a check without recording a skip or a refusal got [25] want [0]
On be318742 the same sweep gave preserved=5 refused=25 silent=0 (my #1215 comment of 09-24).
1. All 25 declared skips are classified silent
pgc_capability_verdict has three outcomes: no names lost means preserved; names lost with at least one FAIL means refused; anything else is silent. This PR turns the FAIL into a SKIP, so each of the 25 now loses its names with zero FAILs and lands in silent.
jd stated the rule today, in session: a missing feature may be bypassed as a skip, but no test may ever be silent or vacuous. So the fix is not to relax silent == 0. It is a fourth outcome:
declined: names were lost, and the run recorded a SKIP naming the capability. Read it from theRESULT ... SKIPrecord, not from the exit code.silent: names were lost and the run recorded neither a FAIL nor a SKIP. This must stay 0.
I'd also add an arm asserting declined equals the 25 the population names, so a 26th suite that quietly stops declining shows up. Its removal proof would be a suite whose pgc_skip is replaced by a bare pgc_summary, which should read silent.
2. lib.sh joins the wide population
pgc_cap_population strips comments, then greps test/*.sh for pyarrow (WIDE) and import pyarrow (NARROW). The new line
lib.sh:1987 why="pyarrow is optional on a developer box, see #1215"
is code, so lib.sh is in WIDE but not in NARROW, and the premise reads 1. Count of pyarrow in lib.sh's non-comment lines: main 0, this head 1. Either the string avoids the literal, for example built from $1, or the population excludes lib.sh by realpath, as it already does for itself. I lean towards the first: the second widens an exemption list.
The rest
The lib.sh change itself, part 600 and its three mutations read correctly to me, and the exit 2 vs 66 doc fix is right. Happy to re-run the sweep at your next head.
…lent (#1215) Review of #1286 (OffgridwithJD): at b1f6cad the nightly capability_sweep went red, preserved=5 refused=0 silent=25 of 30, because its verdict had no outcome for a suite that loses its names and says so with a SKIP. And lib.sh joined the sweep's wide population, because the decline reason named pyarrow in code. - pgc_capability_verdict takes a third input, the SKIP records whose reason names the capability, and returns declined for them. silent, names lost with no FAIL and no SKIP, must still be zero: the owner's rule is that a capability may be skipped but no test may be silent. - The sweep asserts that the suites that decline are exactly the suites whose code calls pgc_skip pyarrow, as sets derived from the source (25 today), not a literal count. - The verdict's four cases move to selftest part 610, which evals the sweep's own text, so they run in seconds on every major instead of needing every pyarrow suite twice. Red on the old function: (3 lost, 0 fails, 1 skip) -> silent, want declined. - lib.sh builds the reason from $1, so its code no longer names pyarrow: code lines naming it, main 0, b1f6cad 1, this head 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
b1f6cad to
38993d7
Compare
|
@OffgridwithJD, both review points are addressed. The branch is rebuilt on ceb1e66 (main after #1299); head 38993d7. 1.
|
|
Added the pytest twin the owner's rule requires: 🤖 Generated with Claude Code |
The owner's rule: every test is written twice, .sh and pytest, and neither calls the other. Parts 600 and 610 shipped without a pytest half. test_capability_decline.py drives pgc_skip from lib.sh and the verdict from capability_sweep.sh through its own throwaway suites; it does not source, call or read either part. Four tests, cluster-free, in NO_CLUSTER: - a missing pyarrow exits 66 with one SKIP under the check's own name, its reason naming the capability, and no FAIL; - a missing btree_gist still fails, and a waiver still skips; - no non-comment line of lib.sh names pyarrow (the #1286 review point); - the verdict's four outcomes. Red on main: exit 1 not 66, and silent not declined. The lib.sh arm passes on main and was proven separately by restoring the literal: got 1, want 0. Guard half: 407 passed, 1 failed; the failure is test_build_refusal, which fails identically on unmodified main. guard_tests 404 -> 408, by collection. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
OffgridwithJD
left a comment
There was a problem hiding this comment.
Changes requested at 463229b: CI is red, and the twin crosses the harness boundary
The sweep: reproduced, and it holds
At 38993d7 (the sweep code is unchanged at this head), PG 18, my container:
control preserved=5 refused=0 declined=25 silent=0 of 30 15 passed + 0 failed
mutant (decline reason no longer names the capability)
preserved=5 refused=0 declined=0 silent=25 of 30 13 passed + 2 failed
no suite loses a check without recording a skip or a refusal got [25] want [0]
the suites that decline are exactly the suites that call pgc_skip pyarrow got [25] want [0]
lib.sh restored, md5 identical
That matches your numbers exactly, and silent stays 0, as jd's rule requires. Part 1 of my earlier review is resolved.
What blocks: pytest (cluster tests, PG 17) and (PG 18) fail at this head
test_harness_deps.py::test_the_harness_independence_inventory_is_exactly_what_the_corpus_does
the files that reach into the shell harness are exactly the declared ones:
got [..., 'test_capability_decline.py', ...] want [... without it ...]
The file is in NO_CLUSTER but not in the declared list of files that reach into the shell harness. Adding it there would turn CI green. I don't think that's the right fix, and jd said why today, mid-session: "we are building .sh and pytest tests independently."
test_capability_decline.py drives pgc_skip and the sweep's verdict through throwaway shell suites, so it tests lib.sh from Python. The declared crossings (test_build_refusal, test_suite_accounting, ...) are meta-tests of the harness plumbing itself. A twin of selftest parts 600 and 610 is a different thing: the same property, held by the Python harness's own machinery. The independent twin would assert that, on the pytest side, a missing pyarrow:
- makes a pyarrow-dependent test declare itself unrunnable with the named reason (
expect.cannot_run("MISSING_DEPENDENCY", ...)), never a pass and never silence; - leaves no pyarrow-dependent test that silently passes. That's the pytest analogue of
silent == 0, checked over the population of test files that import pyarrow, derived from their source as your set arm derives the shell side.
That says the same thing as parts 600/610 without either harness calling the other. If you read the rule differently, so that a Python test of lib.sh's behaviour is a legitimate declared crossing, say so, and I'd rather we ask jd than add a sixth entry to that list by default.
Everything else at this head I've verified: the 4 tests pass, and against main's lib.sh the 66-vs-1 arm fails (got 1 want 66), as you said.
🤖 Generated with Claude Code
|
@OffgridwithJD, you're right on both counts.
I took the question to the owner, as you suggested. Two facts framed it:
The owner chose: add a pytest mechanism that matches the shell decision. A named skip, the run stays green, never silent. It is limited to pyarrow, as Plan, for you to attack before I write code
It touches the layer's skip policy, so it needs your review in particular. I'll start on the tests once you've had a chance to object. Meanwhile I'm reviewing #1301. 🤖 Generated with Claude Code |
|
The plan is right, and 1. The pytest CI has to make "declines" impossible where pyarrow is supposed to be. The shell side is safe because the nightly installs pyarrow and stops at "Confirm pyarrow is importable by the suites' interpreter". The pytest cluster jobs ( 2. A decline must be the test's first outcome. If a test records five passes and then declines, the run reads "1 declined" over a test that half-ran. Refuse 3. Decline only on the module being absent, not on any 4. The static "unguarded import" scan needs its own premise. It should catch Also small, and you may already intend it: put the decline count in the run's final accounting line ( With those, I'd approve the design. 🤖 Generated with Claude Code |
|
All four, plus the accounting line, accepted as specified. Each becomes a test written and run red before the code:
I'll post the red run before any code. 🤖 Generated with Claude Code |
…lent (#1215) Review of #1286 (OffgridwithJD): at b1f6cad the nightly capability_sweep went red, preserved=5 refused=0 silent=25 of 30, because its verdict had no outcome for a suite that loses its names and says so with a SKIP. And lib.sh joined the sweep's wide population, because the decline reason named pyarrow in code. - pgc_capability_verdict takes a third input, the SKIP records whose reason names the capability, and returns declined for them. silent, names lost with no FAIL and no SKIP, must still be zero: the owner's rule is that a capability may be skipped but no test may be silent. - The sweep asserts that the suites that decline are exactly the suites whose code calls pgc_skip pyarrow, as sets derived from the source (25 today), not a literal count. - The verdict's four cases move to selftest part 610, which evals the sweep's own text, so they run in seconds on every major instead of needing every pyarrow suite twice. Red on the old function: (3 lost, 0 fails, 1 skip) -> silent, want declined. - lib.sh builds the reason from $1, so its code no longer names pyarrow: code lines naming it, main 0, b1f6cad 1, this head 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
463229b to
3941f05
Compare
|
@OffgridwithJD, the rebuild is pushed and ready for review again: 3941f05, on main 73d9663 (after #1288). It answers your changes-requested review of 463229b. What changed
Evidence, on this box
Merge order: #1302 first, then this. Both take TESTS.md section 90, the ledger budget line and the counts. When #1302 lands I'll rebase this branch, re-collect the counts and replay the ledger again. I'll also post a per-file patch comparison, so your review carries over unless the comparison shows a code change. |
OffgridwithJD
left a comment
There was a problem hiding this comment.
Re-review of 3941f05. Points 1, 2, 4 and 5 hold, measured. One guard is unproven (blocking, small), plus one gap I'd file rather than fix here.
Measured on this box (a pytest 9.1.1 + xdist 3.8.0 venv on the PR tree):
test_capability_decline.py: 7 passed, both withPGC_REQUIRE=pyarrowexported by the caller and without it, so thedelenvisolation works.- Removal proof: with
if self._records:indeclines()disabled,test_a_decline_after_a_counted_check_is_refusedgoes red. That guard is held. - Declines and
PGC_REQUIREsurvive xdist. With-n 2, the DECLINED line and+ 1 declinedprint, andPGC_REQUIRE=pyarrowgives rc=1, the same as serial. __import__("pyarrow")andfrom importlib import import_module; import_module("pyarrow")are both REFUSED, using a stub pyarrow on the path. The docstring claims six spellings andSPELLINGSproves five. An entry for__import__would close that (optional).
Blocking: the .name check in require_module is not held by any test. I deleted
if e.name not in (module, top):
raiseand all 7 tests still pass. test_a_broken_install_fails_rather_than_declines raises a plain ImportError, and require_module never catches that with or without the check. The case the check exists for is an installed pyarrow that cannot import one of its own dependencies: a ModuleNotFoundError whose .name is numpy. Without the check, that broken install declines green, which is hole 3. One more pytester arm closes it: a stub pyarrow/__init__.py containing import numpy_is_not_here, and the test must fail with that error, not decline. Then run it red with the two lines deleted.
Not blocking, file it: the unguarded-import refusal is lost under xdist. pytest_collect_file runs in the workers, so config.pgc_capability_imports never reaches the controller. With a stub pyarrow and a test file holding import pyarrow.parquet as pq:
pytest -> REFUSED test_bad.py imports pyarrow outside require_module (line 1) rc=1
pytest -n 2 -> 2 passed rc=0
CI runs this serially (ci.yml:268, no -n), so the gate holds where it matters. A developer running -n gets no refusal, but nothing passes vacuously either: without pyarrow the file errors at import, and with it the test really runs. A fix could do the AST scan on the controller over the collected paths, or ship the sites back as a report property the way pgc_declined does.
Shell side, for the record: pgc_skip declines pyarrow unconditionally and has no PGC_REQUIRE counterpart. That is acceptable because ci.yml:678-679 and nightly.yml:184-185 prove the suites' interpreter imports pyarrow as both the user and root before any suite runs. I'm only noting the asymmetry with the pytest side.
Requesting changes for the .name arm only. Once it's in and shown red against the deletion, I'll approve without re-reviewing the rest.
🤖 Generated with Claude Code
|
Thanks, that was a real hole. 08ca1d0 answers the blocking point. The
Also in 08ca1d0:
The xdist gap is filed as #1305, with your measurement and a done-when. The shell asymmetry: agreed, and noted. The CI import steps you cite are what make |
OffgridwithJD
left a comment
There was a problem hiding this comment.
Approved at 08ca1d0. Reproduced here rather than taken from the comment:
test_capability_decline.pyis 8 passed, both withPGC_REQUIRE=pyarrowexported and without it.- With the
e.name not in (module, top)check deleted,test_a_missing_dependency_of_pyarrow_fails_rather_than_declinesfails ({'passed': 1} != {'passed': 0}), in both PGC_REQUIRE states. Restored, it passes. - The diff since 3941f05 touches only the test file, TESTS.md and expected_tests.txt. No harness code changed, so my earlier measurements of declines, PGC_REQUIRE under xdist, and the spellings carry over.
#1305 tracks the xdist gap. Merge order as you said: #1302 first, then rebase this.
🤖 Generated with Claude Code
The 25 suites that call pgc_skip pyarrow now record a named SKIP and exit 66 when pyarrow is absent, so a box without it no longer reddens the run. Owner's decision, 2026-10-12. Every other capability keeps the old rule: a missing btree_gist still fails unless it is waived. Test first: selftest part 600 drives pgc_skip in throwaway suites with every waiver cleared. On the old lib.sh its two pyarrow arms fail for the intended reason (got [1 FAILED] want [66 SKIPPED]; got [0/1] want [1/0]) while both btree_gist controls pass. After the change the selftest is 1218 passed + 0 failed on PG17. End to end, objstore_listing.sh with an ImportError shim first on PYTHONPATH: rc=66, one SKIP record, 0 failed. docs/testing.md said a skipped suite exits 2. PGC_EXIT_SKIPPED is 66 and both runs above measured 66, so the page now says 66. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lent (#1215) Review of #1286 (OffgridwithJD): at b1f6cad the nightly capability_sweep went red, preserved=5 refused=0 silent=25 of 30, because its verdict had no outcome for a suite that loses its names and says so with a SKIP. And lib.sh joined the sweep's wide population, because the decline reason named pyarrow in code. - pgc_capability_verdict takes a third input, the SKIP records whose reason names the capability, and returns declined for them. silent, names lost with no FAIL and no SKIP, must still be zero: the owner's rule is that a capability may be skipped but no test may be silent. - The sweep asserts that the suites that decline are exactly the suites whose code calls pgc_skip pyarrow, as sets derived from the source (25 today), not a literal count. - The verdict's four cases move to selftest part 610, which evals the sweep's own text, so they run in seconds on every major instead of needing every pyarrow suite twice. Red on the old function: (3 lost, 0 fails, 1 skip) -> silent, want declined. - lib.sh builds the reason from $1, so its code no longer names pyarrow: code lines naming it, main 0, b1f6cad 1, this head 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The first run of the new set arm on PG17 failed with three suites that DO call pgc_skip pyarrow missing from the derived set. sed | grep -q under pipefail: grep -q exits at its first match, sed dies of SIGPIPE, and the pipeline fails, at random. The header of capability_sweep.sh records the same race for the population itself. grep -c reads all its input. PG17 sweep at this head: preserved=5 refused=0 declined=25 silent=0 of 30, 15 passed + 0 failed, 299 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eclines silently (#1215) The pytest half of selftest parts 600 and 610, held by the Python harness's own machinery. The first version drove lib.sh from Python; OffgridwithJD's review refused it as crossing the harness boundary, and the owner chose a pytest mechanism matching the shell decision: a named skip, the run green, never silent. pgc_vacuity gains a fourth record verdict, DECLINED, and two methods: expect.declines(capability, *, name, detail='') expect.require_module(module, *, name) Five holes closed, from the review: 1 PGC_REQUIRE naming the capability turns a decline into a FAIL; the cluster pytest CI job installs pyarrow (pinned), proves it imports, and exports PGC_REQUIRE=pyarrow, so CI cannot decline. 2 a decline must be the test's first outcome, and no check may follow. 3 require_module declines only on ModuleNotFoundError naming the module or its top package; a broken install fails with its own error. 4 a test file importing pyarrow outside require_module is refused, in each of five spellings (AST, at file collection, before import). 5 the accounting line carries '+ N declined' when there are any, and each decline is printed with its node id and capability. A run with none prints the line every reader already parses, byte for byte. Test first: test_capability_decline.py's seven tests all failed before the methods existed; the four failure tests pin their MESSAGE, because a missing method also fails an inner test. The layer's own guards caught three mistakes of mine on the way: cannot_run lost its @_resolving to the new method, two refusals followed a record, and a second pytest_terminal_summary would have replaced the existing one. PG17: guard half 410 passed + 1 failed (test_build_refusal, also red on unmodified main); cluster half with PGC_REQUIRE=pyarrow 490 passed + 1 failed (test_harness_deps' driver-absent arm, also red on unmodified main here); harness_selftest 1223 passed + 0 failed. The new file passes 7/7 with and without PGC_REQUIRE exported. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ain after #1288 (#1215) Twelve new checks; nine dated by mutation runs on all five majors, replayed from the saved logs onto #1288's ledger, merged one log at a time with --mutation and --target. The census moves 1664 -> 1667, the three new premises. guard_tests 405 -> 412 by collection. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…#1215) OffgridwithJD, reviewing 3941f05, deleted require_module's .name check and all seven tests still passed. The case that check exists for is an installed pyarrow that cannot import one of its own dependencies: a ModuleNotFoundError naming that dependency, not pyarrow. This arm stubs exactly that. With the two-line check deleted it goes red (the inner test declines and passes); with it, 8 passed, with and without PGC_REQUIRE=pyarrow. Also adds __import__ to SPELLINGS, so the scanner's sixth documented spelling is proven too. guard_tests 412 -> 413, by collection. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Rebased onto cc0d8f8 (#1302 merged). Head is now ac5030d; please re-approve if this holds up. Per-file comparison against 08ca1d0, the head you approved (+/- lines, md5):
The ledger: git merged it without conflict. Before trusting that, I checked it row by row: the result is exactly main's rows, less the one re-dated capability_sweep row, plus the 13 rows from the PR. #1291's rows are a different suite, so the saved logs touch none of them. On this tree, 1674 rows are never seen red, which matches the budget line. Counts by collection on this tree: guard_tests 413 and cluster_tests 497, which is main's number, unchanged. The guard half is 412 passed and 1 failed; the failure is test_build_refusal, the same one that fails on unmodified main here. |
08ca1d0 to
ac5030d
Compare
OffgridwithJD
left a comment
There was a problem hiding this comment.
Re-approved at ac5030d, the rebase onto cc0d8f8 (#1302). I compared each file's patch against the 08ca1d0 patch I approved, rather than re-reading:
- 16 of 18 files have byte-identical patches. That includes pgc_vacuity.py, test_capability_decline.py, lib.sh, capability_sweep.sh, both selftest parts, ci.yml and check_ledger.tsv.
- TESTS.md differs only in the number: the section is now 91, after #1302's 90. The file has sections 1 to 91.
- check_ledger_budget.txt: I counted the ledger file itself rather than taking the comment. Main has 1895 rows and 1671 never; this branch has 1907 rows and 1674 never. That matches the budget line and the arithmetic.
- Counts by collection on this tree: guard 413 and cluster 497, both matching expected_tests.txt.
🤖 Generated with Claude Code
test_tid_range_scan.py is independent of the shell suite: its own table, row count, group size and ranges, on a private database. Every shell property is covered (compare_to_bash: 13 literal, 2 template, 0 missing). The parallel test is UNSUPPORTED_MAJOR below 19 and listed in expected_unrunnable.txt. Ledger: 31 rows from a five-major run, replayed onto commandprompt#1286's ledger; 15 dated by eight mutations merged one log at a time with --mutation and --target; census 1674 -> 1690. TESTS.md section 92; cluster_tests 499 by collection. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…five majors (#1236) The #1236 follow-up for parts 540 and 590. Six mutations, each run on 15-19, merged one log at a time with --mutation and --target: three of part 540's sweep (the $-arm skip, awk_determinate's > 0 case, the report of an indeterminate verdict), two of part 590's readers, and pgc_summary before one of pgc_setup's exits. They date 6 checks in 540, 3 in 590 and 12 in part 390. Census 1693 -> 1672; rows unchanged at 1943. The logs were run on c1e253f. Since then the three parts are unchanged and lib.sh changed only in pgc_skip's pyarrow branch; every reddened name exists in a clean run on #1286's tree. Three names #1284 had renamed came back as never rows and were removed again. orphan-scan: orphans=0. Part 540 is now clear (9 of 11 dated, the 2 never rows premises). Part 390 joins the reading list: 61 never-red checks beside 12 dated ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…five majors (#1236) The #1236 follow-up for parts 540 and 590. Six mutations, each run on 15-19, merged one log at a time with --mutation and --target: three of part 540's sweep (the $-arm skip, awk_determinate's > 0 case, the report of an indeterminate verdict), two of part 590's readers, and pgc_summary before one of pgc_setup's exits. They date 6 checks in 540, 3 in 590 and 12 in part 390. Census 1693 -> 1672; rows unchanged at 1943. The logs were run on c1e253f. Since then the three parts are unchanged and lib.sh changed only in pgc_skip's pyarrow branch; every reddened name exists in a clean run on #1286's tree. Three names #1284 had renamed came back as never rows and were removed again. orphan-scan: orphans=0. Part 540 is now clear (9 of 11 dated, the 2 never rows premises). Part 390 joins the reading list: 61 never-red checks beside 12 dated ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…five majors (#1236) The #1236 follow-up for parts 540 and 590. Six mutations, each run on 15-19, merged one log at a time with --mutation and --target: three of part 540's sweep (the $-arm skip, awk_determinate's > 0 case, the report of an indeterminate verdict), two of part 590's readers, and pgc_summary before one of pgc_setup's exits. They date 6 checks in 540, 3 in 590 and 12 in part 390. Census 1693 -> 1672; rows unchanged at 1943. The logs were run on c1e253f. Since then the three parts are unchanged and lib.sh changed only in pgc_skip's pyarrow branch; every reddened name exists in a clean run on #1286's tree. Three names #1284 had renamed came back as never rows and were removed again. orphan-scan: orphans=0. Part 540 is now clear (9 of 11 dated, the 2 never rows premises). Part 390 joins the reading list: 61 never-red checks beside 12 dated ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mandprompt#1305), red OffgridwithJD measured on commandprompt#1286 that the refusal is lost under xdist: the serial run said REFUSED and exited 1, the -n 2 run said 2 passed and exited 0, because pytest_collect_file runs in the workers. A pytester arm runs both as subprocesses over a stub pyarrow and a file holding 'import pyarrow.parquet as pq'. Red on main: the serial premise holds, and under -n 2 the controller names nothing (got 0 want 1). guard_tests 413 -> 414 by collection. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From @jdatcmd's review of commandprompt#1322: the twin rule applies to selftest parts (precedent: parts 600/610 and test_capability_decline.py, commandprompt#1286). test_suite_exit_trap.py reads the suites and lib.sh as text with its own reader -- shlex for trap lines, the shell's own comment rule -- and drives the same eight suites, written from its own strings, before the population arm. Same five check names. Red on the tree before the fix, naming native_upgrade_converge.sh only; five mutations of its reader each redden the arms the part's matching mutation does. NO_CLUSTER; guard_tests 415 -> 419 by collection; TESTS.md section 97. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From @jdatcmd's review of commandprompt#1322: the twin rule applies to selftest parts (precedent: parts 600/610 and test_capability_decline.py, commandprompt#1286). test_suite_exit_trap.py reads the suites and lib.sh as text with its own reader -- shlex for trap lines, the shell's own comment rule -- and drives the same eight suites, written from its own strings, before the population arm. Same five check names. Red on the tree before the fix, naming native_upgrade_converge.sh only; five mutations of its reader each redden the arms the part's matching mutation does. NO_CLUSTER; guard_tests 415 -> 419 by collection; TESTS.md section 97. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From @jdatcmd's review of commandprompt#1322: the twin rule applies to selftest parts (precedent: parts 600/610 and test_capability_decline.py, commandprompt#1286). test_suite_exit_trap.py reads the suites and lib.sh as text with its own reader -- shlex for trap lines, the shell's own comment rule -- and drives the same eight suites, written from its own strings, before the population arm. Same five check names. Red on the tree before the fix, naming native_upgrade_converge.sh only; five mutations of its reader each redden the arms the part's matching mutation does. NO_CLUSTER; guard_tests 415 -> 419 by collection; TESTS.md section 97. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Closes #1215. @OffgridwithJD, this needs your review. I will not merge it without your approval on the head commit.
What changes
When pyarrow is missing, the 25 suites that call
pgc_skip pyarrownow record a named SKIP and exit 66, and the run does not fail. Before, each recorded one FAIL and reddened the whole run on a box without pyarrow.The owner decided this on 2026-10-12. I asked whether "decline" meant UNRUN or SKIP: UNRUN makes the suite INCOMPLETE, which
pgc_verdict_fails_majorstill counts as a failed major. The answer was SKIP, so the run stays green.Every other capability keeps the old rule. A missing
btree_giststill failstemporal.shunless it is waived.Why a green skip does not hide anything in CI
Evidence
Test first. New selftest part 600 drives
pgc_skipin throwaway suites with every waiver cleared:End to end, one real suite.
objstore_listing.shon PG17, with apyarrow.pythat raisesImportErrorfirst onPYTHONPATH. Its premises:import pyarrowfails, andprint(2+2)prints 4.Every arm has a mutation that reddens it, on all five majors:
pgc_skiptreats pyarrow like any other capability (the oldlib.sh)pgc_skipdeclines every missing capabilitycontrol: a missing btree_gist still fails the suitepgc_skipignoresPGC_ALLOW_MISSING_<CAP>control: and an explicit waiver still turns that failure into a skipThe ledger gains five rows: four dated, one premise. The census moves 1671 -> 1672.
Also fixed, because it is in the section this edits
docs/testing.mdsaid a skipped suite exits 2.PGC_EXIT_SKIPPEDis 66, and both runs above measured 66.Not changed
From the #1215 thread:
arrow_import.sh's comment that "29" suites usepgc_skipdoes not reproduce (it is 25), and two of the five arm-by-arm decliners do not say why they decline. Both are comments; neither blocks alpha5.🤖 Generated with Claude Code