Skip to content

Commit cbf5c5f

Browse files
ahrzbclaude
authored andcommitted
chore(backlog): TASK-45 Done + final summary; TASK-46 star expansion + TASK-47 workload builtins wave 1 created
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent b6e39d7 commit cbf5c5f

3 files changed

Lines changed: 68 additions & 2 deletions

backlog/tasks/task-45 - Specializer-M-boundary-generated-row-marshaller-Python-API.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
---
22
id: TASK-45
33
title: 'Specializer M-boundary: generated row marshaller + Python API'
4-
status: In Progress
4+
status: Done
55
assignee: []
66
created_date: '2026-07-25 02:32'
7-
updated_date: '2026-07-26 09:10'
7+
updated_date: '2026-07-26 11:40'
88
labels: []
99
milestone: m-7
1010
dependencies:
@@ -46,3 +46,9 @@ Stretch plan (recorded 2026-07-26, design doc §3 flag 1 + §10). Measured targe
4646
All four stretches landed on claude/specializer-m-boundary. The marshaller (src/duckdb/mod.rs) does at prepare time everything knowable at prepare time: interned attribute-name PyStrings in fixed field order, input buffers + RunState owned and cleared-not-dropped per call, dict rows via get_item and model rows via getattr on the interned names, output rows by direct pydantic-v2 slot fill. Two assumptions died by measurement: (1) pydantic's literal model_construct API is pure-Python and SLOWER than model_validate (1432 vs 882 ns/row on 2.13) — the shipped path is object.__new__ + object.__setattr__ of __dict__/__pydantic_fields_set__/__pydantic_extra__/__pydantic_private__ at 491 ns, semantically equal (eq, fields_set, assignment all verified); (2) the design doc's AoS row structs buy nothing at L1-resident n — the marshaller fills the existing SoA Batch directly (deliberate deviation, noted in the plan). AC #4 forced real work: ColData::Str became one flat buffer + spans (killing per-cell Strings AND a hidden per-load clone in the JIT's h_load_str), substr/trim became pure sub-span arithmetic, case mapping streams into the arena (Arena::case_map), number→text formats via Arena::push_fmt with DuckF64 on a stack buffer, and h_probe emits without its per-call Vec + ScalarVal clones — all shared between backends, pinned by counting-allocator tests over a probe/arith fixture and a string-heavy program on BOTH backends (the remaining per-call allocs are the output objects themselves plus pyo3's input-list Vec, i.e. the AC's "beyond the output objects"). SpecializedTransform (sql_transform/_specialized.py) reuses the whole fit pipeline minus transformer refs (ValueError at ctor), so window aggregates ride the equi-join rewrite onto cranelift — parity with SQLTransform asserted row-for-row; WHERE stays rejected at the authoring surface (parse_and_validate), while raw DuckDBInferFn keeps it. Bench (scripts/bench_specializer.py, +generic engine via SPECIALIZER_GENERIC_BOUNDARY): noop p50 marshaller vs generic = 1.1/2.1µs at n=1, 468/1192µs at n=1024 (1.9-2.5x, AC #2); vs shipping engines at n=1024 the specializer is 3.7-4.2x faster than native and 2.4-3.8x than codegen (AC #3); cranelift-vs-interp is now visible end-to-end (arith 339 vs 391µs at n=1024). SPECIALIZER_GENERIC_BOUNDARY + .boundary getter mirror the FORCE_INTERP pattern; infer_rows() is the direct hot entry SpecializedTransform uses.
4747
<!-- SECTION:NOTES:END -->
4848

49+
50+
## Final Summary
51+
52+
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
53+
M-boundary delivered and merged (PR #29, rebase-merged 2026-07-26). Generated row marshaller + SpecializedTransform + allocation-free steady state on both backends, with a 17-agent adversarial fleet's 9 confirmed findings (3 root causes) fixed pre-merge: supplied output models keep model_validate semantics, the generic baseline accepts dict rows, reentrant infer falls back instead of erroring. Post-merge the milestone also grew the realistic serving bench (benchmarks/, PR #29): four famous-problem inference paths (titanic 10->24, ames 43->42, ieee-cis fraud 32->41, rossmann 21->44) under an exact three-way parity gate (specializer == DuckDB == handcrafted twin, pytest-enforced). Measured: the specializer beats the handcrafted-Python typed-model server in 16/16 cells (1.1-2.4x), DuckDB-per-call by 1,200-2,700x at n=1, and the previous native/codegen engines build 0/4 scenarios (IS NULL projections, row-x-dim arithmetic unsupported there). Known remaining gap, deliberately reported: a plain-dict handcrafted server is still 1.3-2x faster — typed-output construction is the next perf lever (parked; SQL support prioritized by AmirHossein 2026-07-26).
54+
<!-- SECTION:FINAL_SUMMARY:END -->
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
id: TASK-46
3+
title: 'Specializer SQL support: SELECT * star expansion'
4+
status: To Do
5+
assignee: []
6+
created_date: '2026-07-26 11:42'
7+
labels: []
8+
milestone: m-7
9+
dependencies:
10+
- TASK-45
11+
documentation:
12+
- docs/superpowers/specs/2026-07-25-sql-specializer-design.md
13+
type: feature
14+
ordinal: 40000
15+
---
16+
17+
## Description
18+
19+
<!-- SECTION:DESCRIPTION:BEGIN -->
20+
The single biggest corpus rung: 128 of 625 clean-unsupported corpus cases have `SELECT *` (or `tbl.*`) as their first blocker. Expand the star at bind time in the frontend against DuckDB's measured semantics — column order and naming for the row table alone and under joins (including duplicate-name handling), `tbl.*` qualified forms, and whatever star modifiers the corpus actually uses (EXCLUDE/REPLACE are measured-first: support only what the corpus needs, reject the rest cleanly by name). Pure frontend work — no IR, backend, or boundary changes. Clearing it also de-masks second blockers currently hidden behind star for the builtins wave (TASK-47).
21+
<!-- SECTION:DESCRIPTION:END -->
22+
23+
## Acceptance Criteria
24+
<!-- AC:BEGIN -->
25+
- [ ] #1 Star semantics pinned by measurement against DuckDB 1.5.5 (column order, duplicate-name policy, qualified tbl.*, modifier handling) and recorded as duck_check tests
26+
- [ ] #2 Corpus replay: star-first-blocker cases flip to match or to a NAMED deeper blocker; zero FAILs; match count and the new first-blocker tally recorded here
27+
- [ ] #3 Unsupported star forms (if any remain) reject with a clean "unsupported: ..." naming the form
28+
- [ ] #4 mise gate-specializer green
29+
<!-- AC:END -->
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
id: TASK-47
3+
title: 'Specializer SQL support: workload builtins & predicates wave 1'
4+
status: To Do
5+
assignee: []
6+
created_date: '2026-07-26 11:42'
7+
labels: []
8+
milestone: m-7
9+
dependencies:
10+
- TASK-46
11+
documentation:
12+
- docs/superpowers/specs/2026-07-25-sql-specializer-design.md
13+
- docs/superpowers/specs/2026-07-26-stretch4-builtin-pins.md
14+
type: feature
15+
ordinal: 41000
16+
---
17+
18+
## Description
19+
20+
<!-- SECTION:DESCRIPTION:BEGIN -->
21+
Close the workload ladder measured by the serving-bench scenarios (benchmarks/serving_scenarios/, each module's compromises list) plus the overlapping corpus predicates. Ranked by how many famous-solution pipelines hit the wall: (1) ln/log/log2/log10/log1p/exp — blocked features in all four scenarios (log-fare, log1p amount, log sales, skew fixes); (2) true floor/ceil/trunc — CAST rounds half-even, so decade bins / cents / week buckets are inexpressible; (3) instr/position/strpos + contains/starts_with/ends_with — title extraction, email-domain and device parsing; (4) IN (...) and BETWEEN predicates — also 72+ corpus first-blocker cases; (5) pow/sqrt (fractional) — Box-Cox and sqrt skew features; (6) sin/cos — cyclical hour/month encodings; (7) least/greatest — clamp ergonomics. Every function lands via the measured-pin discipline (builtin-pins spec): pin DuckDB 1.5.5 semantics with duck_check tests FIRST (edge cases: domain errors, NULL propagation, -0.0/NaN/inf, int/float overloads), then lower, then implement on BOTH backends via shared semantic functions. Float-y functions must match DuckDB bit-exactly or trap cleanly — the differential decides.
22+
<!-- SECTION:DESCRIPTION:END -->
23+
24+
## Acceptance Criteria
25+
<!-- AC:BEGIN -->
26+
- [ ] #1 Each shipped function/predicate has measured DuckDB pins recorded as duck_check tests before its implementation landed (domain edges, NULL, special floats)
27+
- [ ] #2 Interpreter and cranelift agree byte-identically on all new ops (shared semantic fns; 500-seed differential extended to cover them)
28+
- [ ] #3 The four serving scenarios' compromises lists re-audited: every gap this wave claims to close is exercised by an upgraded scenario feature or a new duck_check
29+
- [ ] #4 Corpus replay: predicate/function first-blocker cases flip to match or to a named deeper blocker; zero FAILs; new tally recorded here
30+
- [ ] #5 mise gate-specializer green
31+
<!-- AC:END -->

0 commit comments

Comments
 (0)