Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .claude/board/STATUS_BOARD.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
| D-DT64-6-3 | register OGIT verbs as DT64 predicates in 64-wide blocks | Queued | D-DT64-6-2 green |
| D-DT64-6-4 | consumer read-only access via HotPlug activation | Queued | D-DT64-6-3 green |
| D-DT64-6-5 | OGIT becomes cross-check oracle once a domain has attested predicates | Queued | one attested domain |
| D-DT64-6-BS | `crates/lance-graph-dt64`: the bind store (workspace member, contract-only dep). Closes D-DRDT §4 gaps 1–4 (MethodId + SigRev, K3 guard as `SetExpr` + `Logic`, ordered effects, one `resolve`); D5 immutable classid, derived classid + versioned route log; D-DRDT §5 falsifier | In PR (#1869) | 19 tests green, clippy/fmt clean; disable runs (Amendment A.5) |
| D-DT64-6-BS | `crates/lance-graph-dt64`: the bind store (workspace member, contract-only dep). Closes D-DRDT §4 gaps 1–4 (MethodId + SigRev, K3 guard as `SetExpr` + `Logic`, ordered effects, one `resolve`); D5 immutable classid, derived classid + versioned route log; D-DRDT §5 falsifier | **Shipped** #1869 | 19 tests green, clippy/fmt clean; disable runs (Amendment A.5) |

## D-DT64 — DTO Tensor 64: versioned semantic predicate adapter and DR projections (2026-10-26)

Expand Down Expand Up @@ -90,7 +90,7 @@
| **D-ONNX-INTAKE-3** | S3 one complete static subgraph on existing native methods | Tract arm RUN as lab (D-TRACT-HARVEST-0): tiny graph exact, Jina RMSNorm slice bounded | scalar oracle + ORT; no Burn/Tract in the native call path; unsupported nodes refuse |
| **D-ONNX-INTAKE-4** | S4 numeric/quantization parity for real model blockers | Queued (conditional; not authorized) | IntegerExact / bounded FP / SourceParity / CertifiedMath kept distinct |
| **D-ONNX-INTAKE-5** | S5 whole-model forward pass and cost closure | Goal, not authorized | outputs vs ORT under declared tolerance; every cost stage reported |
| **D-TRACT-HARVEST-0** | ONNX graph as a DR#3 graph (nodes Identity, values Property, dep = do_ ∘ read_by) resolved through a DT64 ON×WHEN×DO registry (op signature → classid → native DO); Tract cold facts; ORT (optimizer off) oracle; `crates/tract-harvest-probe` | Lab probe implemented (this PR, redesigned to the graph); plan [d-tract-harvest-0-native-algebra-bridge-v1.md](../plans/d-tract-harvest-0-native-algebra-bridge-v1.md) §0 | 26 tests, 13 disable runs red; full model 4,146/7,620 nodes WHEN-true with inference-stage facts (§0.1), 0 refused for missing facts, >64 positions untiled, first unregistered groups Unsqueeze/Shape/Gather/Concat/MatMul |
| **D-TRACT-HARVEST-0** | ONNX graph as a DR#3 graph (nodes Identity, values Property, dep = do_ ∘ read_by) resolved through a DT64 ON×WHEN×DO registry (one ONNX lens classid; each op signature a field under it labelling a classid-free algebra address → native DO, #1870); Tract cold facts; ORT (optimizer off) oracle; `crates/tract-harvest-probe` | Lab probe implemented (this PR, redesigned to the graph); plan [d-tract-harvest-0-native-algebra-bridge-v1.md](../plans/d-tract-harvest-0-native-algebra-bridge-v1.md) §0 | 26 tests, 13 disable runs red; full model 4,146/7,620 nodes WHEN-true with inference-stage facts (§0.1), 0 refused for missing facts, >64 positions untiled, first unregistered groups Unsqueeze/Shape/Gather/Concat/MatMul |
| **D-TRACT-SHAPE-1** | Cold shape-subgraph folding (Const/Shape/Symbolic/Data classes; fold through the node's own WHEN/DO; stale-input refusal), shape-op registrations (Shape, Gather i64, Unsqueeze, Concat, Reshape, Cast i64, Erf via `vserf`, scalar-Y Where via `blend_i32_scalar`), producer-checked Tract fact admission | **Shipped** #1853 + follow-up In PR (lab probe); plan [d-tract-harvest-0-native-algebra-bridge-v1.md](../plans/d-tract-harvest-0-native-algebra-bridge-v1.md) §0.2–§0.4 | #1853 merged (40 tests, 9 disable runs red; coverage 4,146/0/3,474 → 6,404/56/1,160). Follow-up **In PR**: registry v3 (int64 compares/Where, ConstantOfShape, Expand), optional-output producer test; coverage 6,581/114/925. Checked int64 follow-up **In PR** (plan §0.4): registry v4, int64 Add/Sub/Mul/Div/Range on ndarray #401; `i64_arith` folds and matches ORT; Jina 6,871/1/748, all shape-dependent Reshapes fold; remaining shape-only blockers are the rotary-embedding chain, And, one broadcast LessOrEqual. Rotary follow-up **In PR** (plan §0.5): registry v5 (Cast i64→f32/bool, MatMul f32, Transpose, Cos/Sin, And, any-broadcast compares), pinned external inv_freq; Jina rotary fold matches ORT ≤ 1 ULP; Jina 7,274/0/346, 0 shape-only nodes blocked (#1858 merged). Bind-store consumer follow-up **In PR** (plan §0.6): `bind::route` / `bind::resolve` split the registry into DR64 route and DT64 bind store; equal to `lookup` on all tiny fixtures; Jina 7,274 routed+resolved / 346 unrouted (#1865 merged). **Correction In PR** (plan §0.7): one classid is the ONNX codebook lens; op signatures are items `MethodKey { lens, ordinal }` (registry v6). **Field view** #1867 merged (plan §0.8); ONNX is one classid (`ONNX_LENS`), per-op ids purged from the plan text and from D-DT64-6 A.2 (In PR): registry v7 splits lens-agnostic algebra addresses (`methods`) from the lens's labelled fields (`regs`) and its `WideFieldMask` (`exposed`) |

## D-TFLP — TFLite models on the native polyfill: int8 codes as Palette256 (2026-10-25)
Expand Down
46 changes: 46 additions & 0 deletions .claude/plans/d-dt64-6-routing-bindstore-behavior-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,3 +291,49 @@ The physical lane kind (u32 code vs i32, which picks XLOG's comparator) is the S
- `MethodBinding::footprint()` is ON ∪ reads ∪ writes, and `Resolved::methods_touching(mask)` lists the methods a meaning mask reaches. A risk or RBAC mask thereby applies to behaviour, not only to fields.

Open, for the frame owner (D8): registering a class or declaring an algebra entry moves no revision a frame can check; only routes are versioned. Classes and entries are immutable and append-only, so nothing a frame read can change. Whether a frame should still record the store's catalogue extent (for example a count of bindings) is undecided.

**A.5 addendum 7 (2026-10-30, after #1869 and #1870 merged).** #1870 settles addendum 1's open question on tract-harvest-probe's per-op classids: there is one ONNX lens classid (`ONNX_LENS`), and each op signature is a field under it labelling a classid-free algebra address. That is the shape this crate implements: the lens is a registered class, its fields come from its `ClassView`, and each method's effects reference `AlgebraEntry`s by `AlgebraRef`. Addendum 1's `EffectOp::Call` text is superseded by addendum 3. Still open: whether tract's `MethodKey { lens, ordinal }` and this crate's `MethodRef { class, method }` are one identity (EXO-50); the frame extent question above.

**A.5 addendum 8 (2026-10-30, operator: "ever heard of polyfill?").** The question "who declares the catalogue entries and assigns their ids" had an answer all along: the polyfill. In `ndarray::simd` a consumer names a facade word and nothing else. Nobody declares the word to the consumer and nobody assigns it a number, and which backend realizes it is decided per build. So:
- `AlgebraId` is removed. `AlgebraRef` is the word's facade path; there is no second, numeric spelling.
- The per-entry `SigRev` and `AlgebraRevisionMismatch` are removed. A changed realization keeps the word, and a different operation is a different word.
- `AlgebraEntry { word, inputs }` only mirrors the word's arity so `ArityMismatch` can be checked. The polyfill decides what the word is; the store mirrors it, and a word mirrored with two arities is refused (`AlgebraImmutable`).

Which polyfill (operator: "check lance-graph-relalg and lance-graph-mask-risc, that's the polyfill"): `lance-graph-relalg` describes a selection and lowers it, `lance-graph-mask-risc`'s op vocabulary (`Pred`, `MaskOp`, `Terminal`) is the one polyfill above `ndarray::simd` that every fold lowers to, and `ndarray::simd` computes. So a keyed count names mask-risc's `Terminal::GroupReduce { key: GroupKey::Lane, fold: GroupFold::Count }`, not the `ndarray::simd` word it delegates to. mask-risc has no elementwise i64 arithmetic, so XLOG's multiply names an `ndarray::simd` word. That word was reachable only as `ndarray::hpc::checked_i64::checked_binary_i64`; a consumer never names `hpc`, so ndarray #407 re-exports it through `ndarray::simd`. Disable runs (on commit `d140ab4c8`): removing the `AlgebraImmutable` arm or the `UnknownAlgebra` check each leaves exactly one test red (18 passed, 1 failed).

**A.5 addendum 9 (2026-10-30, operator: "your DTO mapping is one classid one meaning surface, same as ClassView WideFieldMask; did you use the pattern").** No: addendum 8 kept the polyfill as a string-keyed catalogue beside `ClassView`, a second meaning surface. Now the polyfill vocabulary is one lens classid, read the way every class is read:
- Its words are the fields of that lens, and their labels (the mask-risc op or `ndarray::simd` word) come from its `ClassView`.
- A word is a field position, `AlgebraRef { lens, word }`, and a set of words is a `WideFieldMask`.
- `declare_algebra(lens, schema_rev, arity)` binds the lens with one operand count per word. It is immutable like a class (`AlgebraImmutable`).
- `resolve_algebra` reads the lens through its `ClassView`, with the same schema-revision and field-basis checks as `resolve` (one shared `check_basis`). `field_view` gives each word's position and label.
- `words_used(class, lens)` gives a consumer's words as a mask over the lens.

No word gets a classid. This is the ONNX shape of #1870, applied to the polyfill. Disable runs on `9d2fba457`, each turning tests red:

| guard removed | failing tests |
|---|---|
| the `words_used` lens filter | 1 |
| the `AlgebraImmutable` arm | 1 |
| the arity position | 5 |
| the shared basis check | 4 |

Which classid the polyfill lens carries in production is OGAR's mint (D6), not this crate's; the test uses a lab value.

**A.5 addendum 10 (2026-10-30, operator: "make sure that consumers like ONNX are not limited to 64 but instead can choose the other modes like DR256² × 64").** A.1 already gives the binding this job: it names DR64 or DR256 and states its cost in those units. Until now the store only capped a class at 256 fields. `ClassSchema` now carries an `Extent` the consumer chooses:
- The extent is Identity × Property × Predicate, each axis `Width::W64` or `Width::W256`. `Extent::DR64_CUBE` and `Extent::DR256_SQ_X64` are named, and any other combination is allowed.
- Registration refuses fields past the property axis (`FieldsExceedExtent`) and methods past the predicate axis (`MethodsExceedExtent`).
- The extent is part of the immutable binding (D5).
- `dense_bytes` states what a dense Boolean volume of the extent would cost if anyone materialized one: DR64³ is 32 KiB and DR256² × 64 is 512 KiB. It is a cost statement and allocates nothing (§7).
- The polyfill lens declares its extent too.

The test registers an ONNX graph with 200 values: DR64³ refuses it, naming the axis, and DR256² × 64 binds it. A graph with 70 nodes needs a 256-wide predicate axis.

Disable runs on the extent commit:

| guard removed | failing tests |
|---|---|
| the property-axis check | 1 |
| the predicate-axis check | 1 |
| W256 read as 64 | 2 |

Still capped at 64: `tract-harvest-probe`'s `dr3::TILE = 64`, a single DR64 tile built from `relcomp::Rows = [u64; 64]`. That is the tract session's lab crate. Its full model (4,146 of 7,620 nodes WHEN-true) already reports ">64 positions untiled". Lifting it is that session's change; the binding side no longer forces 64.
6 changes: 5 additions & 1 deletion crates/lance-graph-contract/src/morton8x8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,11 @@ mod tests {
for start in (0..=u16::MAX as u32).step_by(run as usize) {
let first = Morton8x8::from_code(start as u16);
let (x0, y0) = (u32::from(first.x()), u32::from(first.y()));
assert_eq!((x0 % side, y0 % side), (0, 0), "j={j} run {start}: corner not aligned");
assert_eq!(
(x0 % side, y0 % side),
(0, 0),
"j={j} run {start}: corner not aligned"
);
let mut seen = vec![false; run as usize];
for c in start..start + run {
let m = Morton8x8::from_code(c as u16);
Expand Down
Loading
Loading