Specializer SQL support: workload builtins & predicates wave 1 — corpus 172 → 240 (TASK-47) - #32
Merged
claude-agent-ahrzb[bot] merged 12 commits intoJul 26, 2026
Conversation
…easurement-first stretch plan Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t for TASK-47 Six-family measurement fleet against DuckDB 1.5.5 through the vectorized path; full pin tables (300+ rows) in pins-wave1/*.json, implementation-shaping decisions condensed in the spec. Headlines: 1-arg log is BASE 10; log(b,x) is bit-exactly log10(x)/log10(b); log family traps on x<=0 while exp/pow/cbrt are total; trig traps on +-inf but passes NaN through bit-exactly; ^ is pow with -2^2=+4 and left associativity; least/greatest ignore NULLs with first-arg ties; round(x,-n) wraps at i64 and needs an oracle-pinned pow10 table; string positions are 1-based codepoints with empty-needle-matches-all; BETWEEN and IN are exact K3 desugars. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ch 2) Pure frontend rewrites onto the existing comparison + Kleene machinery — zero IR/backend changes. DuckDB's whole-construct type unification is reproduced by promoting every side to DOUBLE when any side is (CAST in the rewritten AST, no-op on f64 sides, types NULL literals from context); numeric-with-string/bool mixing rejects by name (exec-time cast semantics we don't model). The pinned truth tables — NULL in every position, NaN-above-inf, empty ranges, signed zeros, NULL list elements (1 IN (1,NULL)=TRUE, 3 IN (1,NULL)=NULL), NOT variants — land as duck_check oracle tests. Corpus: 172 -> 179 match; the remaining BETWEEN corpus cases move to NAMED deeper blockers (COUNT aggregation shapes, NULL-op-NULL typing), zero FAILs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…2/log10/exp/sqrt/cbrt/sin/cos/tan/floor/ceil/trunc/pow (TASK-47 stretch 3a) Fourteen ops end-to-end: IR (NumOp1 + Fpow/Flogb BinOps), parser, verifier-by-sig, interpreter closures over ONE shared semantic fn per op, cranelift helpers delegating to those same fns (floor/ceil/trunc inline CLIF), fuzz generator coverage (trapping ops at low weight — trap agreement is differential signal), frontend catalogue with int->f64 promotion and DuckDB's binder rejections, and NULL-safe lowering: trapping unaries mask NULL payloads to op-safe constants (1.0 for logs — the type default 0.0 is IN the trap domain), and Flogb masks BOTH operands under the COMBINED flag because NULL pre-empts every domain check (pinned: log(-2.0, NULL) is NULL). 1-arg log is base 10; log(b,x) is log10(x)/log10(b) bit-exactly; trig traps on +-inf and passes NaN through untouched; pi() folds to the pinned literal. The ^ operator stays cleanly UNSUPPORTED: sqlparser parses it below * while DuckDB binds it above (measured tree divergence) — pow()/power() carry the semantics; ** does not parse. 21 oracle tests incl. 49-row IEEE pow specials and huge-arg trig reduction fidelity; 659 pytest + 129 cargo green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ains, starts_with/ends_with (+prefix/suffix), length/strlen (TASK-47 stretch 3b) Two IR forms (Str2 with an op enum, SLen) through parser/printer/ verifier/fuzz and both backends via shared semantic fns: 1-based CODEPOINT positions (not bytes, not graphemes — the ZWJ-family pin), empty needle matches everything, byte-wise comparison with zero unicode intelligence, total and NULL-strict in every argument. The SQL-standard position(needle IN haystack) AST form binds needle-first. The corpus REFUTED the fleet's contains-NULL pin (mined cases execute fine): the real rule, re-measured, is that a NULL literal needle binds iff a NON-literal Str haystack anchors overload resolution — mirrored exactly, all four measured combinations reproduced. Corpus: 179 -> 237 match of 678 (+58 with the math wave), zero FAILs. 663 pytest + 129 cargo green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ASK-47 stretch 3c) No IR op: NULL-ignoring semantics, first-argument ties (pinned via -0.0 vs 0.0), and NaN-above-inf all fall out of the CASE / IS NULL / duck_fcmp composition, left-folded for the n-ary form. Literal NULL args are dropped (NULL-ignoring); int/f64 unify whole-call like coalesce; strings compare byte-wise; booleans hit the engine's pre-existing clean comparison limit. Oracle tests cover the pinned NULL/NaN/tie/lossy-2^53 rows. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nario re-audit remaining Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…able, wrapping i64 semantics (TASK-47 stretch 3d) Round2f/Round2i through the full stack. The f64 scale factor is DuckDB's own std::pow(10, k), extracted bit-exactly into a generated 309-entry table (scripts/gen_pow10.py, witness-checked: k=23 is one ulp above strtod 1e23, k=126 one below ucrt pow) — never a runtime powi/powf. Measured asymmetries preserved: round's negative-n branch turns NaN/+-inf into +0.0 while trunc returns the input; integer round with negative digits WRAPS at i64 (round(i64::MAX,-2) = -9223372036854775700) and |n|>=19 collapses to 0 — zero trap conditions in the family. Both ops fuzz-covered; oracle tests include the pow-table ulp witnesses that only the extracted table passes. Corpus: 237 -> 240 match of 678, zero FAILs; 671 pytest green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… via wave-1 builtins (TASK-47 AC #3) Titanic 24->31, Ames 42->54, IEEE-CIS fraud 41->57, Rossmann 44->56 output features, all parity-gated (specializer == DuckDB == handcrafted on 300 seeded rows, cranelift asserted). The compromises the original scenario designs recorded are now real features: ln(1+x) skew transforms everywhere, decade buckets via round(x,-1) and floor, Deotte cents, IN-set membership flags (rare titles, suspicious domains, PUD classes, holiday codes), starts_with/ends_with/instr domain parsing, sin/cos cyclical hour/day/month encodings with pi(), least/greatest clamps and NULL-ignoring join-miss handling. Three store_sales compromise expressions rewrote to their natural builtin forms with identical values. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ture Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ree cross-platform (CI) CI (Linux) failed the two cbrt tests by exactly one ulp: the Linux DuckDB wheel's bundled std::cbrt returns 3.0000000000000004 for cbrt(27) while the Windows wheel (and Rust on both platforms) return 3.0. The oracle itself is platform-inconsistent for this one function, so repr-exact parity is unpinnable: duck_check_ulp compares floats within 1 ulp (positional, no joins), signed zeros still enforced, and the pins spec records the exception — the only one in the wave. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ahrzb
approved these changes
Jul 26, 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.
The builtins wave, measurement-first throughout: a six-family fleet pinned DuckDB 1.5.5's exact edge semantics (300+ pin rows, committed under
docs/superpowers/specs/pins-wave1/) BEFORE any implementation, and every shipped op is the pin.Shipped
BETWEEN/IN→ K3 desugars with whole-construct f64 unification;least/greatest→ CASE + duck-order (NULL-ignoring, first-arg ties, NaN-above-inf all fall out).log(b,x): ln/log/log2/log10/exp/sqrt/cbrt/sin/cos/tan/floor/ceil/trunc/pow. Pins that shaped the code: 1-arglogis base 10;log(b,x)is bit-exactlylog10(x)/log10(b); log family traps on x≤0 (so NULL lowering masks to op-safe constants — 0.0 is inside the trap domain — andFlogbmasks under the combined flag since NULL pre-empts every domain check); trig traps on ±inf but passes NaN through bit-exactly; exp/pow/cbrt are total.std::pow(10,k)— neither correctly-rounded nor plain ucrt — so the table is extracted from the oracle (scripts/gen_pow10.py, ulp witnesses checked at generation). Wrapping i64 round, measured round/trunc non-finite asymmetry preserved.position(n IN s)), contains, starts_with/ends_with (+aliases), length/strlen — 1-based codepoint positions, empty-needle-matches-all, NULL-strict. The corpus refuted one fleet pin (contains-NULL); re-measurement found the real overload-anchoring rule, mirrored exactly.^maps would compute the wrong tree (sqlparser binds it below*, DuckDB above) — named unsupported,pow()carries the semantics;**doesn't parse.Verification
Also in this PR: TASK-46 star-expansion ticket closed with final summary; TASK-47 fully checked.
🤖 Generated with Claude Code