Wave A structural tails: structs-as-lanes + dialect/regex/ingest tails — corpus 511 -> 529 (TASK-56) - #43
Merged
Merged
Conversation
…TASK-56 stage 1) Census re-cut the wave: true lists/structs pool is 7 cases, not ~25. Six-agent pins fleet measured struct-star/nested resolution, FROM colon alias, reverse() (ASCII fast path splits CRLF!), COLUMNS(* REPLACE), paren-less star modifiers, and NULL regex patterns. Stage 1: unmappable row-model columns are now OPAQUE binder entries (position + name) instead of construction errors — they reject on REFERENCE (star expansion included, model-order interleaved), and EXCLUDE/name-filter/REPLACE remove them. Unreferenced timestamp fields no longer block scalar queries. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…regex args, reverse() via UAX-29 (TASK-56 stages 2-5) - rewrite_from_colon_aliases: 'FROM x : T' -> 'FROM T AS x' (measured identical to AS in every behavior; ident-chain right sides only). - rewrite_parenless_replace: '* REPLACE e AS c' wraps ONE item in parens (comma starts a new select item — measured, dup names included); wildcard-star check keeps '3 * replace AS x' multiplication intact. - CAST(NULL AS VARCHAR) recognized as NULL in regex pattern/replacement/ options slots (NULL result / pinned options error, per family member). - reverse(): StrOp1::Reverse in both backends — ASCII inputs BYTE-reverse (DuckDB fast path, splits CRLF), otherwise UAX-29 extended graphemes via unicode-segmentation; no implicit casts (binder error). Lifts the wave-3 descope; its reject test flipped to 10 oracle-pinned cases. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ion path (TASK-56 stage 6) sqlparser already parses the star-with-modifiers argument as WildcardWithOptions — measured identical to the bare '* <modifiers>' select item (pins-waveA/columns-replace.json), so one new arm routes it through expand_star. Alias stamping and the regex-form parser error keep their existing behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nd-time flattening (TASK-56 stage 7) Struct columns (nested pydantic models) flatten to scalar leaf LANES appended after the plain columns; no struct value exists at runtime, so IR/verify/exec are untouched and both backends work unchanged. - plan::StructCol/StructField/StructNode describe the shape; leaf lanes are dotted-path Cols whose names double as the ingest path (both the marshaller and the generic boundary walk them, None short-circuits to NULL leaves — DuckDB's NULL-struct pins fall out for free). - Binder: n-part dotted references resolve longest-qualifier-first WITH BACKTRACKING on column-bind failure (pins-waveA/struct-nested.json); field walks after a bound column are hard errors with DuckDB's shapes. - a.* struct-star expands in place (bare field names, declaration order), EXCLUDE/REPLACE case-insensitive even quoted, REPLACE alias case becomes the output name, table alias still beats the struct column; nested/unmappable fields ride as removable non-scalar entries. - Whole-struct values are named rejections; table stars treat struct columns like opaque ones (EXCLUDE/REPLACE remove them); empty select lists get DuckDB's pinned message. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…itations contract updated (TASK-56 stage 8) - Replay harness builds nested pydantic models from arrow struct types, so the six struct corpus cases replay for real: 529 match / 149 clean-unsupported / 0 FAIL of 678. - tests/test_duckdb_wavea_structural.py: oracle + pinned-value tests for every scope item (struct star/fields/rejections, FROM colon alias, reverse incl. the CRLF ASCII-path row, COLUMNS(* REPLACE), paren-less REPLACE comma rule, NULL regex patterns, lazy non-scalar w/ datetime). - known-limitations.md: reverse() row REMOVED (lifted, twin flipped); structs-of-scalars now documented as SERVING with the named residual rejections (whole value, bracket access, non-scalar fields); lazy reference-time rejection documented; §5 registry-noise extended to n-part struct paths (longest-prefix consequence stays a loud reject). - Twin: reference-time rejection + struct-fields-serve contract tests. Full gate: cargo 163, pytest 607 + 13 xfail, fuzzer included; cranelift verified serving struct+reverse queries. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…est lever; columnar path is the real one Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…g-$ row-path bug + RE2 program-size budget
The standing fuzzer's 20k-case deep run on seed 20260728 caught:
- Class 13: DuckDB's row path literal-optimizes a leading '$'+literal
into a PREFIX match ('$hello' matches 'hello world') while its own
constant fold matches normally — self-inconsistent, unservable.
Reject: unescaped '$' outside a class not followed by end, '|', ')',
'$', or an anchor escape.
- Class 14: counted repetitions can blow RE2's POST-SIMPLIFICATION
program budget ('(\p{L}){1,500}' is 'pattern too large' in DuckDB)
where rust-regex still compiles. Guard: one-sided weight estimate
(\p/\P = 800 range-units, classes = member count, literals 4;
threshold 100k, below the measured ~216k error floor) — the engine may
over-refuse but can never serve where DuckDB errors.
Pins: pins-waveB/fuzzer-20260728.json. Doc + twin rows added. Gates:
cargo 163, pytest 609 + 13 xfail, corpus 529 unchanged, 20k re-sweep on
the finding seed divergence-free.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ahrzb
approved these changes
Jul 28, 2026
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.
Wave A: structural tails — corpus 511 → 529 (TASK-56)
The census re-cut this wave: the old "~25 lists/structs cases" bucket dissolved into 6 real struct cases + assorted type gaps, and zero corpus cases need the list-valued regexp forms. Approved scope ("A makes sense"): a structural-tails wave with no new runtime types.
What now serves (all pins-first,
pins-waveA/*.json+ spec)a.*(incl. EXCLUDE/REPLACE with measured case-insensitivity + alias-case naming), deep field paths (t.t.t.tthrough 8 parts) with DuckDB's longest-prefix-with-backtracking resolution, NULL-struct → NULL fields for free. Whole-struct values, bracket access, and non-scalar fields stay named rejections.EXCLUDE/filters/REPLACEremove them. Wide models with unused date fields now serve scalar queries.FROM b : aprefix alias — token rewrite toa AS b(measured identical in every behavior).reverse()— lifts the wave-3 descope. Measured: DuckDB byte-reverses all-ASCII strings (splits CRLF!) and reverses UAX-29 extended grapheme clusters otherwise — implemented exactly that way viaunicode-segmentation. The limitations row is removed and its twin test flipped in the same commit.COLUMNS(* REPLACE/EXCLUDE …)— measured identical to bare* <modifiers>; routed through the same expansion.* REPLACE e AS c— consumes exactly ONE item (a comma starts a new select item — measured, dup-name behavior reproduced).CAST(NULL AS VARCHAR)regex arguments — NULL pattern/replacement → NULL result across the family; NULL options keep the pinned per-function asymmetry.Gate
docs/known-limitations.mdupdated in lockstep (§3 structs serve, reverse row removed, §5 n-part registry-noise consequence documented).🤖 Generated with Claude Code