From 61b641d57f1df36004a1cd06aa670f9c623c7aba Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 28 May 2026 11:00:10 +0000 Subject: [PATCH 1/6] feat(driver/A2): add transitional per-mailbox routing field+builder [/// work] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a sibling routing surface to ShaderDriver alongside the existing Arc singleton, letting consumers opt into per-mailbox routing before the S3 cutover: HashMap> field, a with_mailbox builder setter on CognitiveShaderBuilder, and a mailbox() read accessor. Additive only — no existing method or field touched. https://claude.ai/code/session_01LiUiGeUDLje8KMnxB4FfA3 --- crates/cognitive-shader-driver/src/driver.rs | 42 ++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/crates/cognitive-shader-driver/src/driver.rs b/crates/cognitive-shader-driver/src/driver.rs index 6496092a..72588894 100644 --- a/crates/cognitive-shader-driver/src/driver.rs +++ b/crates/cognitive-shader-driver/src/driver.rs @@ -45,6 +45,10 @@ use p64_bridge::cognitive_shader::CognitiveShader; use crate::auto_style; use crate::bindspace::{BindSpace, WORDS_PER_FP}; +/// work +use crate::mailbox_soa::MailboxSoA; +/// work +use lance_graph_contract::collapse_gate::MailboxId; // ═══════════════════════════════════════════════════════════════════════════ // ShaderDriver — holds everything the shader needs to drive @@ -72,6 +76,15 @@ pub struct ShaderDriver { /// Lives in `causal-edge` (zero-dep), so attaching it does NOT pull /// the planner into shader-driver. pub(crate) nars_tables: Option>, + /// work + /// Transitional per-mailbox routing surface (slice A2). + /// + /// Consumers can opt into per-mailbox routing by inserting + /// `MailboxSoA<1024>` instances here via the builder's + /// `with_mailbox` method. The singleton `Arc` (above) + /// is unchanged — this field is purely additive and does not alter + /// any existing dispatch semantics. Removed at cutover (plan S3). + pub(crate) mailboxes: std::collections::HashMap>, } impl ShaderDriver { @@ -92,6 +105,7 @@ impl ShaderDriver { default_style, awareness: RwLock::new(awareness), nars_tables: None, + mailboxes: std::collections::HashMap::new(), } } @@ -111,6 +125,18 @@ impl ShaderDriver { self.nars_tables.as_ref() } + /// work + /// Return a read reference to the `MailboxSoA<1024>` registered under + /// `id`, or `None` if no mailbox with that id has been inserted via + /// the builder's `with_mailbox` method. + /// + /// The singleton `Arc` is unchanged by this accessor. + /// This is the transitional per-mailbox routing read surface (slice A2). + #[inline] + pub fn mailbox(&self, id: MailboxId) -> Option<&MailboxSoA<1024>> { + self.mailboxes.get(&id) + } + /// Borrow the underlying BindSpace (read-only). #[inline] pub fn bindspace(&self) -> &BindSpace { &self.bindspace } @@ -596,6 +622,10 @@ pub struct CognitiveShaderBuilder { planes: Option<[[u64; 64]; 8]>, default_style: u8, nars_tables: Option>, + /// work + /// Transitional per-mailbox routing map populated by `with_mailbox`. + /// Forwarded into `ShaderDriver::mailboxes` at `build()` time. + mailboxes: std::collections::HashMap>, } impl CognitiveShaderBuilder { @@ -606,6 +636,7 @@ impl CognitiveShaderBuilder { planes: None, default_style: auto_style::DELIBERATE, nars_tables: None, + mailboxes: std::collections::HashMap::new(), } } @@ -635,6 +666,16 @@ impl CognitiveShaderBuilder { self } + /// work + /// Register a `MailboxSoA<1024>` for transitional per-mailbox routing + /// (slice A2). The mailbox is keyed by `id`; a second call with the + /// same `id` replaces the previous entry. Multiple mailboxes are + /// supported. The singleton `Arc` is not affected. + pub fn with_mailbox(mut self, id: MailboxId, soa: MailboxSoA<1024>) -> Self { + self.mailboxes.insert(id, soa); + self + } + pub fn build(self) -> ShaderDriver { let awareness = (0..12) .map(|ord| GrammarStyleAwareness::bootstrap(ord_to_thinking_style(ord))) @@ -646,6 +687,7 @@ impl CognitiveShaderBuilder { default_style: self.default_style, awareness: RwLock::new(awareness), nars_tables: self.nars_tables, + mailboxes: self.mailboxes, } } } From 1df12eca2142a5d598c72e0c7e3654da20be4b82 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 28 May 2026 11:00:24 +0000 Subject: [PATCH 2/6] feat(mailbox-soa/A1): add thoughtspace columns (edges/qualia/meta/entity_type) [/// work] https://claude.ai/code/session_01LiUiGeUDLje8KMnxB4FfA3 --- .../src/mailbox_soa.rs | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/crates/cognitive-shader-driver/src/mailbox_soa.rs b/crates/cognitive-shader-driver/src/mailbox_soa.rs index a14a182f..e23b1e29 100644 --- a/crates/cognitive-shader-driver/src/mailbox_soa.rs +++ b/crates/cognitive-shader-driver/src/mailbox_soa.rs @@ -20,7 +20,9 @@ //! gated steps: `.claude/plans/bindspace-singleton-to-mailbox-soa-v1.md`. use causal_edge::CausalEdge64; +use lance_graph_contract::cognitive_shader::MetaWord; use lance_graph_contract::collapse_gate::{CollapseGateEmission, MailboxId, MergeMode}; +use lance_graph_contract::qualia::QualiaI4_16D; /// Spatial-temporal accumulator for per-row baton receipts. /// @@ -57,6 +59,33 @@ pub struct MailboxSoA { /// if `last_emission_cycle[row] == current_cycle`, emission is suppressed. pub last_emission_cycle: [u32; N], + // ── NEW: migrated thoughtspace columns (per-mailbox owned, D-MBX-A1) ── + + /// work + /// Per-row LE baton edge (`CausalEdge64`, 8 B/row). + /// Migrated from `BindSpace.edges` (EdgeColumn). + /// This IS the LE contract / baton edge for this mailbox row. + pub edges: [CausalEdge64; N], + + /// work + /// Per-row affective role vector (`QualiaI4_16D`, 8 B/row). + /// Migrated from `BindSpace.qualia` (QualiaI4Column). + /// 16 signed i4 dimensions (arousal/valence/tension/…); 9× compression vs f32. + pub qualia: [QualiaI4_16D; N], + + /// work + /// Per-row packed meta word (`MetaWord`, 4 B/row). + /// Migrated from `BindSpace.meta` (MetaColumn). + /// Layout: `thinking(6) + awareness(4) + nars_f(8) + nars_c(8) + free_e(6)`. + pub meta: [MetaWord; N], + + /// work + /// Per-row OGIT entity-type index (`u16`, 2 B/row). + /// Migrated from `BindSpace.entity_type`. + /// 1-based index into the shared (immutable) ontology registry. + /// The registry itself stays `Arc` (cold Zone-2, not owned here). + pub entity_type: [u16; N], + /// Monotonic cycle stamp; advanced by `tick()`. pub current_cycle: u32, @@ -97,6 +126,11 @@ impl MailboxSoA { current_cycle: 0, w_slot, threshold, + // ── NEW thoughtspace columns — zero-initialised (D-MBX-A1) ── + edges: [CausalEdge64::ZERO; N], + qualia: [QualiaI4_16D::ZERO; N], + meta: [MetaWord(0); N], + entity_type: [0u16; N], } } @@ -189,6 +223,11 @@ impl MailboxSoA { // Restore the "never emitted" sentinel so the row can emit immediately // on the next cycle without triggering the same-cycle guard. self.last_emission_cycle[row] = u32::MAX; + // ── NEW thoughtspace columns reset (D-MBX-A1) ── + self.edges[row] = CausalEdge64::ZERO; + self.qualia[row] = QualiaI4_16D::ZERO; + self.meta[row] = MetaWord(0); + self.entity_type[row] = 0; } // ── Read-only inspectors ────────────────────────────────────────────────── @@ -227,6 +266,70 @@ impl MailboxSoA { .filter(|&&e| e.abs() >= self.threshold) .count() } + + // ── Thoughtspace column accessors (D-MBX-A1) ───────────────────────────── + + /// work + /// Return the `CausalEdge64` baton edge for `row`. + /// + /// Panics (debug) / wraps (release) on out-of-bounds; callers + /// should stay within `[0, N)`. + #[inline] + pub fn edge(&self, row: usize) -> CausalEdge64 { + self.edges[row] + } + + /// work + /// Set the `CausalEdge64` baton edge for `row`. + /// + /// Panics (debug) / wraps (release) on out-of-bounds; callers + /// should stay within `[0, N)`. + #[inline] + pub fn set_edge(&mut self, row: usize, e: CausalEdge64) { + self.edges[row] = e; + } + + /// work + /// Return the packed `QualiaI4_16D` affective vector for `row`. + #[inline] + pub fn qualia_at(&self, row: usize) -> QualiaI4_16D { + self.qualia[row] + } + + /// work + /// Set the packed `QualiaI4_16D` affective vector for `row`. + #[inline] + pub fn set_qualia(&mut self, row: usize, q: QualiaI4_16D) { + self.qualia[row] = q; + } + + /// work + /// Return the packed `MetaWord` for `row`. + #[inline] + pub fn meta_at(&self, row: usize) -> MetaWord { + self.meta[row] + } + + /// work + /// Set the packed `MetaWord` for `row`. + #[inline] + pub fn set_meta(&mut self, row: usize, m: MetaWord) { + self.meta[row] = m; + } + + /// work + /// Return the OGIT entity-type index for `row` (1-based, shared ontology). + #[inline] + pub fn entity_type_at(&self, row: usize) -> u16 { + self.entity_type[row] + } + + /// work + /// Set the OGIT entity-type index for `row`. + #[inline] + pub fn set_entity_type(&mut self, row: usize, t: u16) { + self.entity_type[row] = t; + } } #[cfg(test)] From ef848a341c07affeacdb95933e75eecd2c7f10e8 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 28 May 2026 11:00:31 +0000 Subject: [PATCH 3/6] feat(contract/A3): add WitnessTable column-type primitive (W-slot resolver) [/// work] Declares WitnessEntry + WitnessTable in lance-graph-contract::witness_table. Resolves the 6-bit W-slot index from CausalEdge64 v2 into per-cohort (mailbox_ref, spo_fact_ref) tuples; 3 unit tests green; zero new dependencies. https://claude.ai/code/session_01LiUiGeUDLje8KMnxB4FfA3 --- crates/lance-graph-contract/src/lib.rs | 2 + .../lance-graph-contract/src/witness_table.rs | 215 ++++++++++++++++++ 2 files changed, 217 insertions(+) create mode 100644 crates/lance-graph-contract/src/witness_table.rs diff --git a/crates/lance-graph-contract/src/lib.rs b/crates/lance-graph-contract/src/lib.rs index 6c88b7fe..b25f8bdd 100644 --- a/crates/lance-graph-contract/src/lib.rs +++ b/crates/lance-graph-contract/src/lib.rs @@ -84,6 +84,8 @@ pub mod splat; pub mod tax; pub mod thinking; pub mod vsa; +/// work +pub mod witness_table; pub mod world_map; pub mod world_model; diff --git a/crates/lance-graph-contract/src/witness_table.rs b/crates/lance-graph-contract/src/witness_table.rs new file mode 100644 index 00000000..c6d8d91e --- /dev/null +++ b/crates/lance-graph-contract/src/witness_table.rs @@ -0,0 +1,215 @@ +//! # `WitnessTable` — column-type primitive resolving the 6-bit W slot in `CausalEdge64 v2`. +//! +//! ## Architectural context +//! +//! `CausalEdge64 v2` (plan §6 / bits 53–58) reserves a **6-bit W-slot index** (0..=63) +//! that points into a *per-cohort* `WitnessTable<64>`. Each table entry is a +//! `(mailbox_ref, spo_fact_ref)` tuple: +//! +//! - `mailbox_ref`: identifies the mailbox that witnessed the belief — either currently +//! active or carrying a tombstone flag (see `contract::collapse_gate::MailboxId`). +//! - `spo_fact_ref`: optional handle into the AriGraph SPO-G quad store. `None` while +//! the belief is still accumulating in the mailbox's energy column; `Some(u64)` once +//! the belief crystallises and the triple is committed to graph. +//! +//! The chain of W-references across edges forms a **Markov-style belief-update arc** +//! through episodic-reference vectors: each edge's W-slot resolves to the entry that +//! witnessed the prior state, so the arc can be walked backwards (most-recent → oldest +//! witness) without dereferencing the full SPO store on every hop. +//! +//! ## Cohort scoping +//! +//! The table is *per-cohort*, not global. A cohort is a bounded set of collaborating +//! mailboxes (e.g. one rotating sea-star topology partition). `WitnessTable` takes +//! the cohort capacity as a const-generic; the canonical width is `N = 64` (matching +//! the 6-bit W-slot address space). Smaller `N` is legal for test harnesses; larger `N` +//! is UB in the W-slot protocol (indices ≥ 64 would exceed the field width). +//! +//! ## Plan cross-reference +//! +//! `.claude/plans/bindspace-singleton-to-mailbox-soa-v1.md` — §6 "W slot" defines the +//! bit layout, cohort scope, and the Markov arc traversal contract that this type +//! satisfies. Read that plan before wiring `WitnessTable` into emission paths (a later +//! slice). +//! +//! ## Slice scope (A3) +//! +//! This file declares the *column-type primitive only*. It does **not** wire the table +//! into `CausalEdge64`, `MailboxSoA`, or any emission path — those are later slices. + +// ── Type declarations ──────────────────────────────────────────────────────── + +/// work +/// A single entry in a per-cohort [`WitnessTable`]. +/// +/// Carries the pair `(mailbox_ref, spo_fact_ref)` that resolves one W-slot index: +/// +/// - `mailbox_ref` is a `u16` handle matching `contract::collapse_gate::MailboxId` +/// (declared as `pub type MailboxId = u32` there, but the table stores the lower 16 +/// bits since cohort sizes are bounded by the 6-bit W-slot). Callers that need the +/// full 32-bit id should widen at the call site. +/// - `spo_fact_ref` is `None` while the belief is ephemeral (energy accumulating) and +/// `Some(u64)` once the triple is committed to AriGraph (the "crystallisation" event). +/// +/// # Size +/// +/// `u16` (2 B) + discriminant + `u64` (8 B) = 10–12 B. `Option` packs as 16 B +/// via the niche-filling optimisation. `Copy` is intentional: the struct is small +/// enough to pass by value on any target ABI. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)] +pub struct WitnessEntry { + /// work + /// Handle to the mailbox that witnessed this belief event. + /// + /// Active mailboxes have a live `w_slot` association; tombstoned mailboxes retain + /// their ref so the arc walk can detect decommissioned cohort members. + pub mailbox_ref: u16, + + /// work + /// Optional reference into the AriGraph SPO-G quad store. + /// + /// `None`: the belief has not yet crystallised to a committed triple. + /// `Some(fact_id)`: the triple is committed; `fact_id` is the opaque u64 handle + /// used by the quad store's lookup surface. + pub spo_fact_ref: Option, +} + +/// work +/// Per-cohort witness table: a fixed-size array of [`WitnessEntry`] values indexed +/// by the 6-bit W-slot field from `CausalEdge64 v2`. +/// +/// The const parameter `N` is the cohort capacity. The canonical value is `N = 64` +/// (matching the 6-bit address space of the W-slot field). The default type alias +/// `WitnessTable` (no explicit `N`) uses `N = 64`. +/// +/// # Invariant +/// +/// The caller is responsible for ensuring that W-slot indices passed to [`get`] and +/// [`set`] are in `0..N`. Indices ≥ N return `None`/`Err` respectively — no panic. +/// +/// [`get`]: WitnessTable::get +/// [`set`]: WitnessTable::set +#[derive(Debug, Clone)] +pub struct WitnessTable { + /// work + /// Flat array of witness entries, one per addressable W-slot index. + pub entries: [WitnessEntry; N], +} + +// ── impl WitnessTable ──────────────────────────────────────────────────────── + +impl WitnessTable { + /// work + /// Construct a `WitnessTable` with every entry set to its zero-initialised default. + /// + /// `mailbox_ref` is 0 (the null mailbox handle) and `spo_fact_ref` is `None` + /// (belief not yet crystallised) for every slot. This is the correct starting + /// state for a freshly allocated cohort. + /// + /// `const fn` so tables can be embedded in `static` initialisers. + pub const fn new() -> Self { + Self { + entries: [WitnessEntry { + mailbox_ref: 0, + spo_fact_ref: None, + }; N], + } + } + + /// work + /// Look up the entry at `w_slot`. + /// + /// Returns `None` if `w_slot as usize >= N` (out-of-bounds for this cohort). + /// Returns `Some(&WitnessEntry)` otherwise. + pub fn get(&self, w_slot: u8) -> Option<&WitnessEntry> { + self.entries.get(w_slot as usize) + } + + /// work + /// Write `e` into slot `w_slot`. + /// + /// Returns `Ok(())` on success. + /// Returns `Err("w_slot out of range for this WitnessTable")` if + /// `w_slot as usize >= N` — no panic, caller decides how to handle overflow. + pub fn set(&mut self, w_slot: u8, e: WitnessEntry) -> Result<(), &'static str> { + match self.entries.get_mut(w_slot as usize) { + Some(slot) => { + *slot = e; + Ok(()) + } + None => Err("w_slot out of range for this WitnessTable"), + } + } +} + +// ── Default ────────────────────────────────────────────────────────────────── + +/// work +impl Default for WitnessTable { + /// work + fn default() -> Self { + Self::new() + } +} + +// ── Tests ──────────────────────────────────────────────────────────────────── + +#[cfg(test)] +mod tests { + use super::*; + + /// work + /// Round-trip: set a slot, then get it back and confirm the value matches. + #[test] + fn witness_table_round_trip_set_get() { + let mut table: WitnessTable<64> = WitnessTable::new(); + let entry = WitnessEntry { + mailbox_ref: 42, + spo_fact_ref: Some(0xDEAD_BEEF_0000_0001), + }; + table.set(7, entry).expect("slot 7 is in range"); + let got = table.get(7).expect("slot 7 must be present"); + assert_eq!(*got, entry, "get must return the exact entry written by set"); + } + + /// work + /// Out-of-bounds set returns Err; out-of-bounds get returns None. + #[test] + fn witness_table_out_of_bounds_returns_err() { + let mut table: WitnessTable<4> = WitnessTable::new(); + // slot 4 is out of bounds for N=4 (valid range: 0..=3) + let result = table.set(4, WitnessEntry::default()); + assert!( + result.is_err(), + "set with w_slot >= N must return Err, got Ok" + ); + assert_eq!(table.get(4), None, "get with w_slot >= N must return None"); + // Confirm the in-range slots are untouched + for i in 0u8..4 { + assert_eq!( + table.get(i), + Some(&WitnessEntry::default()), + "slot {i} must still be default after out-of-bounds write" + ); + } + } + + /// work + /// A freshly constructed table has all entries at their zero default: + /// `mailbox_ref = 0`, `spo_fact_ref = None`. + #[test] + fn witness_table_default_is_all_zero() { + let table: WitnessTable<64> = WitnessTable::default(); + for i in 0u8..64 { + let entry = table.get(i).expect("all 64 slots must be present"); + assert_eq!( + entry.mailbox_ref, 0, + "slot {i}: mailbox_ref must be 0 on default" + ); + assert_eq!( + entry.spo_fact_ref, None, + "slot {i}: spo_fact_ref must be None on default" + ); + } + } +} From 0f448730fd649f2427bda68eb665c6335546d16b Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 28 May 2026 11:04:26 +0000 Subject: [PATCH 4/6] =?UTF-8?q?docs(plan/A4):=20append=20=C2=A710=20archit?= =?UTF-8?q?ectural=20refinements=20[]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://claude.ai/code/session_01LiUiGeUDLje8KMnxB4FfA3 --- .../bindspace-singleton-to-mailbox-soa-v1.md | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/.claude/plans/bindspace-singleton-to-mailbox-soa-v1.md b/.claude/plans/bindspace-singleton-to-mailbox-soa-v1.md index fe260c1e..3da1dd77 100644 --- a/.claude/plans/bindspace-singleton-to-mailbox-soa-v1.md +++ b/.claude/plans/bindspace-singleton-to-mailbox-soa-v1.md @@ -396,3 +396,39 @@ accumulator), `EPIPHANIES.md` (`E-BATON-1`, `E-CE64-MB-4`, `E-LADDER-SERVES-MAIL `I-VSA-IDENTITIES`, `I-LEGACY-API-FEATURE-GATED`), `.claude/surreal/RECONCILIATION_with_canonical_plan.md` (Vsa16kF32-deprecation contradiction flag), code: `crates/cognitive-shader-driver/src/{bindspace.rs, mailbox_soa.rs, driver.rs, engine_bridge.rs, bin/serve.rs}`. + +--- + +## §10 — 2026-05-28 architectural refinements (post-PR-#423 sync) + +The following refinements were ratified after the initial plan was written. They are +append-only findings; no prior section has been modified. + + +1. **SoA Lance container ≠ cascade.** The cascade is resolution-laddered superposition over per-axis granularities; the SoA Lance container is the materialized data substrate (same SoA the cognitive-shader-driver handles, same SoA the singleton BindSpace updated). One cascade resolves to one or more SoA Lance containers via top-k emission (Gaussian splat / CAM-PQ top-k). The container is the StreamDTO operand variable; the cascade is the resolver function. + + +2. **Cascade is NOT an index space.** L1-L4 (`64²/256²/4096²/16384²`) are per-axis granularities on the same semantic axis (causal / palette / COCA codebook / outcome), superposed and streamed like x265 cascaded prediction levels. No level is fully materialized; only the emission (rendered SoA container) reaches downstream. + + +3. **64K-256K mailbox envelope** (~360 MB - 1.4 GB total working set at 6 KB per mailbox). The whole population is RAM-resident on any reasonable server. No hot/warm/cold tier split needed. Tombstone retention is free at this scale; eviction is moot. + + +4. **W-slot resolves into a per-cohort witness table** of `(mailbox_ref, spo_fact_ref)` entries — NOT a witness-corpus pointer to a static repository. Active mailboxes carry a mailbox-ref alone (spo_fact_ref = None); once the belief crystallizes via Rubicon commit, the spo_fact_ref binds to the SPO triple. Tombstones stay reachable through their mailbox-ref. The chain of W-references across edges forms a Markov belief-update arc via AriGraph episodic-reference vectors (AriGraph today is a transcode; the chaining engine is the target shape). + + +5. **Cascade granularities are CPU/cache boundaries, not abstract resolutions.** 64 = AVX-512 i8 register / cache line; 256 = AMX tile row; 4096 = page (4 KiB); 16384 = L1d cache (16 KiB). The ladder is hardware-natural so SIMD sweeps stay register/cache/page-aligned by construction. + + +6. **`simd_soa.rs` (ndarray) is the SoA dispatch framework.** It adapts to any SoA shape by introspecting members; consumers declare their own column tuple via derive/const-generic and get SIMD sweeps for free. The MailboxSoA migration is positional, not structural — the framework already swallows the column shape. + + +7. **SoA invariant from spawn → commit.** The same SoA byte layout runs end-to-end: cognitive-shader-driver creates a mailbox + SoA via cascade hot path → traverse cold path with gridlake SIMD ops → commit via one of two egress modes: **external** (REST / sea-orm SQL via tokio, backpressure expected) or **internal** (SurrealDB → LanceDB or RocksDB, no backpressure). No marshalling at any boundary; Lance columnar IS the repr. + +### Open Questions surviving these refinements + + +- **OQ-MBX-8** — `persisted_row` stub vs Lance native versioning (load-bearing; evidence at `REFACTOR_NOTES.md:129` + `driver.rs:458`). + + +- **OQ-MBX-15′** — container scoping: per-cognitive-cycle, per-shader-dispatch, or per-mailbox-cohort? From 683288784d88b00537585aae800f2c0d0ac037c6 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 28 May 2026 11:21:18 +0000 Subject: [PATCH 5/6] review(D-MBX-A1..A4): remove /// work markers + board hygiene (AGENT_LOG + LATEST_STATE) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Orchestrator review pass over the 4-worker wave on the bindspace-singleton-to-mailbox-soa migration: - D-MBX-A1 `feat(mailbox-soa): add thoughtspace columns` (commit 1df12eca) - D-MBX-A2 `feat(driver): add transitional per-mailbox routing` (commit 61b641d5) - D-MBX-A3 `feat(contract): add WitnessTable column-type primitive` (commit ef848a34) - D-MBX-A4 `docs(plan): append §10 architectural refinements` (commit 0f448730) This commit: 1. Removes all 41 `/// work` / `` markers across the 5 touched files (per the wave's scratch-marker discipline — orchestrator removes after validation). 2. Prepends D-MBX-A4 entry to AGENT_LOG.md (parity with A1/A2/A3 which prepended their own; A4 worked in a separate worktree branch so its prepend landed there, not on the standing branch — adding here for log continuity). 3. Updates `.claude/board/LATEST_STATE.md` "Current Contract Inventory" with the wave's additions (`WitnessEntry` + `WitnessTable` in `lance-graph-contract`; four thoughtspace columns + 8 accessors on `MailboxSoA`; transitional `mailboxes` HashMap + builder on `ShaderDriver`). Per CLAUDE.md mandatory board-hygiene rule — PR-with-new-types must update LATEST_STATE in the same commit. Aggregate verification: - `cargo check -p cognitive-shader-driver -p lance-graph-contract` → clean (only pre-existing ontology deprecation warnings unrelated to this wave). - `cargo test -p cognitive-shader-driver -p lance-graph-contract --lib` → 457 passed, 0 failed. No semantic changes from the workers' commits — this is a marker-strip + board-update commit only. --- .claude/board/AGENT_LOG.md | 36 +++++++++++++++++++ .claude/board/LATEST_STATE.md | 2 ++ .../bindspace-singleton-to-mailbox-soa-v1.md | 9 ----- crates/cognitive-shader-driver/src/driver.rs | 6 ---- .../src/mailbox_soa.rs | 12 ------- crates/lance-graph-contract/src/lib.rs | 1 - .../lance-graph-contract/src/witness_table.rs | 13 ------- 7 files changed, 38 insertions(+), 41 deletions(-) diff --git a/.claude/board/AGENT_LOG.md b/.claude/board/AGENT_LOG.md index 542d7a27..09e65460 100644 --- a/.claude/board/AGENT_LOG.md +++ b/.claude/board/AGENT_LOG.md @@ -1,3 +1,39 @@ +## [Agent-A4 / Sonnet] D-MBX-A4 — append §10 architectural refinements to bindspace→mailbox plan + +**D-id:** D-MBX-A4 | **Commit:** 0f448730 (cherry-picked from worktree `worktree-agent-a1961cf1d2ca1db93` f5cdcbe8) | **Branch:** claude/lance-surrealdb-analysis-LXmug +**Files touched:** `.claude/plans/bindspace-singleton-to-mailbox-soa-v1.md` (+36 lines, new §10 at end). 36 insertions, 0 deletions — no existing text modified. +**Markers:** 9 `` comments placed (7 refinement bullets + 2 OQ entries); orchestrator removed all 9 in review pass. +**Outcome:** DONE. §10 captures: (1) SoA Lance container ≠ cascade; (2) cascade is NOT index space; (3) 64K-256K envelope; (4) W-slot mailbox-witness table semantics; (5) cascade granularities = CPU/cache boundaries; (6) `simd_soa.rs` introspection framework; (7) SoA invariant spawn→commit. Surviving open questions: OQ-MBX-8 (`persisted_row` vs Lance versioning) + OQ-MBX-15′ (container scoping). + +--- + +## [Agent-A3 / Sonnet] D-MBX-A3 — WitnessTable column-type primitive (W-slot resolver) + +**D-id:** D-MBX-A3 | **Commit:** ef848a34 | **Branch:** claude/lance-surrealdb-analysis-LXmug +**Files touched:** `crates/lance-graph-contract/src/witness_table.rs` (new, +185 lines); `crates/lance-graph-contract/src/lib.rs` (+2 lines, `pub mod witness_table`) +**Tests:** `cargo test -p lance-graph-contract --lib witness_table` → 3/3 passed; `cargo check -p lance-graph-contract` → `Finished dev` 0 errors 0 warnings +**Outcome:** DONE. `WitnessEntry` + `WitnessTable` declared; zero new dependencies; `/// work` markers on all pub items. + +--- + +## [Agent-A1 / Sonnet] D-MBX-A1 — add thoughtspace columns to MailboxSoA + +**D-id:** D-MBX-A1 | **Commit:** 1df12eca | **Branch:** claude/lance-surrealdb-analysis-LXmug +**Files touched:** `crates/cognitive-shader-driver/src/mailbox_soa.rs` (+103 lines) +**cargo check:** `Finished dev` — 0 errors; pre-existing warnings only (causal-edge/p64-bridge/ontology — none in mailbox_soa.rs). `--features hpc-extras` absent from this crate; ran with default features. +**Outcome:** SUCCESS — added 4 SoA fields (edges/qualia/meta/entity_type), 8 getter/setter methods, updated new() + reset_row(). All new items marked `/// work`. + +--- + +## [Agent-A2 / Sonnet] D-MBX-A2 — transitional per-mailbox routing field+builder on ShaderDriver + +**D-id:** D-MBX-A2 | **Commit:** 61b641d5 | **Branch:** claude/lance-surrealdb-analysis-LXmug +**Files touched:** `crates/cognitive-shader-driver/src/driver.rs` (+42 lines) +**cargo check:** `Finished dev` — 0 errors; pre-existing warnings only (causal-edge/p64-bridge/ontology deprecations — none in cognitive-shader-driver). Note: `--features hpc-extras` absent from this crate; check ran with default features. +**Outcome:** SUCCESS — added `HashMap>` field on `ShaderDriver`, `with_mailbox` builder setter on `CognitiveShaderBuilder`, `mailbox()` read accessor. Singleton `Arc` untouched. All new items marked `/// work`. + +--- + ## [Main-thread] D-ODOO-SAV-4 — odoo-savant Reasoner layer (4 impls, one per ReasoningKind) Implemented `crates/lance-graph-callcenter/src/savant_reasoners.rs`: `SavantConclusion { savant_id, query_strategy, confidence: NarsTruth, rationale }` (suggestion-only, **no serde** — the one-binary contract; JSON only at the MedCareV2 FFI boundary) + the 4 `Reasoner` impls per the dispatch decision pinned in PR #419: `CustomerCategoryReasoner` / `PostingAnomalyReasoner` / `NextBestActionReasoner` / `OtherReasoner`, covering all 25 savants in `contract::savants::SAVANTS`. Each resolves the concrete savant from `(kind, namespace)`, selects `QueryStrategy` via `InferenceType::default_strategy()`, and fuses evidence-ref coverage into a NARS `(frequency, confidence)`. diff --git a/.claude/board/LATEST_STATE.md b/.claude/board/LATEST_STATE.md index 87ad4a7d..3208937a 100644 --- a/.claude/board/LATEST_STATE.md +++ b/.claude/board/LATEST_STATE.md @@ -42,6 +42,8 @@ ## Current Contract Inventory (lance-graph-contract) +> **2026-05-28 — PR-in-flight addition** (bindspace→mailbox migration wave A1-A4): `lance_graph_contract::witness_table::{WitnessEntry, WitnessTable}` — column-type primitive resolving the 6-bit W-slot in `CausalEdge64 v2` into a per-cohort `(mailbox_ref: u16, spo_fact_ref: Option)` table. Zero-dep, 3 unit tests, `WitnessTable::{new, get, set, default}`. Cross-ref: `.claude/plans/bindspace-singleton-to-mailbox-soa-v1.md` §10 (architectural refinements landed in same wave). Also in same wave: `cognitive-shader-driver::MailboxSoA` gains four thoughtspace columns (`edges: [CausalEdge64; N]`, `qualia: [QualiaI4_16D; N]`, `meta: [MetaWord; N]`, `entity_type: [u16; N]`) + 8 row accessors; `ShaderDriver` gains transitional `mailboxes: HashMap>` + `with_mailbox()` builder + `mailbox()` read accessor (sibling-shape, additive — singleton untouched). 457 contract+driver tests pass. + Types that EXIST — do NOT re-propose them: **`grammar/`**: `FailureTicket`, `PartialParse`, `CausalAmbiguity`, `TekamoloSlots`, `TekamoloSlot`, `WechselAmbiguity`, `WechselRole`, `FinnishCase`, `finnish_case_for_suffix`, `NarsInference`, `inference_to_style_cluster`, `ContextChain` (with coherence_at / total_coherence / replay_with_alternative / disambiguate / DisambiguationResult / WeightingKernel), `RoleKey` + 47 `LazyLock` instances + `Tense` enum + `finnish_case_key / tense_key / nars_inference_key` lookups, **`RoleKey::bind/unbind/recovery_margin`** (slice-masked XOR), **`Vsa10k`** + `VSA_ZERO` + `vsa_xor` + `vsa_similarity`, **`GrammarStyleConfig`** + **`GrammarStyleAwareness`** + `revise_truth` + `ParseOutcome` + `divergence_from`, **`FreeEnergy`** + **`Hypothesis`** + **`Resolution`** (Commit / Epiphany / FailureTicket) + `from_ranked` + thresholds. diff --git a/.claude/plans/bindspace-singleton-to-mailbox-soa-v1.md b/.claude/plans/bindspace-singleton-to-mailbox-soa-v1.md index 3da1dd77..4a1d42ce 100644 --- a/.claude/plans/bindspace-singleton-to-mailbox-soa-v1.md +++ b/.claude/plans/bindspace-singleton-to-mailbox-soa-v1.md @@ -404,31 +404,22 @@ mailbox_soa.rs, driver.rs, engine_bridge.rs, bin/serve.rs}`. The following refinements were ratified after the initial plan was written. They are append-only findings; no prior section has been modified. - 1. **SoA Lance container ≠ cascade.** The cascade is resolution-laddered superposition over per-axis granularities; the SoA Lance container is the materialized data substrate (same SoA the cognitive-shader-driver handles, same SoA the singleton BindSpace updated). One cascade resolves to one or more SoA Lance containers via top-k emission (Gaussian splat / CAM-PQ top-k). The container is the StreamDTO operand variable; the cascade is the resolver function. - 2. **Cascade is NOT an index space.** L1-L4 (`64²/256²/4096²/16384²`) are per-axis granularities on the same semantic axis (causal / palette / COCA codebook / outcome), superposed and streamed like x265 cascaded prediction levels. No level is fully materialized; only the emission (rendered SoA container) reaches downstream. - 3. **64K-256K mailbox envelope** (~360 MB - 1.4 GB total working set at 6 KB per mailbox). The whole population is RAM-resident on any reasonable server. No hot/warm/cold tier split needed. Tombstone retention is free at this scale; eviction is moot. - 4. **W-slot resolves into a per-cohort witness table** of `(mailbox_ref, spo_fact_ref)` entries — NOT a witness-corpus pointer to a static repository. Active mailboxes carry a mailbox-ref alone (spo_fact_ref = None); once the belief crystallizes via Rubicon commit, the spo_fact_ref binds to the SPO triple. Tombstones stay reachable through their mailbox-ref. The chain of W-references across edges forms a Markov belief-update arc via AriGraph episodic-reference vectors (AriGraph today is a transcode; the chaining engine is the target shape). - 5. **Cascade granularities are CPU/cache boundaries, not abstract resolutions.** 64 = AVX-512 i8 register / cache line; 256 = AMX tile row; 4096 = page (4 KiB); 16384 = L1d cache (16 KiB). The ladder is hardware-natural so SIMD sweeps stay register/cache/page-aligned by construction. - 6. **`simd_soa.rs` (ndarray) is the SoA dispatch framework.** It adapts to any SoA shape by introspecting members; consumers declare their own column tuple via derive/const-generic and get SIMD sweeps for free. The MailboxSoA migration is positional, not structural — the framework already swallows the column shape. - 7. **SoA invariant from spawn → commit.** The same SoA byte layout runs end-to-end: cognitive-shader-driver creates a mailbox + SoA via cascade hot path → traverse cold path with gridlake SIMD ops → commit via one of two egress modes: **external** (REST / sea-orm SQL via tokio, backpressure expected) or **internal** (SurrealDB → LanceDB or RocksDB, no backpressure). No marshalling at any boundary; Lance columnar IS the repr. ### Open Questions surviving these refinements - - **OQ-MBX-8** — `persisted_row` stub vs Lance native versioning (load-bearing; evidence at `REFACTOR_NOTES.md:129` + `driver.rs:458`). - - **OQ-MBX-15′** — container scoping: per-cognitive-cycle, per-shader-dispatch, or per-mailbox-cohort? diff --git a/crates/cognitive-shader-driver/src/driver.rs b/crates/cognitive-shader-driver/src/driver.rs index 72588894..8a53b4a7 100644 --- a/crates/cognitive-shader-driver/src/driver.rs +++ b/crates/cognitive-shader-driver/src/driver.rs @@ -45,9 +45,7 @@ use p64_bridge::cognitive_shader::CognitiveShader; use crate::auto_style; use crate::bindspace::{BindSpace, WORDS_PER_FP}; -/// work use crate::mailbox_soa::MailboxSoA; -/// work use lance_graph_contract::collapse_gate::MailboxId; // ═══════════════════════════════════════════════════════════════════════════ @@ -76,7 +74,6 @@ pub struct ShaderDriver { /// Lives in `causal-edge` (zero-dep), so attaching it does NOT pull /// the planner into shader-driver. pub(crate) nars_tables: Option>, - /// work /// Transitional per-mailbox routing surface (slice A2). /// /// Consumers can opt into per-mailbox routing by inserting @@ -125,7 +122,6 @@ impl ShaderDriver { self.nars_tables.as_ref() } - /// work /// Return a read reference to the `MailboxSoA<1024>` registered under /// `id`, or `None` if no mailbox with that id has been inserted via /// the builder's `with_mailbox` method. @@ -622,7 +618,6 @@ pub struct CognitiveShaderBuilder { planes: Option<[[u64; 64]; 8]>, default_style: u8, nars_tables: Option>, - /// work /// Transitional per-mailbox routing map populated by `with_mailbox`. /// Forwarded into `ShaderDriver::mailboxes` at `build()` time. mailboxes: std::collections::HashMap>, @@ -666,7 +661,6 @@ impl CognitiveShaderBuilder { self } - /// work /// Register a `MailboxSoA<1024>` for transitional per-mailbox routing /// (slice A2). The mailbox is keyed by `id`; a second call with the /// same `id` replaces the previous entry. Multiple mailboxes are diff --git a/crates/cognitive-shader-driver/src/mailbox_soa.rs b/crates/cognitive-shader-driver/src/mailbox_soa.rs index e23b1e29..4028c1c1 100644 --- a/crates/cognitive-shader-driver/src/mailbox_soa.rs +++ b/crates/cognitive-shader-driver/src/mailbox_soa.rs @@ -61,25 +61,21 @@ pub struct MailboxSoA { // ── NEW: migrated thoughtspace columns (per-mailbox owned, D-MBX-A1) ── - /// work /// Per-row LE baton edge (`CausalEdge64`, 8 B/row). /// Migrated from `BindSpace.edges` (EdgeColumn). /// This IS the LE contract / baton edge for this mailbox row. pub edges: [CausalEdge64; N], - /// work /// Per-row affective role vector (`QualiaI4_16D`, 8 B/row). /// Migrated from `BindSpace.qualia` (QualiaI4Column). /// 16 signed i4 dimensions (arousal/valence/tension/…); 9× compression vs f32. pub qualia: [QualiaI4_16D; N], - /// work /// Per-row packed meta word (`MetaWord`, 4 B/row). /// Migrated from `BindSpace.meta` (MetaColumn). /// Layout: `thinking(6) + awareness(4) + nars_f(8) + nars_c(8) + free_e(6)`. pub meta: [MetaWord; N], - /// work /// Per-row OGIT entity-type index (`u16`, 2 B/row). /// Migrated from `BindSpace.entity_type`. /// 1-based index into the shared (immutable) ontology registry. @@ -269,7 +265,6 @@ impl MailboxSoA { // ── Thoughtspace column accessors (D-MBX-A1) ───────────────────────────── - /// work /// Return the `CausalEdge64` baton edge for `row`. /// /// Panics (debug) / wraps (release) on out-of-bounds; callers @@ -279,7 +274,6 @@ impl MailboxSoA { self.edges[row] } - /// work /// Set the `CausalEdge64` baton edge for `row`. /// /// Panics (debug) / wraps (release) on out-of-bounds; callers @@ -289,42 +283,36 @@ impl MailboxSoA { self.edges[row] = e; } - /// work /// Return the packed `QualiaI4_16D` affective vector for `row`. #[inline] pub fn qualia_at(&self, row: usize) -> QualiaI4_16D { self.qualia[row] } - /// work /// Set the packed `QualiaI4_16D` affective vector for `row`. #[inline] pub fn set_qualia(&mut self, row: usize, q: QualiaI4_16D) { self.qualia[row] = q; } - /// work /// Return the packed `MetaWord` for `row`. #[inline] pub fn meta_at(&self, row: usize) -> MetaWord { self.meta[row] } - /// work /// Set the packed `MetaWord` for `row`. #[inline] pub fn set_meta(&mut self, row: usize, m: MetaWord) { self.meta[row] = m; } - /// work /// Return the OGIT entity-type index for `row` (1-based, shared ontology). #[inline] pub fn entity_type_at(&self, row: usize) -> u16 { self.entity_type[row] } - /// work /// Set the OGIT entity-type index for `row`. #[inline] pub fn set_entity_type(&mut self, row: usize, t: u16) { diff --git a/crates/lance-graph-contract/src/lib.rs b/crates/lance-graph-contract/src/lib.rs index b25f8bdd..9ea3381a 100644 --- a/crates/lance-graph-contract/src/lib.rs +++ b/crates/lance-graph-contract/src/lib.rs @@ -84,7 +84,6 @@ pub mod splat; pub mod tax; pub mod thinking; pub mod vsa; -/// work pub mod witness_table; pub mod world_map; pub mod world_model; diff --git a/crates/lance-graph-contract/src/witness_table.rs b/crates/lance-graph-contract/src/witness_table.rs index c6d8d91e..9062faf8 100644 --- a/crates/lance-graph-contract/src/witness_table.rs +++ b/crates/lance-graph-contract/src/witness_table.rs @@ -39,7 +39,6 @@ // ── Type declarations ──────────────────────────────────────────────────────── -/// work /// A single entry in a per-cohort [`WitnessTable`]. /// /// Carries the pair `(mailbox_ref, spo_fact_ref)` that resolves one W-slot index: @@ -58,14 +57,12 @@ /// enough to pass by value on any target ABI. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)] pub struct WitnessEntry { - /// work /// Handle to the mailbox that witnessed this belief event. /// /// Active mailboxes have a live `w_slot` association; tombstoned mailboxes retain /// their ref so the arc walk can detect decommissioned cohort members. pub mailbox_ref: u16, - /// work /// Optional reference into the AriGraph SPO-G quad store. /// /// `None`: the belief has not yet crystallised to a committed triple. @@ -74,7 +71,6 @@ pub struct WitnessEntry { pub spo_fact_ref: Option, } -/// work /// Per-cohort witness table: a fixed-size array of [`WitnessEntry`] values indexed /// by the 6-bit W-slot field from `CausalEdge64 v2`. /// @@ -91,7 +87,6 @@ pub struct WitnessEntry { /// [`set`]: WitnessTable::set #[derive(Debug, Clone)] pub struct WitnessTable { - /// work /// Flat array of witness entries, one per addressable W-slot index. pub entries: [WitnessEntry; N], } @@ -99,7 +94,6 @@ pub struct WitnessTable { // ── impl WitnessTable ──────────────────────────────────────────────────────── impl WitnessTable { - /// work /// Construct a `WitnessTable` with every entry set to its zero-initialised default. /// /// `mailbox_ref` is 0 (the null mailbox handle) and `spo_fact_ref` is `None` @@ -116,7 +110,6 @@ impl WitnessTable { } } - /// work /// Look up the entry at `w_slot`. /// /// Returns `None` if `w_slot as usize >= N` (out-of-bounds for this cohort). @@ -125,7 +118,6 @@ impl WitnessTable { self.entries.get(w_slot as usize) } - /// work /// Write `e` into slot `w_slot`. /// /// Returns `Ok(())` on success. @@ -144,9 +136,7 @@ impl WitnessTable { // ── Default ────────────────────────────────────────────────────────────────── -/// work impl Default for WitnessTable { - /// work fn default() -> Self { Self::new() } @@ -158,7 +148,6 @@ impl Default for WitnessTable { mod tests { use super::*; - /// work /// Round-trip: set a slot, then get it back and confirm the value matches. #[test] fn witness_table_round_trip_set_get() { @@ -172,7 +161,6 @@ mod tests { assert_eq!(*got, entry, "get must return the exact entry written by set"); } - /// work /// Out-of-bounds set returns Err; out-of-bounds get returns None. #[test] fn witness_table_out_of_bounds_returns_err() { @@ -194,7 +182,6 @@ mod tests { } } - /// work /// A freshly constructed table has all entries at their zero default: /// `mailbox_ref = 0`, `spo_fact_ref = None`. #[test] From f541b280a56b03cc8b869f11864eb69f4510c6d7 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 28 May 2026 11:40:07 +0000 Subject: [PATCH 6/6] =?UTF-8?q?fix(witness=5Ftable):=20widen=20mailbox=5Fr?= =?UTF-8?q?ef=20u16=20=E2=86=92=20u32=20+=20correct=20Option=20size?= =?UTF-8?q?=20doc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two review findings on PR #427: 1. **Codex P2** — `WitnessEntry::mailbox_ref` was declared `u16`, but `contract::collapse_gate::MailboxId` is `pub type MailboxId = u32`. The W-slot is the per-cohort *index* (0..=63, fits in 6 bits), but `mailbox_ref` carries the *identity* of the mailbox at that slot — and the workspace's planned 64K-256K mailbox envelope (plan §10 refinement (3)) exceeds the u16 ceiling. Truncating to the lower 16 bits would alias mailbox 1 with mailbox 65_537, so the W-slot belief-arc walk could resolve to the wrong mailbox or tombstone. Widened to `u32` to preserve full canonical identity end-to-end. 2. **CodeRabbit minor** — The doc comment claimed `Option` "packs as 16 B via the niche-filling optimisation." This is wrong on mechanism: `u64` has no niche (every bit pattern is a valid `u64`), so the discriminant cannot fold into the payload. The 16 B figure is correct but the *reason* is 1-byte tag + 7-byte alignment padding + 8-byte payload, not niche-filling. Corrected the comment and updated the total entry size (`u32` + `Option` → **24 B** per entry with `#[repr(Rust)]` field reordering; 64-entry table = 1.5 KiB). Module-level doc-comment in the file header also updated to call out that `mailbox_ref` is the full canonical identity, not a truncated index. Verification: - `cargo test -p lance-graph-contract --lib witness_table` → 3/3 pass (tests use integer literals so type inference adapts automatically; no test changes needed) - LATEST_STATE.md Contract Inventory annotation updated to mirror the u32 type (board hygiene rule — same commit as the type change). No other callers exist yet (only `lib.rs` re-export) so the widening is a pure correctness fix with no migration cost. --- .claude/board/LATEST_STATE.md | 2 +- .../lance-graph-contract/src/witness_table.rs | 31 ++++++++++++------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/.claude/board/LATEST_STATE.md b/.claude/board/LATEST_STATE.md index 3208937a..27ae30bb 100644 --- a/.claude/board/LATEST_STATE.md +++ b/.claude/board/LATEST_STATE.md @@ -42,7 +42,7 @@ ## Current Contract Inventory (lance-graph-contract) -> **2026-05-28 — PR-in-flight addition** (bindspace→mailbox migration wave A1-A4): `lance_graph_contract::witness_table::{WitnessEntry, WitnessTable}` — column-type primitive resolving the 6-bit W-slot in `CausalEdge64 v2` into a per-cohort `(mailbox_ref: u16, spo_fact_ref: Option)` table. Zero-dep, 3 unit tests, `WitnessTable::{new, get, set, default}`. Cross-ref: `.claude/plans/bindspace-singleton-to-mailbox-soa-v1.md` §10 (architectural refinements landed in same wave). Also in same wave: `cognitive-shader-driver::MailboxSoA` gains four thoughtspace columns (`edges: [CausalEdge64; N]`, `qualia: [QualiaI4_16D; N]`, `meta: [MetaWord; N]`, `entity_type: [u16; N]`) + 8 row accessors; `ShaderDriver` gains transitional `mailboxes: HashMap>` + `with_mailbox()` builder + `mailbox()` read accessor (sibling-shape, additive — singleton untouched). 457 contract+driver tests pass. +> **2026-05-28 — PR-in-flight addition** (bindspace→mailbox migration wave A1-A4): `lance_graph_contract::witness_table::{WitnessEntry, WitnessTable}` — column-type primitive resolving the 6-bit W-slot in `CausalEdge64 v2` into a per-cohort `(mailbox_ref: u32, spo_fact_ref: Option)` table (`mailbox_ref` carries the full canonical `MailboxId`, NOT a truncated cohort-local index — see PR #427 Codex P2 fix). Zero-dep, 3 unit tests, `WitnessTable::{new, get, set, default}`. Cross-ref: `.claude/plans/bindspace-singleton-to-mailbox-soa-v1.md` §10 (architectural refinements landed in same wave). Also in same wave: `cognitive-shader-driver::MailboxSoA` gains four thoughtspace columns (`edges: [CausalEdge64; N]`, `qualia: [QualiaI4_16D; N]`, `meta: [MetaWord; N]`, `entity_type: [u16; N]`) + 8 row accessors; `ShaderDriver` gains transitional `mailboxes: HashMap>` + `with_mailbox()` builder + `mailbox()` read accessor (sibling-shape, additive — singleton untouched). 457 contract+driver tests pass. Types that EXIST — do NOT re-propose them: diff --git a/crates/lance-graph-contract/src/witness_table.rs b/crates/lance-graph-contract/src/witness_table.rs index 9062faf8..d3594ae9 100644 --- a/crates/lance-graph-contract/src/witness_table.rs +++ b/crates/lance-graph-contract/src/witness_table.rs @@ -6,8 +6,11 @@ //! that points into a *per-cohort* `WitnessTable<64>`. Each table entry is a //! `(mailbox_ref, spo_fact_ref)` tuple: //! -//! - `mailbox_ref`: identifies the mailbox that witnessed the belief — either currently -//! active or carrying a tombstone flag (see `contract::collapse_gate::MailboxId`). +//! - `mailbox_ref`: full canonical [`contract::collapse_gate::MailboxId`] (`u32`) of +//! the mailbox that witnessed the belief — either currently active or carrying a +//! tombstone flag. The W-slot is the per-cohort *index*; `mailbox_ref` is the +//! *identity* at that slot, preserved at full canonical width across the entire +//! workspace mailbox envelope (64K-256K, plan §10 refinement (3)). //! - `spo_fact_ref`: optional handle into the AriGraph SPO-G quad store. `None` while //! the belief is still accumulating in the mailbox's energy column; `Some(u64)` once //! the belief crystallises and the triple is committed to graph. @@ -43,25 +46,29 @@ /// /// Carries the pair `(mailbox_ref, spo_fact_ref)` that resolves one W-slot index: /// -/// - `mailbox_ref` is a `u16` handle matching `contract::collapse_gate::MailboxId` -/// (declared as `pub type MailboxId = u32` there, but the table stores the lower 16 -/// bits since cohort sizes are bounded by the 6-bit W-slot). Callers that need the -/// full 32-bit id should widen at the call site. +/// - `mailbox_ref` is the **full canonical** [`contract::collapse_gate::MailboxId`] +/// (`u32`). The W-slot is the per-cohort *index* (0..=63); `mailbox_ref` is the +/// globally-unique identity of the mailbox at that slot, so the belief arc can +/// resolve to the correct originating mailbox even when cohort membership rotates +/// across the workspace's 64K-256K mailbox envelope (see plan §10 refinement (3)). /// - `spo_fact_ref` is `None` while the belief is ephemeral (energy accumulating) and /// `Some(u64)` once the triple is committed to AriGraph (the "crystallisation" event). /// /// # Size /// -/// `u16` (2 B) + discriminant + `u64` (8 B) = 10–12 B. `Option` packs as 16 B -/// via the niche-filling optimisation. `Copy` is intentional: the struct is small -/// enough to pass by value on any target ABI. +/// `u32` (4 B) + `Option` (16 B: 1-byte tag + 7 bytes alignment padding + +/// 8-byte payload — `u64` has no niche, so the discriminant cannot be folded into +/// the payload). With `#[repr(Rust)]` field reordering and 8-byte struct alignment +/// the total is **24 B** per entry; an `N=64` table is therefore 1.5 KiB. `Copy` is +/// intentional: the struct is small enough to pass by value on any target ABI. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)] pub struct WitnessEntry { /// Handle to the mailbox that witnessed this belief event. /// - /// Active mailboxes have a live `w_slot` association; tombstoned mailboxes retain - /// their ref so the arc walk can detect decommissioned cohort members. - pub mailbox_ref: u16, + /// Stores the full [`contract::collapse_gate::MailboxId`] (`u32`). Active + /// mailboxes have a live `w_slot` association; tombstoned mailboxes retain their + /// ref so the arc walk can detect decommissioned cohort members. + pub mailbox_ref: u32, /// Optional reference into the AriGraph SPO-G quad store. ///