Skip to content

Commit a21d577

Browse files
authored
Merge pull request #427 from AdaWorldAPI/claude/lance-surrealdb-analysis-LXmug
feat(mailbox-soa): bindspace→mailbox migration wave A1-A4 (thoughtspace columns + transitional routing + WitnessTable + plan §10)
2 parents a5f3e8d + 1769ab7 commit a21d577

7 files changed

Lines changed: 402 additions & 0 deletions

File tree

.claude/board/AGENT_LOG.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,39 @@
1+
## [Agent-A4 / Sonnet] D-MBX-A4 — append §10 architectural refinements to bindspace→mailbox plan
2+
3+
**D-id:** D-MBX-A4 | **Commit:** 0f448730 (cherry-picked from worktree `worktree-agent-a1961cf1d2ca1db93` f5cdcbe8) | **Branch:** claude/lance-surrealdb-analysis-LXmug
4+
**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.
5+
**Markers:** 9 `<!-- ///work -->` comments placed (7 refinement bullets + 2 OQ entries); orchestrator removed all 9 in review pass.
6+
**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).
7+
8+
---
9+
10+
## [Agent-A3 / Sonnet] D-MBX-A3 — WitnessTable column-type primitive (W-slot resolver)
11+
12+
**D-id:** D-MBX-A3 | **Commit:** ef848a34 | **Branch:** claude/lance-surrealdb-analysis-LXmug
13+
**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`)
14+
**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
15+
**Outcome:** DONE. `WitnessEntry` + `WitnessTable<N=64>` declared; zero new dependencies; `/// work` markers on all pub items.
16+
17+
---
18+
19+
## [Agent-A1 / Sonnet] D-MBX-A1 — add thoughtspace columns to MailboxSoA<N>
20+
21+
**D-id:** D-MBX-A1 | **Commit:** 1df12eca | **Branch:** claude/lance-surrealdb-analysis-LXmug
22+
**Files touched:** `crates/cognitive-shader-driver/src/mailbox_soa.rs` (+103 lines)
23+
**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.
24+
**Outcome:** SUCCESS — added 4 SoA fields (edges/qualia/meta/entity_type), 8 getter/setter methods, updated new() + reset_row(). All new items marked `/// work`.
25+
26+
---
27+
28+
## [Agent-A2 / Sonnet] D-MBX-A2 — transitional per-mailbox routing field+builder on ShaderDriver
29+
30+
**D-id:** D-MBX-A2 | **Commit:** 61b641d5 | **Branch:** claude/lance-surrealdb-analysis-LXmug
31+
**Files touched:** `crates/cognitive-shader-driver/src/driver.rs` (+42 lines)
32+
**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.
33+
**Outcome:** SUCCESS — added `HashMap<MailboxId, MailboxSoA<1024>>` field on `ShaderDriver`, `with_mailbox` builder setter on `CognitiveShaderBuilder`, `mailbox()` read accessor. Singleton `Arc<BindSpace>` untouched. All new items marked `/// work`.
34+
35+
---
36+
137
## [Main-thread] D-ODOO-SAV-4 — odoo-savant Reasoner layer (4 impls, one per ReasoningKind)
238

339
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)`.

.claude/board/LATEST_STATE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242

4343
## Current Contract Inventory (lance-graph-contract)
4444

45+
> **2026-05-28 — PR-in-flight addition** (bindspace→mailbox migration wave A1-A4): `lance_graph_contract::witness_table::{WitnessEntry, WitnessTable<N=64>}` — column-type primitive resolving the 6-bit W-slot in `CausalEdge64 v2` into a per-cohort `(mailbox_ref: u32, spo_fact_ref: Option<u64>)` 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<N>` 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<MailboxId, MailboxSoA<1024>>` + `with_mailbox()` builder + `mailbox()` read accessor (sibling-shape, additive — singleton untouched). 457 contract+driver tests pass.
46+
4547
Types that EXIST — do NOT re-propose them:
4648

4749
**`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<RoleKey>` 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.

.claude/plans/bindspace-singleton-to-mailbox-soa-v1.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,3 +396,30 @@ accumulator), `EPIPHANIES.md` (`E-BATON-1`, `E-CE64-MB-4`, `E-LADDER-SERVES-MAIL
396396
`I-VSA-IDENTITIES`, `I-LEGACY-API-FEATURE-GATED`), `.claude/surreal/RECONCILIATION_with_canonical_plan.md`
397397
(Vsa16kF32-deprecation contradiction flag), code: `crates/cognitive-shader-driver/src/{bindspace.rs,
398398
mailbox_soa.rs, driver.rs, engine_bridge.rs, bin/serve.rs}`.
399+
400+
---
401+
402+
## §10 — 2026-05-28 architectural refinements (post-PR-#423 sync)
403+
404+
The following refinements were ratified after the initial plan was written. They are
405+
append-only findings; no prior section has been modified.
406+
407+
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.
408+
409+
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.
410+
411+
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.
412+
413+
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).
414+
415+
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.
416+
417+
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.
418+
419+
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.
420+
421+
### Open Questions surviving these refinements
422+
423+
- **OQ-MBX-8**`persisted_row` stub vs Lance native versioning (load-bearing; evidence at `REFACTOR_NOTES.md:129` + `driver.rs:458`).
424+
425+
- **OQ-MBX-15′** — container scoping: per-cognitive-cycle, per-shader-dispatch, or per-mailbox-cohort?

crates/cognitive-shader-driver/src/driver.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ use p64_bridge::cognitive_shader::CognitiveShader;
4545

4646
use crate::auto_style;
4747
use crate::bindspace::{BindSpace, WORDS_PER_FP};
48+
use crate::mailbox_soa::MailboxSoA;
49+
use lance_graph_contract::collapse_gate::MailboxId;
4850

4951
// ═══════════════════════════════════════════════════════════════════════════
5052
// ShaderDriver — holds everything the shader needs to drive
@@ -72,6 +74,14 @@ pub struct ShaderDriver {
7274
/// Lives in `causal-edge` (zero-dep), so attaching it does NOT pull
7375
/// the planner into shader-driver.
7476
pub(crate) nars_tables: Option<Arc<NarsTables>>,
77+
/// Transitional per-mailbox routing surface (slice A2).
78+
///
79+
/// Consumers can opt into per-mailbox routing by inserting
80+
/// `MailboxSoA<1024>` instances here via the builder's
81+
/// `with_mailbox` method. The singleton `Arc<BindSpace>` (above)
82+
/// is unchanged — this field is purely additive and does not alter
83+
/// any existing dispatch semantics. Removed at cutover (plan S3).
84+
pub(crate) mailboxes: std::collections::HashMap<MailboxId, MailboxSoA<1024>>,
7585
}
7686

7787
impl ShaderDriver {
@@ -92,6 +102,7 @@ impl ShaderDriver {
92102
default_style,
93103
awareness: RwLock::new(awareness),
94104
nars_tables: None,
105+
mailboxes: std::collections::HashMap::new(),
95106
}
96107
}
97108

@@ -111,6 +122,17 @@ impl ShaderDriver {
111122
self.nars_tables.as_ref()
112123
}
113124

125+
/// Return a read reference to the `MailboxSoA<1024>` registered under
126+
/// `id`, or `None` if no mailbox with that id has been inserted via
127+
/// the builder's `with_mailbox` method.
128+
///
129+
/// The singleton `Arc<BindSpace>` is unchanged by this accessor.
130+
/// This is the transitional per-mailbox routing read surface (slice A2).
131+
#[inline]
132+
pub fn mailbox(&self, id: MailboxId) -> Option<&MailboxSoA<1024>> {
133+
self.mailboxes.get(&id)
134+
}
135+
114136
/// Borrow the underlying BindSpace (read-only).
115137
#[inline]
116138
pub fn bindspace(&self) -> &BindSpace { &self.bindspace }
@@ -596,6 +618,9 @@ pub struct CognitiveShaderBuilder {
596618
planes: Option<[[u64; 64]; 8]>,
597619
default_style: u8,
598620
nars_tables: Option<Arc<NarsTables>>,
621+
/// Transitional per-mailbox routing map populated by `with_mailbox`.
622+
/// Forwarded into `ShaderDriver::mailboxes` at `build()` time.
623+
mailboxes: std::collections::HashMap<MailboxId, MailboxSoA<1024>>,
599624
}
600625

601626
impl CognitiveShaderBuilder {
@@ -606,6 +631,7 @@ impl CognitiveShaderBuilder {
606631
planes: None,
607632
default_style: auto_style::DELIBERATE,
608633
nars_tables: None,
634+
mailboxes: std::collections::HashMap::new(),
609635
}
610636
}
611637

@@ -635,6 +661,15 @@ impl CognitiveShaderBuilder {
635661
self
636662
}
637663

664+
/// Register a `MailboxSoA<1024>` for transitional per-mailbox routing
665+
/// (slice A2). The mailbox is keyed by `id`; a second call with the
666+
/// same `id` replaces the previous entry. Multiple mailboxes are
667+
/// supported. The singleton `Arc<BindSpace>` is not affected.
668+
pub fn with_mailbox(mut self, id: MailboxId, soa: MailboxSoA<1024>) -> Self {
669+
self.mailboxes.insert(id, soa);
670+
self
671+
}
672+
638673
pub fn build(self) -> ShaderDriver {
639674
let awareness = (0..12)
640675
.map(|ord| GrammarStyleAwareness::bootstrap(ord_to_thinking_style(ord)))
@@ -646,6 +681,7 @@ impl CognitiveShaderBuilder {
646681
default_style: self.default_style,
647682
awareness: RwLock::new(awareness),
648683
nars_tables: self.nars_tables,
684+
mailboxes: self.mailboxes,
649685
}
650686
}
651687
}

crates/cognitive-shader-driver/src/mailbox_soa.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
//! gated steps: `.claude/plans/bindspace-singleton-to-mailbox-soa-v1.md`.
2121
2222
use causal_edge::CausalEdge64;
23+
use lance_graph_contract::cognitive_shader::MetaWord;
2324
use lance_graph_contract::collapse_gate::{CollapseGateEmission, MailboxId, MergeMode};
25+
use lance_graph_contract::qualia::QualiaI4_16D;
2426

2527
/// Spatial-temporal accumulator for per-row baton receipts.
2628
///
@@ -57,6 +59,29 @@ pub struct MailboxSoA<const N: usize> {
5759
/// if `last_emission_cycle[row] == current_cycle`, emission is suppressed.
5860
pub last_emission_cycle: [u32; N],
5961

62+
// ── NEW: migrated thoughtspace columns (per-mailbox owned, D-MBX-A1) ──
63+
64+
/// Per-row LE baton edge (`CausalEdge64`, 8 B/row).
65+
/// Migrated from `BindSpace.edges` (EdgeColumn).
66+
/// This IS the LE contract / baton edge for this mailbox row.
67+
pub edges: [CausalEdge64; N],
68+
69+
/// Per-row affective role vector (`QualiaI4_16D`, 8 B/row).
70+
/// Migrated from `BindSpace.qualia` (QualiaI4Column).
71+
/// 16 signed i4 dimensions (arousal/valence/tension/…); 9× compression vs f32.
72+
pub qualia: [QualiaI4_16D; N],
73+
74+
/// Per-row packed meta word (`MetaWord`, 4 B/row).
75+
/// Migrated from `BindSpace.meta` (MetaColumn).
76+
/// Layout: `thinking(6) + awareness(4) + nars_f(8) + nars_c(8) + free_e(6)`.
77+
pub meta: [MetaWord; N],
78+
79+
/// Per-row OGIT entity-type index (`u16`, 2 B/row).
80+
/// Migrated from `BindSpace.entity_type`.
81+
/// 1-based index into the shared (immutable) ontology registry.
82+
/// The registry itself stays `Arc<OntologyRegistry>` (cold Zone-2, not owned here).
83+
pub entity_type: [u16; N],
84+
6085
/// Monotonic cycle stamp; advanced by `tick()`.
6186
pub current_cycle: u32,
6287

@@ -97,6 +122,11 @@ impl<const N: usize> MailboxSoA<N> {
97122
current_cycle: 0,
98123
w_slot,
99124
threshold,
125+
// ── NEW thoughtspace columns — zero-initialised (D-MBX-A1) ──
126+
edges: [CausalEdge64::ZERO; N],
127+
qualia: [QualiaI4_16D::ZERO; N],
128+
meta: [MetaWord(0); N],
129+
entity_type: [0u16; N],
100130
}
101131
}
102132

@@ -189,6 +219,11 @@ impl<const N: usize> MailboxSoA<N> {
189219
// Restore the "never emitted" sentinel so the row can emit immediately
190220
// on the next cycle without triggering the same-cycle guard.
191221
self.last_emission_cycle[row] = u32::MAX;
222+
// ── NEW thoughtspace columns reset (D-MBX-A1) ──
223+
self.edges[row] = CausalEdge64::ZERO;
224+
self.qualia[row] = QualiaI4_16D::ZERO;
225+
self.meta[row] = MetaWord(0);
226+
self.entity_type[row] = 0;
192227
}
193228

194229
// ── Read-only inspectors ──────────────────────────────────────────────────
@@ -227,6 +262,62 @@ impl<const N: usize> MailboxSoA<N> {
227262
.filter(|&&e| e.abs() >= self.threshold)
228263
.count()
229264
}
265+
266+
// ── Thoughtspace column accessors (D-MBX-A1) ─────────────────────────────
267+
268+
/// Return the `CausalEdge64` baton edge for `row`.
269+
///
270+
/// Panics (debug) / wraps (release) on out-of-bounds; callers
271+
/// should stay within `[0, N)`.
272+
#[inline]
273+
pub fn edge(&self, row: usize) -> CausalEdge64 {
274+
self.edges[row]
275+
}
276+
277+
/// Set the `CausalEdge64` baton edge for `row`.
278+
///
279+
/// Panics (debug) / wraps (release) on out-of-bounds; callers
280+
/// should stay within `[0, N)`.
281+
#[inline]
282+
pub fn set_edge(&mut self, row: usize, e: CausalEdge64) {
283+
self.edges[row] = e;
284+
}
285+
286+
/// Return the packed `QualiaI4_16D` affective vector for `row`.
287+
#[inline]
288+
pub fn qualia_at(&self, row: usize) -> QualiaI4_16D {
289+
self.qualia[row]
290+
}
291+
292+
/// Set the packed `QualiaI4_16D` affective vector for `row`.
293+
#[inline]
294+
pub fn set_qualia(&mut self, row: usize, q: QualiaI4_16D) {
295+
self.qualia[row] = q;
296+
}
297+
298+
/// Return the packed `MetaWord` for `row`.
299+
#[inline]
300+
pub fn meta_at(&self, row: usize) -> MetaWord {
301+
self.meta[row]
302+
}
303+
304+
/// Set the packed `MetaWord` for `row`.
305+
#[inline]
306+
pub fn set_meta(&mut self, row: usize, m: MetaWord) {
307+
self.meta[row] = m;
308+
}
309+
310+
/// Return the OGIT entity-type index for `row` (1-based, shared ontology).
311+
#[inline]
312+
pub fn entity_type_at(&self, row: usize) -> u16 {
313+
self.entity_type[row]
314+
}
315+
316+
/// Set the OGIT entity-type index for `row`.
317+
#[inline]
318+
pub fn set_entity_type(&mut self, row: usize, t: u16) {
319+
self.entity_type[row] = t;
320+
}
230321
}
231322

232323
#[cfg(test)]

crates/lance-graph-contract/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ pub mod splat;
8484
pub mod tax;
8585
pub mod thinking;
8686
pub mod vsa;
87+
pub mod witness_table;
8788
pub mod world_map;
8889
pub mod world_model;
8990

0 commit comments

Comments
 (0)