Repository navigation
test: hilbert_curve gains its pytest twin, and the battery no longer reads what the last key left (#1341) - #1651
Merged
Merged
Conversation
OffgridwithJD
force-pushed
the
test/1341-hilbert-curve-twin
branch
from
October 21, 2026 23:46
6700567 to
6965d7f
Compare
87 tasks done
jdatcmd
approved these changes
Oct 22, 2026
jdatcmd
left a comment
Collaborator
There was a problem hiding this comment.
Approved at 6965d7f. Measured on PG17 at main a1b04ee with the memset one byte short (memset(out, 0, keybytes - 1), src/columnar_curve.c:116):
| run | result |
|---|---|
| main's shell, twice | 63 + 121 failed both times |
| this head's shell, twice | 60 + 124 failed both times, the same 124 names |
| this head's twin | 124 failed. I dumped the twin's own records with a small plugin (the pgc_records user property): its 124 FAIL names equal the shell's, byte for byte |
| clean | shell 184/184 on PG15 and PG19; twin 184 passed |
| harness_selftest, this head | 1248/1248, including "the refusal emitters are the ones the tree defines" |
The compare_to_bash changes keep both refusal arms testing something: one uses inline source, and test_the_grader_itself_refuses_the_suite_it_cannot_read now builds a fixture holding the two helpers as they stood. I did not rerun the other sixteen mutants.
Like the rest of the stack, this needs a restate onto main. I'll re-approve one whose non-registry files are unchanged.
OffgridwithJD
force-pushed
the
test/1341-hilbert-curve-twin
branch
2 times, most recently
from
October 22, 2026 05:26
41c29e2 to
c46ba8d
Compare
… guard's (#1341) iceberg_dv.sh gains test/pytest/test_iceberg_dv.py, one check per test under the shell's names, and two holes in the shell are closed, each measured red-first on PG17: - "a manifest/footer offset mismatch is refused (XX001)" read the SQLSTATE alone, and several guards raise XX001. With the offset match removed (the !found refusal skipped), a later XX001 refused the same file and main's shell passed 26/26. Every refusal now reads its own guard's message: refusal() answers the SQLSTATE only when the message carries the guard's phrase, and "<SQLSTATE> (another refusal: ...)" otherwise. - The three "backend still up" checks read SELECT 1, which answers again after crash recovery. With the referenced_data_file check removed a NULL path reaches strcmp and the backend dies on that arm; main passed "backend still up after the DV refusals". They now also read the server log's count of killed backends (crashes/survived, as avro_manifest), and each refusal waits for the server to answer first (await_up), so a crash reddens its own arm and its section's survival check, the same names in both harnesses, and not a timing-dependent tail of collateral. The eight survivor comparisons move to check_text, so an empty oracle no longer matches an empty scan. Measured on PG17, shell then twin as shipped: seventeen mutations, each with the same reds in both (strictgt 7, anyfile/nodup/nov2/noflags/noref/nobigoff 2, the rest 1); 26/26 in each on 15-19. 25 rows dated, 1 never (the survival check after the DV applications, which no mutation crashed). Census 3884 -> 3885 never, 2286 -> 2311 dated, 6196 rows; suites_not_covered 102 -> 101; cluster_tests 2753 -> 2779; TESTS.md §268. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d slot no longer passes (#1341) The pytest twin of test/logical_decoding_source.sh (#754), one check per test, every check by the shell's name, on a private cluster at wal_level=logical. The shell's second slot (pgc_754b) had no heap control. Created after the 5000-row insert, it decoded nothing, and both "and it too emits no decodable change of its own" and "100x the rows does not give 100x the internal records" (0 < anything) passed: main 11/11. A heap table now writes through that slot in the same window and must decode its 5000 inserts ("CONTROL: the second slot decodes the heap table's 5000 inserts"), and the ratio check refuses a slot that carried no internal records. Under that harness mutation both are red in both twins (SAME 2). The pgc_skip message for a missing test_decoding.so was built from pg_config --pkglibdir, so the grader could not read it; it is now a literal, and the twin records the same name (with the plugin moved away on PG17: shell 1 FAIL, twin the same 1 FAIL and 12 declined). No source mutation reddens a check: the claim is that pgcolumnar writes nothing logical decoding can read. A default chunk group of 100 rows still keeps the internal records following groups (114 for 50 groups, under the 10x bound), so it dates nothing. 12/12 shell and 13/13 twin on each of 15-19. Census 3885 -> 3897 never, 2311 dated, 6208 rows (the skip name has no ledger row: it is not a check); suites_not_covered 101 -> 100; cluster_tests 2779 -> 2792; TESTS.md §269. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… longer passes as up (#1341) The twin of test/iceberg_deletes.sh, one test per check under the shell's name. Fixed in both harnesses, measured red-first against main's shell on PG17: - The six "backend still up" checks read SELECT 1, which answers again after crash recovery. With abort() in place of the null-pos refusal, or the partition spec's fields guard removed (a NULL deref, signal 11), main passed the survival check once recovery had finished. They now also read the server log's count of backends killed by a signal, and every reading waits (bounded) for the server, so a crash reddens its own arm and its section's survival check rather than the two arms after it. - Every refusal now also reads its own guard's message: XX001 and 22023 are each raised by several guards here. The oracle comparisons use check_text, so an empty side is not agreement. - "the data file has 5 rows before deletes" reads pgcolumnar's own read_parquet, so it is not a premise (#1339). Twenty-three mutations each redden the same names in shell and twin on PG17; head is 49/49 in both on each of 15-19. The equal-sequence equality check is dated only with both layered guards relaxed: the per-file strict < alone passed, because the pre-skip at the oldest data file's sequence number drops that delete first. Census 3897 -> 3903 never, 2311 -> 2354 dated, 6257 rows; suites_not_covered 100 -> 99; cluster_tests 2792 -> 2841; TESTS.md §270. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…at applied nothing no longer passes (#1341) The twin of test/logical_subscriber.sh, on two private clusters (a heap publisher at wal_level=logical, a columnar subscriber), one check per test, each by the shell's name. Four holes, each measured red-first on main's shell (PG17): - With the insert-only subscription disabled before its UPDATE, main passed 20/20: "skipped by design" and "no apply errors" read after a fixed sleep. An INSERT after the UPDATE must now arrive before either is read. - With no UPDATE sent to the wedge publication, "the error does NOT say only 'row locking'" and "the wedge is real" passed. The first now needs the replication error in the subscriber's log; the second reads "publisher -> subscriber". - With every lock statement failing on a missing table, the three "is not told about replication" checks passed. They now need the generic row-locking error first. - "premise: the second subscription synced before the UPDATE" is reddened by COPY failing in a logical worker, so it is not a premise (#1339) and is dated. The lock loop is unrolled into literal checks so the grader reads each name. Five mutations (hintnoname, nogate, overgate, applyins, syncins) redden the same names in both twins; clean 20/20 on 15-19 in both, and 8/8 head repeats on 17. 20 rows, 16 dated, 4 never. Census 3903 -> 3907 never, 2354 -> 2370 dated, 6277 rows; suites_not_covered 99 -> 98; cluster_tests 2841 -> 2861; TESTS.md §271. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ck that undid nothing no longer passes (#1341) The twin of test/logical_decoding_cdc_recipe.sh, every check by the shell's name, one check per test, on a private cluster at wal_level=logical. Like the shell, it extracts the CDC recipe from docs/user-guide.md at run time and executes it. Two holes, both measured on PG17 against main's shell, fixed in both harnesses: - The rollback arm read the capture count and the row only after ROLLBACK, so a rolled-back INSERT that never ran passed both arms. With it made a duplicate key, so the block stopped there, main passed 35/35. A reading inside the transaction, before the rollback, now requires the row both captured and present ("1:1"). Under the same mutation it is red in shell and twin. - "and it saw the same values the table holds" compared two readings with check. With the server stopped before it, "" = "" passed. It is check_text now. The missing-plugin pgc_skip name is a literal the twin records, and the seven recipe-contains premises are unrolled into literal names the grader can read. Five mutations date seven checks, the same names red in both twins on PG17: pgcolumnar_tuple_delete marking nothing (1), the update writing its new version with every column null (1), the update leaving the old version live (3), and two mutations of the guide's recipe: the trigger not firing on DELETE (2), and every non-DELETE captured as an INSERT (4). 36/36 shell and 37/37 twin on each of 15-19. Census 3907 -> 3936 never, 2370 -> 2377 dated, 6313 rows (the skip name has no ledger row: it is not a check); suites_not_covered 98 -> 97; cluster_tests 2861 -> 2898; TESTS.md §272. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…wn guard's (#1341) The twin of test/iceberg_rest.sh, every check by the shell's name, one check per test. It runs a private cluster restarted with the bearer token in the postmaster environment (a good one, a wrong one, none) against the shell's own REST fixture. Two holes in the shell, each measured red-first on PG17 and fixed in both harnesses: - The 42501 arms read the SQLSTATE alone, and two guards raise 42501. With the allow-list refusing everything and the link-local refusal gone (denyall_noll), "a link-local catalog host is refused even if allow-listed" passed on the allow-list's 42501; with every address read as link-local and the allow-list gone (llall_noallow), "a catalog endpoint off the allow-list is refused" passed on the link-local guard's. Every refusal now reads its own guard's message. - "backend still up after the REST refusals" read SELECT 1, which answers again after crash recovery. With the backend aborting on the catalog's 404 (crash404), main passed it. It now also reads the server log's count of killed backends. Mutants (PG17), SAME reds in shell and twin: tokenlog 1, tokenurl 2, no401 2, no404 1, nocfgobj 1, nocap 1, crash404 2, noauth 4, denyall_noll 8, llall_noallow 8, denyall 8. Clean 14/14 in both on each of 15-19. Seeded: 14 rows, 12 dated, 2 never (the premises). Census 3936 -> 3938 never, 2377 -> 2389 dated, 6327 rows; suites_not_covered 97 -> 96; cluster_tests 2898 -> 2912; TESTS.md §273. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…no longer passes as up (#1341) The twin of test/iceberg_rest_scan.sh, every check by the shell's name, one check per test. It runs a private cluster restarted with the bearer token in the postmaster environment against the shell's own REST fixture, which points loadTable at the committed warehouse relocated into a work directory. One hole in the shell, measured red-first on PG17 and fixed in both harnesses: "backend still up after the REST read" read SELECT 1, which answers again after crash recovery. With the backend aborting on the catalog's 404 (crash404) and the probe 3s later, main passed it. It now also reads the server log's count of killed backends. The not-found arm now reads the catalog's own 404 message, not any 42P01. Mutants (PG17), SAME reds in shell and twin: no404 1, nslast 1, crash404 2, noauth 7, denyall 7. Clean 9/9 in both on each of 15-19. Seeded: 9 rows, 8 dated, 1 never (the premise). Census 3938 -> 3939 never, 2389 -> 2397 dated, 6336 rows; suites_not_covered 96 -> 95; cluster_tests 2912 -> 2921; TESTS.md §274. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nores storage-credentials no longer passes (#1341) The pytest twin of test/iceberg_rest_vended.sh, one check per test under the shell's names, on a private cluster restarted with an explicit environment (every AWS_* removed; the catalog token, and for the ambient arm the AWS_* credentials, passed in), against the shell's own SigV4 S3 fixture and REST catalog. Three holes, each measured on main's shell on PG17 first: - "storage-credentials longest-prefix match selects the right creds" passed with the storage-credentials array never read (nosc, 10/10): the catalog's flat config carried the same right credentials. The fixture catalog now vends a wrong flat config beside the array, so only the array's longest entry reads. - "a wrong vended secret is refused by S3, not bypassed (28000)" read the SQLSTATE alone, and 28000 is also "no credentials": with vended credentials never built (novend) it passed. It now needs the 403 message; the 42501 allow-list arm likewise needs the allow-list's own message. - "backend still up after the vended-credential arms" read SELECT 1, which answers again after crash recovery: with abort() in place of the 403 refusal (abort403) it passed. It now also reads the server log's count of killed backends, and each arm waits for the server first. pg_restart_env also unsets every AWS_* before starting the postmaster, so the "no ambient credentials" premise does not depend on the caller's environment. Six mutations each redden the same names in shell and twin on PG17: nosc 1, shortest 1, novend 4, leak 1, noallow 1, abort403 2. Clean: 10/10 shell and twin on each of 15-19. Seeded: 10 rows, 6 dated, 4 never. Census 3939 -> 3943 never, 2397 -> 2403 dated, 6346 rows; suites_not_covered 95 -> 94; cluster_tests 2921 -> 2931; TESTS.md §275. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d no longer passes as up (#1341) The pytest twin of test/iceberg_rest_server.sh, one check per test under the shell's names, on a private cluster restarted without and then with the catalog token in its environment, against the shell's own REST fixture. Four holes, each measured on main's shell on PG17 first: - "backend still up" read SELECT 1, which answers again after crash recovery: with the half-credential guard removed (the mint runs with a NULL secret and the backend segfaults) or abort() in place of the catalog's 401 refusal, it passed. It now also reads the server log's count of killed backends, and every reading waits for the server first (the segfault had also reddened the next arm as collateral). - "a warehouse option on the SERVER is accepted (not HV00D)" and "oauth options are accepted on a USER MAPPING (no error)" wanted an empty SQLSTATE, which a stopped server also gives: with the server stopped before them, both passed. A statement that ran now reads "ok". - "a link-local oauth_token_uri is refused by the allow-list (42501)" read the SQLSTATE alone, and the link-local guard raises 42501 too: with the allow-list removed it passed. Every refusal now needs its own message. - "a half OAuth2 credential ... is refused before any request" now also counts the fixture's requests. Five mutations each redden the same names in shell and twin on PG17: nohalf 2, abort401 3, nowh 1, noallow 2, nomaptoken 3. Clean: 29/29 shell and twin on each of 15-19. The suite already had its 29 rows: 10 more are dated (12 dated, 17 never). Census 3943 -> 3933 never, 2403 -> 2413 dated, 6346 rows; suites_not_covered unchanged; cluster_tests 2931 -> 2960; TESTS.md §276. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…reads what the last key left (#1341) The twin compiles src/columnar_curve.c with a small driver into a shared library and checks the curve in Python: the permutation test (C1), the memcmp-order adjacency walk (C2), dyadic contiguity (C3), the production-width bridge (C4a), a Python transcription of Skilling's TransposetoAxes for the round trips (C4b), the goldens and the pack's extent (C5), ncols == 1 (C6) and the frozen Z-order bytes (C7), plus the serpentine, Z-order and truncating controls through the same checkers. The driver only encodes and counts. 184 tests, one per check, all in NO_CLUSTER: no connection and no cluster. Two shell changes: - The battery fills every key buffer with 0xa5 before the pack writes it. Under a memset one byte short, which goldens went red depended on what the previous call left in the buffer (121 red on main, a stable 124 now), and a buffer's first use read uninitialized memory. - arms_unrunnable/arms_failed are written out as loops at their call sites. They took a list of names in one argument, so compare_to_bash refused the whole suite; it now reads and grades it. The refusal arm in test_compare_to_bash.py keeps its coverage against a fixture holding the two helpers as they stood, and self-test 480's pinned refusal emitters lose arms_unrunnable (its check renamed from "the two" to "the ones the tree defines", ledger row with it). Measured on PG17: seventeen mutations of src/columnar_curve.c each give the SAME failing names in the shell and the twin, and between them redden every arm except the six premises and the ten INSTRUMENT controls. Clean 184/184 in both harnesses on each of 15-19. Seeded: 184 rows, 168 dated, 16 never. Census 3933 -> 3949 never, 2413 -> 2581 dated, 6530 rows; suites_not_covered 94 -> 93; guard_tests 474 -> 658; TESTS.md §277. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
OffgridwithJD
force-pushed
the
test/1341-hilbert-curve-twin
branch
from
October 22, 2026 14:55
c46ba8d to
8c28f60
Compare
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.
@jdatcmd The pytest twin of
hilbert_curve.sh(#1341), plus two shell fixes. It goes on top of my stack (#1638 → … → #1641) and will be restated there, so it collides with the stack on purpose until then.The twin. It compiles
src/columnar_curve.cwith a small driver into a shared library and calls it through ctypes. The driver only encodes and counts its calls. Every property is checked in Python, with its own readers:max - min + 1 == count, and where C1 is already red the shell's own form is computed instead;There are 184 tests, one per check, all in
NO_CLUSTER: no connection and no cluster.guard_testsgoes 467 → 651. The twin takes about 50 s.Shell audit, red-first. I mutated
src/columnar_curve.c17 ways. Each mutant reddened the suite on main, and between them they reddened every arm except the six premises and the ten INSTRUMENT controls, which link nothing fromsrc/by design. So no shell arm was vacuous. Two things were wrong around the arms:memsetshort(the pack's memset stops one byte short), which goldens went red depended on what the previous call had written into that byte: 121 red on main. The battery now fills every key buffer with 0xa5 before the pack writes it (pk()), and the result is a stable 124. The C5 extent arms still fill their own buffers with 0x00 and 0xff and call the pack directly. The twin's driver does the same fill, and every twin buffer carries guard bytes, sooverrunreds the C5 tail arms instead of segfaulting.compare_to_bashrefused this whole suite.arms_unrunnableandarms_failedtook a list of names in one argument, so its 184 arms were never graded. They are now written out as loops at their call sites, and the grader reads the suite: missing 0, extra 0. The refusal arms keep their coverage.test_the_grader_itself_refuses_the_suite_it_cannot_readnow builds a fixture holding the two helpers as they stood. The pinned refused set becomesnone. Self-test 480's pinned emitters losearms_unrunnable, and its check is renamed "the refusal emitters are the ones the tree defines", ledger row with it.Mutants, PG17, shell then twin as shipped: SAME red sets for all 17.
notransposememsetshortnograymemset48notfixoverruntlowbitcollideundoskip0noexchangelowflip(the header's own 0x5a example)lowtoppackrevsetlastpack32rounds_up(a permutation with scattered sub-cubes; the only one that reds C3)low32Clean runs: 184/184 in both harnesses on each of 15–19. With
CC=/bin/false, both report 184 unrunnable. Withsrc/columnar_curve.cabsent, both fail the 174 battery arms by name, and the 10 controls still pass.Counts:
suites_not_covered113 → 112;Gates: guards 651 passed, collection 2454 =
cluster_tests, ledger gate rc=0, self-test PASSED.🤖 Generated with Claude Code