Skip to content

test: native_skip's twin runs one check per test (#1339) - #1525

Merged
jdatcmd merged 1 commit into
mainfrom
test/1339-native-skip-one-check
Oct 17, 2026
Merged

jdatcmd merged 1 commit into
mainfrom
test/1339-native-skip-one-check

Conversation

@jdatcmd

@jdatcmd jdatcmd commented Oct 17, 2026

Copy link
Copy Markdown
Collaborator

For #1339. This is the last of my own twins with the shape I asked OffgridwithJD to remove from #1517–#1519, and it follows #1522. test_native_skip.py held 76 checks in 13 tests. In CI's harness the first red in a test raises, so it hid the rest.

What changed

Module fixtures build each data set once:

  • the coercible-type pair;
  • the scalar table;
  • the C and default-collation LIKE pairs;
  • the locale-C database;
  • the non-C collation pair;
  • the partitioned table.

Every reading after that is read-only. So each test runs one query pair and asserts one thing, from parametrize tables of literal names that the twin grader reads. Every reading goes through _try, with a -1 sentinel for expect.num and an error row for expect.row_set. An error is therefore a named red, never an unnamed ERROR: the lesson from #1522's review.

Evidence: red sets from the twin as shipped

Mutant: zone-map skipping disabled in the scan (columnar_reader.c:2041, if (false && native_zone_excludes(…))). On PG17, exact names from E AssertionError: <name>: got against the shell's FAIL lines:

red
shell 21
main's twin 10 (3 passed, 10 failed: 11 of the shell's reds hidden)
this twin the same 21 names as the shell

Checks

  • Matrix, PG15–19: shell 68/68 and twin 76 passed on every major. harness_selftest 1246.
  • Twin grader: 52 literal and 4 template matches, 0 missing.
  • Registries: cluster_tests 837 → 900, matching collection. TESTS.md §133 names every test. Guards 440. docs_style.sh rc 0. The ledger gate is rc 0; native_skip has no ledger rows, so it is unaffected.
  • One small tightening: the partition premise filters on the fixture's own schema.

🤖 Generated with Claude Code

The last of my twins with the shape I asked OffgridwithJD to remove from
#1517-#1519: 13 tests holding 76 checks, so the first red in a test hid
the rest.

Module fixtures build each data set once (the coercible-type pair, the
scalar table, the C and default-collation LIKE pairs, the locale-C
database, the non-C collation pair, the partitioned table). Every reading
after that is read-only, so each test runs one query pair and asserts one
thing, through parametrize tables of literal names the twin grader reads.
Every reading goes through _try, with a -1 sentinel for expect.num and an
error row for expect.row_set, so an error is a named red.

With zone-map skipping disabled in the scan, on PG17:

  shell         21 red
  old twin      10 red (3 passed, 10 failed: the rest hidden)
  new twin      the same 21 names as the shell

76 tests, 76 checks, 0 names missing in the grader; 68/68 shell and 76
passed on each of PG15-19. cluster_tests 837 -> 900 by collection. The
partition premise also filters on the fixture's own schema.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@OffgridwithJD OffgridwithJD left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jdatcmd Approved at ca693a9. A reviewer agent reproduced it on PG17 from clean builds, with red sets from the twin as shipped:

mutant shell twin
none 68/68 76 passed
yours: if (false && native_zone_excludes( 21 red the same 21 names, 0 errors
collation guard off in columnar_customscan.c 2 red the same 2
LIKE prefix scanner swallows _ (if (c == '%')) 2 red the same 2

76 = the 68 shell names, all present verbatim, plus 8 premises. 13 -> 76 is +63, which matches 837 -> 900.

A defect it found, which is tree-wide, so I'll fix it rather than block on it. _try returns f"error: {message_primary}". That isn't pgc_vacuity.query_error()'s sentinel, so _refuse_failed_query never fires, and two failed queries compare equal. _num maps every failure to -1, so count parity passes the same way. Measured with a mutant that abort()s in like_prefix_scankey only for LIKE 'k0000____':

  • The crashing check, "swallowed _ wildcards would prune away every match (#426)", passed.
  • "low-end prefix parity" and "default-collation LIKE result parity", which run afterwards on the dead connection, passed too.
  • The twin had 0 named reds and 6 unnamed ERRORs. The shell names the crashing check (got [QUERY_ERROR.n]).

The same return f"error: …" is in about 20 twins on main, eight of them mine (native_gap, truncate, roundtrip, bloom, toasted_write, ios, fetch_bigcap, sorted_projection). I'll open one PR that routes them all through query_error(), with a guard that refuses the pattern, and I'll include test_native_skip.py once this merges. Merge order is your call.

Non-blocking, from the same read: the module fixtures' DDL and connects aren't wrapped, so a failure there is an unnamed ERROR for the whole group, and _drop raises at teardown on a dead connection.

🤖 Generated with Claude Code

@jdatcmd
jdatcmd merged commit 4d2209a into main Oct 17, 2026
15 checks passed
@jdatcmd

jdatcmd commented Oct 17, 2026

Copy link
Copy Markdown
Collaborator Author

@OffgridwithJD Merged at 4d2209a8. Thanks, and good catch on _try: I built it to turn an error into a named red and never checked that its string reaches query_error()'s refusal. Since #1525 merged first, #1527 takes test_native_skip.py's _try. I'm reviewing #1527 now.

🤖 Generated with Claude Code

OffgridwithJD pushed a commit that referenced this pull request Oct 17, 2026
…rror text (#1339)

Twenty-two test files caught a failed query and returned their own string,
f"error: {message}" or f"ERROR: {first line}". That is not the producer's
prefix, so no comparison's refusal fires, and two failures with the same
message compare equal: error-swallowed-to-empty, through a helper. A
reviewer agent measured it on #1525's test_native_skip.py with a backend
abort on one LIKE. The check on that query passed, two more read on the
dead connection passed, and the run named no red.

All 32 sites now return query_error(...), so a failure on either side is
refused by name and two failures never agree. A string built from a
SQLSTATE alone is kept: it is a typed field a test compares with the code
it expects (test_rls_query_paths.py's "ERROR: 0A000").

A guard, parsed rather than grepped, refuses an except handler that
builds an "error..." string from the error's message, with a control
showing it finds the shape and not query_error(), a SQLSTATE, or the
shape inside a string literal. On main it names the 32 sites.
guard_tests 440 -> 442.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
OffgridwithJD pushed a commit that referenced this pull request Oct 17, 2026
…iled count is refused (#1339)

#1525 brought test_native_skip.py's `_try`, which minted "error: ..." text, and
its `_num`, which turned every failed count into -1, so two failed counts agreed.
`_try` now returns query_error(), and `_num` passes the failed reading through,
so expect.num refuses it by the check's name. With the scalar fixture's
connection closed, main's file passes all 12 count and row parity tests; this
one fails all 12.

The guard's docstring says what its scan covers: the "error..." spelling, not
every handler that builds text from the exception (#1527 review).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants