|
| 1 | +# CausalEdge64 — SPO-Palette Variant (causal-edge crate) |
| 2 | + |
| 3 | +> **READ BY:** truth-architect, integration-lead, palette-engineer, family-codec-smith, certification-officer, anyone touching `NarsTables` / `lance-graph-planner::cache` / `cognitive-shader-driver::BindSpace::EdgeColumn` |
| 4 | +> |
| 5 | +> **PAIRED WITH:** `causal-edge-64-thinking-engine-variant.md` (the OTHER `CausalEdge64` type in this workspace; see also `causal-edge-64-synergies-and-pr-trajectory.md` for cross-comparison) |
| 6 | +> |
| 7 | +> **Status:** FINDING (verified against shipped source 2026-05-14) |
| 8 | +
|
| 9 | +--- |
| 10 | + |
| 11 | +## 1. Identity |
| 12 | + |
| 13 | +**Type:** `causal_edge::CausalEdge64` (the "SPO-palette variant", "NARS variant", "Pearl variant"). |
| 14 | + |
| 15 | +**Definition site:** `crates/causal-edge/src/edge.rs:60` |
| 16 | + |
| 17 | +```rust |
| 18 | +#[derive(Clone, Copy, PartialEq, Eq, Hash)] |
| 19 | +pub struct CausalEdge64(pub u64); |
| 20 | +``` |
| 21 | + |
| 22 | +**Crate:** `causal-edge` (in workspace `members` per CLAUDE.md; sibling of `lance-graph` core; depended on by `lance-graph-planner`). |
| 23 | + |
| 24 | +**One-line role:** the 64-bit causal **neuron** — one register holds a complete SPO causal proposition with NARS truth, Pearl rung, propagated direction, NARS inference type, palette plasticity, and a temporal index. |
| 25 | + |
| 26 | +**Doctrine line** (from `edge.rs:1-3`): |
| 27 | +> *"CausalEdge64: the atomic causal unit. One u64. One register. One read. Full causal edge with epistemic state."* |
| 28 | +
|
| 29 | +--- |
| 30 | + |
| 31 | +## 2. Bit Layout |
| 32 | + |
| 33 | +From `edge.rs:44-72`: |
| 34 | + |
| 35 | +```text |
| 36 | +[ 0: 7] S palette index u8 (256 subject archetypes) |
| 37 | +[ 8: 15] P palette index u8 (256 predicate archetypes) |
| 38 | +[16: 23] O palette index u8 (256 object archetypes) |
| 39 | +[24: 31] NARS frequency u8 (f = val/255 ∈ [0, 1]) |
| 40 | +[32: 39] NARS confidence u8 (c = val/255 ∈ [0, 1]) |
| 41 | +[40: 42] Causal mask 3b (Pearl's 2³ — see CausalMask enum) |
| 42 | +[43: 45] Direction triad 3b (sign(palette[idx].dim0) per S,P,O — propagated) |
| 43 | +[46: 48] Inference type 3b (NARS rule: Deduction/Induction/Abduction/Revision/Synthesis + 3 reserved) |
| 44 | +[49: 51] Plasticity flags 3b (hot/cold per S,P,O plane — palette-reassignment gate) |
| 45 | +[52: 63] Temporal index 12b (4096 time slots — coarse cycle bucket) |
| 46 | +
|
| 47 | +Total 64b (zero unused bits) |
| 48 | +``` |
| 49 | + |
| 50 | +**Constants** (`edge.rs:63-76`): |
| 51 | + |
| 52 | +```rust |
| 53 | +const S_SHIFT: u32 = 0; |
| 54 | +const P_SHIFT: u32 = 8; |
| 55 | +const O_SHIFT: u32 = 16; |
| 56 | +const FREQ_SHIFT: u32 = 24; |
| 57 | +const CONF_SHIFT: u32 = 32; |
| 58 | +const CAUSAL_SHIFT: u32 = 40; |
| 59 | +const DIR_SHIFT: u32 = 43; |
| 60 | +const INFER_SHIFT: u32 = 46; |
| 61 | +const PLAST_SHIFT: u32 = 49; |
| 62 | +const TEMPORAL_SHIFT: u32 = 52; |
| 63 | + |
| 64 | +const BYTE_MASK: u64 = 0xFF; |
| 65 | +const BITS3_MASK: u64 = 0b111; |
| 66 | +const BITS12_MASK: u64 = 0xFFF; |
| 67 | +``` |
| 68 | + |
| 69 | +--- |
| 70 | + |
| 71 | +## 3. Field Semantics |
| 72 | + |
| 73 | +### 3.1 S / P / O palette indices (bits 0-23) |
| 74 | + |
| 75 | +Three 8-bit indices into three separate 256-entry palette codebooks. **Not role keys** — role identity is given by *which* 8-bit slot the index sits in (S is bits 0-7, P is 8-15, O is 16-23). Role keys (per CLAUDE.md "The Click") live elsewhere as 4K-bit Vsa16kF32 slices. |
| 76 | + |
| 77 | +Addresses 256³ ≈ 16M (S, P, O) content tuples per edge. |
| 78 | + |
| 79 | +### 3.2 NARS frequency + confidence (bits 24-39) |
| 80 | + |
| 81 | +NARS truth value (Wang 2013 NAL semantics): |
| 82 | + |
| 83 | +- `f = positive_evidence / total_evidence ∈ [0, 1]` |
| 84 | +- `c = total_evidence / (total_evidence + k) ∈ [0, 1]` where `k = 1` (NARS personality constant) |
| 85 | + |
| 86 | +Accessors at `edge.rs:152-220`: |
| 87 | + |
| 88 | +```rust |
| 89 | +pub fn frequency_u8(self) -> u8 { (self.0 >> FREQ_SHIFT) as u8 } |
| 90 | +pub fn confidence_u8(self) -> u8 { (self.0 >> CONF_SHIFT) as u8 } |
| 91 | +pub fn frequency(self) -> f32 { /* val/255 */ } |
| 92 | +pub fn confidence(self) -> f32 { /* val/255 */ } |
| 93 | +pub fn expectation(self) -> f32 { /* c × (f − 0.5) + 0.5 */ } |
| 94 | +pub fn evidence_weight(self) -> f32 { /* c / (1 − c) */ } |
| 95 | +``` |
| 96 | + |
| 97 | +### 3.3 Causal Mask (bits 40-42) — Pearl's 2³ Ladder |
| 98 | + |
| 99 | +From `pearl.rs:11-49`: |
| 100 | + |
| 101 | +```text |
| 102 | +0b000 (None) → No planes active. Aggregate prior. |
| 103 | +0b001 (O) → Object only. Outcome marginal. |
| 104 | +0b010 (P) → Predicate only. Intervention marginal. |
| 105 | +0b011 (PO) → Predicate + Object. Level 2: Intervention P(Y|do(X)). |
| 106 | +0b100 (S) → Subject only. Entity marginal. |
| 107 | +0b101 (SO) → Subject + Object. Level 1: Association P(Y|X). |
| 108 | +0b110 (SP) → Subject + Predicate. Confounder detection. |
| 109 | +0b111 (SPO) → All planes active. Level 3: Counterfactual P(Y_x|X',Y'). |
| 110 | +``` |
| 111 | + |
| 112 | +Accessors at `edge.rs:221-278`: |
| 113 | + |
| 114 | +```rust |
| 115 | +pub fn causal_mask(self) -> CausalMask |
| 116 | +pub fn set_causal_mask(&mut self, m: CausalMask) |
| 117 | +pub const fn matches_causal(&self, query_mask: u8) -> bool |
| 118 | +pub fn matches_causal_mask(&self, query_mask: CausalMask) -> bool |
| 119 | +pub fn s_active(self) -> bool |
| 120 | +pub fn p_active(self) -> bool |
| 121 | +pub fn o_active(self) -> bool |
| 122 | +``` |
| 123 | + |
| 124 | +Pearl-rung is **load-bearing** for predicate-pushdown paths (cycle-speed projection filters). |
| 125 | + |
| 126 | +### 3.4 Direction triad (bits 43-45) — propagated polarity |
| 127 | + |
| 128 | +`sign(palette[s_idx].dim0)`, same for P and O. NOT a static cache — `forward()` at `edge.rs:457` propagates direction from the *weight* edge, not from current palette state. Comment at line 457: |
| 129 | + |
| 130 | +```rust |
| 131 | +weight.direction(), // TODO: recompute from composed palette dim0 signs |
| 132 | +``` |
| 133 | + |
| 134 | +That TODO marks direction as **load-bearing inference state**, not a derived value. Dropping direction requires either recomputing from palette (loses composition history) or accepting an information loss. |
| 135 | + |
| 136 | +Accessors at `edge.rs:286-310`: |
| 137 | + |
| 138 | +```rust |
| 139 | +pub fn direction(self) -> u8 |
| 140 | +pub fn set_direction(&mut self, d: u8) |
| 141 | +pub fn s_pathological(self) -> bool |
| 142 | +pub fn p_pathological(self) -> bool |
| 143 | +pub fn o_pathological(self) -> bool |
| 144 | +``` |
| 145 | + |
| 146 | +### 3.5 Inference Type (bits 46-48) — NARS rule applied |
| 147 | + |
| 148 | +From `edge.rs:9-26`: |
| 149 | + |
| 150 | +```rust |
| 151 | +pub enum InferenceType { |
| 152 | + Deduction = 0, // A→B, B→C ⊢ A→C. Follow the chain. |
| 153 | + Induction = 1, // A→B, A→C ⊢ B→C. Generalize from shared cause. |
| 154 | + Abduction = 2, // A→B, C→B ⊢ A→C. Infer from shared effect. |
| 155 | + Revision = 3, // Merge two truth values for the same statement. |
| 156 | + Synthesis = 4, // Combine complementary evidence across domains. |
| 157 | + Reserved5 = 5, |
| 158 | + Reserved6 = 6, |
| 159 | + Reserved7 = 7, |
| 160 | +} |
| 161 | +``` |
| 162 | + |
| 163 | +5 used + 3 reserved. Read in `forward()` at `edge.rs:406-439` — selects the NARS rule that produces the output truth values. |
| 164 | + |
| 165 | +### 3.6 Plasticity (bits 49-51) — per-plane palette-reassignment gate |
| 166 | + |
| 167 | +From `plasticity.rs:6-92`: |
| 168 | + |
| 169 | +```rust |
| 170 | +pub struct PlasticityState(u8); |
| 171 | + |
| 172 | +pub const ALL_FROZEN: Self = Self(0b000); // Established clinical pattern. |
| 173 | +pub const ALL_HOT: Self = Self(0b111); // New/uncertain edge. |
| 174 | +pub const S_HOT: Self = Self(0b001); // Only S-plane plastic. |
| 175 | +pub const P_HOT: Self = Self(0b010); |
| 176 | +pub const O_HOT: Self = Self(0b100); |
| 177 | + |
| 178 | +pub fn s_hot(self) -> bool |
| 179 | +pub fn p_hot(self) -> bool |
| 180 | +pub fn o_hot(self) -> bool |
| 181 | +pub fn freeze_s(self) -> Self |
| 182 | +pub fn heat_s(self) -> Self |
| 183 | +// ... plus per-plane freeze_p/o + heat_p/o |
| 184 | +``` |
| 185 | + |
| 186 | +**Distinct from NARS confidence:** plasticity gates archetype reassignment per plane; confidence gates evidence weighting for revision. High `c` typically correlates with `ALL_FROZEN` but not always (e.g., clinical-pattern lock vs. exploratory mode). |
| 187 | + |
| 188 | +### 3.7 Temporal index (bits 52-63) — 4096-slot cycle bucket |
| 189 | + |
| 190 | +12-bit coarse time bucket. Read in `forward()` at `edge.rs:446`: |
| 191 | + |
| 192 | +```rust |
| 193 | +let t_out = self.temporal().max(weight.temporal()); |
| 194 | +``` |
| 195 | + |
| 196 | +**This is the field that is genuinely redundant** with (a) AriGraph `Triplet.timestamp: u64` (at commit time) and (b) `SpoWitnessChain` position (per-cycle order). It is the leading candidate for v2 bit-reclaim. |
| 197 | + |
| 198 | +--- |
| 199 | + |
| 200 | +## 4. Key Methods |
| 201 | + |
| 202 | +### 4.1 `pack()` — full constructor |
| 203 | + |
| 204 | +`edge.rs:84-110`: |
| 205 | + |
| 206 | +```rust |
| 207 | +pub fn pack( |
| 208 | + s_idx: u8, p_idx: u8, o_idx: u8, |
| 209 | + frequency: u8, confidence: u8, |
| 210 | + causal_mask: CausalMask, |
| 211 | + direction: u8, |
| 212 | + inference: InferenceType, |
| 213 | + plasticity: PlasticityState, |
| 214 | + temporal: u16, |
| 215 | +) -> Self |
| 216 | +``` |
| 217 | + |
| 218 | +### 4.2 `forward()` — the BNN-style cognitive composition |
| 219 | + |
| 220 | +`edge.rs:393-462` — composes two edges (self = activation, weight = learned edge) into a new edge: |
| 221 | + |
| 222 | +1. **Palette composition** (lines 401-403): three 256×256 compose-table lookups (compose_s, compose_p, compose_o) — one per plane. O(1) per plane. |
| 223 | +2. **NARS truth propagation** (lines 406-439): switch on `weight.inference_type()` → applies Deduction / Induction / Abduction / Revision / Synthesis truth formula → produces `(f_out, c_out)`. |
| 224 | +3. **Causal mask AND** (lines 442-443): `mask_out = self.causal_mask() & weight.causal_mask()` — only planes active in both survive. |
| 225 | +4. **Temporal max** (line 446): `t_out = self.temporal().max(weight.temporal())`. |
| 226 | +5. **Inherit plasticity** from weight (line 459). |
| 227 | + |
| 228 | +This IS the cycle-speed cognitive forward pass — pure register operations + three 256×256 table lookups. Cache-friendly when the compose tables are L2-resident. |
| 229 | + |
| 230 | +### 4.3 `learn()` — evidence-driven revision |
| 231 | + |
| 232 | +`edge.rs:464+` (Learning section). Applies NARS revision rule to merge observed evidence with existing truth; updates plasticity flags based on confidence transitions. |
| 233 | + |
| 234 | +### 4.4 Distance accessors |
| 235 | + |
| 236 | +`edge.rs:370-384` (per-plane Hamming distance via palette distance tables): |
| 237 | + |
| 238 | +```rust |
| 239 | +pub fn distance_masked(&self, other: &Self, |
| 240 | + s_dm: &[u8; 65536], |
| 241 | + p_dm: &[u8; 65536], |
| 242 | + o_dm: &[u8; 65536], |
| 243 | + mask: u8) -> u32 |
| 244 | +``` |
| 245 | + |
| 246 | +Filtered by 3-bit mask — only sums the planes active in the mask. O(1) per plane. |
| 247 | + |
| 248 | +--- |
| 249 | + |
| 250 | +## 5. Consumers |
| 251 | + |
| 252 | +### 5.1 `lance-graph-planner::cache::nars_engine` |
| 253 | + |
| 254 | +Per CLAUDE.md "Session: AutocompleteCache + p64 Convergence": |
| 255 | + |
| 256 | +> *`nars_engine.rs`: SpoHead, Pearl 2³, NarsTables (causal-edge hot path), StyleVectors* |
| 257 | +
|
| 258 | +The planner re-exports CausalEdge64 from the causal-edge crate, packages it into `NarsTables` (precomputed NARS lookup tables), and consumes it in the AutocompleteCache. |
| 259 | + |
| 260 | +### 5.2 `cognitive-shader-driver::BindSpace::EdgeColumn` |
| 261 | + |
| 262 | +Per CLAUDE.md "AGI-as-glove" doctrine: |
| 263 | + |
| 264 | +> *Planner (why/how, causal composition) = a write to `EdgeColumn` (`CausalEdge64`). Never a new bridge.* |
| 265 | +
|
| 266 | +`EdgeColumn` is one of the 4 BindSpace columns in the SoA: `FingerprintColumns / QualiaColumn / MetaColumn / EdgeColumn`. The SPO-palette `CausalEdge64` is the per-row entry in `EdgeColumn`. |
| 267 | + |
| 268 | +### 5.3 AriGraph SPO commit path |
| 269 | + |
| 270 | +The `spo_bridge::promote_to_spo()` gate (per W5 spec for sprint-10) commits CausalEdge64-grounded inferences into AriGraph as `Triplet` rows when truth confidence passes a `TruthGate` threshold. The CausalEdge64's S/P/O palette indices map to AriGraph subject/predicate/object entity references. |
| 271 | + |
| 272 | +### 5.4 `p64::convergence` |
| 273 | + |
| 274 | +Per `crates/lance-graph-planner/src/cache/convergence.rs:1-23`: |
| 275 | + |
| 276 | +```text |
| 277 | +Cold path (columns/rows): |
| 278 | + AriGraph TripletGraph → SPO strings → DataFusion → Arrow |
| 279 | +
|
| 280 | +Hot path (p64 palette): |
| 281 | + AriGraph Triplets → Base17 fingerprints → Palette → CognitiveShader |
| 282 | + → 8 predicate layers × 64×64 attention = 4096 heads |
| 283 | + → CausalEdge64 forward/learn = O(1) per head |
| 284 | + → NarsTables revision = O(1) per truth update |
| 285 | +
|
| 286 | +Convergence: |
| 287 | + Cold path BUILDS the graph (via LLM, slow) |
| 288 | + Hot path SERVES the graph (via palette, fast) |
| 289 | + p64 IS the bridge between them |
| 290 | +``` |
| 291 | + |
| 292 | +This is the canonical convergence — the SPO-variant CausalEdge64 is the unit of "O(1) per head" at the hot path. |
| 293 | + |
| 294 | +--- |
| 295 | + |
| 296 | +## 6. Hot-Path Role |
| 297 | + |
| 298 | +**Zone-1 (cycle-speed):** YES. CausalEdge64 is the per-row payload of `BindSpace::EdgeColumn`; SoA sweeps over the column run `forward()` and `learn()` at O(1) per row + three 256×256 table lookups. Cache-resident; ~50-200 ns per row at typical CPU speeds when tables are L2-hot. |
| 299 | + |
| 300 | +**Zone-2 (SPO-as-3D-vector ANN search):** Indirect — CausalEdge64's `distance_masked()` is the per-edge primitive that the `blasgraph` + `neighborhood` cascade (HEEL → HIP → TWIG → LEAF) ranks edges by. The S/P/O palette indices are the addresses; the distance is computed via per-plane 256×256 palette-distance tables. |
| 301 | + |
| 302 | +**Zone-3 (DataFusion cold path):** Indirect — when triples promote to AriGraph SPO, they become `Triplet` rows that DataFusion can query columnwise. The CausalEdge64's truth values flow into the persisted truth columns. But the edge itself is not read directly by DataFusion. |
| 303 | + |
| 304 | +--- |
| 305 | + |
| 306 | +## 7. Cross-references |
| 307 | + |
| 308 | +- **Paired with:** `causal-edge-64-thinking-engine-variant.md` (the OTHER `CausalEdge64` type — same name, different bit layout, different semantics, different consumers). |
| 309 | +- **Synergies + drift analysis:** `causal-edge-64-synergies-and-pr-trajectory.md`. |
| 310 | +- **AGI-as-glove doctrine:** `lab-vs-canonical-surface.md` (the 4 BindSpace columns; CausalEdge64 = EdgeColumn). |
| 311 | +- **Encoding stack:** `encoding-ecosystem.md` (Full → ZeckBF17 → BGZ17 → CAM-PQ → Scent → CausalEdge64). |
| 312 | +- **NARS semantics:** `lance-graph-planner/src/cache/nars_engine.rs` (NarsTables, SpoHead, MASK_SPO). |
| 313 | +- **Pearl ladder:** `causal-edge/src/pearl.rs` (CausalMask enum). |
| 314 | +- **Plasticity:** `causal-edge/src/plasticity.rs` (PlasticityState). |
| 315 | +- **p64 convergence:** `lance-graph-planner/src/cache/convergence.rs` (the bridge where this variant lives in the hot path). |
| 316 | +- **Sprint-10 v2 layout proposal:** `.claude/plans/causaledge64-mailbox-rename-soa-v1.md` (parent plan §3); `.claude/specs/pr-ce64-mb-2-causaledge64-v2.md` (W2 spec); `.claude/specs/pr-ce64-mb-2-pal8-nars-regression.md` (W3 spec). |
| 317 | +- **SPOW tetrahedron (witness as 4th vertex):** `.claude/plans/oxigraph-arigraph-cognitive-shader-soa-merge-v1.md` §8. |
| 318 | + |
| 319 | +--- |
| 320 | + |
| 321 | +## 8. The v2 Bit-Reclaim Decision |
| 322 | + |
| 323 | +This variant is the target of the sprint-10 CausalEdge64-v2 work (PR-CE64-MB-2). The bit-reclaim debate (CSI-1 in `.claude/board/sprint-log-10/meta-review.md`) concerns which bits to drop to make room for new fields (G-slot, W-slot, truth-band lens). Current meta-review recommendation: **drop temporal (12b) + drop G_slot-from-edge (5b) = 17b freed**; keep direction/plasticity/inference (load-bearing dispatch payload per the corrected hot-path analysis). |
| 324 | + |
| 325 | +See `causal-edge-64-synergies-and-pr-trajectory.md` §4 for the full bit-reclaim trade analysis. |
| 326 | + |
| 327 | +--- |
| 328 | + |
| 329 | +*Last verified: 2026-05-14 against shipped `crates/causal-edge/src/edge.rs` + `pearl.rs` + `plasticity.rs` + `convergence.rs`.* |
0 commit comments