From ae57c15910770d87f6a65ee4b6dc316434b9c20a Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 21:02:33 +0000 Subject: [PATCH 01/10] causal-edge: orientation contract tests for bits 43..45 (red: no Orientation yet) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- .../causal-edge/tests/orientation_contract.rs | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 crates/causal-edge/tests/orientation_contract.rs diff --git a/crates/causal-edge/tests/orientation_contract.rs b/crates/causal-edge/tests/orientation_contract.rs new file mode 100644 index 000000000..657f0cb52 --- /dev/null +++ b/crates/causal-edge/tests/orientation_contract.rs @@ -0,0 +1,86 @@ +//! D-CGW-1: CE64 bits 43..45 carry one meaning everywhere, the orientation +//! (`causal_edge::orientation::Orientation`). These pin the code table, the +//! accessor and both writers to that one table, and field isolation 43..45 +//! against its neighbours 40..42 (Pearl) and 46..49 (inference mantissa). +#![cfg(feature = "causal-edge-v2-layout")] + +use causal_edge::edge::InferenceType; +use causal_edge::orientation::Orientation; +use causal_edge::pearl::CausalMask; +use causal_edge::plasticity::PlasticityState; +use causal_edge::CausalEdge64; + +#[test] +fn code_table_is_one_to_one_over_three_bits() { + let mut seen = [false; 8]; + for o in Orientation::ALL { + let c = o.code(); + assert!(c < 8, "{o:?} code {c} does not fit 3 bits"); + assert!(!seen[c as usize], "{o:?} shares code {c}"); + seen[c as usize] = true; + assert_eq!(Orientation::from_code(c), o, "round trip of {o:?}"); + } + assert!(seen.iter().all(|&s| s), "every 3-bit code names an orientation"); + // Only the low three bits are read. + assert_eq!(Orientation::from_code(0b1010), Orientation::from_code(0b010)); +} + +#[test] +fn zero_is_the_core_argument() { + assert_eq!(Orientation::from_code(0), Orientation::Core); + assert_eq!(CausalEdge64(0).orientation(), Orientation::Core); +} + +#[test] +fn accessor_and_setter_agree_for_every_code() { + for o in Orientation::ALL { + let mut e = CausalEdge64(0); + e.set_orientation(o); + assert_eq!(e.orientation(), o); + assert_eq!((e.0 >> 43) & 0b111, u64::from(o.code()), "{o:?} lands on 43..45"); + } +} + +#[test] +fn both_packers_write_the_same_table() { + for o in Orientation::ALL { + let v2 = CausalEdge64::pack_v2(1, 2, 3, 200, 100, CausalMask::SPO, o, PlasticityState::ALL_HOT); + assert_eq!(v2.orientation(), o, "pack_v2 {o:?}"); + #[allow(deprecated)] + let v1 = CausalEdge64::pack( + 1, + 2, + 3, + 200, + 100, + CausalMask::SPO, + o, + InferenceType::Deduction, + PlasticityState::ALL_HOT, + 0, + ); + assert_eq!(v1.orientation(), o, "pack {o:?}"); + } +} + +#[test] +fn orientation_is_isolated_from_its_neighbours() { + // Every bit outside 43..45 set: writing the orientation must not move any. + let outside = !(0b111u64 << 43); + for o in Orientation::ALL { + let mut e = CausalEdge64(outside); + e.set_orientation(o); + assert_eq!(e.0 & outside, outside, "{o:?} disturbed a neighbour"); + assert_eq!(e.orientation(), o); + } + // And the neighbours' setters must not move the orientation. + for o in Orientation::ALL { + let mut e = CausalEdge64(0); + e.set_orientation(o); + e.set_causal_mask(CausalMask::SPO); + let e = e.with_inference_mantissa(-6); + assert_eq!(e.orientation(), o, "{o:?} moved by a neighbour write"); + assert_eq!(e.causal_mask(), CausalMask::SPO); + assert_eq!(e.inference_mantissa(), -6); + } +} From 72e0ff019714a576c78493e5beb0ffbf141f8879 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 21:05:06 +0000 Subject: [PATCH 02/10] causal-edge: bits 43..45 are the orientation (D-CGW-1) Orientation (Core = 0, then the seven Haspelmath dative-map functions) is the one meaning of bits 43..45. direction()/set_direction() become orientation()/set_orientation(); pack and pack_v2 take an Orientation, so every writer is checked by the compiler. The S/P/O pathological triad is removed, not moved: nothing in production wrote it, and the planner's confounder check computes its directions from population masks. Removed: s/p/o_pathological, concern_level, the simplified CausalNetwork::detect_simpsons_paradox. CausalMask::simpsons_paradox_risk stays as a function over directions the caller computes. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- crates/causal-edge/src/edge.rs | 77 +++++++------------ crates/causal-edge/src/edge_v3.rs | 30 ++++---- crates/causal-edge/src/layout.rs | 11 +-- crates/causal-edge/src/lib.rs | 6 +- crates/causal-edge/src/network.rs | 33 -------- crates/causal-edge/src/orientation.rs | 64 +++++++++++++++ crates/causal-edge/src/pearl.rs | 7 +- crates/causal-edge/src/syllogism.rs | 8 +- crates/causal-edge/src/v2_layout_tests.rs | 38 ++++----- crates/causal-edge/tests/ce64_op_contract.rs | 4 +- .../tests/t4_learn_plasticity_patterns.rs | 2 +- 11 files changed, 147 insertions(+), 133 deletions(-) create mode 100644 crates/causal-edge/src/orientation.rs diff --git a/crates/causal-edge/src/edge.rs b/crates/causal-edge/src/edge.rs index 9f9aab322..695d8e513 100644 --- a/crates/causal-edge/src/edge.rs +++ b/crates/causal-edge/src/edge.rs @@ -4,6 +4,7 @@ use super::pearl::CausalMask; use super::plasticity::PlasticityState; +use crate::orientation::Orientation; use crate::isa::{Compose, IsaFault, Opcode}; /// NARS inference types encoded in 3 bits. @@ -186,7 +187,7 @@ const O_SHIFT: u32 = 16; const FREQ_SHIFT: u32 = 24; const CONF_SHIFT: u32 = 32; const CAUSAL_SHIFT: u32 = 40; -const DIR_SHIFT: u32 = 43; +const ORIENT_SHIFT: u32 = 43; const INFER_SHIFT: u32 = 46; // v1 plasticity bit position; under v2 plasticity moves to `crate::layout::PLAST_SHIFT`. // Live on the v1 pack/read paths, dead under the default v2 feature. @@ -239,7 +240,7 @@ impl CausalEdge64 { frequency: u8, confidence: u8, causal_mask: CausalMask, - direction: u8, + orientation: Orientation, inference: InferenceType, plasticity: PlasticityState, temporal: u16, @@ -251,7 +252,7 @@ impl CausalEdge64 { v |= (frequency as u64) << FREQ_SHIFT; v |= (confidence as u64) << CONF_SHIFT; v |= ((causal_mask as u64) & BITS3_MASK) << CAUSAL_SHIFT; - v |= ((direction as u64) & BITS3_MASK) << DIR_SHIFT; + v |= (orientation.code() as u64) << ORIENT_SHIFT; // v2 layout: write the signed mantissa (4 bits, bits 46-49) via the // enum→mantissa mapping so that subsequent reads via inference_mantissa() // + InferenceType::from_mantissa() round-trip the *semantic* meaning. @@ -442,37 +443,18 @@ impl CausalEdge64 { (self.0 >> CAUSAL_SHIFT) & 0b001 != 0 } - // ─── Direction Triad ──────────────────────────────────────────── + // ─── Orientation (bits 43..45) ────────────────────────────────── - /// 3-bit direction triad: sign(dim0) per S, P, O. - /// bit 0 = S pathological, bit 1 = P pathological, bit 2 = O pathological. + /// The relation's orientation (bits 43..45); see [`Orientation`]. #[inline(always)] - pub fn direction(self) -> u8 { - ((self.0 >> DIR_SHIFT) & BITS3_MASK) as u8 + pub fn orientation(self) -> Orientation { + Orientation::from_code(((self.0 >> ORIENT_SHIFT) & BITS3_MASK) as u8) } - /// Set direction triad. + /// Set the orientation (bits 43..45). #[inline] - pub fn set_direction(&mut self, d: u8) { - self.0 = (self.0 & !(BITS3_MASK << DIR_SHIFT)) | (((d as u64) & BITS3_MASK) << DIR_SHIFT); - } - - /// Is the subject plane pathological (dim0 negative)? - #[inline(always)] - pub fn s_pathological(self) -> bool { - self.direction() & 0b001 != 0 - } - - /// Is the predicate plane pathological? - #[inline(always)] - pub fn p_pathological(self) -> bool { - self.direction() & 0b010 != 0 - } - - /// Is the outcome plane pathological? - #[inline(always)] - pub fn o_pathological(self) -> bool { - self.direction() & 0b100 != 0 + pub fn set_orientation(&mut self, o: Orientation) { + self.0 = (self.0 & !(BITS3_MASK << ORIENT_SHIFT)) | ((o.code() as u64) << ORIENT_SHIFT); } // ─── Inference Type ───────────────────────────────────────────── @@ -805,7 +787,7 @@ impl CausalEdge64 { f_out, c_out, mask_out, - rhs.direction(), // TODO: recompute from composed palette dim0 signs + rhs.orientation(), // the conclusion is read in the second premise's orientation op.inference_type(), rhs.plasticity(), t_out, @@ -902,13 +884,6 @@ impl CausalEdge64 { self.causal_mask() == CausalMask::SPO && self.confidence() >= confidence_threshold } - /// Clinical concern level: count of pathological planes. - #[inline] - pub fn concern_level(self) -> u8 { - let d = self.direction(); - (d & 1) + ((d >> 1) & 1) + ((d >> 2) & 1) - } - /// Is this edge fully frozen (all planes)? #[inline] pub fn is_frozen(self) -> bool { @@ -935,11 +910,11 @@ impl CausalEdge64 { frequency: u8, confidence: u8, causal_mask: CausalMask, - direction: u8, + orientation: Orientation, plasticity: PlasticityState, ) -> Self { use crate::layout::{ - BITS3_MASK as B3, CAUSAL_SHIFT as LCA, CONF_SHIFT as LC, DIR_SHIFT as LD, + BITS3_MASK as B3, CAUSAL_SHIFT as LCA, CONF_SHIFT as LC, ORIENT_SHIFT as LD, FREQ_SHIFT as LF, O_SHIFT as LO, PLAST_SHIFT as LPL, P_SHIFT as LP, S_SHIFT as LS, }; let mut v: u64 = 0; @@ -949,7 +924,7 @@ impl CausalEdge64 { v |= (frequency as u64) << LF; v |= (confidence as u64) << LC; v |= ((causal_mask as u64) & B3) << LCA; - v |= ((direction as u64) & B3) << LD; + v |= (orientation.code() as u64) << LD; // inference mantissa defaults to 0 (Identity/neutral) v |= ((plasticity.bits() as u64) & B3) << LPL; // W-slot, truth-band, spare default to 0 @@ -1463,7 +1438,7 @@ impl std::fmt::Debug for CausalEdge64 { .field("f", &format!("{:.3}", self.frequency())) .field("c", &format!("{:.3}", self.confidence())) .field("pearl", &self.causal_mask()) - .field("dir", &format!("{:03b}", self.direction())) + .field("orient", &self.orientation()) .field("infer", &self.inference_type()) .field("plast", &self.plasticity()) .field("t", &self.temporal()) @@ -1546,7 +1521,7 @@ mod tests { 209, 181, // f=0.82, c=0.71 CausalMask::PO, // interventional level - 0b101, // S and O pathological + Orientation::Recipient, InferenceType::Deduction, PlasticityState::S_HOT, 42, // temporal index @@ -1558,7 +1533,7 @@ mod tests { assert_eq!(edge.frequency_u8(), 209); assert_eq!(edge.confidence_u8(), 181); assert_eq!(edge.causal_mask(), CausalMask::PO); - assert_eq!(edge.direction(), 0b101); + assert_eq!(edge.orientation(), Orientation::Recipient); assert_eq!(edge.inference_type(), InferenceType::Deduction); assert_eq!(edge.plasticity(), PlasticityState::S_HOT); assert_eq!(edge.temporal(), 42); @@ -1573,7 +1548,7 @@ mod tests { 204, 178, // f=0.80, c=0.70 CausalMask::SPO, - 0, + crate::orientation::Orientation::Core, InferenceType::Deduction, PlasticityState::ALL_HOT, 1, @@ -1585,7 +1560,7 @@ mod tests { 229, 204, // f=0.90, c=0.80 CausalMask::SPO, - 0, + crate::orientation::Orientation::Core, InferenceType::Deduction, PlasticityState::ALL_FROZEN, 2, @@ -1620,7 +1595,7 @@ mod tests { 204, 127, // f=0.80, c=0.50 CausalMask::SPO, - 0, + crate::orientation::Orientation::Core, InferenceType::Revision, PlasticityState::ALL_HOT, 1, @@ -1632,7 +1607,7 @@ mod tests { 204, 127, // same frequency, same confidence CausalMask::SPO, - 0, + crate::orientation::Orientation::Core, InferenceType::Revision, PlasticityState::ALL_HOT, 2, @@ -1655,7 +1630,7 @@ mod tests { 200, 200, CausalMask::PO, - 0, + crate::orientation::Orientation::Core, InferenceType::Deduction, PlasticityState::ALL_FROZEN, 0, @@ -1681,7 +1656,7 @@ mod tests { 200, 200, CausalMask::SPO, - 0, + Orientation::Core, InferenceType::Revision, PlasticityState::ALL_HOT, 100, @@ -1693,7 +1668,7 @@ mod tests { 200, 200, CausalMask::SPO, - 0, + Orientation::Core, InferenceType::Revision, PlasticityState::ALL_HOT, 200, @@ -1725,7 +1700,7 @@ mod tests { 200, 200, mask, - 0, + crate::orientation::Orientation::Core, InferenceType::Deduction, PlasticityState::ALL_FROZEN, 0, diff --git a/crates/causal-edge/src/edge_v3.rs b/crates/causal-edge/src/edge_v3.rs index 6cce816bc..2d1e3e319 100644 --- a/crates/causal-edge/src/edge_v3.rs +++ b/crates/causal-edge/src/edge_v3.rs @@ -40,7 +40,7 @@ //! ```text //! [0] MO freq u8 (NARS frequency) //! [1] MO conf u8 (NARS confidence) -//! [2] KA causal_mask(3) | direction(3) why-planes + chain dir +//! [2] KA causal_mask(3) | orientation(3) why-planes + orientation //! [3] KA inference_mantissa(i4 low) | plasticity(3 high) //! [4..6] LO target u16 (the node whose CAM-PQ IS the SPO — NO SPO here) //! [6] anaphora nibble (i4 low, −8..+7; 0 = none) @@ -64,7 +64,7 @@ //! relative chain offset the producer sets explicitly, never inherited. //! //! Under the v2 layout the 64 bits are fully partitioned — S/P/O, freq, conf, -//! causal_mask, direction, inference i4, plasticity, w_slot, truth, spare — so +//! causal_mask, orientation, inference i4, plasticity, w_slot, truth, spare — so //! "every field preserved" IS "every bit preserved" once the SPO is resupplied. //! //! ### The signed mantissa is carried RAW, never through `InferenceType` @@ -107,7 +107,7 @@ impl CausalEdgeV3 { /// pointing `target` at the node whose CAM-PQ facet holds that SPO. /// /// **Every other meaningful v2 field is preserved**: freq, conf, - /// causal_mask, direction, the RAW signed inference mantissa, plasticity, + /// causal_mask, orientation, the RAW signed inference mantissa, plasticity, /// w_slot, the truth/topology 2-bit ordinal, and the spare/band 3-bit /// ordinal. Paired with [`Self::rehydrate`] this is a bit-exact round trip /// once the same SPO is resupplied — see the module doc. @@ -123,7 +123,7 @@ impl CausalEdgeV3 { let mut p = [0u8; 12]; p[0] = e.frequency_u8(); p[1] = e.confidence_u8(); - p[2] = (e.causal_mask() as u8 & 0b111) | ((e.direction() & 0b111) << 3); + p[2] = (e.causal_mask() as u8 & 0b111) | (e.orientation().code() << 3); let mantissa = e.inference_mantissa() as u8 & 0x0F; p[3] = mantissa | ((e.plasticity().bits() & 0b111) << 4); let t = target.to_le_bytes(); @@ -200,9 +200,9 @@ impl CausalEdgeV3 { CausalMask::from_bits(self.payload[2] & 0b111) } - /// Direction triad (3 bits, sign(dim0) per S,P,O) — byte 2, bits 3..6. - pub fn direction(&self) -> u8 { - (self.payload[2] >> 3) & 0b111 + /// Orientation (CE64 bits 43..45, see [`crate::Orientation`]) — byte 2, bits 3..6. + pub fn orientation(&self) -> crate::Orientation { + crate::Orientation::from_code(self.payload[2] >> 3) } /// The RAW 4-bit signed inference mantissa (−8..=7) — byte 3, low nibble. @@ -283,7 +283,7 @@ impl CausalEdgeV3 { self.frequency(), self.confidence(), self.causal_mask(), - self.direction(), + self.orientation(), // placeholder ONLY — overwritten by set_inference_mantissa below. InferenceType::Deduction, self.plasticity(), @@ -366,7 +366,7 @@ mod tests { f, c, CausalMask::from_bits(mask), - 0, + crate::orientation::Orientation::Core, InferenceType::Deduction, PlasticityState::ALL_HOT, 0, @@ -608,7 +608,7 @@ mod tests { 200, 180, CausalMask::from_bits(0b101), - 0b010, + crate::orientation::Orientation::from_code(0b010), PlasticityState::ALL_HOT, ) .with_inference_mantissa(m); @@ -640,7 +640,7 @@ mod tests { 255, 255, CausalMask::from_bits(0b111), - 0b111, + crate::orientation::Orientation::from_code(0b111), PlasticityState::ALL_HOT, ) .with_inference_mantissa(m); @@ -663,7 +663,7 @@ mod tests { /// /// Every meaningful CE64-v2 field is asserted after CE64 → V3 → CE64 with /// the SAME resolved SPO resupplied. Under v2 the 64 bits are fully - /// partitioned (S/P/O · freq · conf · mask · direction · mantissa · + /// partitioned (S/P/O · freq · conf · mask · orientation · mantissa · /// plasticity · w_slot · truth · spare), so this is also a whole-register /// bit-identity check — asserted as such at the end. /// @@ -697,7 +697,7 @@ mod tests { freq, conf, CausalMask::from_bits(mask), - dir, + crate::orientation::Orientation::from_code(dir), PlasticityState::from_bits(0b101), ) .with_inference_mantissa(mant) @@ -719,7 +719,7 @@ mod tests { assert_eq!(got.frequency_u8(), freq, "freq"); assert_eq!(got.confidence_u8(), conf, "conf"); assert_eq!(got.causal_mask() as u8, mask, "causal_mask"); - assert_eq!(got.direction(), dir, "direction"); + assert_eq!(got.orientation().code(), dir, "orientation"); assert_eq!(got.inference_mantissa(), mant, "inference i4"); assert_eq!(got.plasticity().bits(), 0b101, "plasticity"); assert_eq!(got.w_slot(), w, "w_slot"); @@ -749,7 +749,7 @@ mod tests { 4, 5, CausalMask::from_bits(0), - 0, + crate::orientation::Orientation::Core, PlasticityState::from_bits(0), ) .with_w_slot(0x2A) // 0b101010 diff --git a/crates/causal-edge/src/layout.rs b/crates/causal-edge/src/layout.rs index 70de1918f..6729faadc 100644 --- a/crates/causal-edge/src/layout.rs +++ b/crates/causal-edge/src/layout.rs @@ -11,7 +11,8 @@ pub const O_SHIFT: u32 = 16; pub const FREQ_SHIFT: u32 = 24; pub const CONF_SHIFT: u32 = 32; pub const CAUSAL_SHIFT: u32 = 40; -pub const DIR_SHIFT: u32 = 43; +/// Orientation (bits 43..45); see [`crate::orientation::Orientation`]. +pub const ORIENT_SHIFT: u32 = 43; // ── v1→v2 EXPANDED field ──────────────────────────────────────────────────── /// Inference mantissa: 4-bit signed (−8..+7). @@ -125,7 +126,7 @@ const _LAYOUT_COVERAGE: () = { | (BYTE_MASK << FREQ_SHIFT) // bits 24-31 | (BYTE_MASK << CONF_SHIFT) // bits 32-39 | (BITS3_MASK << CAUSAL_SHIFT) // bits 40-42 - | (BITS3_MASK << DIR_SHIFT) // bits 43-45 + | (BITS3_MASK << ORIENT_SHIFT) // bits 43-45 | (BITS4_MASK << INFER_SHIFT) // bits 46-49 (4b signed mantissa) | (BITS3_MASK << PLAST_SHIFT) // bits 50-52 (shifted from v1) | (BITS6_MASK << W_SHIFT) // bits 53-58 (NEW) @@ -347,8 +348,8 @@ impl CausalTopology { /// `ReasoningBand::Counterfactual`. /// - `Perspective` = perspective/decentration reasoning (I/Thou/It, /// Self/Other/World). This is **not** -/// [`super::edge::CausalEdge64::direction`] (bits 43-45), the -/// pathology-per-plane sign triad. +/// [`super::edge::CausalEdge64::orientation`] (bits 43-45), the function +/// a relation is read in. /// - `Meta` = reasoning ABOUT reasoning/evidence/revision (meta-cognition), /// independent of every other field on the edge. /// - `Transcendent` = mechanically, the highest ordinal this 3-bit @@ -401,7 +402,7 @@ pub enum ReasoningBand { /// inference mantissa's −6 slot. Counterfactual = 4, /// Perspective/decentration reasoning. See the orthogonality note re: - /// `direction`. + /// `orientation`. Perspective = 5, /// Meta-cognitive reasoning (reasoning about reasoning/evidence/revision). Meta = 6, diff --git a/crates/causal-edge/src/lib.rs b/crates/causal-edge/src/lib.rs index 2750902f4..80c6aa03d 100644 --- a/crates/causal-edge/src/lib.rs +++ b/crates/causal-edge/src/lib.rs @@ -2,14 +2,14 @@ //! //! One atomic u64 encoding the complete causal unit: //! SPO palette indices, NARS truth value, Pearl's causal hierarchy, -//! direction diagnostic, inference type, plasticity state, and temporal index. +//! orientation, inference type, plasticity state, and temporal index. //! //! ## Bit Layout //! //! ```text //! 63 52 51 49 48 46 45 43 42 40 39 32 31 24 23 16 15 8 7 0 //! ┌──────────┬───────┬───────┬───────┬──────┬──────────┬──────────┬──────┬──────┬──────┐ -//! │ temporal │plasti │infer │direct │causal│ NARS c │ NARS f │ O │ P │ S │ +//! │ temporal │plasti │infer │orient │causal│ NARS c │ NARS f │ O │ P │ S │ //! │ 12 bit │3 bit │3 bit │3 bit │3 bit │ 8 bit │ 8 bit │ 8bit │ 8bit │ 8bit │ //! └──────────┴───────┴───────┴───────┴──────┴──────────┴──────────┴──────┴──────┴──────┘ //! ``` @@ -56,6 +56,7 @@ pub mod edge_v3; pub mod isa; pub mod layout; pub mod network; +pub mod orientation; pub mod pearl; pub mod plasticity; pub mod syllogism; @@ -67,6 +68,7 @@ mod v2_layout_tests; pub use edge::CausalEdge64; pub use edge_v3::CausalEdgeV3; pub use isa::{Compose, IsaFault, Opcode}; +pub use orientation::Orientation; pub use pearl::CausalMask; pub use plasticity::PlasticityState; pub use syllogism::{Figure, Syllogism}; diff --git a/crates/causal-edge/src/network.rs b/crates/causal-edge/src/network.rs index 288d596c7..8bf41da8d 100644 --- a/crates/causal-edge/src/network.rs +++ b/crates/causal-edge/src/network.rs @@ -122,39 +122,6 @@ impl CausalNetwork { results } - /// Detect Simpson's Paradox: find edges where S_O and _PO disagree. - /// - /// Returns edge indices with potential Simpson's Paradox, - /// along with the associational and interventional directions. - pub fn detect_simpsons_paradox(&self) -> Vec<(usize, u8, u8)> { - let mut paradoxes = Vec::new(); - - for (i, &edge) in self.edges.iter().enumerate() { - // Check if this edge has enough evidence - if edge.confidence() < 0.5 { - continue; - } - - // Compare direction at S_O (association) vs _PO (intervention) - // We need to query neighbors at both levels to get directions. - // Simplified: check if the edge's own direction bits suggest - // conflicting signals across planes. - let dir = edge.direction(); - let s_path = dir & 0b001 != 0; // S pathological - let o_path = dir & 0b100 != 0; // O pathological - - // If subject is pathological AND outcome is pathological, - // but the predicate (treatment) is NOT pathological, - // there may be confounding: sick patients get treated, - // treatment works, but S_O still shows negative association. - if s_path && o_path && !(dir & 0b010 != 0) { - paradoxes.push((i, dir, edge.causal_mask() as u8)); - } - } - - paradoxes - } - /// Evidence audit: trace how a specific edge's truth value evolved. /// /// Returns edges with the same SPO indices sorted by temporal index. diff --git a/crates/causal-edge/src/orientation.rs b/crates/causal-edge/src/orientation.rs new file mode 100644 index 000000000..267dc3210 --- /dev/null +++ b/crates/causal-edge/src/orientation.rs @@ -0,0 +1,64 @@ +//! CE64 bits 43..45: the orientation of a relation. +//! +//! One meaning everywhere (D-CGW-1): the function a relation is read in, on +//! Haspelmath's dative semantic map (Haspelmath 2003, Fig. 8.1). `Core` (0) +//! is the plain core argument, which is also every relation no reader has +//! oriented: a Moore lane writes 0 here, because its direction is its slot and +//! polarity, not a function on this map. +//! +//! These bits used to hold a per-plane S/P/O "pathological" sign triad. Nothing +//! in production wrote it, and the planner's confounder check computes its +//! directions from population masks, so the triad and its readers were removed +//! rather than moved (D-CGW-1). + +/// The orientation code of a relation (bits 43..45 of a [`crate::CausalEdge64`]). +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +#[repr(u8)] +pub enum Orientation { + /// Plain core argument, or not oriented by any reader. + #[default] + Core = 0, + /// Direction (allative: "to the town"). + Direction = 1, + /// Recipient ("gave it to her"). + Recipient = 2, + /// Experiencer ("it seems to me"). + Experiencer = 3, + /// Purpose ("for the meal"). + Purpose = 4, + /// Beneficiary ("bought it for him"). + Beneficiary = 5, + /// Predicative possessor ("the book is mine"). + PredicativePossessor = 6, + /// External possessor ("broke his arm" read as "broke the arm to him"). + ExternalPossessor = 7, +} + +impl Orientation { + /// All eight orientations, in code order. + pub const ALL: [Self; 8] = [ + Self::Core, + Self::Direction, + Self::Recipient, + Self::Experiencer, + Self::Purpose, + Self::Beneficiary, + Self::PredicativePossessor, + Self::ExternalPossessor, + ]; + + /// The 3-bit code written to bits 43..45. + #[inline(always)] + #[must_use] + pub const fn code(self) -> u8 { + self as u8 + } + + /// The orientation a code names. Only the low three bits are read, so every + /// value names exactly one orientation. + #[inline(always)] + #[must_use] + pub const fn from_code(code: u8) -> Self { + Self::ALL[(code & 0b111) as usize] + } +} diff --git a/crates/causal-edge/src/pearl.rs b/crates/causal-edge/src/pearl.rs index fd1bd247c..1c2a96095 100644 --- a/crates/causal-edge/src/pearl.rs +++ b/crates/causal-edge/src/pearl.rs @@ -98,7 +98,12 @@ impl CausalMask { /// Detect Simpson's Paradox potential: /// S_O and _PO disagree in direction → confounding present. - /// Requires checking both projections' direction triads. + /// + /// The two directions are computed by the caller from populations (the + /// planner's confounder check counts the outcome in the exposed and + /// unexposed groups); bit 2 set means the outcome is rarer in the first + /// group. They are never read from an edge: bits 43..45 hold the + /// orientation (D-CGW-1). pub fn simpsons_paradox_risk(so_direction: u8, po_direction: u8) -> bool { // If S_O shows negative association (O pathological) // but _PO shows positive effect (O healthy under P), diff --git a/crates/causal-edge/src/syllogism.rs b/crates/causal-edge/src/syllogism.rs index 6dcf39392..bca4fa308 100644 --- a/crates/causal-edge/src/syllogism.rs +++ b/crates/causal-edge/src/syllogism.rs @@ -221,7 +221,7 @@ impl CausalEdge64 { f, c, mask, - 0, // direction: neutral; recomputed from composed palette downstream + crate::orientation::Orientation::Core, // direction: neutral; recomputed from composed palette downstream figure.rule(), PlasticityState::ALL_HOT, 0, // temporal: structural under v2 (chain-position / AriGraph anchor) @@ -248,7 +248,7 @@ mod tests { f, c, CausalMask::SPO, - 0, + crate::orientation::Orientation::Core, InferenceType::Deduction, PlasticityState::ALL_HOT, 0, @@ -381,7 +381,7 @@ mod tests { 200, 200, CausalMask::SPO, - 0, + crate::orientation::Orientation::Core, InferenceType::Deduction, PlasticityState::ALL_HOT, 0, @@ -394,7 +394,7 @@ mod tests { 200, 200, CausalMask::PO, - 0, + crate::orientation::Orientation::Core, InferenceType::Deduction, PlasticityState::ALL_HOT, 0, diff --git a/crates/causal-edge/src/v2_layout_tests.rs b/crates/causal-edge/src/v2_layout_tests.rs index 4536609cf..8cd6a3898 100644 --- a/crates/causal-edge/src/v2_layout_tests.rs +++ b/crates/causal-edge/src/v2_layout_tests.rs @@ -93,7 +93,7 @@ mod v2_layout_tests { 209, 181, // NARS f=0.82, c=0.71 CausalMask::PO, // interventional level - 0b101, // direction triad + crate::orientation::Orientation::from_code(0b101), // orientation InferenceType::Deduction, PlasticityState::S_HOT, 0, // temporal = 0 (v1 compat; bits 52-63 must be 0 for v2 clean read) @@ -111,7 +111,7 @@ mod v2_layout_tests { assert_eq!(v2.frequency_u8(), 209, "frequency disturbed"); assert_eq!(v2.confidence_u8(), 181, "confidence disturbed"); assert_eq!(v2.causal_mask(), CausalMask::PO, "causal_mask disturbed"); - assert_eq!(v2.direction(), 0b101, "direction disturbed"); + assert_eq!(v2.orientation().code(), 0b101, "orientation disturbed"); // V2 fields must be what we set assert_eq!(v2.w_slot(), 10, "w_slot not set"); @@ -291,7 +291,7 @@ mod v2_layout_tests { 200, 200, CausalMask::None, - 0, + crate::orientation::Orientation::Core, PlasticityState::ALL_FROZEN, ); assert_eq!(e.w_slot(), 0, "pack_v2: w_slot defaults to 0"); @@ -326,7 +326,7 @@ mod v2_layout_tests { 200, 200, CausalMask::SPO, - 0, + crate::orientation::Orientation::Core, PlasticityState::ALL_FROZEN, ); weight = weight.with_inference_mantissa(-1); @@ -366,7 +366,7 @@ mod v2_layout_tests { 200, 200, CausalMask::SPO, - 0, + crate::orientation::Orientation::Core, PlasticityState::ALL_FROZEN, ); edge = edge @@ -416,7 +416,7 @@ mod v2_layout_tests { 200, 200, CausalMask::SPO, - 0, + crate::orientation::Orientation::Core, InferenceType::Abduction, PlasticityState::ALL_FROZEN, 0, @@ -441,7 +441,7 @@ mod v2_layout_tests { 200, 200, CausalMask::SPO, - 0, + crate::orientation::Orientation::Core, InferenceType::Counterfactual, PlasticityState::ALL_FROZEN, 0, @@ -466,7 +466,7 @@ mod v2_layout_tests { 200, 200, CausalMask::SPO, - 0, + crate::orientation::Orientation::Core, InferenceType::Intervention, PlasticityState::ALL_FROZEN, 0, @@ -608,7 +608,7 @@ mod v2_layout_tests { 0xDD, 0xEE, CausalMask::SPO, - 0b111, + crate::orientation::Orientation::from_code(0b111), PlasticityState::ALL_HOT, ) .with_w_slot(63) @@ -649,9 +649,9 @@ mod v2_layout_tests { "causal_mask disturbed by with_topology" ); assert_eq!( - after.direction(), + after.orientation().code(), 0b111, - "direction disturbed by with_topology" + "orientation disturbed by with_topology" ); assert_eq!( after.inference_mantissa(), @@ -678,7 +678,7 @@ mod v2_layout_tests { 0xDD, 0xEE, CausalMask::SPO, - 0b111, + crate::orientation::Orientation::from_code(0b111), PlasticityState::ALL_HOT, ) .with_w_slot(63) @@ -717,9 +717,9 @@ mod v2_layout_tests { "causal_mask disturbed by with_reasoning_band" ); assert_eq!( - after.direction(), + after.orientation().code(), 0b111, - "direction disturbed by with_reasoning_band" + "orientation disturbed by with_reasoning_band" ); assert_eq!( after.inference_mantissa(), @@ -804,7 +804,7 @@ mod v2_layout_tests { 44, // frequency 55, // confidence CausalMask::SO, - 0b110, // direction + crate::orientation::Orientation::from_code(0b110), // direction PlasticityState::P_HOT, ) .with_w_slot(17) @@ -833,9 +833,9 @@ mod v2_layout_tests { "causal_mask disturbed by new setters" ); assert_eq!( - edge.direction(), + edge.orientation().code(), 0b110, - "direction disturbed by new setters" + "orientation disturbed by new setters" ); assert_eq!( edge.inference_mantissa(), @@ -868,7 +868,7 @@ mod v2_layout_tests { 200, 200, CausalMask::SPO, - 0, + crate::orientation::Orientation::Core, PlasticityState::ALL_FROZEN, ) .with_inference_mantissa(InferenceType::Counterfactual.to_mantissa()); @@ -939,7 +939,7 @@ mod v2_layout_tests { 100, conf, CausalMask::None, - 0, + crate::orientation::Orientation::Core, PlasticityState::ALL_FROZEN, ) .with_topology(CausalTopology::Direct); diff --git a/crates/causal-edge/tests/ce64_op_contract.rs b/crates/causal-edge/tests/ce64_op_contract.rs index 12a936dfb..9e4d9c59e 100644 --- a/crates/causal-edge/tests/ce64_op_contract.rs +++ b/crates/causal-edge/tests/ce64_op_contract.rs @@ -38,7 +38,7 @@ fn edge(f: u8, c: u8, rule: InferenceType) -> CausalEdge64 { f, c, CausalMask::SPO, - 0, + causal_edge::Orientation::Core, rule, PlasticityState::ALL_HOT, 0, @@ -161,7 +161,7 @@ fn syllogize_conclusion_carries_neither_field() { 200, 200, CausalMask::SPO, - 0, + causal_edge::Orientation::Core, InferenceType::Deduction, PlasticityState::ALL_HOT, 0, diff --git a/crates/causal-edge/tests/t4_learn_plasticity_patterns.rs b/crates/causal-edge/tests/t4_learn_plasticity_patterns.rs index e0ed90c6b..5fe6b4b01 100644 --- a/crates/causal-edge/tests/t4_learn_plasticity_patterns.rs +++ b/crates/causal-edge/tests/t4_learn_plasticity_patterns.rs @@ -28,7 +28,7 @@ fn edge(s: u8, p: u8, o: u8, c: u8, plast: PlasticityState) -> CausalEdge64 { 200, c, CausalMask::SO, - 0b101, + causal_edge::Orientation::from_code(0b101), InferenceType::Abduction, plast, 0, From a6a04abba2db6881682cff62c2d7ef085faa94fe Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 21:10:43 +0000 Subject: [PATCH 03/10] contract: Moore tenant tests for orientation (red): direction is slot+polarity, an oriented edge is refused Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- .../lance-graph-contract/src/moore_tenant.rs | 51 +++++++++++-------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/crates/lance-graph-contract/src/moore_tenant.rs b/crates/lance-graph-contract/src/moore_tenant.rs index 6d15eca1c..c0ef29719 100644 --- a/crates/lance-graph-contract/src/moore_tenant.rs +++ b/crates/lance-graph-contract/src/moore_tenant.rs @@ -646,39 +646,48 @@ mod tests { } } - /// H. A Moore direction is refused by a sign-triple consumer; a sign - /// triple is passed through. + /// H. A Moore lane's direction is its slot and polarity, nothing else. #[test] - fn h_direction_refusal() { + fn h_direction_is_slot_and_polarity() { for slot in MooreSlot::ALL { for pol in [false, true] { let d = MooreNars16::new(0, 0, 0, pol, 0).direction(slot); - assert_eq!( - d, - DirectionReading::Moore { - slot, - polarity: pol - } - ); - assert_eq!( - d.require_sign_triple(), - Err(DirectionRefusal { - slot, - polarity: pol - }) - ); + assert_eq!(d, MooreDirection { slot, polarity: pol }); } } - for bits in 0..8u8 { + } + + /// H2. CE64 bits 43..45 are the orientation (D-CGW-1). A Moore lane has + /// none, so lifting an oriented edge is refused instead of dropping it, + /// and a refusal writes nothing. A Core (0) edge lifts. + #[test] + fn h2_an_oriented_edge_is_refused() { + let pol = [false; MOORE_LANES]; + let core = [edge(5, 0, 7); MOORE_LANES]; + let mut value = [0u8; VALUE_SLAB_LEN]; + assert_eq!(MooreTenantMut::new(&mut value).lift_ce64(&core, pol), Ok(5)); + for code in 1..8u64 { + let mut edges = core; + edges[3] |= code << 43; + let mut value = [0u8; VALUE_SLAB_LEN]; assert_eq!( - DirectionReading::SignTriple(bits).require_sign_triple(), - Ok(bits) + MooreTenantMut::new(&mut value).lift_ce64(&edges, pol), + Err(MooreRefusal::Oriented { + slot: MooreSlot::ALL[3], + code: code as u8 + }) ); + assert_eq!(value, [0u8; VALUE_SLAB_LEN], "a refusal writes nothing"); } } + /// A CE64 word with witness `w` and Epi5 `epi`, orientation `Core` + /// (a Moore tenant holds no orientation), other bits from `salt`. fn edge(w: u8, epi: u8, salt: u64) -> u64 { - let base = salt.wrapping_mul(0x9E37_79B9_7F4A_7C15) & !(0x3Fu64 << 53) & !(0x1Fu64 << 59); + let base = salt.wrapping_mul(0x9E37_79B9_7F4A_7C15) + & !(0x3Fu64 << 53) + & !(0x1Fu64 << 59) + & !(0b111u64 << 43); base | (u64::from(w & 0x3F) << 53) | (u64::from(epi & 0x1F) << 59) } From 0e2a6e51c6ffb077c7cad8122f747c86180ed432 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 21:11:28 +0000 Subject: [PATCH 04/10] contract: a Moore lane's direction is MooreDirection; lift_ce64 refuses an oriented edge (D-CGW-1) DirectionReading/SignTriple and require_sign_triple were the per-tenant reading binding D-CGW-1 replaced: bits 43..45 have one meaning, the orientation. A Moore lane holds none, so lifting an edge whose orientation is not Core is refused instead of silently dropped. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- .../lance-graph-contract/src/moore_tenant.rs | 74 ++++++++----------- 1 file changed, 30 insertions(+), 44 deletions(-) diff --git a/crates/lance-graph-contract/src/moore_tenant.rs b/crates/lance-graph-contract/src/moore_tenant.rs index c0ef29719..51e0072a5 100644 --- a/crates/lance-graph-contract/src/moore_tenant.rs +++ b/crates/lance-graph-contract/src/moore_tenant.rs @@ -19,8 +19,10 @@ //! under the shipped ISA operations, and it carries two refusals that a //! consumer must honour: //! -//! - **Direction.** A Moore lane's direction is `(slot, polarity)`. It has no -//! S/P/O sign triple, so [`DirectionReading::require_sign_triple`] refuses it. +//! - **Orientation.** A Moore lane's direction is `(slot, polarity)` +//! ([`MooreDirection`]); it holds no CE64 orientation (bits 43..45), so +//! [`MooreTenantMut::lift_ce64`] refuses an edge whose orientation is not +//! `Core` (0) instead of dropping it. //! - **Witness.** One witness covers all eight lanes. It is held by the owner, //! not stored in these bytes, and [`MooreTenantMut::lift_ce64`] refuses //! input whose lanes carry different witnesses. @@ -114,8 +116,9 @@ impl MooreSlot { /// bits 11..15 Epi5 (CE64 59..63; codes 24..31 reserved) /// ``` /// -/// CE64 bits 43..45 (the S/P/O sign triple) and 53..58 (the witness) are not -/// here: direction is `(slot, polarity)` and the witness is tenant-scoped. +/// CE64 bits 43..45 (the orientation, always `Core` for a Moore lane) and +/// 53..58 (the witness) are not here: direction is `(slot, polarity)` and the +/// witness is tenant-scoped. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] #[repr(transparent)] pub struct MooreNars16(pub u16); @@ -184,17 +187,18 @@ impl MooreNars16 { } } - /// How this lane's direction is read: `(slot, polarity)`. + /// This lane's direction: its slot and polarity. #[must_use] - pub const fn direction(self, slot: MooreSlot) -> DirectionReading { - DirectionReading::Moore { + pub const fn direction(self, slot: MooreSlot) -> MooreDirection { + MooreDirection { slot, polarity: self.polarity(), } } - /// Read the lane from a CE64 register. Direction (43..45) and witness + /// Read the lane from a CE64 register. Orientation (43..45) and witness /// (53..58) are not read; `polarity` supplies the Moore-local bit. + /// [`MooreTenantMut::lift_ce64`] checks both before calling this. #[must_use] pub const fn from_ce64(edge: u64, polarity: bool) -> Self { Self::new( @@ -206,9 +210,8 @@ impl MooreNars16 { ) } - /// CE64 bits 40..63 for this lane under `witness`. The direction bits - /// (43..45) are zero: the Moore reading carries no sign triple. Bits - /// 0..39 (S/P/O, F, C) are the caller's. + /// CE64 bits 40..63 for this lane under `witness`. The orientation bits + /// (43..45) are zero (`Core`). Bits 0..39 (S/P/O, F, C) are the caller's. #[must_use] pub const fn ce64_upper(self, witness: u8) -> u64 { ((self.pearl() as u64) << 40) @@ -219,41 +222,12 @@ impl MooreNars16 { } } -/// How a CE64 direction is to be read. +/// A Moore lane's direction: the neighbour it points at and which way. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum DirectionReading { - /// Bits 43..45 are the canonical S/P/O sign triple. - SignTriple(u8), - /// The direction is the lane's slot and polarity; there is no sign triple. - Moore { - /// The lane's neighbour. - slot: MooreSlot, - /// `false` = outbound, `true` = inbound. - polarity: bool, - }, -} - -impl DirectionReading { - /// The S/P/O sign triple, for a consumer that reads one. - /// - /// # Errors - /// - /// [`DirectionRefusal`] for a Moore-local reading, which has no sign - /// triple. A sign-triple consumer must not reinterpret it. - pub const fn require_sign_triple(self) -> Result { - match self { - DirectionReading::SignTriple(bits) => Ok(bits & 0x7), - DirectionReading::Moore { slot, polarity } => Err(DirectionRefusal { slot, polarity }), - } - } -} - -/// A sign-triple consumer was handed a Moore-local direction. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct DirectionRefusal { - /// The lane the refused direction came from. +pub struct MooreDirection { + /// The lane's neighbour. pub slot: MooreSlot, - /// Its polarity. + /// `false` = outbound, `true` = inbound. pub polarity: bool, } @@ -276,6 +250,14 @@ pub enum MooreRefusal { /// That lane's witness. found: u8, }, + /// A lane's CE64 orientation (bits 43..45) is not `Core`; a Moore tenant + /// holds no orientation. + Oriented { + /// The offending lane. + slot: MooreSlot, + /// Its orientation code. + code: u8, + }, } /// Read access to the three tenants in a value slab. @@ -384,6 +366,10 @@ impl<'a> MooreTenantMut<'a> { found: w, }); } + let code = ((edge >> 43) & 0x7) as u8; + if code != 0 { + return Err(MooreRefusal::Oriented { slot, code }); + } let lane = MooreNars16::from_ce64(edge, polarity[slot.index()]); lane.epistemic(slot)?; lanes[slot.index()] = lane; From e7df3357b6f67ae6ab10125b01ea4bfd04cd2ca8 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 21:20:05 +0000 Subject: [PATCH 05/10] D-CGW-1: migrate every CE64 writer and reader to Orientation Writers pass an Orientation to pack/pack_v2 (zero literals become Core; fixture bit patterns keep their bits through Orientation::from_code). deepnsm-v2 wire writes the contract's Orientation instead of its own u8 table. Probes that read 43..45 as a per-class angle or a pathology triad are marked superseded; the moore_nars16 Simpson tests are removed with the detector they tested; the gomoku probe no longer writes its Moore direction into 43..45. docs/architecture/ce64-semantic-upper-half.md: 43..45 settled as orientation. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- .../examples/affordance_measurement_probe.rs | 6 +- .../examples/alpha_world_provenance_probe.rs | 2 +- .../examples/ce64_cycle_survival_probe.rs | 4 +- .../examples/ce64_nextstate_probe.rs | 2 +- .../epistemic_reading_conflict_probe.rs | 2 +- .../examples/moore_nars_gomoku_probe.rs | 3 +- .../examples/pearl_ladder_probe.rs | 4 +- .../revision_epistemic_writer_probe.rs | 2 +- .../examples/spog_witness_probe.rs | 2 +- .../examples/witness_angle_probe.rs | 20 ++- crates/cognitive-shader-driver/src/driver.rs | 2 +- .../src/edge_v3_compare.rs | 6 +- crates/deepnsm-v2/src/wire.rs | 95 +++++++------- .../tests/p2_p3_edge_pearl.rs | 6 +- .../tests/p4_discovery_edge.rs | 2 +- .../lance-graph-osint/tests/p5_syllogize.rs | 2 +- .../tests/p6_real_coca_2cube.rs | 6 +- .../examples/d_rpf_table_1_bench.rs | 2 +- .../examples/dcr_w0_replay_budget.rs | 2 +- .../examples/house_differential.rs | 2 +- .../examples/self_orchestration_probe.rs | 2 +- .../examples/staunen_scheduler_probe.rs | 4 +- .../src/cache/nars_engine.rs | 2 +- .../src/chain_counterfactual.rs | 2 +- .../lance-graph-planner/src/chain_replay.rs | 2 +- crates/lance-graph-planner/src/pearl.rs | 2 +- .../tests/chain_confidence.rs | 2 +- .../tests/d_rpf_table_1.rs | 2 +- .../tests/maturation_ladder.rs | 2 +- .../tests/moore_nars16_probe.rs | 123 ++---------------- .../tests/residue_fixed_point.rs | 2 +- .../examples/multihop_witness_confidence.rs | 2 +- .../tests/intervene_counterfactual.rs | 4 +- crates/p64-bridge/src/lib.rs | 4 +- crates/thinking-engine/src/layered.rs | 2 +- docs/architecture/ce64-semantic-upper-half.md | 22 ++-- 36 files changed, 129 insertions(+), 222 deletions(-) diff --git a/crates/cognitive-shader-driver/examples/affordance_measurement_probe.rs b/crates/cognitive-shader-driver/examples/affordance_measurement_probe.rs index d9c0959e8..1efdd2d43 100644 --- a/crates/cognitive-shader-driver/examples/affordance_measurement_probe.rs +++ b/crates/cognitive-shader-driver/examples/affordance_measurement_probe.rs @@ -222,7 +222,7 @@ fn busy_edge(pearl: CausalMask) -> CausalEdge64 { 200, 150, pearl, - 0b101, + causal_edge::Orientation::from_code(0b101), PlasticityState::from_bits(0b011), ) .with_inference_mantissa(-6) @@ -372,7 +372,7 @@ mod tests { v, 255 - v, CausalMask::SPO, - 0b101, + causal_edge::Orientation::from_code(0b101), PlasticityState::from_bits(0b011), ); same(with_code( @@ -382,7 +382,7 @@ mod tests { } for v in 0..8u8 { let mut d = base; - d.set_direction(v); + d.set_orientation(causal_edge::Orientation::from_code(v)); same(d); let mut pl = base; pl.set_plasticity(PlasticityState::from_bits(v)); diff --git a/crates/cognitive-shader-driver/examples/alpha_world_provenance_probe.rs b/crates/cognitive-shader-driver/examples/alpha_world_provenance_probe.rs index dde6d24dc..e355eada2 100644 --- a/crates/cognitive-shader-driver/examples/alpha_world_provenance_probe.rs +++ b/crates/cognitive-shader-driver/examples/alpha_world_provenance_probe.rs @@ -104,7 +104,7 @@ fn edge(s: u8, p: u8, o: u8) -> CausalEdge64 { 200, 180, CausalMask::SO, - 0b010, + causal_edge::Orientation::from_code(0b010), PlasticityState::ALL_HOT, ) .with_inference_mantissa(1) diff --git a/crates/cognitive-shader-driver/examples/ce64_cycle_survival_probe.rs b/crates/cognitive-shader-driver/examples/ce64_cycle_survival_probe.rs index eff3d3d2c..2d688b6ec 100644 --- a/crates/cognitive-shader-driver/examples/ce64_cycle_survival_probe.rs +++ b/crates/cognitive-shader-driver/examples/ce64_cycle_survival_probe.rs @@ -116,13 +116,13 @@ fn with_code(edge: CausalEdge64, code: u8) -> CausalEdge64 { /// The tracked relation as an observation carrying `(f, c)`. S/P/O match the /// register, so `learn` never re-targets it. fn observation(f: u8, c: u8) -> CausalEdge64 { - CausalEdge64::pack_v2(1, 2, 3, f, c, CausalMask::SO, 0, PlasticityState::ALL_HOT) + CausalEdge64::pack_v2(1, 2, 3, f, c, CausalMask::SO, causal_edge::Orientation::Core, PlasticityState::ALL_HOT) } /// The register before any evidence: code `Direct × Open`, no confidence. fn initial() -> CausalEdge64 { with_code( - CausalEdge64::pack_v2(1, 2, 3, 128, 0, CausalMask::SO, 0, PlasticityState::ALL_HOT), + CausalEdge64::pack_v2(1, 2, 3, 128, 0, CausalMask::SO, causal_edge::Orientation::Core, PlasticityState::ALL_HOT), CODE_OPEN, ) } diff --git a/crates/cognitive-shader-driver/examples/ce64_nextstate_probe.rs b/crates/cognitive-shader-driver/examples/ce64_nextstate_probe.rs index 69cf806e7..9767210aa 100644 --- a/crates/cognitive-shader-driver/examples/ce64_nextstate_probe.rs +++ b/crates/cognitive-shader-driver/examples/ce64_nextstate_probe.rs @@ -91,7 +91,7 @@ fn busy() -> CausalEdge64 { 201, 149, CausalMask::SO, - 0b101, + causal_edge::Orientation::from_code(0b101), PlasticityState::from_bits(0b011), ) .with_inference_mantissa(-6) diff --git a/crates/cognitive-shader-driver/examples/epistemic_reading_conflict_probe.rs b/crates/cognitive-shader-driver/examples/epistemic_reading_conflict_probe.rs index 488d93df0..a490e46d2 100644 --- a/crates/cognitive-shader-driver/examples/epistemic_reading_conflict_probe.rs +++ b/crates/cognitive-shader-driver/examples/epistemic_reading_conflict_probe.rs @@ -70,7 +70,7 @@ fn base() -> CausalEdge64 { 200, 150, CausalMask::SPO, - 0, + causal_edge::Orientation::Core, PlasticityState::from_bits(0), ) } diff --git a/crates/cognitive-shader-driver/examples/moore_nars_gomoku_probe.rs b/crates/cognitive-shader-driver/examples/moore_nars_gomoku_probe.rs index 07842682f..f07925b7f 100644 --- a/crates/cognitive-shader-driver/examples/moore_nars_gomoku_probe.rs +++ b/crates/cognitive-shader-driver/examples/moore_nars_gomoku_probe.rs @@ -950,7 +950,8 @@ fn question(s: &Snap) -> CausalMask { fn record(p: &Pending, w: u8, act: i32, surprise: u8, epi: EpistemicState5) -> CausalEdge64 { let mut e = CausalEdge64(0); e.set_causal_mask(p.question); - e.set_direction(p.dir); + // The Moore direction (`p.dir`) is not a CE64 field: bits 43..45 are the + // orientation (D-CGW-1), which a Moore move leaves at `Core`. e.set_inference_mantissa(act.clamp(-7, 7) as i8); e.0 = (e.0 & !PLAST_MASK) | (u64::from(surprise & 7) << PLAST_SHIFT); e.set_w_slot(w); diff --git a/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs b/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs index 214bee7e0..622042c5b 100644 --- a/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs +++ b/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs @@ -623,7 +623,7 @@ mod tests { for direction in 0u8..8 { let mut q = baseline_q; - q.set_direction(direction); + q.set_orientation(causal_edge::Orientation::from_code(direction)); let measured = reason(q, &ev, Edit::None); assert_eq!( computed(&measured), @@ -632,7 +632,7 @@ mod tests { ); assert_eq!(measured.edge(), q); let out = revise(&measured, rd(&decl)).unwrap(); - assert_eq!(out.direction(), direction); + assert_eq!(out.orientation().code(), direction); assert_eq!(certification(out), Certification3::Causes); } } diff --git a/crates/cognitive-shader-driver/examples/revision_epistemic_writer_probe.rs b/crates/cognitive-shader-driver/examples/revision_epistemic_writer_probe.rs index 04944d01c..7c71a847d 100644 --- a/crates/cognitive-shader-driver/examples/revision_epistemic_writer_probe.rs +++ b/crates/cognitive-shader-driver/examples/revision_epistemic_writer_probe.rs @@ -305,7 +305,7 @@ fn initial() -> CausalEdge64 { 177, 91, CausalMask::SO, - 0, + causal_edge::Orientation::Core, PlasticityState::ALL_HOT, ), CODE_OPEN, diff --git a/crates/cognitive-shader-driver/examples/spog_witness_probe.rs b/crates/cognitive-shader-driver/examples/spog_witness_probe.rs index 79b378f26..279d96c46 100644 --- a/crates/cognitive-shader-driver/examples/spog_witness_probe.rs +++ b/crates/cognitive-shader-driver/examples/spog_witness_probe.rs @@ -214,7 +214,7 @@ fn edge(s: u8, p: u8, o: u8, w: u8) -> CausalEdge64 { 200, 180, CausalMask::SO, - 0b010, + causal_edge::Orientation::from_code(0b010), PlasticityState::ALL_HOT, ) .with_inference_mantissa(1) diff --git a/crates/cognitive-shader-driver/examples/witness_angle_probe.rs b/crates/cognitive-shader-driver/examples/witness_angle_probe.rs index 35193fb5b..72278aa14 100644 --- a/crates/cognitive-shader-driver/examples/witness_angle_probe.rs +++ b/crates/cognitive-shader-driver/examples/witness_angle_probe.rs @@ -1,5 +1,11 @@ //! D-WA-0: Witness × Angle as a declared, sparse local source coordinate. //! +//! ⊘ SUPERSEDED BY D-CGW-1 (2026-10-16): every CE64 field has one meaning, +//! fixed by the `causal-edge` contract, and bits 43..45 are the orientation +//! (`causal_edge::Orientation`). A per-class reading of those bits, which this +//! probe tests, is no longer allowed. The probe is kept as a record and reads +//! the orientation's code as its "angle"; it is not a model for new code. +//! //! Claim under test: inside a world the Alpha route has already selected, //! two resident CE64 fields can address a local source reading under a law //! the class declares: @@ -19,8 +25,8 @@ //! //! # Readings of the same bits that refuse here //! -//! - **Pathology triad**: the shipped meaning of bits 43..45 -//! (`s/p/o_pathological`). +//! - **Pathology triad**: the former meaning of bits 43..45 +//! (`s/p/o_pathological`, removed by D-CGW-1). //! - **Cohort witness**: the shipped meaning of bits 53..58 in //! `witness_table::WitnessTable` (slot → `(mailbox_ref, spo_fact_ref)`). //! @@ -189,7 +195,7 @@ fn local_source( if !gens.contains(&generation) { return Err(Refusal::UndeclaredGeneration(generation)); } - let (witness, angle) = (edge.w_slot(), edge.direction()); + let (witness, angle) = (edge.w_slot(), edge.orientation().code()); if witness == 0 { return Err(Refusal::NoAnchor); } @@ -215,7 +221,7 @@ fn edge(witness: u8, angle: u8) -> CausalEdge64 { 200, 180, CausalMask::SO, - angle, + causal_edge::Orientation::from_code(angle), PlasticityState::ALL_HOT, ) .with_inference_mantissa(1) @@ -228,7 +234,7 @@ fn main() { println!( " bits w={} a={}", e.w_slot(), - e.direction() + e.orientation().code() ); for (name, c, g) in [ ("observations gen 1", CLASS_OBS, 1), @@ -355,12 +361,12 @@ mod tests { 10, 20, CausalMask::SPO, - 5, + causal_edge::Orientation::from_code(5), PlasticityState::ALL_HOT, ) .with_w_slot(23), edge(23, 5).with_inference_mantissa(-6), - CausalEdge64::pack_v2(0, 0, 0, 0, 0, CausalMask::None, 5, PlasticityState::ALL_HOT) + CausalEdge64::pack_v2(0, 0, 0, 0, 0, CausalMask::None, causal_edge::Orientation::from_code(5), PlasticityState::ALL_HOT) .with_w_slot(23), ]; for e in others { diff --git a/crates/cognitive-shader-driver/src/driver.rs b/crates/cognitive-shader-driver/src/driver.rs index 76a4c0bd5..1eaa1b8b8 100644 --- a/crates/cognitive-shader-driver/src/driver.rs +++ b/crates/cognitive-shader-driver/src/driver.rs @@ -527,7 +527,7 @@ impl ShaderDriver { f, c, CausalMask::from_bits(h.predicates & 0x07), - 0, + causal_edge::Orientation::Core, style_ord_to_inference(style_ord), PlasticityState::from_bits(0), (h.cycle_index & 0xFFF) as u16, diff --git a/crates/cognitive-shader-driver/src/edge_v3_compare.rs b/crates/cognitive-shader-driver/src/edge_v3_compare.rs index 3ee4136c1..923b9bcb7 100644 --- a/crates/cognitive-shader-driver/src/edge_v3_compare.rs +++ b/crates/cognitive-shader-driver/src/edge_v3_compare.rs @@ -97,7 +97,7 @@ mod tests { f, c, CausalMask::from_bits(predicates & 0x07), - 0, + causal_edge::Orientation::Core, InferenceType::Deduction, PlasticityState::from_bits(0), cycle & 0xFFF, @@ -153,7 +153,7 @@ mod tests { 200, 190, CausalMask::from_bits(0b111), - 0, + causal_edge::Orientation::Core, InferenceType::Deduction, PlasticityState::from_bits(0), 5, @@ -165,7 +165,7 @@ mod tests { 200, 190, CausalMask::from_bits(0b111), - 0, + causal_edge::Orientation::Core, InferenceType::Deduction, PlasticityState::from_bits(0), 900, diff --git a/crates/deepnsm-v2/src/wire.rs b/crates/deepnsm-v2/src/wire.rs index c79162a15..236894a5c 100644 --- a/crates/deepnsm-v2/src/wire.rs +++ b/crates/deepnsm-v2/src/wire.rs @@ -15,7 +15,7 @@ //! | 24..31 | frequency | `lance-graph-arm-discovery` [`arm_to_truth_u8`], rule `(S, P) → O` over independent verses: `f = cooccur / antecedent` | //! | 32..39 | confidence | the same: `c = cooccur / (cooccur + k)`, `k = 1` (the NAL horizon) | //! | 40..42 | Pearl ladder | the TEKAMOLO read: a Kausal lane stated on this event → `PO` (the claim sits at the intervention rung); otherwise `SO` (association) | -//! | 43..45 | orientation / syntax | the Haspelmath function the relation is read in ([`orientation_code`]): the dative-map functions the clause's attested forms allow, narrowed by its TEKAMOLO lanes; `0` = plain core argument or undecided. The clause path ([`Origin`]) goes to the topology in 59..63 | +//! | 43..45 | orientation / syntax | the Haspelmath function the relation is read in ([`orientation_of`]): the dative-map functions the clause's attested forms allow, narrowed by its TEKAMOLO lanes; `0` = plain core argument or undecided. The clause path ([`Origin`]) goes to the topology in 59..63 | //! | 46..49 | activation i4 | what this sentence's update caused: the change of the statement's arm frequency over the prior state, in eighths, clamped to `-8..=7`; `0` when the update changes nothing | //! | 50..52 | novelty → wisdom | the statement's rung after this update, `1` Staunen ..= `7` wisdom | //! | 53..58 | belief-state update | W slot into the cohort's [`WitnessTable`]: the entry that witnessed this statement's PRIOR state; `0` = first sighting or the prior is in another cohort | @@ -109,7 +109,7 @@ use std::collections::{HashMap, HashSet}; -use causal_edge::{CausalEdge64, CausalMask}; +use causal_edge::{CausalEdge64, CausalMask, Orientation}; use lance_graph_arm_discovery::{arm_to_truth_u8, CandidateRule, Item}; use lance_graph_contract::causal_witness::{CausalWitnessFacet, Locus}; use lance_graph_contract::epistemic_state5::{Certification3, Epi5Gen, EpistemicState5, Topology2}; @@ -137,37 +137,37 @@ use crate::tekamolo::{read_clause, GrammarHeuristics, LaneAddress, ReadParams}; /// The TEKAMOLO lane index of Kausal, in Te-Ka-Mo-Lo order. pub const KAUSAL_LANE: usize = 1; -/// The orientation code of a Haspelmath function (bits 43..45): the +/// The orientation a Haspelmath function is written as (bits 43..45): the /// function the relation is read in, on the dative semantic map -/// (Haspelmath 2003, Fig. 8.1). `0` is the plain core argument (no dative-map -/// function); `1..=7` are the seven functions below. `Judicantis` has no code. +/// (Haspelmath 2003, Fig. 8.1). The code table is the contract's +/// [`Orientation`]; this only names which [`DativeFunction`] each one is. +/// `Judicantis` has no orientation. #[must_use] -pub const fn orientation_code(f: DativeFunction) -> Option { +pub const fn orientation_of(f: DativeFunction) -> Option { match f { - DativeFunction::Direction => Some(1), - DativeFunction::Recipient => Some(2), - DativeFunction::Experiencer => Some(3), - DativeFunction::Purpose => Some(4), - DativeFunction::Beneficiary => Some(5), - DativeFunction::PredicativePossessor => Some(6), - DativeFunction::ExternalPossessor => Some(7), + DativeFunction::Direction => Some(Orientation::Direction), + DativeFunction::Recipient => Some(Orientation::Recipient), + DativeFunction::Experiencer => Some(Orientation::Experiencer), + DativeFunction::Purpose => Some(Orientation::Purpose), + DativeFunction::Beneficiary => Some(Orientation::Beneficiary), + DativeFunction::PredicativePossessor => Some(Orientation::PredicativePossessor), + DativeFunction::ExternalPossessor => Some(Orientation::ExternalPossessor), DativeFunction::Judicantis => None, } } -/// The function an orientation code names; `None` for `0` (core argument) -/// and anything above 7. +/// The function an orientation names; `None` for [`Orientation::Core`]. #[must_use] -pub const fn orientation_function(code: u8) -> Option { - match code { - 1 => Some(DativeFunction::Direction), - 2 => Some(DativeFunction::Recipient), - 3 => Some(DativeFunction::Experiencer), - 4 => Some(DativeFunction::Purpose), - 5 => Some(DativeFunction::Beneficiary), - 6 => Some(DativeFunction::PredicativePossessor), - 7 => Some(DativeFunction::ExternalPossessor), - _ => None, +pub const fn orientation_function(o: Orientation) -> Option { + match o { + Orientation::Core => None, + Orientation::Direction => Some(DativeFunction::Direction), + Orientation::Recipient => Some(DativeFunction::Recipient), + Orientation::Experiencer => Some(DativeFunction::Experiencer), + Orientation::Purpose => Some(DativeFunction::Purpose), + Orientation::Beneficiary => Some(DativeFunction::Beneficiary), + Orientation::PredicativePossessor => Some(DativeFunction::PredicativePossessor), + Orientation::ExternalPossessor => Some(DativeFunction::ExternalPossessor), } } @@ -815,25 +815,25 @@ pub fn wire( if f & lanes != 0 { f &= lanes; } - let code = match f.count_ones() { - 0 => 0, + let orientation = match f.count_ones() { + 0 => Orientation::Core, 1 => { let func = DativeFunction::ALL[f.trailing_zeros() as usize]; - orientation_code(func).unwrap_or_else(|| { + orientation_of(func).unwrap_or_else(|| { rep.orientation_unrepresented += 1; - 0 + Orientation::Core }) } _ => { rep.orientation_ambiguous += 1; undecided[k] = true; - 0 + Orientation::Core } }; - if code != 0 { + if orientation != Orientation::Core { rep.orientation_coded += 1; } - rows[first + k].edge.set_direction(code); + rows[first + k].edge.set_orientation(orientation); } } @@ -1130,26 +1130,27 @@ mod tests { EpistemicState5::decode(Epi5Gen::V1, e.epistemic_raw5()).unwrap() } - /// The seven listed functions round-trip through codes 1..=7; code 0 is - /// the plain core argument; Judicantis has no code. + /// The seven listed functions round-trip through the contract's codes + /// 1..=7; `Core` (0) is the plain core argument; Judicantis has none. #[test] fn orientation_codes_round_trip() { for f in DativeFunction::ALL { - match orientation_code(f) { - Some(c) => assert_eq!(orientation_function(c), Some(f)), + match orientation_of(f) { + Some(o) => assert_eq!(orientation_function(o), Some(f)), None => assert_eq!(f, DativeFunction::Judicantis), } } let codes: Vec = DativeFunction::ALL .iter() - .filter_map(|&f| orientation_code(f)) + .filter_map(|&f| orientation_of(f)) + .map(Orientation::code) .collect(); assert_eq!( codes, [1, 2, 3, 4, 5, 6, 7], "all seven non-zero states used" ); - assert_eq!(orientation_function(0), None); + assert_eq!(orientation_function(Orientation::Core), None); } #[test] @@ -1169,7 +1170,7 @@ mod tests { assert_eq!(last.novelty_wisdom(), 3); assert_eq!(epi(last).certification(), Certification3::Related); assert_eq!(epi(last).topology(), Topology2::Direct); - assert_eq!(last.direction(), 0, "no attested form: plain core argument"); + assert_eq!(last.orientation(), Orientation::Core, "no attested form: plain core argument"); assert_eq!(last.causal_mask(), CausalMask::SO); // The rows of one statement are its time series. let rungs: Vec = rows.iter().map(|r| r.edge.novelty_wisdom()).collect(); @@ -1398,7 +1399,7 @@ mod tests { let (rows, rep) = run(&[v]); assert_eq!(rows.len(), 2); assert_eq!(rows[0].origin, Some(Origin::SubjRelative)); - assert_eq!(rows[0].edge.direction(), 0); + assert_eq!(rows[0].edge.orientation(), Orientation::Core); assert_eq!(rows[0].loci.at(Locus::Antecedent), 1); assert_eq!(rep.antecedent_bound, 1); assert_eq!(epi(rows[0].edge).topology(), Topology2::IndirectKnown); @@ -1477,7 +1478,7 @@ mod tests { gave_to(vec![]), vec![form(TO, &[DativeFunction::Recipient])], ); - assert_eq!(w.rows[0].edge.direction(), 2, "Recipient"); + assert_eq!(w.rows[0].edge.orientation(), Orientation::Recipient, "Recipient"); assert_eq!(w.report.orientation_coded, 1); let w = run_forms( gave_to(vec![]), @@ -1486,7 +1487,7 @@ mod tests { &[DativeFunction::Direction, DativeFunction::Recipient], )], ); - assert_eq!(w.rows[0].edge.direction(), 0); + assert_eq!(w.rows[0].edge.orientation(), Orientation::Core); assert_eq!(w.report.orientation_ambiguous, 1); // A second clause without the form stays at 0. let mut second = vec![Reading::stop()]; @@ -1497,8 +1498,8 @@ mod tests { ); assert_eq!(w.rows.len(), 2); assert_eq!( - w.rows[1].edge.direction(), - 0, + w.rows[1].edge.orientation(), + Orientation::Core, "the form is in the other clause" ); } @@ -1539,9 +1540,9 @@ mod tests { ) .unwrap(); assert!(w.rows[0].tekamolo[3].is_some(), "the Lokal lane landed"); - assert_eq!(w.rows[0].edge.direction(), 1, "Direction"); + assert_eq!(w.rows[0].edge.orientation(), Orientation::Direction, "Direction"); let w = wire(&[(1, 1)], &ins, 1, &abi(), None, ReadParams::RIGHT_CORNER).unwrap(); - assert_eq!(w.rows[0].edge.direction(), 0, "no lane: undecided"); + assert_eq!(w.rows[0].edge.orientation(), Orientation::Core, "no lane: undecided"); } /// Quorum points at the nearest agreeing row, Contradiction at the @@ -1571,7 +1572,7 @@ mod tests { let r = rows .get(1) .expect("the certain triple survives the ambiguity"); - assert_eq!(r.edge.direction(), 0); + assert_eq!(r.edge.orientation(), Orientation::Core); assert_eq!(epi(r.edge).topology(), Topology2::Unknown); assert_eq!(r.edge.novelty_wisdom(), 1, "unresolved: no climb"); } diff --git a/crates/lance-graph-osint/tests/p2_p3_edge_pearl.rs b/crates/lance-graph-osint/tests/p2_p3_edge_pearl.rs index b1c81f1e8..30ec78124 100644 --- a/crates/lance-graph-osint/tests/p2_p3_edge_pearl.rs +++ b/crates/lance-graph-osint/tests/p2_p3_edge_pearl.rs @@ -77,7 +77,7 @@ fn p2_edge_round_trips_palette_indices_and_mask() { freq, conf, CausalMask::SPO, - 0, + causal_edge::Orientation::Core, PlasticityState::ALL_FROZEN, ); @@ -106,7 +106,7 @@ fn p2_causal_distance_of_two_edges_is_the_plane_sum() { 128, 200, CausalMask::SPO, - 0, + causal_edge::Orientation::Core, PlasticityState::ALL_FROZEN, ) }; @@ -134,7 +134,7 @@ fn p3_pearl_masks_drop_exactly_the_excluded_plane() { 128, 200, CausalMask::PO, // Level-2 Intervention on the osint_person pair - 0, + causal_edge::Orientation::Core, PlasticityState::ALL_FROZEN, )) }; diff --git a/crates/lance-graph-osint/tests/p4_discovery_edge.rs b/crates/lance-graph-osint/tests/p4_discovery_edge.rs index 3461f412b..660fe2686 100644 --- a/crates/lance-graph-osint/tests/p4_discovery_edge.rs +++ b/crates/lance-graph-osint/tests/p4_discovery_edge.rs @@ -127,7 +127,7 @@ fn p4_rule_truth_packs_into_causal_edge() { truth.frequency, truth.confidence, CausalMask::SPO, - 0, + causal_edge::Orientation::Core, PlasticityState::ALL_FROZEN, ); assert_eq!(edge.frequency_u8(), truth.frequency, "freq → edge wire"); diff --git a/crates/lance-graph-osint/tests/p5_syllogize.rs b/crates/lance-graph-osint/tests/p5_syllogize.rs index a195bd19c..c6819f328 100644 --- a/crates/lance-graph-osint/tests/p5_syllogize.rs +++ b/crates/lance-graph-osint/tests/p5_syllogize.rs @@ -25,7 +25,7 @@ const IS_A: u8 = 0x07; // predicate placeholder slot (shared) /// Build an `is_a`-style premise edge on the palette with the given truth bytes. fn premise(s: u8, o: u8, f: u8, c: u8) -> CausalEdge64 { - CausalEdge64::pack_v2(s, IS_A, o, f, c, CausalMask::SPO, 0, PlasticityState::ALL_FROZEN) + CausalEdge64::pack_v2(s, IS_A, o, f, c, CausalMask::SPO, causal_edge::Orientation::Core, PlasticityState::ALL_FROZEN) } #[test] diff --git a/crates/lance-graph-osint/tests/p6_real_coca_2cube.rs b/crates/lance-graph-osint/tests/p6_real_coca_2cube.rs index 96f0dd764..76cd03d80 100644 --- a/crates/lance-graph-osint/tests/p6_real_coca_2cube.rs +++ b/crates/lance-graph-osint/tests/p6_real_coca_2cube.rs @@ -114,7 +114,7 @@ fn p6_real_coca_spo_round_trips_the_edge_carrier() { 200, // freq — Grok-grade truth ≈0.78, the COCA-wire stand-in 163, // conf CausalMask::SPO, - 0, + causal_edge::Orientation::Core, PlasticityState::ALL_FROZEN, ); @@ -150,7 +150,7 @@ fn p6_real_coca_2cube_ladder_holds_on_a_real_parse() { 200, 163, CausalMask::SPO, - 0, + causal_edge::Orientation::Core, PlasticityState::ALL_FROZEN, )); let ctx = head_of(CausalEdge64::pack_v2( @@ -160,7 +160,7 @@ fn p6_real_coca_2cube_ladder_holds_on_a_real_parse() { 200, 163, CausalMask::SPO, - 0, + causal_edge::Orientation::Core, PlasticityState::ALL_FROZEN, )); diff --git a/crates/lance-graph-planner/examples/d_rpf_table_1_bench.rs b/crates/lance-graph-planner/examples/d_rpf_table_1_bench.rs index cb835309b..82c33f679 100644 --- a/crates/lance-graph-planner/examples/d_rpf_table_1_bench.rs +++ b/crates/lance-graph-planner/examples/d_rpf_table_1_bench.rs @@ -85,7 +85,7 @@ fn edge(f: u8, c: u8, op: InferenceType) -> CausalEdge64 { f, c, CausalMask::SPO, - 0, + causal_edge::Orientation::Core, op, PlasticityState::ALL_HOT, 0, diff --git a/crates/lance-graph-planner/examples/dcr_w0_replay_budget.rs b/crates/lance-graph-planner/examples/dcr_w0_replay_budget.rs index 67598995a..bc8519d55 100644 --- a/crates/lance-graph-planner/examples/dcr_w0_replay_budget.rs +++ b/crates/lance-graph-planner/examples/dcr_w0_replay_budget.rs @@ -150,7 +150,7 @@ fn edge(rng: &mut Lcg, infer: InferenceType) -> CausalEdge64 { (128 + rng.below(128)) as u8, (128 + rng.below(100)) as u8, CausalMask::PO, - 0b101, + causal_edge::Orientation::from_code(0b101), infer, PlasticityState::S_HOT, 0, diff --git a/crates/lance-graph-planner/examples/house_differential.rs b/crates/lance-graph-planner/examples/house_differential.rs index 096c4ac1c..0b31f167b 100644 --- a/crates/lance-graph-planner/examples/house_differential.rs +++ b/crates/lance-graph-planner/examples/house_differential.rs @@ -747,7 +747,7 @@ fn run_a1c( freq_u8, conf_u8, CausalMask::PO, - 0b101, + causal_edge::Orientation::from_code(0b101), InferenceType::Abduction, PlasticityState::S_HOT, 0, diff --git a/crates/lance-graph-planner/examples/self_orchestration_probe.rs b/crates/lance-graph-planner/examples/self_orchestration_probe.rs index 705338821..fa69ec844 100644 --- a/crates/lance-graph-planner/examples/self_orchestration_probe.rs +++ b/crates/lance-graph-planner/examples/self_orchestration_probe.rs @@ -109,7 +109,7 @@ fn edge(s: u8, o: u8, f: u8, c: u8, mask: CausalMask) -> CausalEdge64 { f, c, mask, - 0b101, + causal_edge::Orientation::from_code(0b101), InferenceType::Deduction, PlasticityState::S_HOT, 0, diff --git a/crates/lance-graph-planner/examples/staunen_scheduler_probe.rs b/crates/lance-graph-planner/examples/staunen_scheduler_probe.rs index 6e83ae7cc..1b02aaebc 100644 --- a/crates/lance-graph-planner/examples/staunen_scheduler_probe.rs +++ b/crates/lance-graph-planner/examples/staunen_scheduler_probe.rs @@ -109,7 +109,7 @@ fn edge(s: u8, o: u8, mask: CausalMask) -> CausalEdge64 { 200, 200, mask, - 0b101, + causal_edge::Orientation::from_code(0b101), InferenceType::Deduction, PlasticityState::S_HOT, 0, @@ -723,7 +723,7 @@ fn fold( surprisal: surprise, activation, question: b.r.causal_mask() as u8, - orientation: b.r.direction(), + orientation: b.r.orientation().code(), fc_before, fc_after: fc(b.r), w: b.r.w_slot(), diff --git a/crates/lance-graph-planner/src/cache/nars_engine.rs b/crates/lance-graph-planner/src/cache/nars_engine.rs index f9de444bd..44ffde54d 100644 --- a/crates/lance-graph-planner/src/cache/nars_engine.rs +++ b/crates/lance-graph-planner/src/cache/nars_engine.rs @@ -564,7 +564,7 @@ impl NarsEngine { head.freq, head.conf, CausalMask::from_bits(head.pearl), - 0, // direction + causal_edge::Orientation::Core, // direction infer_type, PlasticityState::from_bits(0b111), // all hot head.temporal as u16, diff --git a/crates/lance-graph-planner/src/chain_counterfactual.rs b/crates/lance-graph-planner/src/chain_counterfactual.rs index 443c6c986..75d0e7f09 100644 --- a/crates/lance-graph-planner/src/chain_counterfactual.rs +++ b/crates/lance-graph-planner/src/chain_counterfactual.rs @@ -305,7 +305,7 @@ mod tests { freq, conf, CausalMask::PO, - 0b101, + causal_edge::Orientation::from_code(0b101), InferenceType::Deduction, PlasticityState::S_HOT, 0, diff --git a/crates/lance-graph-planner/src/chain_replay.rs b/crates/lance-graph-planner/src/chain_replay.rs index 549d6104f..9fe73e9a2 100644 --- a/crates/lance-graph-planner/src/chain_replay.rs +++ b/crates/lance-graph-planner/src/chain_replay.rs @@ -393,7 +393,7 @@ pub(crate) mod tests { (100 + rng.below(150)) as u8, (100 + rng.below(120)) as u8, CausalMask::PO, - 0b101, + causal_edge::Orientation::from_code(0b101), InferenceType::Deduction, PlasticityState::S_HOT, 0, diff --git a/crates/lance-graph-planner/src/pearl.rs b/crates/lance-graph-planner/src/pearl.rs index 7786dff5b..6eaf6ade1 100644 --- a/crates/lance-graph-planner/src/pearl.rs +++ b/crates/lance-graph-planner/src/pearl.rs @@ -515,7 +515,7 @@ mod tests { freq, conf, mask, - 0b101, + causal_edge::Orientation::from_code(0b101), InferenceType::Deduction, PlasticityState::S_HOT, 0, diff --git a/crates/lance-graph-planner/tests/chain_confidence.rs b/crates/lance-graph-planner/tests/chain_confidence.rs index 3d530cb19..25f686d49 100644 --- a/crates/lance-graph-planner/tests/chain_confidence.rs +++ b/crates/lance-graph-planner/tests/chain_confidence.rs @@ -32,7 +32,7 @@ fn edge(f: u8, c: u8) -> CausalEdge64 { f, c, CausalMask::SPO, - 0, + causal_edge::Orientation::Core, InferenceType::Deduction, PlasticityState::ALL_HOT, 0, diff --git a/crates/lance-graph-planner/tests/d_rpf_table_1.rs b/crates/lance-graph-planner/tests/d_rpf_table_1.rs index 0ed03d192..ebe48a81f 100644 --- a/crates/lance-graph-planner/tests/d_rpf_table_1.rs +++ b/crates/lance-graph-planner/tests/d_rpf_table_1.rs @@ -41,7 +41,7 @@ fn edge(f: u8, c: u8, op: InferenceType) -> CausalEdge64 { f, c, CausalMask::SPO, - 0, + causal_edge::Orientation::Core, op, PlasticityState::ALL_HOT, 0, diff --git a/crates/lance-graph-planner/tests/maturation_ladder.rs b/crates/lance-graph-planner/tests/maturation_ladder.rs index ed274f857..a69732e86 100644 --- a/crates/lance-graph-planner/tests/maturation_ladder.rs +++ b/crates/lance-graph-planner/tests/maturation_ladder.rs @@ -251,7 +251,7 @@ fn raw_edge(s: u8, o: u8, freq: u8) -> CausalEdge64 { freq, 200, CausalMask::SO, - 0b101, + causal_edge::Orientation::from_code(0b101), InferenceType::Deduction, PlasticityState::from_bits(0), 0, diff --git a/crates/lance-graph-planner/tests/moore_nars16_probe.rs b/crates/lance-graph-planner/tests/moore_nars16_probe.rs index 37fc01a50..3c2a03e48 100644 --- a/crates/lance-graph-planner/tests/moore_nars16_probe.rs +++ b/crates/lance-graph-planner/tests/moore_nars16_probe.rs @@ -15,14 +15,14 @@ //! The two canonical fields MooreNars16 does not hold are absent for //! different reasons, and each has its own falsifier: //! -//! - **Direction3** is the canonical S/P/O sign triple. No ISA operation reads -//! it to compute anything (`forward` copies the weight's, `syllogize` writes -//! 0, `learn` never reads it). A Moore tenant declares a DIFFERENT reading: -//! lane geometry (the slot) x a polarity bit. A consumer of the sign triple -//! must refuse the Moore reading. The production consumer, -//! `CausalNetwork::detect_simpsons_paradox`, takes bare edges and CANNOT -//! refuse today: it silently reports "no pattern" (pinned below). The -//! refusal here is the contract a tagged boundary would have to provide. +//! - **Direction3** (CE64 43..45) was a per-plane S/P/O sign triple when +//! this probe was written. ⊘ D-CGW-1 (2026-10-16) made those bits the +//! orientation (`causal_edge::Orientation`), one meaning everywhere, and +//! removed the triad and its only consumer (`detect_simpsons_paradox`). A +//! Moore lane holds no orientation; the contract's `lift_ce64` now refuses +//! an oriented edge. This probe's projection predates that and still drops +//! the bits, so its equivalence below excludes them: it is a record of the +//! #1406 measurement, not a model for new code. //! - **Witness6** is lifted to the tenant: one W for all eight lanes. That is //! valid only if two lanes of one tenant never need different W at once; //! the projection refuses a tenant whose lanes disagree. @@ -42,8 +42,6 @@ use causal_edge::edge::CausalEdge64; use causal_edge::isa::{IsaFault, Opcode}; -use causal_edge::network::CausalNetwork; -use causal_edge::tables::NarsTables; use lance_graph_contract::epistemic_state5::{Epi5Gen, EpistemicState5}; // ─── CE64 field geometry (v2 layout) ──────────────────────────────────── @@ -164,20 +162,11 @@ fn directed_relation(slot: usize, lane: MooreNars16) -> ((i8, i8), (i8, i8)) { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -enum DirectionReading { - /// CE64 bits 43..45 are the canonical S/P/O sign triple. - SignTriple, - /// Direction is (lane slot, polarity); CE64 bits 43..45 carry nothing. - Moore { slot: usize, polarity: bool }, -} - -/// A logical operand: the CE64 the ISA executes on, plus how its direction -/// bits are to be read. +/// A logical operand: the CE64 the ISA executes on. Its direction is the +/// lane's slot and polarity, which stay in the tenant. #[derive(Clone, Copy, Debug)] struct Operand { edge: CausalEdge64, - reading: DirectionReading, } #[derive(Debug, PartialEq, Eq)] @@ -192,24 +181,6 @@ enum Refusal { }, } -/// The required behaviour of a sign-triple consumer behind a tagged boundary -/// (Simpson's pattern S and O pathological, P not, as -/// `CausalNetwork::detect_simpsons_paradox` reads it): refuse a Moore -/// reading, which has no sign triple. Probe-local; the production detector -/// does not see the tag (see the test after this one). -#[derive(Debug, PartialEq, Eq)] -struct ReadingMismatch; - -fn simpson_pattern(op: Operand) -> Result { - match op.reading { - DirectionReading::SignTriple => { - let d = op.edge.direction(); - Ok(d & 0b001 != 0 && d & 0b100 != 0 && d & 0b010 == 0) - } - DirectionReading::Moore { .. } => Err(ReadingMismatch), - } -} - // ─── Tenant ───────────────────────────────────────────────────────────── /// Representation mutations, used to prove each projection choice is @@ -305,13 +276,7 @@ impl MooreTenant { e = Field::Plasticity.set(e, u64::from(lane.plasticity3())); e = Field::W.set(e, u64::from(witness)); e = Field::Epi5.set(e, u64::from(lane.epi5())); - Operand { - edge: e, - reading: DirectionReading::Moore { - slot: k, - polarity: lane.polarity(), - }, - } + Operand { edge: e } } } @@ -682,72 +647,6 @@ fn polarity_reverses_the_relation_and_leaves_plasticity_alone() { } } -/// 3. A sign-triple consumer refuses the Moore reading and still works on the -/// canonical one. Without the reading tag it would read the zeroed bits and -/// silently report "no Simpson pattern". -#[test] -fn sign_triple_consumers_refuse_the_moore_reading() { - let mut r = Rng(0x51); - let (mut edges, polarity, _) = tenant_fixture(&mut r); - edges[2].set_direction(0b101); // S and O pathological, P not: Simpson - let canonical_op = Operand { - edge: edges[2], - reading: DirectionReading::SignTriple, - }; - assert_eq!(simpson_pattern(canonical_op), Ok(true)); - - let tenant = MooreTenant::project(edges, polarity, Mutation::None).unwrap(); - let moore = tenant.operand(2); - assert_eq!(simpson_pattern(moore), Err(ReadingMismatch)); - // What an untagged read would have said: the triple is gone. - let untagged = Operand { - reading: DirectionReading::SignTriple, - ..moore - }; - assert_eq!(simpson_pattern(untagged), Ok(false)); -} - -/// MEASURED GAP (pinned): the production sign-triple consumer cannot refuse. -/// `CausalNetwork::detect_simpsons_paradox` reads bare edges, so a -/// Moore-reconstructed edge (sign triple zeroed) is reported as "no pattern" -/// rather than refused. A Moore resident path must not reach this detector -/// until it takes a tagged operand. -/// -/// FAILS IF: the detector starts refusing or flagging the Moore edge (then -/// flip this test and say which boundary does it). -#[test] -fn the_production_simpson_detector_cannot_refuse_a_moore_edge() { - let mut r = Rng(0x52); - let (mut edges, polarity, _) = tenant_fixture(&mut r); - edges[2].set_direction(0b101); - edges[2].set_confidence_u8(200); // the detector skips c < 0.5 - let tenant = MooreTenant::project(edges, polarity, Mutation::None).unwrap(); - let detect = |edge: CausalEdge64| { - let zeros = || Box::new([0u8; 256 * 256]); - let dz = || Box::new([0u16; 256 * 256]); - CausalNetwork { - edges: vec![edge], - row_ptr: vec![], - col_idx: vec![], - edge_idx: vec![], - compose_s: zeros(), - compose_p: zeros(), - compose_o: zeros(), - dist_s: dz(), - dist_p: dz(), - dist_o: dz(), - nars_tables: NarsTables::build(1), - current_time: 0, - } - .detect_simpsons_paradox() - .len() - }; - // Can-fire: the canonical edge is flagged. - assert_eq!(detect(edges[2]), 1); - // The Moore edge is silently not flagged; nothing refuses it. - assert_eq!(detect(tenant.operand(2).edge), 0); -} - // ─── F: Witness ownership scope ───────────────────────────────────────── /// Can two lanes of one tenant need different W at once? The projection diff --git a/crates/lance-graph-planner/tests/residue_fixed_point.rs b/crates/lance-graph-planner/tests/residue_fixed_point.rs index 88bfab000..0b8888fc4 100644 --- a/crates/lance-graph-planner/tests/residue_fixed_point.rs +++ b/crates/lance-graph-planner/tests/residue_fixed_point.rs @@ -69,7 +69,7 @@ fn raw_edge(s: u8, o: u8) -> CausalEdge64 { 200, 200, CausalMask::SO, - 0b101, + causal_edge::Orientation::from_code(0b101), InferenceType::Deduction, PlasticityState::S_HOT, 0, diff --git a/crates/lance-graph/examples/multihop_witness_confidence.rs b/crates/lance-graph/examples/multihop_witness_confidence.rs index b0171258c..2e9ccc43d 100644 --- a/crates/lance-graph/examples/multihop_witness_confidence.rs +++ b/crates/lance-graph/examples/multihop_witness_confidence.rs @@ -84,7 +84,7 @@ fn main() { freq0, conf0, CausalMask::SPO, - 0, // direction + causal_edge::Orientation::Core, // direction InferenceType::Revision, PlasticityState::from_bits(0b111), // all hot 0, diff --git a/crates/lance-graph/tests/intervene_counterfactual.rs b/crates/lance-graph/tests/intervene_counterfactual.rs index 59cd51dbd..05ae305fd 100644 --- a/crates/lance-graph/tests/intervene_counterfactual.rs +++ b/crates/lance-graph/tests/intervene_counterfactual.rs @@ -124,7 +124,7 @@ fn causal_edge_intervention_roundtrip() { 200, 200, CausalMask::PO, // Level 2: Intervention — P and O active, S projected out - 0, + causal_edge::Orientation::Core, InferenceType::Intervention, PlasticityState::ALL_FROZEN, 42, @@ -156,7 +156,7 @@ fn causal_edge_counterfactual_roundtrip() { 200, 200, CausalMask::SPO, // Level 3: Counterfactual — all planes active - 0, + causal_edge::Orientation::Core, InferenceType::Counterfactual, PlasticityState::ALL_FROZEN, 99, diff --git a/crates/p64-bridge/src/lib.rs b/crates/p64-bridge/src/lib.rs index cbd75979c..69b677d77 100644 --- a/crates/p64-bridge/src/lib.rs +++ b/crates/p64-bridge/src/lib.rs @@ -544,7 +544,7 @@ mod tests { 200, // frequency 150, // confidence CausalMask::SO, // causal: S+O active (association) - 0, // direction + causal_edge::Orientation::Core, // direction InferenceType::Deduction, // inference PlasticityState::from_bits(0), // plasticity 0, // temporal @@ -584,7 +584,7 @@ mod tests { 128, 128, CausalMask::from_bits((i % 7) as u8), - 0, + causal_edge::Orientation::Core, infer_types[i % 5], PlasticityState::from_bits(0), 0, diff --git a/crates/thinking-engine/src/layered.rs b/crates/thinking-engine/src/layered.rs index 8e33386e9..724b3c773 100644 --- a/crates/thinking-engine/src/layered.rs +++ b/crates/thinking-engine/src/layered.rs @@ -219,7 +219,7 @@ impl CascadeChannels8 { freq_u8, conf_u8, causal_mask, - 0, + causal_edge::Orientation::Core, causal_edge::PlasticityState::ALL_FROZEN, ) .with_inference_mantissa(mantissa_signed) diff --git a/docs/architecture/ce64-semantic-upper-half.md b/docs/architecture/ce64-semantic-upper-half.md index dba995d44..738cfe6ce 100644 --- a/docs/architecture/ce64-semantic-upper-half.md +++ b/docs/architecture/ce64-semantic-upper-half.md @@ -23,7 +23,7 @@ as current behaviour and the diagram's name as a proposed interpretation. | 24..31 | F, frequency | `frequency_u8` | same | | 32..39 | C, confidence | `confidence_u8` | same | | 40..42 | Pearl ladder: asks the causal question | `CausalMask` (`pearl.rs`): `SO` association, `PO` intervention, `SPO` counterfactual, `SP` confounder detection, plus the marginals `None`, `O`, `P`, `S` | same. The diagram's "ablation" row has no mask of its own: ablation is the counterfactual edit (a cut), as the diagram's reasoning loop also says | -| 43..45 | orientation / syntax: which way the relation is read | `direction()`: a 3-bit triad, one "pathological" sign bit per S, P, O plane | different reading. Grammar, Gestalt, Moore and relation direction are not implemented on these bits | +| 43..45 | orientation / syntax: which way the relation is read | `orientation()` → `Orientation` (`orientation.rs`): 0 `Core`, then the seven Haspelmath dative-map functions (Direction, Recipient, Experiencer, Purpose, Beneficiary, Predicative possessor, External possessor) | same (D-CGW-1). The old S/P/O "pathological" sign triad was removed: nothing in production wrote it. A Moore lane writes `Core`; its direction is its slot and polarity | | 46..49 | activation i4: +7 excitation … −8 inhibition | signed i4 inference mantissa: sign = chain direction, magnitude = NARS rule index; +6 Intervention, −6 Counterfactual | different reading. In code this field names the inference operation, not an excitation level | | 50..52 | entropy / novelty: how unresolved or surprising | `PlasticityState`: one bit per S, P, O plane, hot = accepts palette reassignment under evidence pressure | different reading. Plasticity is related to how settled a plane is, but it is not an entropy measure | | 53..58 | belief-state update: witness / G breadcrumb | `w_slot()`: witness corpus root handle, 0..=63, 0 = no anchor. The G-slot was dropped in v2 (L-3) | partly. The six bits hold one handle; the W1 → W2 → W3 history in the diagram is not stored in the edge | @@ -49,12 +49,12 @@ as current behaviour and the diagram's name as a proposed interpretation. Three things are kept apart: - **Physical encoding**: which bits a field occupies (`layout.rs`). -- **Declared reading**: what those bits mean for a given tenant. The S/P/O - sign triad on bits 43..45 is the one reading implemented today. It does - not oblige every future tenant to read those bits the same way, and a - different reading (for example a Moore slot plus polarity, with the axis - fixed by the tenant's HHTL address) does not reconstruct the sign triad. - Readings are told apart by a versioned binding, never inferred. +- **Meaning**: what those bits mean. Each field has one meaning everywhere, + fixed by the `causal-edge` contract, like a wire format (D-CGW-1). No + tenant reads a field its own way; a field changes meaning only by amending + the contract once, with every reader migrated in the same change. Readings + that are not the field's meaning (qualia, a Moore slot and polarity) sit + beside the edge in the row, never inside it. - **ISA operation**: what an instruction computes on the declared reading (`crates/causal-edge/src/isa.rs`). The decoder executes only the implemented inference codes, and each instruction declares which fields @@ -62,9 +62,9 @@ Three things are kept apart: ## Open -- Whether bits 43..52 should be re-read as orientation, activation and - novelty. That would change the meaning of bits that existing code writes, - so it needs a version gate (`I-LEGACY-API-FEATURE-GATED`). It is not done - here. +- Bits 43..45 are settled as the orientation (D-CGW-1). Bits 46..49 stay + the inference mantissa; activation moves to a row field (D-CGW-9). Bits + 50..52 still carry two writers' meanings (plasticity in `learn`, the + novelty → wisdom rung in `wire`) and need a ruling. - Where a belief-update history longer than one witness handle lives. It is not in the edge. From 375b6c4daf87d4e41023d6093c215a585c9768c7 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 21:49:23 +0000 Subject: [PATCH 06/10] board: D-CGW-1 in PR; D-ASM-11 arm B as a lanewise span fold; #1593 arc entry Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- .claude/board/LATEST_STATE.md | 4 ++++ .claude/board/PR_ARC_INVENTORY.md | 7 +++++++ .claude/board/STATUS_BOARD.md | 4 ++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.claude/board/LATEST_STATE.md b/.claude/board/LATEST_STATE.md index fad59c90b..6c04f3329 100644 --- a/.claude/board/LATEST_STATE.md +++ b/.claude/board/LATEST_STATE.md @@ -1,3 +1,7 @@ +## 2026-10-16 — D-CGW-1: CE64 bits 43..45 are the orientation (in PR) + +`causal_edge::Orientation` (Core + the seven Haspelmath dative functions) is the one meaning of 43..45; `direction()` → `orientation()`, `pack`/`pack_v2` take it. The S/P/O pathological triad and `detect_simpsons_paradox` are removed (no production writer). Contract `MooreDirection` replaces `DirectionReading`; `lift_ce64` refuses an oriented edge. #1593 merged (`124eb6cf`). Entry `2026-10-16-d-cgw-1-orientation-contract.md`. + ## 2026-10-16 — synergy map since #1579 (entry `2026-10-16-synergy-map-since-1579.md`, in PR) - Revises every point of the #1579 map against merges #1580–#1591. D2 (preimage op) closed as a violation; L6 closed (#1544 closed); X17 and D8 partly closed by #1582. Decisions recorded: 43..45 amended to orientation in the contract, activation becomes a row field, OpenPSI modulators only into qualia. diff --git a/.claude/board/PR_ARC_INVENTORY.md b/.claude/board/PR_ARC_INVENTORY.md index b4aaadb46..b2feb2ee2 100644 --- a/.claude/board/PR_ARC_INVENTORY.md +++ b/.claude/board/PR_ARC_INVENTORY.md @@ -1,3 +1,10 @@ +## 2026-10-16 — lance-graph PR #1593 (merged `124eb6cf`, branch `ccr-9f3b8075-74u47l-synergy-1591`, head `526a0bc5`) — synergy map since #1579; config note reword; D-ARG-1..4 queued + +- **Added:** entry `2026-10-16-synergy-map-since-1579.md` (§1–§9: revision of every base point, CE64 vs identity/edge tenants and the 24×i4 loci, triangle join as presence-plane intersection); `.cargo/config.toml` note on the avx and v2 arms; STATUS rows D-CGW-13/14 and D-ARG-1..4. +- **Locked:** none (board and a config comment). +- **Deferred / open:** D-CGW-1 (in PR after this), D-CGW-9, D-CGW-14, D-ARG-1..4. +- **Confidence:** board-index checks green; Codex P2 (contract migration presented as done) fixed in `b6f3f40a`. + ## 2026-10-16 — lance-graph PR #1591 (merged `e53f2325`, branch `ccr-9f3b8075-74u47l-ce64-grammar-wiring`, head `cd1b1b3c`, 24 commits incl. a merge of main) — deepnsm-v2 wire: every CE64 field of a parsed triple from its source, Gadamer gate first; plan D-CGW-0..14 - **Added:** `deepnsm_v2::wire` (verses → rows: F/C from the arm, Pearl from TEKAMOLO, 43..45 = Haspelmath dative function, W = the statement's Markov arc in `WitnessTable<64>`, epistemic state from the support balance, loci Antecedent / TEKAMOLO / Quorum / Contradiction); the Gadamer gate (`contract::revision`) admits before anything is counted; `DativeFunction::ALL`; `causal-edge` `activation` / `novelty_wisdom` accessors; probe `lance-graph-quack/examples/wired_reasoning_probe.rs` (741 rows, 0 rule violations); plan `ce64-grammar-wiring-v1.md`; entry `2026-10-16-grammar-coordinates-annotation-wiring.md` §10–11. diff --git a/.claude/board/STATUS_BOARD.md b/.claude/board/STATUS_BOARD.md index 03b0380e8..1077ff18d 100644 --- a/.claude/board/STATUS_BOARD.md +++ b/.claude/board/STATUS_BOARD.md @@ -5,7 +5,7 @@ Plan: `.claude/plans/ce64-grammar-wiring-v1.md`. Entry: `entries/2026-10-16-gram | D-id | scope | status | gate / falsifier | |---|---|---|---| | **D-CGW-0** | `deepnsm-v2::wire`: CE64 0..63 from named sources; Gadamer gate before counting; W = Markov arc in `WitnessTable<64>`; activation = update-caused frequency change; 43..45 = Haspelmath function; Antecedent / TEKAMOLO / Quorum / Contradiction loci; qualia register; `wired_reasoning_probe` | In PR | 229 tests; probe 741 rows, 5 rules, 0 violations; disable runs red per entry §7–§11 | -| **D-CGW-1** | one global meaning per CE64 field, held in the `causal-edge` contract (no per-tenant readings; superseded the same day); amend 43..45 to orientation with all triad readers migrated | Queued — approved 2026-10-16 as its own test-first PR (readers census: synergy map since #1579 §4 S8; also `syllogize`/`execute`, ledger N1) | one code table shared by accessor, writer and readers; field isolation 43..49. **Gate:** wire edges stay in the probe until this lands | +| **D-CGW-1** | one global meaning per CE64 field, held in the `causal-edge` contract (no per-tenant readings; superseded the same day); amend 43..45 to orientation with all triad readers migrated | In PR (branch `ccr-9f3b8075-74u47l-cgw1`): `causal_edge::Orientation` on 43..45, `pack`/`pack_v2` take it, the S/P/O triad removed (no production writer), Moore `lift_ce64` refuses an oriented edge; entry `2026-10-16-d-cgw-1-orientation-contract.md`. 46..49 (D-CGW-9) and 50..52 still open | one code table shared by accessor, writer and readers; field isolation 43..49. **Gate:** wire edges stay in the probe until this lands | | **D-CGW-2** | frequency-ranked default reading (COCA, DeReKo) + antecedent-tested promotion of the alternative (relative pronoun) with agreement | Queued | `der Mann, der …` promoted; `der Mann gab der Frau …` silent; English `that` promoted without a COCA Rel tag | | **D-CGW-3** | case morphology decides argument order in the parser (`Den Hund biss der Mann`) | Queued | OVS flips, SVO unchanged, syncretic case unresolved; UD German GSD dev measured | | **D-CGW-4** | counterfactual lanes: `CausalCandidate` → `Causes` only with `IncreaseEligible` ∧ `Necessary` | Queued | necessary / dispensable / not-run triple | @@ -94,7 +94,7 @@ Council 2026-10-16: `metta-datalog-assimilation-v1-council-v3.md` is the ratifie | **D-ASM-8** | `learn`-shaped measures (marginals, MI/PMI, cosine, Jaccard) as a reading of pair counts in `lance-graph-arm-discovery`; counts from D-ASM-3, never a loop; no `lance-graph-learn` crate (entry `2026-10-16-asm-accepted-proposals.md`) | Queued (not authorized; gated on D-ASM-3) | measures == an oracle run of upstream `learn` on one corpus; `(opencog matrix)` definitions sourced first | | **D-ASM-9** | `lance-graph-das` attention-broker probe: `w = edge.count / node.count`, rent, spread over the D-ASM-2 hop | Queued (not authorized; gated on D-ASM-2; crate not created) | attention values == DAS broker on one fixture; crate created only when the probe runs | | **D-ASM-10** | MORK as fourth oracle (Hyperon · PeTTa · datafrog · MORK), built as a separate binary outside the workspace, results only | Queued (not authorized) | MORK answers recorded beside the other three, divergences recorded, never averaged | -| **D-ASM-11** | **⛔ VIOLATION — GATHER. DO NOT BUILD. CORRECT: D-HOLO-H14c / H14d.** Leapfrog probe on a cyclic 3-way join, split into Q-E (exact existence mask where the semijoin chain over-approximates) and Q-A (binding enumeration emitting keyed counts, D-ASM-3's missing carrier), written from the paper (Veldhuizen, *Leapfrog Triejoin*, arXiv 1210.0481v5, ICDT '14); the zipper shape is the probe's question, not a premise — arm A: leapfrog triejoin over the existing sealed ordered lanes, with aperture depth as `open`/`up` and a galloping `seek` from the cursor (the paper's amortized O(1 + log(N/m)); today's `bound_aperture` is a fresh `partition_point`); cleanest, already integrated; arm B: leapfrog triejoin over a prefix-shared trie zipper (PathMap-like), studied as prior art to learn from (worst-case optimal on cyclic joins, which a semijoin chain is not); the arm that wins on cost per element and integration is adopted, and what B teaches (variable order, prefix sharing, seek pattern) is carried into A either way | Queued (not authorized; gated on D-ASM-2). Pre-work in #1587: F4 fixture, bag oracle, `seek_from` (P-1), GYO (P-3), P-7 insufficiency shown (entry `2026-10-16-wcoj-probes-1-3.md`); closing atoms split into D-ASM-11A/B | Q-E: mask == datafrog's SET of head rows; Q-A: == datafrog as a BAG; per-element cost on the v4 arm only; margin and lessons pre-registered before the run; findings from B recorded even when A wins | +| **D-ASM-11** | **⛔ VIOLATION — GATHER. DO NOT BUILD. CORRECT: D-HOLO-H14c / H14d.** Leapfrog probe on a cyclic 3-way join, split into Q-E (exact existence mask where the semijoin chain over-approximates) and Q-A (binding enumeration emitting keyed counts, D-ASM-3's missing carrier), written from the paper (Veldhuizen, *Leapfrog Triejoin*, arXiv 1210.0481v5, ICDT '14); the zipper shape is the probe's question, not a premise — arm A: leapfrog triejoin over the existing sealed ordered lanes, with aperture depth as `open`/`up` and a galloping `seek` from the cursor (the paper's amortized O(1 + log(N/m)); today's `bound_aperture` is a fresh `partition_point`); cleanest, already integrated; arm B: leapfrog triejoin over a prefix-shared trie zipper (PathMap-like), studied as prior art to learn from (worst-case optimal on cyclic joins, which a semijoin chain is not); the arm that wins on cost per element and integration is adopted, and what B teaches (variable order, prefix sharing, seek pattern) is carried into A either way | Queued (not authorized; gated on D-ASM-2). 2026-10-16: arm B is a lanewise span fold over the WordNet DN lanes (each `is_a` level an ordered lane, seek = span), gated on range-as-span (lane-fold capstone point 4); an element-wise zip and a cyclic n-hop stay refused residuals. Pre-work in #1587: F4 fixture, bag oracle, `seek_from` (P-1), GYO (P-3), P-7 insufficiency shown (entry `2026-10-16-wcoj-probes-1-3.md`); closing atoms split into D-ASM-11A/B | Q-E: mask == datafrog's SET of head rows; Q-A: == datafrog as a BAG; per-element cost on the v4 arm only; margin and lessons pre-registered before the run; findings from B recorded even when A wins | | **D-ASM-11A** | **⛔ VIOLATION — GATHER. DO NOT BUILD. CORRECT: D-HOLO-H14c / H14d.** Closing atom for functional relations: `Pred::EqU32ViaLane` + ndarray `eq_u32_via_lane_to_mask` (spec `.claude/plans/wcoj-closing-atoms-v1.md` §2) | Spec ratified 2026-10-16; authorized 2026-10-16 (ungated from D-ASM-2); ndarray #364 closed unmerged 2026-10-16 | G1 exact mask == datafrog; G2 op count fixed and < the disjunction; G5-A disables | | **D-ASM-11B** | **⛔ VIOLATION — GATHER. DO NOT BUILD. CORRECT: D-HOLO-H14c / H14d.** Closing atom for n:m relations: `MaskOp::RunsMeet` (gated, beside `Gather`) + ndarray `runs_meet_under_to_mask` + lgj-abi status arm (spec §3) | Spec ratified 2026-10-16; authorized 2026-10-16, after D-ASM-11A | G0 fixtures; G3 edge oracle + projection; G4 elements-touched slope 1.5 ± 0.1; G5-B disables | | **D-ASM-12** | `lance-graph-cog`: deterministic content → NodeGuid atom address, shared by the D-ASM-1b binder and the `atomspace-lance` StorageNode adapter (which calls it); replaces the Rocks `n@`/`l@`/`a@`/`h@` indexes | Queued (not authorized; crate not created) | same content → same address from both callers; no string or hash index reachable from a row; adapter carries no layout of its own | From 287fca08305f759b2eb806ec28e7982fe4a07233 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 21:50:14 +0000 Subject: [PATCH 07/10] board: entry for D-CGW-1 (orientation contract, edge-facet census, WordNet DN decision) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- ...2026-10-16-d-cgw-1-orientation-contract.md | 89 +++++++++++++++++++ .claude/board/entries/README.md | 3 +- 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 .claude/board/entries/2026-10-16-d-cgw-1-orientation-contract.md diff --git a/.claude/board/entries/2026-10-16-d-cgw-1-orientation-contract.md b/.claude/board/entries/2026-10-16-d-cgw-1-orientation-contract.md new file mode 100644 index 000000000..8f760f2dc --- /dev/null +++ b/.claude/board/entries/2026-10-16-d-cgw-1-orientation-contract.md @@ -0,0 +1,89 @@ +# 2026-10-16 — D-CGW-1: CE64 bits 43..45 are the orientation + +**Status:** SHIPPED IN PR (branch ccr-9f3b8075-74u47l-cgw1). + +## What changed + +- New `causal_edge::orientation::Orientation` (`crates/causal-edge/src/orientation.rs`): + a 3-bit code. `Core` = 0, then Direction, Recipient, Experiencer, Purpose, + Beneficiary, PredicativePossessor, ExternalPossessor (Haspelmath 2003 dative + map). `from_code` reads the low three bits, so every value names exactly one + orientation. +- `CausalEdge64::direction()/set_direction()` are now + `orientation()/set_orientation()`. `pack` and `pack_v2` take an + `Orientation`, so the compiler lists every writer. `layout::DIR_SHIFT` is + renamed `ORIENT_SHIFT`. `CausalEdgeV3::direction()` became `orientation()`. +- Removed, not moved: `s/p/o_pathological`, `concern_level`, + `CausalNetwork::detect_simpsons_paradox`. Reason: no production code wrote + the triad. The only production writer of 43..45 was `deepnsm-v2::wire`, which + already wrote Haspelmath codes. The planner's `ConfounderCheck` + (`lance-graph-planner/src/pearl.rs`) computes its two directions from + population masks. `CausalMask::simpsons_paradox_risk(so, po)` stays, documented + as taking caller-computed directions. +- `deepnsm-v2::wire` writes the contract's `Orientation`. Its own u8 table became + `orientation_of(DativeFunction) -> Option` and + `orientation_function(Orientation)`. +- Contract `moore_tenant`: `DirectionReading`, `SignTriple`, + `require_sign_triple` and `DirectionRefusal` (a per-tenant reading binding) are + replaced by `MooreDirection { slot, polarity }`. `MooreTenantMut::lift_ce64` + refuses an edge whose orientation is not `Core` with the new + `MooreRefusal::Oriented { slot, code }`. A refusal writes nothing. +- About 85 call sites migrated across causal-edge, deepnsm-v2, lance-graph, + lance-graph-planner, cognitive-shader-driver, lance-graph-osint, p64-bridge and + thinking-engine. Zero literals became `Orientation::Core`. Fixture bit patterns + kept their bits through `Orientation::from_code`. +- Probes that read 43..45 per class (`witness_angle_probe`) or as the triad + (`moore_nars16_probe`) are marked superseded. The moore_nars16 Simpson tests + were removed with the detector they tested. `moore_nars_gomoku_probe` no longer + writes its Moore direction into 43..45. +- `docs/architecture/ce64-semantic-upper-half.md`: 43..45 are settled. The + "declared reading per tenant" paragraph is replaced by one meaning per field. + +## Tests + +- `crates/causal-edge/tests/orientation_contract.rs` (5 tests, written first and + committed red): + - the code table is one-to-one over 3 bits; + - zero is `Core`; + - accessor and setter agree; + - both packers write the same table; + - field isolation of 43..45 against 40..42 and 46..49. +- Contract `moore_tenant`: `h_direction_is_slot_and_polarity` and + `h2_an_oriented_edge_is_refused`. Disable run: removing the refusal check turns + `h2` red (11 passed, 1 failed). Restored afterwards. +- causal-edge passes on both the v2 default and `--no-default-features` (v1). + +## Edge facet census (Haiku card, spot-checked) + +- Production writers of the 16-byte edge facet: two. + - `lance-graph-contract/src/aiwar.rs:117-119` (out-of-family slots, bytes + 12..15). + - `symbiont/src/domino.rs:95-97` (bytes 0 and 12). +- Both use the old 12+4 slot reading. +- All other non-default constructions are test code. No code assigns a row's + `.edges` field directly. + +## Decided 2026-10-16 (conversation) + +- WordNet: `is_a` is the identity facet's DN path (16-nibble, already wired by + `deepnsm-v2::promote::{tiers_of, key_at}`). `part_of` and other relations go to + the edge facet, read as 16 slots through the ClassView. The 128-bit facet + format already exists (D-HPR-6a), so there is no layout change. The missing + piece is the caller: AriGraph, which is D-ARG-3. +- A leapfrog trie zipper over DN keys is a lanewise span fold (each DN level is + an ordered lane; a seek is a span). It is input to D-ASM-11 arm B and depends + on range-as-span (lane-fold capstone point 4). Per the capstone, a real + element-wise zip and a cyclic n-hop are refused residuals, so the triangle in §9 of `2026-10-16-synergy-map-since-1579.md` + qualifies only as span intersections plus one terminal AND. + +## OPEN + +- 46..49 are still read as activation by `wire` and as Energy4 by Moore tenants. + D-CGW-9 moves activation to a row field. +- 50..52 carries plasticity (`learn`) and the novelty → wisdom rung (`wire`). It + needs a ruling. +- The two production edge-facet writers still use the 12+4 slot reading. +- WordNet DN gates are not measured: + - G1: chain depth ≤ 12/16; + - G2: fan-out per level ≤ code width; + - G3: multi-parent synsets. diff --git a/.claude/board/entries/README.md b/.claude/board/entries/README.md index ea282263f..c43e8da0d 100644 --- a/.claude/board/entries/README.md +++ b/.claude/board/entries/README.md @@ -25,7 +25,7 @@ index row, (3) no duplicate entry id. Checks 1 and 2 are deliberately opposite directions; the stranding this convention prevents shows up in exactly one of them, never both. -362 entries, 2026-08-06 .. 2026-10-16. +363 entries, 2026-08-06 .. 2026-10-16. | date | entry id | finding | file | |---|---|---|---| @@ -40,6 +40,7 @@ exactly one of them, never both. | 2026-10-16 | `ledger-revision-1582-1591` | | [2026-10-16-ledger-revision-1582-1591.md](2026-10-16-ledger-revision-1582-1591.md) | | 2026-10-16 | `grammar-coordinates-annotation-wiring` | | [2026-10-16-grammar-coordinates-annotation-wiring.md](2026-10-16-grammar-coordinates-annotation-wiring.md) | | 2026-10-16 | `D-HOLO-H14d` | | [2026-10-16-d-holo-h14d-logic-mask-read.md](2026-10-16-d-holo-h14d-logic-mask-read.md) | +| 2026-10-16 | `D-CGW-1` | | [2026-10-16-d-cgw-1-orientation-contract.md](2026-10-16-d-cgw-1-orientation-contract.md) | | 2026-10-16 | `coresearch-wcoj-leapfrog` | | [2026-10-16-coresearch-wcoj-leapfrog.md](2026-10-16-coresearch-wcoj-leapfrog.md) | | 2026-10-16 | `board-catchup-open-items` | | [2026-10-16-board-catchup-open-items.md](2026-10-16-board-catchup-open-items.md) | | 2026-10-16 | `D-ASM` | | [2026-10-16-asm-accepted-proposals.md](2026-10-16-asm-accepted-proposals.md) | From 9a9373f674cf73ff4f478ead79a84a3786e37e37 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 22:07:39 +0000 Subject: [PATCH 08/10] D-CGW-1: rustfmt the migrated files Formatting only. The five causal-edge clippy findings (edge.rs 120, 236, 821, 826, 906) predate this branch and are not touched here. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- crates/causal-edge/src/edge.rs | 6 ++--- crates/causal-edge/src/v2_layout_tests.rs | 6 ++--- .../causal-edge/tests/orientation_contract.rs | 27 ++++++++++++++++--- .../examples/ce64_cycle_survival_probe.rs | 22 +++++++++++++-- .../examples/witness_angle_probe.rs | 13 +++++++-- crates/deepnsm-v2/src/wire.rs | 24 ++++++++++++++--- .../lance-graph-contract/src/moore_tenant.rs | 8 +++++- .../tests/p2_p3_edge_pearl.rs | 6 ++++- .../tests/p4_discovery_edge.rs | 6 ++--- .../lance-graph-osint/tests/p5_syllogize.rs | 17 ++++++++++-- crates/p64-bridge/src/lib.rs | 20 +++++++------- 11 files changed, 120 insertions(+), 35 deletions(-) diff --git a/crates/causal-edge/src/edge.rs b/crates/causal-edge/src/edge.rs index 695d8e513..35db4f697 100644 --- a/crates/causal-edge/src/edge.rs +++ b/crates/causal-edge/src/edge.rs @@ -4,8 +4,8 @@ use super::pearl::CausalMask; use super::plasticity::PlasticityState; -use crate::orientation::Orientation; use crate::isa::{Compose, IsaFault, Opcode}; +use crate::orientation::Orientation; /// NARS inference types encoded in 3 bits. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -914,8 +914,8 @@ impl CausalEdge64 { plasticity: PlasticityState, ) -> Self { use crate::layout::{ - BITS3_MASK as B3, CAUSAL_SHIFT as LCA, CONF_SHIFT as LC, ORIENT_SHIFT as LD, - FREQ_SHIFT as LF, O_SHIFT as LO, PLAST_SHIFT as LPL, P_SHIFT as LP, S_SHIFT as LS, + BITS3_MASK as B3, CAUSAL_SHIFT as LCA, CONF_SHIFT as LC, FREQ_SHIFT as LF, + ORIENT_SHIFT as LD, O_SHIFT as LO, PLAST_SHIFT as LPL, P_SHIFT as LP, S_SHIFT as LS, }; let mut v: u64 = 0; v |= (s_idx as u64) << LS; diff --git a/crates/causal-edge/src/v2_layout_tests.rs b/crates/causal-edge/src/v2_layout_tests.rs index 8cd6a3898..05e8e8384 100644 --- a/crates/causal-edge/src/v2_layout_tests.rs +++ b/crates/causal-edge/src/v2_layout_tests.rs @@ -91,9 +91,9 @@ mod v2_layout_tests { 7, 201, // S, P, O palette indices 209, - 181, // NARS f=0.82, c=0.71 - CausalMask::PO, // interventional level - crate::orientation::Orientation::from_code(0b101), // orientation + 181, // NARS f=0.82, c=0.71 + CausalMask::PO, // interventional level + crate::orientation::Orientation::from_code(0b101), // orientation InferenceType::Deduction, PlasticityState::S_HOT, 0, // temporal = 0 (v1 compat; bits 52-63 must be 0 for v2 clean read) diff --git a/crates/causal-edge/tests/orientation_contract.rs b/crates/causal-edge/tests/orientation_contract.rs index 657f0cb52..7bb2f8794 100644 --- a/crates/causal-edge/tests/orientation_contract.rs +++ b/crates/causal-edge/tests/orientation_contract.rs @@ -20,9 +20,15 @@ fn code_table_is_one_to_one_over_three_bits() { seen[c as usize] = true; assert_eq!(Orientation::from_code(c), o, "round trip of {o:?}"); } - assert!(seen.iter().all(|&s| s), "every 3-bit code names an orientation"); + assert!( + seen.iter().all(|&s| s), + "every 3-bit code names an orientation" + ); // Only the low three bits are read. - assert_eq!(Orientation::from_code(0b1010), Orientation::from_code(0b010)); + assert_eq!( + Orientation::from_code(0b1010), + Orientation::from_code(0b010) + ); } #[test] @@ -37,14 +43,27 @@ fn accessor_and_setter_agree_for_every_code() { let mut e = CausalEdge64(0); e.set_orientation(o); assert_eq!(e.orientation(), o); - assert_eq!((e.0 >> 43) & 0b111, u64::from(o.code()), "{o:?} lands on 43..45"); + assert_eq!( + (e.0 >> 43) & 0b111, + u64::from(o.code()), + "{o:?} lands on 43..45" + ); } } #[test] fn both_packers_write_the_same_table() { for o in Orientation::ALL { - let v2 = CausalEdge64::pack_v2(1, 2, 3, 200, 100, CausalMask::SPO, o, PlasticityState::ALL_HOT); + let v2 = CausalEdge64::pack_v2( + 1, + 2, + 3, + 200, + 100, + CausalMask::SPO, + o, + PlasticityState::ALL_HOT, + ); assert_eq!(v2.orientation(), o, "pack_v2 {o:?}"); #[allow(deprecated)] let v1 = CausalEdge64::pack( diff --git a/crates/cognitive-shader-driver/examples/ce64_cycle_survival_probe.rs b/crates/cognitive-shader-driver/examples/ce64_cycle_survival_probe.rs index 2d688b6ec..653fdfca2 100644 --- a/crates/cognitive-shader-driver/examples/ce64_cycle_survival_probe.rs +++ b/crates/cognitive-shader-driver/examples/ce64_cycle_survival_probe.rs @@ -116,13 +116,31 @@ fn with_code(edge: CausalEdge64, code: u8) -> CausalEdge64 { /// The tracked relation as an observation carrying `(f, c)`. S/P/O match the /// register, so `learn` never re-targets it. fn observation(f: u8, c: u8) -> CausalEdge64 { - CausalEdge64::pack_v2(1, 2, 3, f, c, CausalMask::SO, causal_edge::Orientation::Core, PlasticityState::ALL_HOT) + CausalEdge64::pack_v2( + 1, + 2, + 3, + f, + c, + CausalMask::SO, + causal_edge::Orientation::Core, + PlasticityState::ALL_HOT, + ) } /// The register before any evidence: code `Direct × Open`, no confidence. fn initial() -> CausalEdge64 { with_code( - CausalEdge64::pack_v2(1, 2, 3, 128, 0, CausalMask::SO, causal_edge::Orientation::Core, PlasticityState::ALL_HOT), + CausalEdge64::pack_v2( + 1, + 2, + 3, + 128, + 0, + CausalMask::SO, + causal_edge::Orientation::Core, + PlasticityState::ALL_HOT, + ), CODE_OPEN, ) } diff --git a/crates/cognitive-shader-driver/examples/witness_angle_probe.rs b/crates/cognitive-shader-driver/examples/witness_angle_probe.rs index 72278aa14..baac4b719 100644 --- a/crates/cognitive-shader-driver/examples/witness_angle_probe.rs +++ b/crates/cognitive-shader-driver/examples/witness_angle_probe.rs @@ -366,8 +366,17 @@ mod tests { ) .with_w_slot(23), edge(23, 5).with_inference_mantissa(-6), - CausalEdge64::pack_v2(0, 0, 0, 0, 0, CausalMask::None, causal_edge::Orientation::from_code(5), PlasticityState::ALL_HOT) - .with_w_slot(23), + CausalEdge64::pack_v2( + 0, + 0, + 0, + 0, + 0, + CausalMask::None, + causal_edge::Orientation::from_code(5), + PlasticityState::ALL_HOT, + ) + .with_w_slot(23), ]; for e in others { assert_eq!(stamped(CLASS_OBS, 1, e).unwrap(), base, "{:016x}", e.0); diff --git a/crates/deepnsm-v2/src/wire.rs b/crates/deepnsm-v2/src/wire.rs index 236894a5c..242247db3 100644 --- a/crates/deepnsm-v2/src/wire.rs +++ b/crates/deepnsm-v2/src/wire.rs @@ -1170,7 +1170,11 @@ mod tests { assert_eq!(last.novelty_wisdom(), 3); assert_eq!(epi(last).certification(), Certification3::Related); assert_eq!(epi(last).topology(), Topology2::Direct); - assert_eq!(last.orientation(), Orientation::Core, "no attested form: plain core argument"); + assert_eq!( + last.orientation(), + Orientation::Core, + "no attested form: plain core argument" + ); assert_eq!(last.causal_mask(), CausalMask::SO); // The rows of one statement are its time series. let rungs: Vec = rows.iter().map(|r| r.edge.novelty_wisdom()).collect(); @@ -1478,7 +1482,11 @@ mod tests { gave_to(vec![]), vec![form(TO, &[DativeFunction::Recipient])], ); - assert_eq!(w.rows[0].edge.orientation(), Orientation::Recipient, "Recipient"); + assert_eq!( + w.rows[0].edge.orientation(), + Orientation::Recipient, + "Recipient" + ); assert_eq!(w.report.orientation_coded, 1); let w = run_forms( gave_to(vec![]), @@ -1540,9 +1548,17 @@ mod tests { ) .unwrap(); assert!(w.rows[0].tekamolo[3].is_some(), "the Lokal lane landed"); - assert_eq!(w.rows[0].edge.orientation(), Orientation::Direction, "Direction"); + assert_eq!( + w.rows[0].edge.orientation(), + Orientation::Direction, + "Direction" + ); let w = wire(&[(1, 1)], &ins, 1, &abi(), None, ReadParams::RIGHT_CORNER).unwrap(); - assert_eq!(w.rows[0].edge.orientation(), Orientation::Core, "no lane: undecided"); + assert_eq!( + w.rows[0].edge.orientation(), + Orientation::Core, + "no lane: undecided" + ); } /// Quorum points at the nearest agreeing row, Contradiction at the diff --git a/crates/lance-graph-contract/src/moore_tenant.rs b/crates/lance-graph-contract/src/moore_tenant.rs index 51e0072a5..c28dd6ec0 100644 --- a/crates/lance-graph-contract/src/moore_tenant.rs +++ b/crates/lance-graph-contract/src/moore_tenant.rs @@ -638,7 +638,13 @@ mod tests { for slot in MooreSlot::ALL { for pol in [false, true] { let d = MooreNars16::new(0, 0, 0, pol, 0).direction(slot); - assert_eq!(d, MooreDirection { slot, polarity: pol }); + assert_eq!( + d, + MooreDirection { + slot, + polarity: pol + } + ); } } } diff --git a/crates/lance-graph-osint/tests/p2_p3_edge_pearl.rs b/crates/lance-graph-osint/tests/p2_p3_edge_pearl.rs index 30ec78124..d886e3a95 100644 --- a/crates/lance-graph-osint/tests/p2_p3_edge_pearl.rs +++ b/crates/lance-graph-osint/tests/p2_p3_edge_pearl.rs @@ -86,7 +86,11 @@ fn p2_edge_round_trips_palette_indices_and_mask() { assert_eq!(edge.p_idx(), pi, "p_idx round-trip"); assert_eq!(edge.o_idx(), oi, "o_idx round-trip"); // The Pearl level the edge was stamped with round-trips. - assert_eq!(edge.causal_mask(), CausalMask::SPO, "causal_mask round-trip"); + assert_eq!( + edge.causal_mask(), + CausalMask::SPO, + "causal_mask round-trip" + ); // Frequency/confidence quantized bytes survive too. assert_eq!(edge.frequency_u8(), freq, "frequency_u8 round-trip"); assert_eq!(edge.confidence_u8(), conf, "confidence_u8 round-trip"); diff --git a/crates/lance-graph-osint/tests/p4_discovery_edge.rs b/crates/lance-graph-osint/tests/p4_discovery_edge.rs index 660fe2686..61d20aff1 100644 --- a/crates/lance-graph-osint/tests/p4_discovery_edge.rs +++ b/crates/lance-graph-osint/tests/p4_discovery_edge.rs @@ -121,9 +121,9 @@ fn p4_rule_truth_packs_into_causal_edge() { // impact slot. Palette indices are illustrative here (P1 pinned their metric); // P4's teeth are that the discovery truth round-trips into the edge wire. let edge = CausalEdge64::pack_v2( - 1, // militaryUse=yes palette index - 0, // "implies" predicate slot - 3, // impact=high palette index + 1, // militaryUse=yes palette index + 0, // "implies" predicate slot + 3, // impact=high palette index truth.frequency, truth.confidence, CausalMask::SPO, diff --git a/crates/lance-graph-osint/tests/p5_syllogize.rs b/crates/lance-graph-osint/tests/p5_syllogize.rs index c6819f328..5162a51d5 100644 --- a/crates/lance-graph-osint/tests/p5_syllogize.rs +++ b/crates/lance-graph-osint/tests/p5_syllogize.rs @@ -25,7 +25,16 @@ const IS_A: u8 = 0x07; // predicate placeholder slot (shared) /// Build an `is_a`-style premise edge on the palette with the given truth bytes. fn premise(s: u8, o: u8, f: u8, c: u8) -> CausalEdge64 { - CausalEdge64::pack_v2(s, IS_A, o, f, c, CausalMask::SPO, causal_edge::Orientation::Core, PlasticityState::ALL_FROZEN) + CausalEdge64::pack_v2( + s, + IS_A, + o, + f, + c, + CausalMask::SPO, + causal_edge::Orientation::Core, + PlasticityState::ALL_FROZEN, + ) } #[test] @@ -70,7 +79,11 @@ fn p5_identical_statement_is_revision_not_syllogism() { // Same S and O ⇒ NARS revision territory, not a syllogism. let e1 = premise(A, B, 255, 100); let e2 = premise(A, B, 255, 200); - assert_eq!(e1.figure(e2), None, "identical S,O ⇒ revision, not syllogism"); + assert_eq!( + e1.figure(e2), + None, + "identical S,O ⇒ revision, not syllogism" + ); assert!(e1.syllogize(e2).is_none()); } diff --git a/crates/p64-bridge/src/lib.rs b/crates/p64-bridge/src/lib.rs index 69b677d77..2aa018f52 100644 --- a/crates/p64-bridge/src/lib.rs +++ b/crates/p64-bridge/src/lib.rs @@ -538,16 +538,16 @@ mod tests { #[test] fn edge_to_palette_addressing() { let edge = CausalEdge64::pack( - 10, // S - 5, // P - 20, // O - 200, // frequency - 150, // confidence - CausalMask::SO, // causal: S+O active (association) - causal_edge::Orientation::Core, // direction - InferenceType::Deduction, // inference - PlasticityState::from_bits(0), // plasticity - 0, // temporal + 10, // S + 5, // P + 20, // O + 200, // frequency + 150, // confidence + CausalMask::SO, // causal: S+O active (association) + causal_edge::Orientation::Core, // direction + InferenceType::Deduction, // inference + PlasticityState::from_bits(0), // plasticity + 0, // temporal ); let (row, col) = edge_to_block(&edge); From 394d8ebc5ea484dd65a419099193e6c78d73b8f2 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 22:23:17 +0000 Subject: [PATCH 09/10] D-CGW-1: Moore ISA-equivalence fixture draws Core-oriented edges lift_ce64 now refuses an edge whose bits 43..45 are not Core, so the random fixture clears them. The divergence check compares every bit, since no field is excluded any more. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- .../tests/moore_tenant_isa_equivalence.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/crates/lance-graph-planner/tests/moore_tenant_isa_equivalence.rs b/crates/lance-graph-planner/tests/moore_tenant_isa_equivalence.rs index d64a325ac..26528c270 100644 --- a/crates/lance-graph-planner/tests/moore_tenant_isa_equivalence.rs +++ b/crates/lance-graph-planner/tests/moore_tenant_isa_equivalence.rs @@ -5,14 +5,15 @@ //! into `ValueTenant::MooreNars16` with `MooreTenantMut::lift_ce64`, read back //! with `MooreTenantView`, and rebuilt as `payload40 | ce64_upper(witness)`. //! The shipped ops (`forward` both ways, `learn` both ways, `syllogize`) must -//! give the same result on the rebuilt edge as on the original, on every -//! field except the S/P/O sign triple, which the Moore reading does not carry. +//! give the same result on the rebuilt edge as on the original. Bits 43..45 +//! (the orientation, D-CGW-1) are `Core` on every edge: a Moore lane holds no +//! orientation, and `lift_ce64` refuses an edge that carries one. use causal_edge::edge::CausalEdge64; use lance_graph_contract::canonical_node::VALUE_SLAB_LEN; use lance_graph_contract::moore_tenant::{MooreSlot, MooreTenantMut, MooreTenantView}; -const DIRECTION: u64 = 0b111 << 43; +const ORIENTATION: u64 = 0b111 << 43; const W: u64 = 0x3F << 53; const EPI5: u64 = 0x1F << 59; const PAYLOAD40: u64 = (1 << 40) - 1; @@ -36,7 +37,7 @@ const EXECUTABLE: [u64; 5] = [0x1, 0x2, 0xF, 0x4, 0x5]; fn canonical(r: &mut Rng, w: u64) -> u64 { let code = EXECUTABLE[(r.next() % 5) as usize]; - (r.next() & !W & !EPI5 & !MANTISSA) | (w << 53) | ((r.next() % 24) << 59) | (code << 46) + (r.next() & !W & !EPI5 & !MANTISSA & !ORIENTATION) | (w << 53) | ((r.next() % 24) << 59) | (code << 46) } fn tables() -> [Box<[u8; 256 * 256]>; 3] { @@ -100,7 +101,7 @@ fn divergences(rounds: usize, witness_of: fn(u8) -> u8) -> usize { let a = ops(edges[k], partner, &t); let b = ops(rebuilt, partner, &t); for i in 0..5 { - if a[i] & !DIRECTION != b[i] & !DIRECTION { + if a[i] != b[i] { diff += 1; } } From 0ee072cb08d0e4041a2286ae73fedf9534afa70c Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 22:23:30 +0000 Subject: [PATCH 10/10] D-CGW-1: rustfmt the Moore ISA-equivalence fixture Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- .../tests/moore_tenant_isa_equivalence.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/lance-graph-planner/tests/moore_tenant_isa_equivalence.rs b/crates/lance-graph-planner/tests/moore_tenant_isa_equivalence.rs index 26528c270..bc5287a07 100644 --- a/crates/lance-graph-planner/tests/moore_tenant_isa_equivalence.rs +++ b/crates/lance-graph-planner/tests/moore_tenant_isa_equivalence.rs @@ -37,7 +37,10 @@ const EXECUTABLE: [u64; 5] = [0x1, 0x2, 0xF, 0x4, 0x5]; fn canonical(r: &mut Rng, w: u64) -> u64 { let code = EXECUTABLE[(r.next() % 5) as usize]; - (r.next() & !W & !EPI5 & !MANTISSA & !ORIENTATION) | (w << 53) | ((r.next() % 24) << 59) | (code << 46) + (r.next() & !W & !EPI5 & !MANTISSA & !ORIENTATION) + | (w << 53) + | ((r.next() % 24) << 59) + | (code << 46) } fn tables() -> [Box<[u8; 256 * 256]>; 3] {