Skip to content

Wave A structural tails: structs-as-lanes + dialect/regex/ingest tails — corpus 511 -> 529 (TASK-56) - #43

Merged
claude-agent-ahrzb[bot] merged 8 commits into
masterfrom
task-56-wave-c
Jul 28, 2026
Merged

Wave A structural tails: structs-as-lanes + dialect/regex/ingest tails — corpus 511 -> 529 (TASK-56)#43
claude-agent-ahrzb[bot] merged 8 commits into
masterfrom
task-56-wave-c

Conversation

@claude-agent-ahrzb

Copy link
Copy Markdown

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)

  • Structs of scalars — struct row columns (nested pydantic models) flatten to scalar lanes at bind time. a.* (incl. EXCLUDE/REPLACE with measured case-insensitivity + alias-case naming), deep field paths (t.t.t.t through 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.
  • Lazy non-scalar rejection — unmappable row columns (timestamps, lists) reject on reference (star included), not at construction; EXCLUDE/filters/REPLACE remove them. Wide models with unused date fields now serve scalar queries.
  • FROM b : a prefix alias — token rewrite to a 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 via unicode-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.
  • Paren-less * 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

  • Corpus replay: 529 match / 149 clean-unsupported / 0 FAIL of 678 (was 511).
  • cargo 163 green; pytest 607 passed + 13 xfail (fuzzer + limitations twin included).
  • Cranelift verified serving struct + reverse queries (no silent interp fallback).
  • docs/known-limitations.md updated in lockstep (§3 structs serve, reverse row removed, §5 n-part registry-noise consequence documented).

🤖 Generated with Claude Code

ahrzb and others added 8 commits July 28, 2026 02:39
…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>
@claude-agent-ahrzb
claude-agent-ahrzb Bot merged commit bfe711e into master Jul 28, 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