Skip to content

Specializer wave 5: structural + dialect sweep — corpus 395 -> 484 (TASK-52) - #38

Merged
claude-agent-ahrzb[bot] merged 10 commits into
masterfrom
task-52
Jul 26, 2026
Merged

Specializer wave 5: structural + dialect sweep — corpus 395 -> 484 (TASK-52)#38
claude-agent-ahrzb[bot] merged 10 commits into
masterfrom
task-52

Conversation

@claude-agent-ahrzb

Copy link
Copy Markdown

What

The wave-5 structural + dialect sweep: ten commits taking served-bit-exactly from 395 to 484 of 678 (58% -> 71%), zero wrong answers and zero replay FAILs throughout. Pins-first as always: an 8-agent measurement fleet (7 DuckDB areas + a sqlparser capability spike) committed as docs/superpowers/specs/2026-07-26-wave5-structural-pins.md + pins-wave5/*.json before any implementation, with a post-landing addendum recording the corrections the corpus caught.

Stages (each landed with tests + corpus replay green)

Stage Corpus What
1a 395 Frontend parses with GenericDialect — measured strict superset of DuckDbDialect (adds ^@, * ILIKE, * RENAME); corpus byte-identical
1b 397 Colon prefix alias k: expr via token pre-rewrite — sqlparser misparses it silently as a Snowflake JSON path, so no parse-error fallback could ever catch it
2 427 Bracket subscripts + slices s[i] / s[a:b] bound onto the wave-3 kernels: chained access, open-bound desugar ([:b][1:b], NULL is NOT an open bound), step-slices reject, and the asymmetric ±2^32 runtime trap window per-row on both backends
3 431 Bitwise << >> & | + xor(): new i64 BinOps with DuckDB's five-step << trap ladder and total >>; DuckDB puts all four in ONE flat left-assoc tier while sqlparser tiers them, so the frontend re-associates maximal runs in source order; ^ stays unsupported (it is pow with an unmirrorable precedence); fold shares the duck_shl kernel so folding and trapping can never disagree
4 446 ^@ -> the starts_with kernel; GLOB gets a dedicated byte-level matcher (one-byte ?, byte-set classes where only ! negates and ^ is literal, [a-] is dead, \ escapes outside classes, malformed patterns match nothing) reached via a LIKE __glob_pat(...) marker rewrite; NOT GLOB stays a parse error exactly like DuckDB
5 477 Star forms: name filters * LIKE/ILIKE/NOT LIKE/GLOB over column names, qualified EXCLUDE, * REPLACE, * RENAME — and the duplicate-name contract: DuckDB's own boundary rename (left-to-right, own-case _N, case-insensitive collision check incl. candidates), identical to its subquery rename and .df() dedup, verified against .df()
6 484 Binder tail: lateral aliases with real-column-wins shadowing in SELECT and WHERE, NULL <op> NULL typing by operator, main.tbl qualifier, NATURAL JOIN desugared to USING with the pinned hard error, t AS u(x, y) via a Cow column view, mixed BETWEEN/IN literal casts with half-away rounding

Corpus-caught corrections (the three-outcome contract at work)

Two replay FAILs during stage 6, both fixed and recorded in the spec addendum: NULL ^@ NULL needed Str-typed nulls, and non-numeric string literals in an IN-list against a column stay clean-unsupported because DuckDB converts at execution time — the corpus case on an empty table succeeds.

Verification

  • 148 Rust tests + 553 py tests green; interp backend identical except the deliberate backend-identity guards from the bench-guard fix
  • Corpus replay: 484 match / 192 clean-unsupported / 2 known-divergent, zero FAILs
  • clippy clean on all wave files
  • Serving-bench parity gate passed on all four scenarios; typed path at 1.4–2.0× over handcrafted python in 16/16 cells — 27 new surface forms cost the hot path nothing

🤖 Generated with Claude Code

ahrzb and others added 10 commits July 26, 2026 23:49
…zed scope

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…sured before implementation (TASK-52)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ict superset (TASK-52 stage 1a)

Spike (pins-wave5/sqlparser-spike.json): GenericDialect accepts every form
DuckDbDialect did plus ^@ (PGStartsWith), * ILIKE, * RENAME; nothing was
DuckDbDialect-only. Regression net: cargo test 129 green, py gate 545+13
green, corpus replay byte-identical (395 match / 281 unsupported / 2
known-divergent, zero FAILs).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… corpus 395 -> 397 (TASK-52 stage 1b)

sqlparser parses DuckDB's colon alias SILENTLY WRONG (Snowflake JsonAccess)
under every dialect, so no parse-error fallback can catch it; rewrite.rs
desugars 'ident COLON' at select-item start to 'expr AS ident' on the token
stream before parsing. Handles quoted aliases, nested selects, DISTINCT/ALL,
and leaves :: casts and bracketed slice colons untouched. The binder's
JsonAccess rejection stays as backstop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… 397 -> 427 (TASK-52 stage 2)

The wave-3 kernels (StrOp2i::Extract, SKind::Sslice) already matched the
wave-5 pins; this binds the bracket AST syntax onto them: chained access,
open-bound desugar ([:b]==[1:b], [a:]==[a:-1] — NULL is NOT an open bound),
step slices reject with DuckDB's not-implemented shape, and the extract
index gets substr's +-2^32 runtime trap window on both backends (per-row,
NULL-skipped, matching pins-wave5/subscripts-extended.json).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ation — corpus 427 -> 431 (TASK-52 stage 3)

New i64 BinOps on both backends: Ishl with DuckDB's five-step trap ladder
(negative value even << 0, negative count, zero shortcut before the range
check, count >= 64, overflow at 2^(63-count) via i128), Ishr total
(out-of-range counts -> 0, arithmetic otherwise), Iand/Ior/Ixor plain
two's-complement. DuckDB puts << >> & | in ONE flat left-assoc tier while
sqlparser tiers them — the frontend re-associates maximal runs in source
order before binding (user parens stop the flatten). xor is function-only;
^ stays cleanly unsupported (it is pow with a precedence sqlparser can't
mirror). Fold reuses the same duck_shl kernel so folding and trapping
can never disagree.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…her — corpus 431 -> 446 (TASK-52 stage 4)

^@ binds to the existing starts_with kernel (byte-prefix, VARCHAR-only, no
implicit casts). GLOB gets a real byte-level matcher (StrOp2::Glob, both
backends): ? consumes ONE byte (not a codepoint), classes are byte-sets
where only ! negates ('^' is a literal member), ']' is literal-if-first,
'-' literal-if-first else a range whose endpoint may be ']' ('[a-]' is
dead), backslash escapes outside classes only (dangling = dead), and
malformed patterns match nothing rather than erroring — all measured
(pins-wave5/text-operators.json). sqlparser can't parse GLOB at all, so
rewrite.rs turns infix GLOB into LIKE with a __glob_pat identity marker
the binder unwraps; NOT GLOB stays a parse error exactly like DuckDB, and
the marker name is reserved at the frontend gate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…orpus 446 -> 477 (TASK-52 stage 5)

Star forms per pins-wave5/star-forms.json: name filters * LIKE/ILIKE/
NOT LIKE/GLOB over declared-case column names (LIKE cs, ILIKE Unicode
fold, GLOB via the byte matcher; zero matches errors, filter follows
EXCLUDE), * REPLACE (position/name kept, type may change, sees EXCLUDEd
originals), * RENAME (silent on nonexistent targets, ambiguous renames all
copies), qualified EXCLUDE (strips one table's copy; unqualified strips
all; EXCLUDE of a USING-merged column stays unsupported — DuckDB unmerges
it). sqlparser can only parse * ILIKE and treats it as mutually exclusive
with EXCLUDE, so rewrite.rs encodes the real operator AND any absorbed
EXCLUDE entries into a marker inside the ILIKE pattern.

Duplicate output names: the frontend reject is gone — dedup_output_names
applies DuckDB's own boundary rename (left-to-right, first keeps its name,
own-case _N smallest free, case-insensitive collision check covering
generated candidates: id,ID -> id,ID_1; id,id,id_1 -> id,id_1,id_1_1).
Identical to DuckDB's subquery/CTE/CTAS rename and .df() dedup, verified
against .df() in tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…), NULL-op typing, mixed IN literals — corpus 477 -> 484 (TASK-52 stage 6)

Per pins-wave5/binder-tail.json: lateral aliases with real-column-wins
shadowing in SELECT and WHERE (WHERE now binds after the projection so
DuckDB's alias-in-WHERE extension resolves; forward references get the
pinned cannot-be-referenced-before-defined error); NULL <op> NULL types by
operator (+ - * % BIGINT, / DOUBLE, comparisons BOOLEAN, ^@/|| VARCHAR);
main.tbl resolves to the bare dynamic table while other schema qualifiers
stay unsupported (DuckDB itself errors, never a bare-name fallback);
NATURAL JOIN desugars to USING over common columns case-insensitively with
the pinned hard error when none exist; t AS u(x, y) renames via a Cow
column view (partial list = prefix rename, old names and the original
table name fully shadowed, positions unchanged so marshalling still uses
the original field names); BETWEEN/IN numeric-with-string/bool LITERALS
cast to the numeric side (half-away rounding) — non-numeric literals stay
clean-unsupported because DuckDB converts at EXECUTION time (an empty
input succeeds; caught by corpus replay, not guessed).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t fixes, TASK-52 all ACs checked + Done

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@claude-agent-ahrzb
claude-agent-ahrzb Bot merged commit ba8bf98 into master Jul 26, 2026
1 check passed
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.

1 participant