You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: SQLProjection — marginalization over __THIS__
Rename SQLTransform to SQLProjection (strict projections only) and
implement the fit half: window aggregates over __THIS__ are marginalized
into materialized params tables plus a rewritten serving_sql that LEFT
JOINs them via IS NOT DISTINCT FROM. Parsing is DuckDB's own
json_serialize_sql/json_deserialize_sql — the oracle's grammar and
printer, no second SQL dialect. Confit is untouched.
Fit is two-stage, both stages fuzz-derived: windows_sql reruns the
original computation with each window re-projected (GROUP BY and solo
window queries drift by an ulp — DuckDB sums floats in operator-chain-
dependent order), then per-keyset SELECT DISTINCT collapses the
materialized values. Fit pins threads=1: DuckDB's parallel window
aggregation is not bit-deterministic (measured 1/500).
The gate is differential: original SQL over train == serving_sql joined
to fitted params, both executed by DuckDB, bit-exact including schema —
plus a seeded 500-case fuzz, AST shape pins, and a named-refusal table.
Serving (infer/infer_batch through Confit) stays NotImplementedError —
the named next loop.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: README.md
+25-18Lines changed: 25 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -10,13 +10,7 @@ This repository is a workspace of two packages:
10
10
| package | what it is |
11
11
|---|---|
12
12
|[`packages/confit`](packages/confit)|**Confit** — the serving engine. SQL plus static tables frozen at fit time are partially evaluated, once, into a native function. Serves bit-exact with DuckDB or refuses at build time. Usable on its own. |
13
-
|[`packages/sql-transform`](packages/sql-transform)| The authoring surface: `SQLTransform`. **Not implemented** — signatures only, being rebuilt on Confit. |
14
-
15
-
> **sql-transform is a stub.** Its implementation was deliberately removed --
16
-
> the DataFusion engine, the codegen backend, the batch `transform()` path and
17
-
> the fit pipeline are all gone. What remains is the interface, raising
18
-
> `NotImplementedError`, as the contract for a rebuild on Confit.
19
-
> **Confit itself is complete and unaffected.**
13
+
|[`packages/sql-transform`](packages/sql-transform)| The authoring surface: `SQLProjection`. The **fit half works**: window aggregates over `__THIS__` are marginalized into materialized params tables plus a rewritten serving SQL. The serving half (through Confit) is a later loop. |
20
14
21
15
## Installation
22
16
@@ -67,23 +61,35 @@ fn.infer_rows([Row(age=40.0)]) # row objects in, row objects out
67
61
fn.infer_arrow(pa.table({"age": [40.0]})) # pa.Table in, pa.Table out
68
62
```
69
63
70
-
`sql_transform.SQLTransform` is the intended authoring layer on top of it --
71
-
write SQL with window aggregates, `fit()` to freeze them, then serve. It is
72
-
currently **not implemented**; see [packages/sql-transform](packages/sql-transform).
64
+
`sql_transform.SQLProjection` is the authoring layer on top of it — write SQL
65
+
with window aggregates, `fit()` to freeze them. The fit half works today; see
66
+
[packages/sql-transform](packages/sql-transform).
67
+
68
+
```python
69
+
from sql_transform import SQLProjection
70
+
71
+
p = SQLProjection(
72
+
"SELECT (age - avg(age) OVER (PARTITION BY country)) AS d FROM __THIS__"
73
+
).fit(train)
74
+
p.serving_sql # the rewritten projection: params joins instead of aggregates
75
+
p.params # {"__CF_PARAMS_0__": <pyarrow.Table>}
76
+
```
73
77
74
78
## Architecture
75
79
76
-
The intended two-phase shape, of which **only the second phase exists today**:
80
+
The two-phase shape — **fit works, the wiring between the phases is the next
81
+
loop**:
77
82
78
83
```
79
84
SQL over __THIS__
80
85
│
81
86
▼
82
-
fit(train) ── freeze each window aggregate (e.g. MEAN(age)) into a typed
83
-
│ __STATE__ table and rewrite the SQL to reference it instead
84
-
│ of recomputing. [NOT IMPLEMENTED]
87
+
fit(train) ── marginalize each window aggregate (e.g. avg(age) OVER
88
+
│ (PARTITION BY country)) into a materialized params table and
89
+
│ rewrite the SQL to LEFT JOIN it instead of recomputing.
90
+
│ Bit-exact with DuckDB by differential gate. [WORKS]
85
91
│
86
-
│ rewritten SQL + frozen state
92
+
│ rewritten SQL + frozen params [wiring: NOT IMPLEMENTED]
87
93
▼
88
94
Confit ── partially evaluates the pair into a native function: binding-time
89
95
│ analysis collapses every static lookup into a prepare-time probe,
@@ -105,9 +111,10 @@ The expression surface, joins to static tables, the row-shape contract
105
111
mined from DuckDB's own test suite replay bit-exact, with the remainder clean,
106
112
named build-time rejections.
107
113
108
-
The authoring layer on top — window-aggregate `fit`, typed I/O, sklearn
109
-
transformer references, and composing one transform into another — is what the
110
-
rebuild has to supply.
114
+
The authoring layer's window-aggregate `fit` (marginalization) works; typed
115
+
I/O, serving through Confit, static tables in authored SQL, and the broader
116
+
DRAFT-20 program (fitted model artifacts as params tables) are the named next
Every method raises `NotImplementedError`. The signatures, defaults and return
12
-
types are all that remain, and they are the contract a rebuild has to satisfy:
13
-
14
-
| method | intended behaviour |
15
-
|---|---|
16
-
|`SQLTransform(sql)`| accept SQL (or a t-string) over `__THIS__`|
17
-
|`from_file(path)`| same, read from a file |
18
-
|`fit(table, this_model=None)`| freeze window-aggregate state into static tables, rewrite the SQL to reference them, specialize via Confit; returns self |
19
-
|`infer(row)` / `infer_batch(rows)`| serve rows through the specialized function |
20
-
|`backend` / `boundary`| report which engine and boundary the fitted function uses |
21
-
22
-
The serving half already exists and is unaffected: [Confit](../confit) takes SQL
23
-
plus frozen static tables and partially evaluates them into a native function,
24
-
bit-exact with DuckDB or refusing at build time. What was removed here is the
25
-
fit half, the DataFusion batch engine, the codegen backend, and transform
26
-
composition.
27
-
28
-
Tests in this package assert only that the surface exists and refuses honestly —
29
-
they fail if a method is dropped, renamed, or quietly starts returning something.
26
+
The serving half (`infer`/`infer_batch` through [Confit](../confit)) is a later
27
+
loop and still raises `NotImplementedError`.
28
+
29
+
## The contract
30
+
31
+
Strict projection: `SELECT <exprs> FROM __THIS__`. Everything else — WHERE,
32
+
GROUP BY, joins, subqueries, CTEs, running windows, order-sensitive
33
+
aggregates — is refused at construction with a named error. Serve-or-refuse,
34
+
no third mode.
35
+
36
+
Parsing is DuckDB's own (`json_serialize_sql` / `json_deserialize_sql`): the
37
+
oracle's grammar and the oracle's printer, no second SQL dialect anywhere.
38
+
39
+
The correctness gate is differential: for every accepted projection, the
40
+
original SQL over training data must be **bit-exact** with `serving_sql`
41
+
joined against the fitted params — both executed by DuckDB (single-threaded:
42
+
DuckDB's parallel float window aggregation is not bit-deterministic even
43
+
against itself). NULL partition keys are one partition and join back via
44
+
`IS NOT DISTINCT FROM`; join multiplicity is provable, not tested.
0 commit comments