Skip to content

Commit f789f62

Browse files
committed
symbiont: ractor = ownership guarantee, not a message bus (align D2 to canon)
Operator: "no tokio, we use ractor as a runtime ownership guarantee, it's a dummy; we don't use ractor messages." A message-passing ractor actor would have contradicted E-CE64-MB-4 (mailbox-as-owner: Rust move/&mut proves no-aliasing/no-race/no-UAF at compile time) and #477 (nothing transmitted between mailboxes). Dropped that plan — no tokio, no Actor::spawn, no messages. SymbiontBoard's single `&mut self` owner ALREADY IS that guarantee in plain Rust (what ractor hosts in prod, a structural/dummy wrapper). step() drives by owned mutation, never a message. D2's loop is therefore complete for the POC; the only genuinely-live deferral is replacing the u32 tick with a real Lance versions() stream (needs a live dataset) + the SurrealQL re-read. Doc-only: kanban_loop.rs module doc reframed; STATUS_BOARD D2 deferred fixed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CcpLeEC3XK8Eye53GKBVvi
1 parent 6b2114e commit f789f62

2 files changed

Lines changed: 15 additions & 5 deletions

File tree

.claude/board/STATUS_BOARD.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ The golden image (`crates/symbiont`, workspace-`exclude`d): the full Ada stack i
88
| D1 | Grid→NodeRow bridge — each bus = 1 SoA board, f64 → `Energy` tenant | symbiont/bridge.rs | **Shipped** | 2 probes green; 64 buses→64 NodeRows, perturbation in the Energy(f32) tenant, all finite |
99
| E2 | Parallel SoA sweep at scale (16k boards = 8 MiB, zero-copy) | symbiont/bridge.rs | **Shipped** | `run_scale_demo(16384)` → 8 MiB, all 16384 Energy tenants finite |
1010
| D3-AMX | Domino POC — 16-board AMX 16×16 BF16 Morton-tile cascade + NaN-projection | symbiont/domino.rs | **Shipped** | 3/3 tests green; 256 boards × 16 AMX-16×16 batches × 3-stage BF16 Morton-tile Domino cascade, NaN-clean via the projection surface. Polyfill-only (`ndarray::simd::bf16_tile_gemm_16x16` re-export `05bfea7a` jirak; `f32_to_bf16_batch_rne`; only `morton4` consumer-side). **Ran AVX-512 fallback** — AMX genuinely OFF on this guest (functional probe `/tmp/amxcheck`: XCR0 tile bits 17/18 = 0, `arch_prctl(158)` XTILEDATA = **-95 -EOPNOTSUPP** kernel refuses; CPUID also masked). NOT merely CPUID-masked → cannot be enabled here; a forced byte-encoded TDPBF16PS would fault. AMX dispatch correct + arch_prctl-158 gotcha-safe; fires `[AMX TDPBF16PS]` on an AMX-granted guest. |
11-
| D2 | Kanban loop — pure-SoA slice (version-tick → `NextPhaseScheduler``try_advance_phase`) | symbiont/kanban_loop.rs | **Shipped (slice)** | 2/2 tests green; `SymbiontBoard` impls `MailboxSoaView`+`MailboxSoaOwner` over the `Vec<NodeRow>`, a `u32` tick stands in for the Lance subscription; drove `Planning→CognitiveWork[BF16 Domino sweep]→Evaluation→Commit`, Libet anchor on the Σ-crossing, halted absorbing in 3 cycles, NaN-clean. Reuses the COMPLETE contract kanban surface (`KanbanColumn`/`KanbanMove`/`NextPhaseScheduler`/`MailboxSoa{View,Owner}`) — zero new types. **Deferred (named):** live `LanceVersionScheduler`/`LanceVersionWatcher` subscription, the ractor `Actor` wrapper (pattern off `StubConsumerActor`), SurrealQL `read_via_kv_lance`. |
11+
| D2 | Kanban loop — pure-SoA slice (version-tick → `NextPhaseScheduler``try_advance_phase`) | symbiont/kanban_loop.rs | **Shipped (slice)** | 2/2 tests green; `SymbiontBoard` impls `MailboxSoaView`+`MailboxSoaOwner` over the `Vec<NodeRow>`, a `u32` tick stands in for the Lance subscription; drove `Planning→CognitiveWork[BF16 Domino sweep]→Evaluation→Commit`, Libet anchor on the Σ-crossing, halted absorbing in 3 cycles, NaN-clean. Reuses the COMPLETE contract kanban surface (`KanbanColumn`/`KanbanMove`/`NextPhaseScheduler`/`MailboxSoa{View,Owner}`) — zero new types. **ractor = ownership guarantee** (no messages, no tokio; E-CE64-MB-4 / #477 "nothing transmitted between mailboxes") — already embodied by `SymbiontBoard`'s single `&mut` owner, NOT a deferred message actor. **Deferred (needs a live Lance dataset):** replace the `u32` tick with the real version stream (`LanceVersionScheduler`/`LanceVersionWatcher` over `versions()`) + SurrealQL `read_via_kv_lance`. |
1212
| E1 | Spain-grid acceptance gate (real fixture, NaN-free, clippy+machete clean) | symbiont | Queued | the north star — first N *real* nodes on the SoA in parallel |
1313
| BT | Battle-test plan (probes A1–E3, gated behind singleton-BindSpace→SoA) | workspace | **Shipped (doc)** | `crates/symbiont/BATTLE_TEST_PLAN.md`; A1 partial-green + D1 green; A2–E3 specced |
1414

crates/symbiont/src/kanban_loop.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,20 @@
1616
//! Evaluation → Commit` (absorbing → halt). The scheduler PROPOSES (`&view`); the
1717
//! owner DISPOSES (`&mut`) — R1 read/write split, the same as in the contract.
1818
//!
19-
//! DEFERRED (named, shipped types to swap in): the real Lance subscription
20-
//! (`lance-graph` `LanceVersionScheduler::drive_at_latest` / callcenter
21-
//! `LanceVersionWatcher::wait_changed`), the ractor `Actor` wrapper (pattern off
22-
//! `lance-graph-supervisor` `StubConsumerActor`), and the SurrealQL re-read
19+
//! OWNERSHIP (operator, 2026-06-20): ractor is the **runtime ownership
20+
//! guarantee**, NOT a message bus — "the mailbox-as-owner ... Rust move/ownership
21+
//! semantics prove no aliasing / no data race / no use-after-free at compile
22+
//! time" (CLAUDE.md E-CE64-MB-4; PR #477: nothing is serialized or transmitted
23+
//! between mailboxes). So there is **no ractor message actor here and no tokio**:
24+
//! `SymbiontBoard`'s single `&mut self` owner IS that guarantee, in plain Rust —
25+
//! ractor would host the exact same ownership in prod (a structural/dummy
26+
//! wrapper, never a message handler). `step()` drives the loop by direct owned
27+
//! mutation, never by sending a message.
28+
//!
29+
//! DEFERRED (the genuinely-live half — both need a live Lance dataset): replace
30+
//! the `u32` `version_tick` with the real Lance version stream
31+
//! (`LanceVersionScheduler::drive_at_latest` over `VersionedGraph::versions()` /
32+
//! callcenter `LanceVersionWatcher`), and wire the SurrealQL re-read
2333
//! (`surreal_container::view::read_via_kv_lance`).
2434
2535
use lance_graph_contract::canonical_node::NodeRow;

0 commit comments

Comments
 (0)