mask-risc: the terminal elects materialization — fused Range ∩ plane → Count/Any - #1268
Conversation
…→ Count/Any
A mask expression denotes membership; whether it becomes bits is the
terminal's decision. Program::fused_terminal() recognises
Pred::Range{lo,hi} optionally gated by a RESIDENT plane and folded by
Count or Any, and execute_into evaluates it over the plane's touched words
plus two register-masked edge words: no scratch slot carved, no derived
membership word written, no row id. Keep is never fused — it is the
explicit election of a bitmap.
- ir.rs: FusedTerminal / FusedFold, Program::fused_terminal, derived
Program::requires_scratch, touched_words (the one span spelling)
- exec.rs: fused dispatch after the slot-ceiling check, validation kept
total via a local bookkeeping word; Scratch::for_program /
over_for_program carve zero slots when !requires_scratch
- tests/fused_terminal.rs: fold vs Keep vs scalar oracle over 4 row
counts x 4 plane shapes x the named edge ranges; poisoned-arena gate
(fold writes nothing, Keep's carve is visible); allocation twin;
exact-shape guard; touched-word law; validation still refuses
No ndarray primitive needed: the range's interior mask is all ones, so
existing popcount_batch_u64 / mask_any over the borrowed plane suffice.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG
The harness runs tests on parallel threads; a process-wide counter picked up 120 stray bytes from a sibling test inside the sizing window. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG
…Count Reports latency (median), derived membership words written and plane words read separately; asserts both arms agree on every case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG
…uted for Range ∩ plane New entry records the Wave 0 re-audit (tiled scratch made the population-sized claims stale; derived tile writes remained), the fused lowering, measurements, disable-verified falsifiers, and the WORKING-MODEL classification of the remaining ops. Status cells updated for D-WFL-W2b‴ and D-WFL-T1-FUSED′ only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_45fdeef7-4598-4086-b4b1-8ff211f93fb5) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: daa1585682
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let mut written = [0u64; 1]; | ||
| validate(program, planes, foreign, out_shape(&out), &mut written)?; |
There was a problem hiding this comment.
Size the fused validation bitmap for the destination slot
When a valid fused program writes to scratch slot 64 or higher, this one-word bitmap cannot record the destination: validate silently fails to mark the out-of-range bit and then rejects the terminal read with ScratchReadBeforeWrite. For example, a single Pred::Range { dst: 64 } followed by Count { mask: Scratch(64) } is accepted by Program::new and succeeds on the reference path, but now fails in execute_into; size the temporary bitmap for the addressed slot or validate the fused shape without scratch bookkeeping.
Useful? React with 👍 / 👎.
…ithout rebasing execute_into is now execute_extent over 0..n_rows. A partial extent is an outer restriction in the same absolute row coordinates as Planes: only the words it touches are visited (extent_tiles), a cut word is restricted in a register at the terminal, lanes and masks are never copied or rebased, and the #1268 fused fold intersects the program's range with the extent. Partial extents accept Count/Any/All/MaskedSum/Min/Max (shipped merge laws) and Keep (writes only in-extent bits of its absolute Out::Mask); anything else is ExtentUnsupported. Foreign planes are key-addressed and never sliced. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG
Nine STATUS_BOARD rows still read "In PR" or "Queued" for work that has merged. Each flip was checked against origin/main before editing: - D-WFL-FUSE Shipped: single-op #1270, multi-op chains ≤3 planes #1272 - D-WFL-W2b‴ Shipped W2b-A #1268; W2b-B reuse burden stays OPEN - D-WFL-EXTENT Shipped #1269 (`execute_extent`) - D-WFL-T1-FUSED, T1-FUSED′ Shipped (ndarray #322 + #1270) - D-WFL-L0 Shipped #1251 - D-WFL-W2a Shipped #1268: un-gated Pred::Range, Count = hi−lo, Any = lo<hi, zero scratch (`run_fused`) - D-WFL-W2a′ Shipped #1268: `requires_scratch()` derived from the fused lowerings, never a caller flag - D-WFL-2 Partially shipped: range Count/Any landed as a lowering, the `BoundedMask` window is not built Status cells only; every row's description is unchanged, and the old status is kept after "was:" where it carried detail. The row count stays at 2203 lines. Also corrects one exec.rs comment that still described the Boolean fold as "a single 2/3-input op"; since #1272 it collapses whole chains. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG
Summary
This PR implements capstone wave W2b-A ("mask expression → terminal").
The core idea: a mask expression denotes a set of rows. Whether that set is ever written out as a bitmap should be decided by the terminal, not by the op that computes it.
For
Range[lo,hi) ∩ resident planefolded toCountorAny, the executor now computes the answer directly from the resident plane:Keepis never fused. It is the explicit request for a bitmap, and it still writes the demandedOut::Mask.Re-audit before building (Wave 0, on main
33df0710)words_for(n_rows)". Since quack: HAVING over the K sinks, with a NULL-preserving grouped SUM #1266, scratch is tile-sized (at most 8 words).mask_set_range+mask_and_assign, then read the result back withpopcount_batch_u64. It also walked every tile, however narrow the range.Changes (
crates/lance-graph-mask-risc)Program::fused_terminal()recognises exactly[Pred{Range, under: None | Plane}]followed byCountorAnyon that slot.Program::requires_scratch()is derived fromfused_terminal(), not a separate flag.touched_words(lo, hi)is the single definition of the touched word span, used by both the executor and the tests.execute_intodispatches fused programs before its scratch checks. Validation still runs in full; it tracks its one declared slot in a local word instead of the caller's scratch.Scratch::for_program/over_for_programcarve zero slots whenrequires_scratch()is false.No second evaluator, no new IR, and no ndarray change.
D-WFL-T1-FUSED′ is refuted for this shape. A range's interior words are all ones, so the existing
popcount_batch_u64/mask_anyover the borrowed plane slice are enough. This was a lowering rule (as D-WFL-FUSE predicted), not a missing primitive. The general plane-∩-plane count still has no buffer-free primitive; see the board entry.Measurements
cargo run --release -p lance-graph-mask-risc --example range_fused_probe. The two arms are asserted equal on every case. Latencies are medians in ns.The word columns come from the executor's contract, not from instrumentation. The fused arm's zero writes is the value the gate test below enforces.
Tests (
tests/fused_terminal.rs, 7 tests, disable-verified)Keep→ popcount/any == scalar oracle.[65,65),[0,0), single row, aligned/unalignedloandhi, inside one word, across one word, across tiles, a tail shorter than 64 rows, whole population.u64::MAX, and must still be allu64::MAXafter the fold runs. A twin check proves the same probe does seeKeep's carve.Scratch::for_programallocates 0 bytes for a fold, counted per thread. A twin check proves the counter seesKeep's allocation.Allterminal is not fused.lo == hi→ 0 words, otherwisefloor((hi-1)/64) - floor(lo/64) + 1.fused_terminalentirely turns 4 of the 7 tests red.cargo test -p lance-graph-mask-risc -p lance-graph-quackpasses, including the DuckDB differential.clippy -D warningsand fmt are clean.Board
.claude/board/entries/2026-09-23-terminal-elects-materialization-range-plane.md. It also records a working-model classification of the remaining ops.Not done here
🤖 Generated with Claude Code
https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG
Generated by Claude Code