Repository navigation
test: parallel_degree gains its pytest twin, and a degree nobody read no longer passes (#1341) - #1642
Merged
Merged
Conversation
…k no longer tests one path twice (#1341) test/pytest/test_read_stream.py ports the checks of test/read_stream.sh by name. The suite compares five query shapes with a heap twin, with pgcolumnar.enable_read_stream on and then off; one shell fix, in both twins: - The setting arrives by ALTER DATABASE SET, whose error the shell's q drops. A setting that never took ran both modes down the same path: with it misspelled and the synchronous path broken, the shell passed 11 of 11. Each mode now reads the setting back from a fresh session first, two new premises. - The ten comparisons were named through $mode in a loop; they are literal. The stripe premise carries its count and leaves lossy_arms.tsv. Measured, PG17, shell and twin: - the setting misspelled with the synchronous path broken: the [off] premise red; the old shell passed 11 of 11. - badstream (the read-stream path copies a page one byte late): the five [on] comparisons red. badsync (the synchronous path does): the five [off] comparisons red. Each red set is identical in both twins. - clean: 13 of 13 on PG15 to PG19 in both twins. Ledger: 13 rows, 10 dated by the two mutations and 3 never. suites_not_covered 113 -> 112, cluster_tests 2454 -> 2467, TESTS.md section 256. Census 3793 -> 3794 never, 2073 -> 2085 dated, 5879 rows. The ledger gate and the guards pass over 8d2bf1b. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… file no longer passes it (#1341) test/pytest/test_parquet_level_width.py ports all 7 checks of test/parquet_level_width.sh by name. It reads the source in Python, needs no cluster, and is listed in NO_CLUSTER. Three shell fixes, in both twins: - "no local copy of the helper survives" summed grep -c over the writer and the reader; grep prints nothing for a missing file, so with the writer's path wrong the sum read 0 and the shell passed 7 of 7. It now reads only when both files exist, and says so otherwise. - "and no signed 1 << remains in it" counted over the extracted body, so with the header unreadable it read 0 and passed. It now needs a body. - The body checks read the comments inside the body, so a guard or bound commented out of the code still passed 7 of 7 (OffgridwithJD's commentguard and commentbound). The body now has its comments blanked, multi-line ones included. Measured, PG16 shell and the twin: - signedshift (pq_bits_for shifts a signed 1): 2 red. unbounded (the b < 31 bound removed): 1 red. localcopy (a local bits_for back in the writer): 1 red. commentguard (the non-positive guard commented out): 1 red. commentbound (the b < 31 bound commented out): 1 red. commentml (the guard in a multi-line comment): 1 red. Each red set is identical in both twins (the comment mutants on PG17). - clean: 7 of 7 on PG15 to PG19 in the shell, and in the twin. Ledger: 7 rows, 5 dated by the four mutations and 2 never. suites_not_covered 144 -> 143, guard_tests 464 -> 471, TESTS.md section 224. Census 3543 -> 3545 never, 1798 -> 1803 dated, 5348 rows. The ledger gate and the guards (471) pass over 555e5ef. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… error no longer pass it (#1341) test/pytest/test_parquet_nested.py ports all 6 checks of test/parquet_nested.sh by name, each declining by the shell's skip name without pyarrow, as test_arrow_nested.py does for the Arrow sibling. Two shell fixes, in both twins, mirroring arrow_nested's: - "nested Parquet values match expectation" compared only the rows the file held, so a zero-row file of the same schema printed MATCH; it now requires every id 1..5000 once. - "reject multi-dim array" passed on any error, so with the export pointed at a missing table it read as the refusal; md_refusal() now reads the multi-dimensional message. Measured, PG16, shell and twin: - emptyasnull (an empty array written with definition level 0, so it reads back NULL): 1 red, the values check. nomultidim (the refusal removed): 1 red, the multi-dim check. Each red set is identical in both twins. - clean: 6 of 6 on PG15 to PG19 in both twins. Ledger: 6 rows, 2 dated by the two mutations and 4 never. suites_not_covered 111 -> 110, cluster_tests 2467 -> 2473, TESTS.md section 258. Census 3796 -> 3800 never, 2090 -> 2092 dated, 5892 rows. The ledger gate and the guards pass over 1b1922e. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nts no longer agree (#1341) test/pytest/test_parquet_nested_import.py ports all 7 checks of test/parquet_nested_import.sh by name. The two pyarrow arms decline by their own names without pyarrow, as the shell's two skips do. One shell fix, in both twins: - "import count matches" compared two counts with check, under which two empty readings agree: with both tables missing, the shell passed it. It is check_num. The set hashes already gave each failed query its own value, so the round-trips could not agree on two failures. Measured, PG16, shell and twin: - readempty (the reader takes an empty Parquet list for a NULL array): 3 red, the two round-trips and the pyarrow oracle; the counts stay green, as they should. The red set is identical in both twins. - clean: 7 of 7 on PG15 to PG19 in both twins. Ledger: 7 rows, 3 dated by the mutation and 4 never. suites_not_covered 110 -> 109, cluster_tests 2473 -> 2480, TESTS.md section 259. Census 3800 -> 3804 never, 2092 -> 2095 dated, 5899 rows. The ledger gate and the guards pass over 9109cc2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
OffgridwithJD
approved these changes
Oct 21, 2026
OffgridwithJD
left a comment
Collaborator
There was a problem hiding this comment.
@jdatcmd Approving 7548c88b (its own commit, on #1631). Measured on PG17 (~/pg/17-w), shell then twin as shipped:
| run | shell | twin |
|---|---|---|
| head, PG17 and PG18 | 6/6 | 6/6 |
nopartial (if (false && workers > 0)) |
3 red: columnar plan, cap ("no reading (heap=[4] col=[])"), degree | the same 3 (the degree one is a named VacuityError: "num() needs numbers on both sides") |
noest (the #451 uncompressed estimate never applied) |
1 red: degree | the same 1 |
overask (pages * 243) |
2 red: cap, degree | the same 2 |
underask (mine: pages / 9) |
1 red: degree | the same 1 |
nocomp (mine: default codec none) |
green | green |
nocomp is why I'm fine with "premise: the columnar table really is smaller on disk" keeping its prefix: with compression off the columnar table is still smaller (no per-row tuple headers), so no one-line codec change reddens it. The three relabelled checks are dated by mutants that red them in both harnesses, and the cap check now refuses a missing count.
🤖 Generated with Claude Code
87 tasks done
… not its fixture CI failed the harness guards and both cluster-test jobs with: REFUSED test_parquet_nested_import.py imports pyarrow outside require_module (line 63) REFUSED test_parquet_nested_import.py imports pyarrow outside require_module (line 64) The module fixture imported pyarrow itself to write the reference file. A fixture cannot decline, so main's guard refuses the import. The fixture now keeps the database and the directory, and the pyarrow arm runs once, from the first pyarrow test, with the modules that test's require_module returned. The check names and the count are unchanged. Measured: - Red, the parent's twin: test_harness_deps "the guard half of the corpus runs without a database driver" fails with the REFUSED lines above. - Green: the twin is 7/7 on PG17 and PG19. With pyarrow hidden it is 5 pass + 2 declined, each pyarrow arm by its own name. - Mutant, the reference file one row short: both pyarrow arms fail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd no longer passes as survived (#1341) test/pytest/test_parquet_count_bounds.py ports all 17 checks of test/parquet_count_bounds.sh by name, using the shell's crafter and declining by the shell's skip name without pyarrow. Three shell fixes, in both twins: - The survival checks read SELECT 1, which answers again after crash recovery. With the num_values bound removed (#570), the 2^62 file crashed the backend and "and the backend survived it" and "survived the list over-read" passed on main. They now also need the server log's count of killed backends unmoved since setup, as avro_manifest does since #1576; the same crash now reads "no ([1], 1 backend crashes)". - The two phantom-row checks caught only the exact count the crafter declares (40, 8). They now catch any count above the file's true one. No mutation here produced a different count, so this hardening is not shown red first: under both #571 guards removed, the leak was the declared 40, which main caught too. - The crafter premise covers all seven files; the three list files were never checked. Measured, PG16, shell and twin: - no570 (the num_values range check removed): the backend crashes. Both harnesses red the rejection, the survival check and the detail; what else reds depends on how long recovery takes, so the counts differ (7 in the shell, 11 in the twin), all from reads during recovery. - no571 alone is masked: pq_require_entry rejects the same files at decode time with the same message, so the suite stays 17/17. - noentry (pq_require_entry refuses nothing): 2 red, the two list checks, the same in both twins. no571 with noentry: 9 red, the same 9. - clean: 17 of 17 on PG15 to PG19 in both twins. Ledger: 17 rows, 2 dated by noentry and 15 never. The num_values and num_rows mutations crash the backend and redden collateral checks, so the ledger cannot attribute them. suites_not_covered 125 -> 124, cluster_tests 2169 -> 2186, TESTS.md section 233. The ledger gate, guards (467), name grading and the self-test pass over 9bd1850. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t by importing pyarrow in it CI failed the harness guards and both cluster-test jobs with: REFUSED test_parquet_count_bounds.py imports pyarrow outside require_module (line 83) The module fixture imported pyarrow to decide whether to build at all. A fixture cannot decline, so main's guard refuses the import. Each test now declines by the shell's skip name first, and only then asks for the fixture with request.getfixturevalue. The fixture no longer imports anything, and it never runs on a box without pyarrow. The check names and the count are unchanged. Measured: - Red, the parent: test_harness_deps "the guard half of the corpus runs without a database driver" fails with the REFUSED line above. - Green: test_harness_deps and test_capability_decline, 30 passed, no REFUSED line. The twin is 17/17 on PG17 and PG19; with pyarrow hidden it is 17 declined. - Probe: wanting 9 honest rows fails with "got = 8, want = 9", so the fixture still crafts and imports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… no longer passes (#1341) test/pytest/test_parallel_degree.py ports all 6 checks of test/parallel_degree.sh by name. Three shell checks could pass with nothing measured; all three are fixed in both twins. - With the server stopped after ANALYZE, main's shell passed three of six checks. "identical data is granted the same parallel degree" compared "none" with "none"; it is now check_num. "both tables hold the same rows" compared "" with ""; it is now check_num. "the worker cap is not what decides either arm" read a missing worker count as 0; it now needs two numbers. With the edit, the fixed shell reds all six. - Three checks lose their premise: prefix under #1339. The columnar rows, the columnar partial path and the columnar degree under the cap are pgcolumnar's own work, and a one-line change reddens each. Measured, PG17, shell and twin: - server stopped after ANALYZE: 6 red in the fixed shell and in the twin (the twin drops its database instead); main's shell passed 3 of 6. - the #451 estimate never applied (2 workers against heap's 4): 1 red. The estimate over-asking (pages * 9): 1 red. Over-asking into the cap (pages * 243): 2 red. The partial path never added: 3 red (main's shell: 2, the cap check passed). An insert that drops one row: 1 red. Each red set is identical in both twins. - clean: 6 of 6 on PG15 to PG19 in both twins. Ledger: 6 rows, 4 dated by the five mutations and 2 never. suites_not_covered 108 -> 107, cluster_tests 2497 -> 2503, TESTS.md section 261. Census 3819 -> 3821 never, 2097 -> 2101 dated, 5922 rows. The ledger gate and the guards pass over 23f3d52. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jdatcmd
force-pushed
the
test/1341-parallel-degree-twin
branch
from
October 22, 2026 01:06
7548c88 to
1e65109
Compare
Collaborator
Author
OffgridwithJD
approved these changes
Oct 22, 2026
OffgridwithJD
left a comment
Collaborator
There was a problem hiding this comment.
@jdatcmd Re-approving the rebased head 1e651097 (I approved 7548c88b).
- Content unchanged: compared file by file against
7548c88b, this PR's own +/- lines match, and it's one commit over its new parent. Only the budget, expected_tests and TESTS.md differ, and those only restate counts. - Gates at the stack tip
bdaaa098: guards 474 passed, collection 2670 =cluster_tests, census 3850 = the tsv's never count.
🤖 Generated with Claude Code
jdatcmd
added a commit
that referenced
this pull request
Oct 22, 2026
…ing line (#1613) A comparison refused with a VacuityError takes no record ("a refusal marks nothing", pinned), so the accounting line left it out. A twin under a mutant then printed fewer failures than the shell's FAILs, sometimes `0 fail`, and a runner reading the red set by name had to parse VacuityError text, which missed some (#1624, #1642, #1644). Option 2 from #1613, as OffgridwithJD chose it: refusals stay out of the records, each refusal that failed its test prints REFUSED <name>: <reason> and the accounting line adds `N refused` to its total. So the shell's FAIL names are the twin's FAIL names plus its REFUSED names, read straight off the two outputs. The part is printed only when present, so a run without refusals prints the line every reader already parses, byte for byte. How: `_resolving` notes a VacuityError raised before any record, with the check name bound from the call. pytest_runtest_makereport sends it on the report (`pgc_refused`, so it crosses the xdist boundary like the records) only when it is the exception that failed the test. A refusal a test catches on purpose, as the layer's own guard tests do, is not reported. Measured: - Red: the new test_a_refused_comparison_is_counted_and_named, serial and under -n 2, failed with "'accounting: 2 pass + 1 fail + 0 unrun + 1 refused = 4' is absent"; the inner outcomes (2 failed, 2 passed) held. - Green: both cases pass. Mutant: report every noted refusal, not only the one that failed the test: both cases red again (the caught one counted). - A real twin, catalog_filter_reads on PG17 with stats() raising: shell "5 passed + 2 failed = 7"; twin "5 pass + 0 fail + 0 unrun + 2 refused = 7", and its two REFUSED names are the shell's two FAIL names. Before this change the twin's line read "5 pass + 0 fail + 0 unrun = 5". - Harness selftest 1248/1248 (before the review). Review (OffgridwithJD): refusals raised by expect.row_set (it refuses a failed query itself, before delegating to rows) and expect.wrote (it raises its three refusals directly) went through no _resolving wrapper, so they were neither counted nor named; 127 call sites in the twins. Both are now wrapped. The fixture refuses through all three paths: red on the previous head with "accounting: 2 pass + 1 fail + 0 unrun + 1 refused = 4" where 3 refusals were raised; green with "... + 3 refused = 6" and a REFUSED line for each. The one-record-per-call guard now lists row_set and wrote among the wrapped methods. Guards 806 passed (guard_tests 804 -> 806 on main 9ab6a4c). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #1631; merges after it. This head sits on my restated stack (#1622, #1628–#1631), so the registry counts in the commit message are re-derived against that stack. Counts quoted in the body below are from the port's original base.
What I re-ran myself before opening (PG17): the
nopartialmutant. Main's shell passes "the worker cap is not what decides either arm" (4 passed + 2 failed, neither of them that check). This shell fails it:got [no reading (heap=[4] col=[])] want [yes]. The twin fails the same 3 names as the shell.@OffgridwithJD, this is the pytest twin of
test/parallel_degree.sh(#1341). It also fixes three shell checks that could pass with nothing measured. One commit,df344d71, on1d1e0850.What was fixed
I stopped the server right after ANALYZE, so every reading came back empty. Main's shell still passed three of its six checks:
nonewithnone. It now usescheck_num.""with"". It now usescheck_num.no reading.With the same edit, the fixed shell reds all six checks by name.
Three checks lose their
premise:prefix under #1339. In each case the check reads pgcolumnar's own work, and a one-line mutant reddens it (see the table):both tables hold the same rowsthe columnar plan is parallelthe worker cap is not what decides either armTwo checks keep the prefix and arrive in the ledger as
never: the columnar table being smaller on disk, and the heap plan being parallel.Main's shell, this shell and the twin under each edit and mutant (PG17)
columnar_customscan.c: the #451 estimate never applied (columnar 2 workers, heap 4)columnar_customscan.c: the estimate over-asks,pages * 9(6 workers)columnar_customscan.c: the estimate over-asks into the cap,pages * 243(8 workers)columnar_customscan.c: the partial path is never added (if (false && workers > 0))columnar_tableam.c:tuple_insertdrops the row whose first column is 1None of the mutants crashed the backend, so there are no timing-dependent reds.
One twin run was not clean the first time. The PG16 twin run on the rebased tree failed to start its cluster:
could not bind IPv4 address "127.0.0.1": Address already in useon port 29768, because another agent's cluster held the port. The rerun passed 6 of 6. Both logs are listed under Logs.Gates (over
1d1e0850)census stated 3720, ledger holds 3720: they agree,ceiling against origin/main: 117 -> 116, which does not rise.467 passed.compare_to_bash.py:VERDICT: every bash property is covered(6 literal matches).cluster_tests 2339(was 2333).harness_selftest.sh:PASSED.unported_suites.txtloses the suite.This branch conflicts with the parallel_flush_optin twin branch. Both start from
1d1e0850, so both claim TESTS.md section 252,suites_not_covered 117 -> 116and the nextcluster_testsstep, and both append to the ledger and the budget. Whichever lands second has to be rebased and its registries regenerated.Logs
The logs are in
/tmp/claude-1006/-home-jdatcmd/ed97498f-58ee-4453-98bc-cbf3cfaf41b1/scratchpad/portlogs/parallel_degree/:main-pg17.log,main-deadserver.logandmainshell-<mutant>.log.shell-*.log. The five clean logs merged into the ledger areshell-clean-pg15.logtoshell-clean-pg19.log.twin-*.log.rebased-shell-pg*.logandrebased-twin-pg*.log.rebased-twin-pg16.logholds the passing rerun; the first run's port collision is quoted above.gate-pg*.log,guards.logandselftest.log.mut-<mutant>.patch,edit-deadserver.patchandedit-deadserver-twin.patch.🤖 Generated with Claude Code