From e6d02ee150c6d66f0559dc006fc00992f0fe6608 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 11 Oct 2026 09:06:11 +0000 Subject: [PATCH 1/2] Plan: SQL() as a polyfill of R2IL procedures over mask-risc (D-SQLP) SQL operations become ogar-loco PROC_DEF bodies over R2IL fold-reading calls: no new opcode, no meta layer. FoldDialect moves from a probe test file into a lance-graph-r2il crate; quack, plan_eval and the SAP binder lower through the procedures, gated on byte-identical Programs. Declared queries compile to Rust at build time; ad-hoc sql() text runs interpreted. Nothing past W1 until the D-SQLP-3 benchmark clears its threshold. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015JH7YkXs5us6g3tG8NiFfP --- .claude/board/INTEGRATION_PLANS.md | 9 ++ .claude/board/STATUS_BOARD.md | 16 +++ .claude/plans/sql-polyfill-r2il-v1.md | 150 ++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 .claude/plans/sql-polyfill-r2il-v1.md diff --git a/.claude/board/INTEGRATION_PLANS.md b/.claude/board/INTEGRATION_PLANS.md index d098c3f8d..876fca353 100644 --- a/.claude/board/INTEGRATION_PLANS.md +++ b/.claude/board/INTEGRATION_PLANS.md @@ -1,3 +1,12 @@ +## 2026-10-11 (4) — sql-polyfill-r2il-v1 — SQL() as a polyfill of R2IL procedures over mask-risc → `.claude/plans/sql-polyfill-r2il-v1.md` + +**Status:** PROPOSAL (D-SQLP-0..8). Nothing past W1 authorized until the D-SQLP-3 benchmark clears its pre-registered threshold. + +- SQL operations become `ogar-loco` `PROC_DEF` bodies over R2IL fold-reading calls; no new opcode and no meta layer (loco already nests via `PROC_DEF`/`PROC_CALL`). +- `FoldDialect` moves from a probe test file into a `lance-graph-r2il` crate; mask-risc stays the only engine. +- Declared queries compile to Rust at build time (the only "compile time" mode); ad-hoc `sql()` text runs interpreted at mask-risc's per-tile cost. +- quack, lance-graph-java `plan_eval` and the SAP binder lower through the procedures, gated on byte-identical `Program`s; Java's `sql()` is one Panama call with Valhalla value records. + ## 2026-10-11 (3) — key16-contiguous-match-v1 — a contiguous fast path for the 16-byte key match → `.claude/plans/key16-contiguous-match-v1.md` **Status:** PROPOSAL (D-KEY16-0..5). No kernel change authorized until the D-KEY16-2 probe clears its pre-registered threshold. diff --git a/.claude/board/STATUS_BOARD.md b/.claude/board/STATUS_BOARD.md index b4af614f5..c1367bd2b 100644 --- a/.claude/board/STATUS_BOARD.md +++ b/.claude/board/STATUS_BOARD.md @@ -1,3 +1,19 @@ +## D-SQLP — SQL() as a polyfill of R2IL procedures over mask-risc (2026-10-11) + +Plan: `.claude/plans/sql-polyfill-r2il-v1.md`. + +| D-id | Deliverable | Status | Gate | +|---|---|---|---| +| **D-SQLP-0** | Plan + board rows | In PR | — | +| **D-SQLP-1** | `FoldDialect` moved into a `lance-graph-r2il` crate | Queued | existing `row_bridge.rs` tests unchanged and green; one arity table | +| **D-SQLP-2** | First procedures (`filter_lt`, `sum`, `group_sum`, `margin`) as `PROC_DEF` bodies | Queued | scalar-reference parity; two disable runs red | +| **D-SQLP-3** | Benchmark: direct ndarray vs hand-built `Program` vs interpreted procedure | Queued | interpreted ≤ 1.05× hand-built at 65,536 and 1M rows (pre-registered) | +| **D-SQLP-4** | Build-time generator: declared procedure → Rust with const-generic opcodes | Queued, gated on D-SQLP-3 | ≤ 1.05× direct ndarray; no interpreter dispatch in the hot loop | +| **D-SQLP-5** | quack, `plan_eval`, SAP binder lower through the procedures | Queued, gated on D-SQLP-3 | byte-identical `mask_risc::Program` for every pinned case | +| **D-SQLP-6** | lance-graph-java `sql()` membrane (one Panama call, value records); parser decision | Queued | `ApiSurfaceTest`; no row-proportional Java allocation; `AllTests` on JDK 28 | +| **D-SQLP-7** | Backlog: refused fold opcodes, `IntAdd`, i64/f64/decimal/date lanes | Queued (per item, mask-risc first) | per-item parity on every realization row | +| **D-SQLP-8** | Mint `0xC400` / `0xC401` in `ogar-vocab` | Queued (OGAR request) | provisional notes replaced; no persisted GUID before | + ## D-KEY16 — contiguous fast path for the 16-byte key match (2026-10-11) Plan: `.claude/plans/key16-contiguous-match-v1.md`. diff --git a/.claude/plans/sql-polyfill-r2il-v1.md b/.claude/plans/sql-polyfill-r2il-v1.md new file mode 100644 index 000000000..a880fac07 --- /dev/null +++ b/.claude/plans/sql-polyfill-r2il-v1.md @@ -0,0 +1,150 @@ +# sql-polyfill-r2il-v1 — SQL() as a polyfill of R2IL procedures over mask-risc + +**Status:** PROPOSAL (D-SQLP-0..8). Nothing beyond W1 is authorized until the +D-SQLP-3 benchmark clears its pre-registered threshold. +**Date:** 2026-10-11. **Repos:** lance-graph (crate, procedures, codegen, +quack/SAP front ends), lance-graph-java (`sql()` membrane, `plan_eval`), +OGAR (fold-band bytes, concept mint), ndarray (missing lane primitives). + +## 1. Overview + +One query vocabulary for every front end, with no new layer and no new +engine: + +```text +Java sql() ─Panama call─┐ +quack ─────────────┤ +SAP binder ─────────────┼─▶ SQL procedures (loco PROC_DEF bodies) +Rust caller ─────────────┘ │ bodies are R2IL fold-reading calls + ▼ + FoldDialect ──▶ mask_risc::Program ──▶ ndarray::simd +``` + +This is ndarray's SIMD shape one tier up. ndarray names SIMD words and its +backends implement them; here SQL procedure names are the API, R2IL calls +implement them, and mask-risc is the only engine. Java sees one Panama call, +and Valhalla value records carry the parameters and result handles; no +opcode, mask or lane crosses (lance-graph-java `CLAUDE.md`, "THE JAVA SURFACE +IS `sql()`"). + +It follows the 2026-09-05 lance-graph ruling that planning moves to +`ogar-loco` / `ogar-r2il` and DataFusion is in a grace period +(E-PLANNING-MIGRATES-TO-LOCO-R2IL-DATAFUSION-IS-GRACE-PERIOD-1). + +## 2. What exists (VERIFIED-IN-CODE, 2026-10-11) + +- **OGAR `ogar-loco`** nests behaviour already: shared-core `PROC_DEF` + (`0x83`), `PROC_CALL` (`0x84`), `PROC_ARG` (`0x85`), per-opcode `body_refs`, + an interpreter that follows body references with a recursion-depth limit, + and `Vocabulary::branches` (`vocabulary.rs:261`), the predicate a cast to + code would ask. +- **OGAR `ogar-r2il`** is one opcode table with two readings: the machine + reading (`CONCEPT_R2IL_MACHINE = 0xC400`, 82 R2IL opcodes at `0x90..0xE1`) + and the fold reading (`CONCEPT_R2IL_FOLD = 0xC401`) with a 12-opcode + extension band at `0xE2..0xED` (`VIA`, `RANGE`, `SUM`, `MIN`, `MAX`, + `GROUP_SUM`, `KEY_RUNS`, `ANY`, `ALL`, `KEEP`, `SCATTER_OR`, `BLEND`). A + fold byte is minted only for a mask-risc `Pred`/`Terminal` that already has + its own parity case. Both concept ids are PROVISIONAL (not minted in + `ogar-vocab`). +- **lance-graph `FoldDialect`** executes the fold reading over mask-risc. It + lives only in `crates/r2il-mask-abi-probe/tests/row_bridge.rs`, a test file + in a workspace-excluded probe crate. Measured there: a join predicate plus a + local compare runs in 2 facade passes against quack's 3; nothing + proportional to row count reaches the interpreter stack; a scalar fold + (`SUM`) finalizes and runs a `Program` at the point it is reached, which is + how `SUM(revenue|m) - SUM(cost|m)` is expressed when a single-terminal + `Program` cannot express it. Wired: `VIA`, `SUM`, `GROUP_SUM`, `RANGE`, + `KEEP` and R2IL `Load`, `IntSub`, `IntAnd`, `IntNot`, `IntEqual`, + `IntSLess`, `PopCount`. Refused by name: `MIN`, `MAX`, `KEY_RUNS`, `ANY`, + `ALL`, `SCATTER_OR`, `BLEND`, `IntAdd`, and the unsigned compares + (mask-risc has none). +- **Front ends that lower to `mask_risc::Program` today:** quack + (`lance-graph-quack/src/lib.rs`: `lower`, `lower_fused`, `lower_group_by`, + `lower_avg`); lance-graph-java `plan_eval` (`lgj-abi/src/exports.rs`, + with the `lowering_convergence` test module proving its `Program` equals + quack's); `lance-graph-sap` (CATS boundary adapters, "no SAP evaluator"). +- **Column types mask-risc reads:** `LaneRef::{I32, U32, U64}` plus strided + reads; quack's binder knows `FieldKind::{I32, Code}` only. + +## 3. What does not exist + +- No crate holds `FoldDialect`; nothing in production calls it. +- No SQL procedure bodies. +- No loco-body → Rust code generator. `ogar-emitter` emits OGAR classes as + triples/DDL, and `ogar-render-askama` renders class artifacts; neither + turns a `FunctionBody` into Rust. +- No `sql()` export in lance-graph-java. +- No float, decimal, date or i64-compare lanes in mask-risc; no ndarray i64 + or float compare-to-mask. + +## 4. Decisions + +- **DECISION: SQL operations are procedures, not opcodes.** Each SQL operation + is a `PROC_DEF` body made of R2IL fold-reading calls. BASIS: the fold band's + own admission rule (a byte needs an execution-level reason), and the + anti-lasagne rule (a layer must hold information no other layer holds). A + procedure that can be written from existing calls earns neither. REVISIT + WHEN: a SQL operation cannot be written from R2IL calls; then the missing + piece is a mask-risc capability first, an R2IL byte second. +- **DECISION: no V4 meta layer between `ogar-r2il` and `ogar-loco`.** The + nesting it would provide is `PROC_DEF`/`PROC_CALL`, which loco already has. +- **DECISION: one spelling per operation.** Once the crate exists, every + front end lowers through the procedures. A front end that still builds + `mask_risc::Program` directly is a second spelling of the same query. +- **SCOPE: two execution modes, never mixed up in claims.** + - *Declared queries* (in the schema, like SAP CDS views, or prepared): a + build step generates Rust from the procedure bodies; LLVM sees plain + generic code and the layer costs nothing at runtime. This is the only + mode where "compile time" is true. + - *Ad-hoc SQL text at runtime* (Java `sql("…")` with a new string): the + body is built when the query arrives and runs through the interpreter and + mask-risc. Cost is one opcode dispatch per 16,384-row tile, the same as + mask-risc today. Still no work on the Java side. +- **DECISION: Java holds no operations.** `sql()` is one Panama downcall; + parameters and results cross as Valhalla value records and handles; every + public call stays O(1) in rows (lance-graph-java `CLAUDE.md`). +- **OPEN: SQL text parser.** DataFusion is in its grace period, so its parser + is not the route. Candidates: a standalone parser crate, or a declared-query + schema that needs no text parser for the compile-time mode. Decided in W6. +- **OPEN: the SAP cost comparison.** "Orders of magnitude cheaper than SAP" is + a hypothesis until W3/W4 are measured against a stated reference workload. + +## 5. Waves + +| Wave | D-id | Repo | Work | Gate (all must pass) | +|---|---|---|---|---| +| W0 | D-SQLP-0 | lance-graph | This plan + board rows | — | +| W1 | D-SQLP-1 | lance-graph | Move `FoldDialect` and its `Val`/`FoldError` types from `r2il-mask-abi-probe/tests/row_bridge.rs` into a workspace crate `lance-graph-r2il`; the probe's tests depend on it | every existing `row_bridge.rs` test passes unchanged against the crate; still one arity table in the tree (`ogar_r2il`'s); no new opcode; the named refusals still refuse | +| W2 | D-SQLP-2 | lance-graph | First procedures as `PROC_DEF` bodies over R2IL calls: `filter_lt` (`Load` + `IntSLess` + `KEEP`), `sum`, `group_sum`, and `margin` (two `SUM` + `IntSub`) | each answer equals a scalar reference on fixtures with ≥ 3 groups and both empty and full selections; no new opcode; disable runs: drop `KEEP` from `filter_lt` → red; swap `IntSub` operands in `margin` → red | +| W3 | D-SQLP-3 | lance-graph | Benchmark `margin` three ways: direct `ndarray::simd` calls, hand-built mask-risc `Program`s, the interpreted procedure. N = 65,536 and 1,048,576; selectivity ~1 % and ~50 % | answers identical before timing; release, quiet machine, median of 101 runs, avx512 and avx2 reported separately. Pre-registered: interpreted ≤ 1.05× hand-built `Program` at both N | +| W4 | D-SQLP-4 | lance-graph | Build-time generator: a declared procedure body → Rust that calls mask-risc / `ndarray::simd` directly, with opcodes as const generics (the `ternlog::` pattern) | generated code's answers identical to the interpreted body; generated ≤ 1.05× direct ndarray at both N; disassembly of the hot loop contains no interpreter dispatch | +| W5 | D-SQLP-5 | lance-graph, lance-graph-java | quack, `plan_eval` and the SAP binder lower through the procedures | for every case `lowering_convergence` and quack's tests pin, the `mask_risc::Program` produced through the procedures is byte-identical to today's; no other behaviour change | +| W6 | D-SQLP-6 | lance-graph-java, lance-graph | `sql()` membrane: one Panama downcall (new ABI minor), parameters and result handles as value records; parser decision (§4 OPEN) | `ApiSurfaceTest` green (no opcode, mask or FFM type in a public signature); allocation gate shows no row-proportional Java allocation; full `AllTests` + consumer mains on JDK 28 | +| W7 | D-SQLP-7 | ndarray, lance-graph, OGAR | Backlog, one item at a time, mask-risc first: `MIN`, `MAX`, `KEY_RUNS`, `ANY`, `ALL`, `SCATTER_OR`, `BLEND`, `IntAdd`; lanes for i64 compares, f64, decimal (scaled i64), date (i32 days) | per item: ndarray primitive with parity on every realization row → mask-risc `Pred`/`Terminal` with parity → `FoldDialect` wiring → procedure; each its own PR | +| W8 | D-SQLP-8 | OGAR | Mint `0xC400` / `0xC401` in `ogar-vocab` (request to OGAR; this plan does not mint) | the provisional notes in `ogar-r2il` are replaced by minted ids; no persisted GUID uses them before | + +**Kill conditions.** W3 interpreted > 1.5× hand-built at either N → stop +before W4/W5; keep W1 and W2, and re-plan around where the time went. W4 +generated code slower than direct ndarray beyond the threshold → ship no +generator; declared queries use the interpreted path. A W5 `Program` that is +not byte-identical is a lowering bug: fix it, never re-pin the expectation. + +## 6. Order and ownership + +W1 → W2 → W3 → (W4, W5) → W6. W7 runs alongside from W2 on, driven by what +the procedures need. W8 is a request that can go out now. + +- lance-graph: W1–W5 (W5's quack and SAP parts). +- lance-graph-java: W5 (`plan_eval`), W6. +- ndarray: W7 primitives; needs a session with push access to + `AdaWorldAPI/ndarray`. +- OGAR: W7 fold bytes, W8. + +## 7. Non-goals + +- No new opcode for a SQL operation that procedures can express. +- No meta layer or second IR between `ogar-r2il` and `ogar-loco`. +- No new DataFusion code. +- No computation, materialization or opcode on the Java side. +- No GPU or JIT backend until W3/W4 numbers show per-tile dispatch costs + something measurable. From 730bfa441257513ec8d5942c82b48e8bf95cc36a Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 11 Oct 2026 09:15:37 +0000 Subject: [PATCH 2/2] Plan D-SQLP: unblock W2-W3, scalar IntAdd, real Java Program oracle - Authorize W1-W3, which build what the D-SQLP-3 benchmark measures; gate W4 onward on it (the old wording deadlocked W2/W3). - IntAdd is scalar-only: wire it in FoldDialect like IntSub, with no ndarray or mask-risc change. - lance-graph-java's lowering_convergence compares row counts, not Programs; W5 now adds a Program-level test before requiring byte-identical Programs. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015JH7YkXs5us6g3tG8NiFfP --- .claude/board/INTEGRATION_PLANS.md | 2 +- .claude/board/STATUS_BOARD.md | 4 ++-- .claude/plans/sql-polyfill-r2il-v1.md | 18 ++++++++++++------ 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/.claude/board/INTEGRATION_PLANS.md b/.claude/board/INTEGRATION_PLANS.md index 876fca353..c76afb44a 100644 --- a/.claude/board/INTEGRATION_PLANS.md +++ b/.claude/board/INTEGRATION_PLANS.md @@ -1,6 +1,6 @@ ## 2026-10-11 (4) — sql-polyfill-r2il-v1 — SQL() as a polyfill of R2IL procedures over mask-risc → `.claude/plans/sql-polyfill-r2il-v1.md` -**Status:** PROPOSAL (D-SQLP-0..8). Nothing past W1 authorized until the D-SQLP-3 benchmark clears its pre-registered threshold. +**Status:** PROPOSAL (D-SQLP-0..8). W1–W3 authorized; nothing from W4 on until the D-SQLP-3 benchmark clears its pre-registered threshold. - SQL operations become `ogar-loco` `PROC_DEF` bodies over R2IL fold-reading calls; no new opcode and no meta layer (loco already nests via `PROC_DEF`/`PROC_CALL`). - `FoldDialect` moves from a probe test file into a `lance-graph-r2il` crate; mask-risc stays the only engine. diff --git a/.claude/board/STATUS_BOARD.md b/.claude/board/STATUS_BOARD.md index c1367bd2b..c9957437d 100644 --- a/.claude/board/STATUS_BOARD.md +++ b/.claude/board/STATUS_BOARD.md @@ -9,9 +9,9 @@ Plan: `.claude/plans/sql-polyfill-r2il-v1.md`. | **D-SQLP-2** | First procedures (`filter_lt`, `sum`, `group_sum`, `margin`) as `PROC_DEF` bodies | Queued | scalar-reference parity; two disable runs red | | **D-SQLP-3** | Benchmark: direct ndarray vs hand-built `Program` vs interpreted procedure | Queued | interpreted ≤ 1.05× hand-built at 65,536 and 1M rows (pre-registered) | | **D-SQLP-4** | Build-time generator: declared procedure → Rust with const-generic opcodes | Queued, gated on D-SQLP-3 | ≤ 1.05× direct ndarray; no interpreter dispatch in the hot loop | -| **D-SQLP-5** | quack, `plan_eval`, SAP binder lower through the procedures | Queued, gated on D-SQLP-3 | byte-identical `mask_risc::Program` for every pinned case | +| **D-SQLP-5** | quack, `plan_eval`, SAP binder lower through the procedures | Queued, gated on D-SQLP-3 | byte-identical `mask_risc::Program` for every pinned case; lance-graph-java first gets a `Program`-level test (today's `lowering_convergence` compares row counts) | | **D-SQLP-6** | lance-graph-java `sql()` membrane (one Panama call, value records); parser decision | Queued | `ApiSurfaceTest`; no row-proportional Java allocation; `AllTests` on JDK 28 | -| **D-SQLP-7** | Backlog: refused fold opcodes, `IntAdd`, i64/f64/decimal/date lanes | Queued (per item, mask-risc first) | per-item parity on every realization row | +| **D-SQLP-7** | Backlog: refused fold opcodes and i64/f64/decimal/date lanes (mask-risc first); scalar `IntAdd` (`FoldDialect` only) | Queued (per item) | population items: parity on every realization row; scalar items: scalar test, `Addr`/`Addr` refusal kept | | **D-SQLP-8** | Mint `0xC400` / `0xC401` in `ogar-vocab` | Queued (OGAR request) | provisional notes replaced; no persisted GUID before | ## D-KEY16 — contiguous fast path for the 16-byte key match (2026-10-11) diff --git a/.claude/plans/sql-polyfill-r2il-v1.md b/.claude/plans/sql-polyfill-r2il-v1.md index a880fac07..d55883319 100644 --- a/.claude/plans/sql-polyfill-r2il-v1.md +++ b/.claude/plans/sql-polyfill-r2il-v1.md @@ -1,7 +1,8 @@ # sql-polyfill-r2il-v1 — SQL() as a polyfill of R2IL procedures over mask-risc -**Status:** PROPOSAL (D-SQLP-0..8). Nothing beyond W1 is authorized until the -D-SQLP-3 benchmark clears its pre-registered threshold. +**Status:** PROPOSAL (D-SQLP-0..8). W1–W3 are authorized: they build what the +D-SQLP-3 benchmark measures. Nothing from W4 on is authorized until that +benchmark clears its pre-registered threshold. **Date:** 2026-10-11. **Repos:** lance-graph (crate, procedures, codegen, quack/SAP front ends), lance-graph-java (`sql()` membrane, `plan_eval`), OGAR (fold-band bytes, concept mint), ndarray (missing lane primitives). @@ -61,8 +62,10 @@ It follows the 2026-09-05 lance-graph ruling that planning moves to - **Front ends that lower to `mask_risc::Program` today:** quack (`lance-graph-quack/src/lib.rs`: `lower`, `lower_fused`, `lower_group_by`, `lower_avg`); lance-graph-java `plan_eval` (`lgj-abi/src/exports.rs`, - with the `lowering_convergence` test module proving its `Program` equals - quack's); `lance-graph-sap` (CATS boundary adapters, "no SAP evaluator"). + whose `lowering_convergence` test compares the ROW COUNTS the two + lowerings select, not the `Program`s they build, over 28 combine vectors; + `lowering_convergence.rs` `eval_plan_lower` vs `run(quack::lower(..))`); + `lance-graph-sap` (CATS boundary adapters, "no SAP evaluator"). - **Column types mask-risc reads:** `LaneRef::{I32, U32, U64}` plus strided reads; quack's binder knows `FieldKind::{I32, Code}` only. @@ -74,6 +77,9 @@ It follows the 2026-09-05 lance-graph ruling that planning moves to triples/DDL, and `ogar-render-askama` renders class artifacts; neither turns a `FunctionBody` into Rust. - No `sql()` export in lance-graph-java. +- No structural (`Program`-level) comparison between lance-graph-java's + `plan_lower` and any other lowering; the existing differential checks + answers only. - No float, decimal, date or i64-compare lanes in mask-risc; no ndarray i64 or float compare-to-mask. @@ -118,9 +124,9 @@ It follows the 2026-09-05 lance-graph ruling that planning moves to | W2 | D-SQLP-2 | lance-graph | First procedures as `PROC_DEF` bodies over R2IL calls: `filter_lt` (`Load` + `IntSLess` + `KEEP`), `sum`, `group_sum`, and `margin` (two `SUM` + `IntSub`) | each answer equals a scalar reference on fixtures with ≥ 3 groups and both empty and full selections; no new opcode; disable runs: drop `KEEP` from `filter_lt` → red; swap `IntSub` operands in `margin` → red | | W3 | D-SQLP-3 | lance-graph | Benchmark `margin` three ways: direct `ndarray::simd` calls, hand-built mask-risc `Program`s, the interpreted procedure. N = 65,536 and 1,048,576; selectivity ~1 % and ~50 % | answers identical before timing; release, quiet machine, median of 101 runs, avx512 and avx2 reported separately. Pre-registered: interpreted ≤ 1.05× hand-built `Program` at both N | | W4 | D-SQLP-4 | lance-graph | Build-time generator: a declared procedure body → Rust that calls mask-risc / `ndarray::simd` directly, with opcodes as const generics (the `ternlog::` pattern) | generated code's answers identical to the interpreted body; generated ≤ 1.05× direct ndarray at both N; disassembly of the hot loop contains no interpreter dispatch | -| W5 | D-SQLP-5 | lance-graph, lance-graph-java | quack, `plan_eval` and the SAP binder lower through the procedures | for every case `lowering_convergence` and quack's tests pin, the `mask_risc::Program` produced through the procedures is byte-identical to today's; no other behaviour change | +| W5 | D-SQLP-5 | lance-graph, lance-graph-java | quack, `plan_eval` and the SAP binder lower through the procedures | quack and SAP: for every case their tests pin, the `mask_risc::Program` produced through the procedures is byte-identical to today's. lance-graph-java: first add a `Program`-level test comparing the procedure lowering against the legacy `plan_lower` output (none exists today; `lowering_convergence` compares row counts only), then require byte-identical `Program`s for its 28 combine vectors. No other behaviour change | | W6 | D-SQLP-6 | lance-graph-java, lance-graph | `sql()` membrane: one Panama downcall (new ABI minor), parameters and result handles as value records; parser decision (§4 OPEN) | `ApiSurfaceTest` green (no opcode, mask or FFM type in a public signature); allocation gate shows no row-proportional Java allocation; full `AllTests` + consumer mains on JDK 28 | -| W7 | D-SQLP-7 | ndarray, lance-graph, OGAR | Backlog, one item at a time, mask-risc first: `MIN`, `MAX`, `KEY_RUNS`, `ANY`, `ALL`, `SCATTER_OR`, `BLEND`, `IntAdd`; lanes for i64 compares, f64, decimal (scaled i64), date (i32 days) | per item: ndarray primitive with parity on every realization row → mask-risc `Pred`/`Terminal` with parity → `FoldDialect` wiring → procedure; each its own PR | +| W7 | D-SQLP-7 | ndarray, lance-graph, OGAR | Backlog, one item at a time. Population items, mask-risc first: `MIN`, `MAX`, `KEY_RUNS`, `ANY`, `ALL`, `SCATTER_OR`, `BLEND`; lanes for i64 compares, f64, decimal (scaled i64), date (i32 days). Scalar items: `IntAdd` | population items: ndarray primitive with parity on every realization row → mask-risc `Pred`/`Terminal` with parity → `FoldDialect` wiring → procedure. Scalar items: `FoldDialect` wiring over `Val::Scalar` only, the way `IntSub` already is (`row_bridge.rs`, `INT_SUB` arm), with a scalar test and the `Addr`/`Addr` refusal kept; no ndarray or mask-risc change. Each item its own PR | | W8 | D-SQLP-8 | OGAR | Mint `0xC400` / `0xC401` in `ogar-vocab` (request to OGAR; this plan does not mint) | the provisional notes in `ogar-r2il` are replaced by minted ids; no persisted GUID uses them before | **Kill conditions.** W3 interpreted > 1.5× hand-built at either N → stop