Repository navigation
test: native_parquet_schema gets its pytest twin, and bad magic must be refused by the magic check (#1341) - #1476
Merged
Merged
Conversation
…es ALTER EXTENSION UPDATE (#1341 item 66) Between installing a new library and running ALTER EXTENSION pgcolumnar UPDATE, a database runs the 1.0-alpha5 library over its 1.0-alpha4 catalog. The library deletes from pgcolumnar.retired_group, which that catalog lacks, so DROP TABLE, TRUNCATE and pgcolumnar.vacuum() on a columnar table fail there with 42P01 'columnar metadata table "pgcolumnar.retired_group" does not exist', which names neither the cause nor the remedy. Measured: each refusal changes nothing, reads and writes work throughout, and after the update all three succeed on the same rows. open_columnar_table's error now carries a hint naming the update. docs/installation.md's "If you skipped step 3" shows the error and the hint. Red first, both twins, PG18: native_upgrade_converge gains the window's arms in a database at the previous release's catalog (the newest fixture), and the three refusal arms fail on main with `got [42P01|no-hint]`. test_native_upgrade_converge.py is their partial twin, declared INCOMPLETE; it stages the previous release's base script from test/fixtures as the shell does. Green on 15-19 in both twins. cluster_tests 660 -> 661 by collection; TESTS.md gets section 143. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… still be set to a row store (#1341) test_fk_referencing.py asserts every shell check by name; compare_to_bash grades it as covering all 28 (27 checks on PG17+, and the pre-17 branch's own), and it joins COMPLETE. The conversion guard's over-rejection control converted a table with no foreign key back to heap, so it could not see a guard that refused every SET ACCESS METHOD on a referenced table whatever the target: with the guard's columnar-target test removed, the suite stayed 26/26. A new arm sets the referenced table itself to heap; under that mutant both twins now fail it. cluster_tests 661 -> 666 by collection; TESTS.md gets section 144. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tations of the foreign-key guards (#1341) 28 rows from five-major runs (27/27 on 17-19, 26/26 on 15-16). Dated on PG18 by: the referenced-side refusal removed (5), the guard keyed on the referencing table (8), the conversion refusal removed (8), and the conversion refused whatever the target (1). suites_not_covered 219 -> 218; the census is 3647 rows, 2686 never, 961 dated, restated on main db56168. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_truncate_cleanup.py asserts every shell check by name; compare_to_bash grades it as covering all 25, and it joins COMPLETE. It runs in a private database, since the snapshot counts every pgcolumnar catalog row and the shared one holds every other test's. The shell suite needed no change: each of its arms already goes red under a mutation of the path it names. cluster_tests 666 -> 672 by collection; TESTS.md gets section 145. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mutations of the truncate paths (#1341) 25 rows from five-major runs (25/25 on each of 15-19). Dated on PG18 by a rewrite that keeps the retired storage's rows (7) or its stale write state (1), an in-place truncate that skips the projections' storages (8), and a storage-tree delete that skips them (1). suites_not_covered 218 -> 217; the census is 3672 rows, 2695 never, 977 dated, restated on main db56168. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…zone-map answer that ignores deletes (#1341) test_native_dml.py asserts every shell check by name; compare_to_bash grades it as covering all 15, and it joins COMPLETE. The min/max arm could not fail as its comment claimed. The deletes (id % 7 = 0) removed neither the smallest nor the largest id, so min and max were the same whether or not the deleted rows counted; and measured with groups that hold deletes left on the zone-map path, min/max(id) still came out right while min/max(k) came out wrong (10|50000 for 20|49990). The suite stayed 13/13. The deletes now include ids 1 and 5000, a premise asserts on heap that min and max moved, and the arm takes min/max over k as well as id; under that mutant both twins fail it. The index arms gain a premise that the lookups take the primary-key index, so they test the index fetch's delete check rather than the scan. cluster_tests 672 -> 673 by collection; TESTS.md gets section 146. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ons (#1341) 15 rows from five-major runs (15/15 on each of 15-19). Dated on PG18 by: a row group with deletes still answering min/max from zone maps (1), count(*) from metadata not subtracting deleted rows (3), and the index fetch ignoring the delete vector (5). suites_not_covered 217 -> 216; the census is 3687 rows, 2702 never, 985 dated, restated on main db56168. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…longer pass its survival arm (#1341) test_native_dict_underfill.py asserts every shell check by name; compare_to_bash grades it as covering all 4, and it joins COMPLETE. It turns the post-codec encoding choice off for its own session, where the shell sets it for its database. The survival arm was a fresh SELECT 1, which a crashed backend passes once crash recovery has finished, and the suite computed a crash flag it never checked. It now counts "terminated by signal" in the server log. The rejection arm matched 'does not match|corrupt|invalid|out of' in any message, which "out of memory" satisfies too; it now requires XX001. A premise asserts the inflation rewrote the chunk's descriptor. cluster_tests 673 -> 674 by collection; TESTS.md gets section 147. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 rows from five-major runs (4/4 on each of 15-19). Dated on PG18 by the DICT fill check removed (1) and replaced by a crash (2, one shared). suites_not_covered 216 -> 215; the census is 3691 rows, 2704 never, 987 dated, restated on main db56168. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ers can see a double count and a deleted row (#1341) test_native_decode_gating.py asserts every shell check by name; compare_to_bash grades it as covering all 29, and it joins COMPLETE. It sets the width gate off for its session, where the shell pins it off for its cluster. Two of the filter counters' guarantees could not fail: - every row of the needle's surviving vector matched, so the producer's re-test of that vector rejected nothing, and a producer counting its rejections a second time read exactly right: with the non-counting filter disabled the suite stayed 26/26. A qual that half of vector 0 passes now asserts its rejections are counted once. - the counters were checked only on the table without deletes, so with the evaluator's deleted-row test removed the suite stayed 26/26. Rows Removed by Filter is now checked on the multi-group table with deletes, against heap's live count. The multi-group fixture's DELETE ran through the gating it was built to test (its WHERE is an unprunable qual too), so a gating mutant broke the fixture rather than the arms. It now runs with the width gate out of reach, and its premise counts the surviving rows with count(*) instead of a gated WHERE. cluster_tests 674 -> 676 by collection; TESTS.md gets section 148. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…our mutations of phase 2 (#1341) 29 rows from five-major runs (29/29 on each of 15-19). Dated on PG18 by: the per-vector evaluation never run (4), a deleted row counted as filtered (1), every vector skipped (7), and a double count in the producer (2). No premise is dated: the fixture no longer depends on the gating under test. suites_not_covered 215 -> 214; the census is 3720 rows, 2722 never, 998 dated, restated on main db56168. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d settings are proven absent by SQLSTATE (#1341) test_native_decode_gate_width.py asserts every shell check by name; compare_to_bash grades it as covering all 35, and it joins COMPLETE. It holds the threshold for its session, where the shell sets it per database because every helper opens a new connection. The two premises that the rejected probe settings were not shipped compared SHOW's output with the empty string: q returns empty for a dead connection too, and an empty expectation is the shape the pytest layer refuses. Both twins now require SHOW to raise 42704 (undefined_object). cluster_tests 676 -> 677 by collection; TESTS.md gets section 149. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y three mutations of the width gate (#1341) 35 rows from five-major runs (35/35 on each of 15-19). Dated on PG18 by gating whatever the width (2), > for >= (1) and a payload count one too high (1, shared). suites_not_covered 214 -> 213; the census is 3755 rows, 2754 never, 1001 dated, restated on main db56168. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…by arms test what they name (#1341) test_pg_dump_roundtrip.py asserts every shell check by name; compare_to_bash grades it as covering all 25 names (40 checks over the two formats), and it joins COMPLETE. It dumps a private source database and restores it into fresh ones. Two arms could not fail as claimed: - "restored index answers a point lookup" disabled seqscan and bitmapscan, but the columnar scan is neither, and with the index dropped from the restored database the lookup still answered 12345: the suite stayed 36/36. A premise now asserts the lookup's plan uses dt_id_idx. - "restored sort_by resolves and applies" checked the row count after vacuum_sorted, which is 20000 whatever it sorted on: with the sort keys replaced by column 1 the suite stayed 36/36. It now counts (host, ts) inversions in scan order, which must be 0, with a premise that the restored table has some before the call. cluster_tests 677 -> 680 by collection; TESTS.md gets section 150. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… mutations (#1341) 40 rows from five-major runs (40/40 on each of 15-19). Dated on PG18 by: options (6) and projection declarations (8) no longer registered with pg_extension_config_dump, rebuild_projections() skipping missing projections (7), drop_projection keeping its declaration (8), and vacuum_sorted on the wrong column (2). suites_not_covered 213 -> 212; the census is 3795 rows, 2778 never, 1017 dated, restated on main db56168. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dex (#1341) The shell's "the index still answers the same range" never touched the index: right after pg_upgrade there are no planner statistics, the planner took the columnar scan for the range even with seqscan off, and the arm passed with c_id dropped after the upgrade. The arm and a new premise now run with the custom scan off, and the premise asserts the plan scans c_id. test_pg_upgrade.py carries all 16 checks by the shell's name. Like the shell it needs two majors: --pg-config is the new one, PGC_UPGRADE_FROM_PG_CONFIG the old one, whose extension it builds from a copy of the tree. The matrix runs one major at a time, so there it declines, listed for 15-19 in expected_unrunnable.txt. cluster_tests 680 -> 681, TESTS.md section 151. The suite has its own check() and records nothing, so no ledger rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd names a refused step (#1341) jdatcmd, reviewing #1461: under root, initdb refused ("cannot be run as root"), _sh discarded the code, and the failure surfaced one step later as a FileNotFoundError for postgresql.conf. initdb, pg_ctl and pg_upgrade now go through _server_tool, which drops to postgres with runuser when euid is 0 (as pgc_cluster._asroot and lib.sh do), chowns the data directories, and raises naming the step and its stderr. initdb passes -U postgres, and the socket directory is the datadir, as pgc_cluster pins it. A failed make of the old major's extension now shows its stderr too. Measured as root (sudo, PG17 -> PG18): 585369d fails with that FileNotFoundError, this commit is 16/16. As a normal user: 16/16. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ms replay a write (#1341) Measured: compact on r retired nothing, because vacuum had already reclaimed every deleted row, so "compact replays identically" compared a state compact never changed. The fixture now gives compact one fully deleted row group, and a new arm asserts it was retired (1|1). "vacuum rewrote r into a new relfilenode on the primary" does the same for vacuum, and a premise pins r2's second batch, without which the module-less replay arms passed on a failed INSERT. Red first: with vacuum returning before it rewrites, the old shell is 41/41 green and the new one reddens the vacuum arm. With compact retiring nothing, the new compact arm is red. test_replication.py carries all 44 checks by the shell's name, on a private primary, a streaming standby and an isolated restore. COMPLETE gains replication, TESTS.md section 152, cluster_tests 681 -> 682. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ions (#1341) The suite had no rows. All 44 checks enter from five-major runs (44/44 on each of 15-19). Dated by: no SMGR truncate record, data and gap pages written without WAL, vacuum returning early, compact retiring nothing. suites_not_covered 212 -> 211; census 3839 rows / 2811 never / 1028 dated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e recluster's visibility-map rule (#1341 item 70) Two measured gaps in "index scan returns each row once": - with the index dropped after the recluster it stayed green, because with only seqscan and the custom scan off the count went through the disabled seqscan. Bitmap scans are off now too, and "premise: the count takes an index-only scan of n_id_uq" asserts the plan. - with recluster's PgColumnarVMClearForRowRange removed the whole suite stayed green: no VM bit was ever set, so every index-only probe fetched from the heap. A VACUUM before the recluster sets them (an arm checks the pre-recluster count answers from the index), and the old entries, still in the index, are then counted twice: 81409 for 40960. test_native_recluster.py carries all 14 checks by the shell's name. COMPLETE gains native_recluster, TESTS.md section 153, cluster_tests 682 -> 683. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…utations (#1341 item 70) The suite had no rows. All 14 checks enter from five-major runs (14/14 on each of 15-19). Dated by: no index entry for a rewritten row, no old group retired, the VM left set over the retired row numbers, AccessExclusiveLock, and a sort key of no columns. suites_not_covered 211 -> 210; census 3853 rows / 2817 never / 1036 dated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… its own reason (#1341 item 70) Three attribution faults, measured under mutations of the drop hook: - every cleanup arm compared with the suite's starting snapshot, so one leak reddened every arm after it: with the cleanup gated on the columnar AM, the never-columnar heap arm went red on aac_t's rows. Each now compares with the snapshot taken just before its own table. - REFRESH MATERIALIZED VIEW reused the CREATE arm's matview and went red as 'relation "rwm" does not exist'. It now refreshes a matview of its own, made WITH NO DATA (a premise), and reddens on the hook's own error. - "premise: and took pgcolumnar.options with it" went red when the member skip was removed, because DROP EXTENSION aborted: a product change, so an arm (#1236). test_alter_am_cleanup.py carries all 47 checks by the shell's name, in four tests on databases of their own. COMPLETE gains alter_am_cleanup, TESTS.md section 154, cluster_tests 683 -> 687. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… mutations of the drop hook (#1341 item 70) The suite had no rows. All 47 checks enter from five-major runs (47/47 on each of 15-19). suites_not_covered 210 -> 209; census 3900 rows / 2843 never / 1057 dated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… reuse turned off (#1341 item 70) With an online compaction never reserving from a freed range, the shell stayed 36/36 green. Measured why: - the four "repeated" recluster('n', 'id') calls each returned 0: recluster self-gates on a table already in that key's order, so they wrote nothing and the file plateaued with reuse disabled. They now alternate v and id, and a new arm requires each to rewrite. Without reuse the file then grows 311296 -> 901120, and the plateau arm reddens. - "free space is being reused (bounded, not growing per cycle)" asserted free_space > 0, the arm before it again. It now compares with the count after the first cycle, and reddens as 1 -> 5 rows. test_native_reclaim.py carries all 37 checks by the shell's name in three tests; maintenance_due's eight refusals are a loop table, so the loop-reader guard's file list gains native_reclaim. COMPLETE gains native_reclaim, TESTS.md section 155, cluster_tests 687 -> 690. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd the threshold guards (#1341 item 70) One new check enters never; 17 of the suite's never rows are dated from five-major runs (37/37 on each of 15-19). Census 3901 rows / 2828 never / 1073 dated; suites_not_covered unchanged (209). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ive" must reclaim (#1341) With pgcolumnar.vacuum() returning before it rewrote anything, the shell stayed 19/19 green: its alternative arms asserted only that vacuum() returned and kept the rows. A premise now counts the fixture's deleted rows (6666) when the table is made, before any REPACK can touch it, and "and it reclaimed the deleted rows" requires 0 after vacuum(). test_native_repack.py carries all 21 checks (and the shell's REPACK skip and dead-server names) on a private cluster at wal_level=logical, which REPACK (CONCURRENTLY) needs. Below 19 it declines UNSUPPORTED_MAJOR, listed for 15-18 in expected_unrunnable.txt. The loop-reader guard's file list gains native_repack. COMPLETE gains native_repack, TESTS.md section 156, cluster_tests 690 -> 691. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ations (#1341) The suite had no rows. 21 checks enter from PostgreSQL 19 and the REPACK skip from 15-18. suites_not_covered 209 -> 208; census 3923 rows / 2838 never / 1085 dated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_native_join_vector_agg.py carries all 13 checks by the shell's name. The shell needed no change: removing the join-filter check, the key and uniqueness checks, or the join-rel path each reddens it, and its ledger rows for those are already dated. COMPLETE gains native_join_vector_agg, TESTS.md section 157, cluster_tests 691 -> 692. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_native_writer.py carries all 10 checks by the shell's name. The shell needed no change: each of its catalog arms reddens under a mutation of the writer or of the drop cleanup. COMPLETE gains native_writer, TESTS.md section 158, cluster_tests 692 -> 693. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ions (#1341) The suite had no rows. suites_not_covered 208 -> 207; census 3933 rows / 2841 never / 1092 dated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rence cannot be the fold (#1341) The arm "the folded aggregate equals the non-fold aggregate" trusted that FOLDOFF turned the fold off. Measured: with FOLDOFF leaving the fold on and the payload list missing v, the shell stayed 4/4 green, both sides reading the same wrong sum. "premise: the reference runs without the batch fold" now reads the reference's EXPLAIN ANALYZE, and "the non-fold aggregate equals the generator's own answer" checks the reference against a query with no table in it. test_native_batch_fold_projection.py carries all 6 checks by the shell's name. COMPLETE gains native_batch_fold_projection, TESTS.md section 159, cluster_tests 693 -> 694. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#1341) The suite had no rows. Dated by the payload list omitting the last column and the fold never taken. suites_not_covered 207 -> 206; census 3939 rows / 2845 never / 1094 dated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… closes the reader side (#1341) The suite pins the descriptor's bytes and then claims the table "reads back". Measured: with the reader taking rawLen and encLen from each other's offsets, the shell stayed 16/16 green. The bytes on disk were right, and count(*) and sum(a) are answered from the catalog and the zone maps without decoding a page. "every row reads back as the generator wrote it (a decoding read)" compares every row's text with the generator's, and reddens. test_native_encdesc_golden.py carries all 17 checks by the shell's name. COMPLETE gains native_encdesc_golden, TESTS.md section 160, cluster_tests 694 -> 695. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…our codec mutations (#1341) The suite had no rows. suites_not_covered 206 -> 205; census 3956 rows / 2853 never / 1103 dated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…be refused by the magic check (#1341) "bad magic rejected (empty At output)" passed on any error. Measured: with the PAR1 magic check skipped, the same 33-byte file is still refused, as a corrupt footer, and the shell stayed 35/35 green. The arm now requires the magic check's own message, "is not a Parquet file (bad magic)". test_native_parquet_schema.py carries all 35 checks by the shell's name in two tests; the six that need pyarrow to write their fixture decline through require_module, as the shell's skip them. COMPLETE gains native_parquet_schema, TESTS.md section 161, cluster_tests 695 -> 697. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ive reader mutations (#1341) The suite had no rows. suites_not_covered 205 -> 204; census 3991 rows / 2883 never / 1108 dated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jdatcmd
approved these changes
Oct 16, 2026
jdatcmd
left a comment
Collaborator
There was a problem hiding this comment.
Approving b20dbb2.
Measured on PG17: native_parquet_schema.sh 35/35.
test_native_parquet_schema.py passes its first test here (29 checks). It declines its pyarrow test, because my root pytest environment has no pyarrow (the shell's system python3 does). That's a correct decline here: CI's cluster job installs pyarrow and sets PGC_REQUIRE=pyarrow, so the six checks run there.
The magic mutant, run myself: the PAR1 check skipped (if (false && …)).
| suite | result |
|---|---|
| main's shell | 35/35 green |
| this PR's | bad magic is rejected by the magic check, got [no (ERROR: … has a corrupt Parquet footer)] |
| the twin | the same arm, got 'no (… has a corrupt Parquet footer)' |
The tsv at this head is 3991 / 2883 / 1108. My chain #1451 → #1459 → #1475 also touches the ledger, so whichever lands second restates.
Collaborator
This was referenced Oct 16, 2026
jdatcmd
added a commit
that referenced
this pull request
Oct 16, 2026
… 3 (#1478) pgc_source_stamp_path keyed an unreadable pg_config on md5(path) cut to three hex characters, 4096 values. Selftest 340's "two unreadable pg_configs do not alias onto one stamp" builds its two broken pg_configs in a random mktemp directory, so they collided about once in 4096 runs. #1476's suites (PG 18) job hit one, though the same head passed twice locally. Red first: a new arm uses two paths, under /tmp/pgc-collide-870, whose md5s share their first three hex characters (235) and differ at eight. With three characters it is SAME on every run; the key now keeps eight, as the readable branch does, and the arm reads "different". The paths need not exist: the key hashes the path string. harness_selftest 1246/1246; the guards pass (438). The measured example in 340's comment is re-measured for the new width. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jdatcmd
added a commit
that referenced
this pull request
Oct 16, 2026
… 3 (#1478) pgc_source_stamp_path keyed an unreadable pg_config on md5(path) cut to three hex characters, 4096 values. Selftest 340's "two unreadable pg_configs do not alias onto one stamp" builds its two broken pg_configs in a random mktemp directory, so they collided about once in 4096 runs. #1476's suites (PG 18) job hit one, though the same head passed twice locally. Red first: a new arm uses two paths, under /tmp/pgc-collide-870, whose md5s share their first three hex characters (235) and differ at eight. With three characters it is SAME on every run; the key now keeps eight, as the readable branch does, and the arm reads "different". The paths need not exist: the key hashes the path string. harness_selftest 1246/1246; the guards pass (438). The measured example in 340's comment is re-measured for the new width. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jdatcmd
added a commit
that referenced
this pull request
Oct 16, 2026
… 3 (#1478) pgc_source_stamp_path keyed an unreadable pg_config on md5(path) cut to three hex characters, 4096 values. Selftest 340's "two unreadable pg_configs do not alias onto one stamp" builds its two broken pg_configs in a random mktemp directory, so they collided about once in 4096 runs. #1476's suites (PG 18) job hit one, though the same head passed twice locally. Red first: a new arm uses two paths, under /tmp/pgc-collide-870, whose md5s share their first three hex characters (235) and differ at eight. With three characters it is SAME on every run; the key now keeps eight, as the readable branch does, and the arm reads "different". The paths need not exist: the key hashes the path string. harness_selftest 1246/1246; the guards pass (438). The measured example in 340's comment is re-measured for the new width. 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 #1474 (merge after it). Two commits:
75ac07ed(the twin and the shell fix) andb20dbb24(the ledger seed).What was wrong
"bad magic rejected (empty At output)" asserted only that the query printed nothing, and any error satisfies that. With the PAR1 magic check skipped, the same 33-byte file is still refused, as
has a corrupt Parquet footer, and the shell stayed 35/35 green. The arm, now "bad magic is rejected by the magic check", requires the magic check's own message,is not a Parquet file (bad magic).Mutations of the reader (PG18)
corrupt Parquet footer)type of c_i2REQUIRED column reports nullable=ffield ids report as written(0,1,2)a file without field ids reports NULL, not zero(0/2)The twin
test_native_parquet_schema.pycarries all 35 checks by the shell's name (compare_to_bash: 9 literal, 2 template, 0 missing), in two tests. The six checks that need pyarrow to write their fixture are in the second test. It declines throughrequire_moduleas its first outcome, matching the shell's six named skips. Files go inserver_dir.Runs
Head is 35/35 in both twins on each of 15, 16, 17, 18 and 19, with pyarrow installed.
Ledger
suites_not_covered205 → 204. The census is 3991 / 2883 / 1108.pgc_ledger.py gatereturns rc 0.Counts and guards
cluster_tests695 → 697, and pytest collects 697.COMPLETEgains the suite, and TESTS.md gains §161.harness_selftest.shpasses, anddocs_style.shpasses.🤖 Generated with Claude Code