From d8c2306a8ba81ea3c8ebc28d8cad522f2644401b Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Wed, 7 Oct 2026 23:26:36 +0200 Subject: [PATCH 1/5] D-CE64-SEM-0: probe semantic upper-half transition loop --- .../examples/pearl_ladder_probe.rs | 233 +++++++++++++++++- 1 file changed, 232 insertions(+), 1 deletion(-) diff --git a/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs b/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs index 135f76f59..a2dc6b4d9 100644 --- a/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs +++ b/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs @@ -66,7 +66,7 @@ use causal_edge::pearl::CausalMask; use causal_edge::plasticity::PlasticityState; use causal_edge::tables::NarsTables; use lance_graph_contract::causal_audit::SupportBasis; -use lance_graph_contract::epistemic_state5::{Certification3, Topology2}; +use lance_graph_contract::epistemic_state5::{fact, facts_population, Certification3, Topology2}; use lance_graph_planner::dismech_counterfactual::{CutContext, DEFAULT_FREQUENCY_BAR}; use lance_graph_planner::dismech_replay::{ChainStep, ComposeTables}; @@ -536,6 +536,94 @@ fn topology(e: CausalEdge64) -> Topology2 { Topology2::from_ordinal(e.epistemic_raw5() & 0b11).expect("2-bit ordinal") } +// ── Candidate semantic upper-half reading ───────────────────────────────── +// +// D-CE64-SEM-0 is deliberately probe-local. It does NOT rename the shipped +// fields yet. The question is whether the current physical carriers can support +// one coherent transition loop without inventing another object: +// +// 40..42 Pearl question +// 43..45 orientation / syntax +// 46..49 signed activation (reaction, not opcode) +// 50..52 novelty / epistemic entropy proxy +// 53..58 belief-state update breadcrumb +// 59..63 canonical EpistemicState5 +// +// If these falsifiers survive, a later PR can decide which readings deserve +// contract names. Until then the production accessors keep their current names. +mod semantic_upper_half { + use super::*; + use causal_edge::layout::{PLAST_MASK, PLAST_SHIFT}; + + /// Read bits 50..52 as one probe-local 3-bit novelty ordinal. + pub fn novelty3(edge: CausalEdge64) -> u8 { + ((edge.0 & PLAST_MASK) >> PLAST_SHIFT) as u8 + } + + /// Write the probe-local novelty reading without changing any other bit. + pub fn with_novelty3(edge: CausalEdge64, novelty: u8) -> CausalEdge64 { + CausalEdge64( + (edge.0 & !PLAST_MASK) | ((u64::from(novelty & 0b111)) << PLAST_SHIFT), + ) + } + + /// Quantize the maximum entropy of the surviving EpistemicState5 + /// population: ceil(log2(popcount)). One surviving state is settled (0); + /// all 24 meaningful V1 states fit in 5. Integer-only and deterministic. + pub fn population_novelty(required: u32) -> u8 { + let n = facts_population(required).count_ones(); + if n <= 1 { + 0 + } else { + (u32::BITS - (n - 1).leading_zeros()) as u8 + } + } + + /// The signed i4 is a REACTION reading here, not the operation code. + /// Positive means the edit raised the terminal frequency; negative means + /// it lowered it. Quantize |delta| in 32-point buckets into 1..=7. + pub fn activation(reaction: Reaction) -> i8 { + let (factual, counterfactual) = match reaction { + Reaction::LoadBearing { + factual, + counterfactual, + } + | Reaction::TruthOnly { + factual, + counterfactual, + } => (factual, counterfactual), + Reaction::Inert { .. } => return 0, + }; + let delta = i16::from(counterfactual) - i16::from(factual); + if delta == 0 { + return 0; + } + let magnitude = if delta < 0 { -delta } else { delta } as u16; + let q = ((magnitude + 31) / 32).clamp(1, 7) as i8; + if delta > 0 { q } else { -q } + } + + pub fn with_activation(edge: CausalEdge64, reaction: Reaction) -> CausalEdge64 { + edge.with_inference_mantissa(activation(reaction)) + } + + /// W records a BELIEF-STATE UPDATE. A thought that produced no + /// EpistemicState5 transition does not steal the breadcrumb. + pub fn record_belief_update( + before: CausalEdge64, + after: CausalEdge64, + witness: u8, + ) -> CausalEdge64 { + if before.epistemic_raw5() == after.epistemic_raw5() { + after.with_w_slot(before.w_slot()) + } else { + after.with_w_slot(witness & 0x3f) + } + } +} + +use semantic_upper_half::*; + // ── The script ──────────────────────────────────────────────────────────── fn main() { @@ -1042,4 +1130,147 @@ mod tests { Operation::Association ); } + + /// D-CE64-SEM-0. One real CUI-BONO trajectory crosses the proposed + /// upper-half reading without inventing another carrier. Hydration and PO + /// move Epi5 and therefore advance W; SPO produces a measured activation + /// but no new belief-state breadcrumb because Epi5 does not move. + #[test] + fn semantic_loop_records_only_real_belief_state_updates() { + let rp = Replay::new(); + let mut b = related_population(); + add_positive_trial(&mut b); + let model = b.build(); + let ev = evidence(&model, &rp); + + let mut start = query( + CausalMask::SO, + Contract::Related, + Topology2::IndirectUnknown, + ) + .with_w_slot(0); + start = with_novelty3( + start, + population_novelty(fact::IND_UNKNOWN | fact::RELATED), + ); + assert_eq!(novelty3(start), 2, "four certification cells still survive"); + + // A real A -> B -> Y hydration moves topology, so it earns breadcrumb 1. + let (hydrated, h) = hydrate(start, (A, B, Y), &rp.steps).unwrap(); + assert_eq!(h, Hydration::Hydrated); + let mut hydrated = record_belief_update(start, hydrated, 1); + hydrated = with_novelty3( + hydrated, + population_novelty(fact::IND_KNOWN | fact::RELATED), + ); + assert_eq!(hydrated.w_slot(), 1); + assert_eq!(novelty3(hydrated), 2); + assert_eq!( + (topology(hydrated), certification(hydrated)), + (Topology2::IndirectKnown, Certification3::Related) + ); + + // The randomized PO arms earn Causes. That is another epistemic move, + // so W advances and the surviving population collapses to one state. + let (causal, m) = step(hydrated, CausalMask::PO, &ev, Edit::None); + assert_eq!(m.earned(), Some(Certification3::Causes)); + let mut causal = record_belief_update(hydrated, causal, 2); + causal = with_novelty3( + causal, + population_novelty(fact::IND_KNOWN | fact::CAUSES), + ); + assert_eq!(causal.w_slot(), 2); + assert_eq!(novelty3(causal), 0, "one epistemic state survives"); + assert_eq!( + (topology(causal), certification(causal)), + (Topology2::IndirectKnown, Certification3::Causes) + ); + + // The SPO cut is mechanically real but earns no new Epi5 state. + // Its measured reaction becomes activation; the belief-update + // breadcrumb stays on the PO transition that actually changed Epi5. + let (spo, m) = step(causal, CausalMask::SPO, &ev, Edit::CutStep(1)); + let reaction = m.reaction().expect("counterfactual replay measured"); + let spo = record_belief_update(causal, with_activation(spo, reaction), 3); + assert_eq!(activation(reaction), -3); + assert_eq!(spo.inference_mantissa(), -3); + assert_eq!(spo.w_slot(), 2, "no epistemic transition, no new breadcrumb"); + assert_eq!(spo.epistemic_raw5(), causal.epistemic_raw5()); + } + + /// The i4 activation is a measured reaction, not a disguised SPO opcode: + /// the SAME counterfactual operator yields opposite signs for two cuts. + #[test] + fn activation_is_reaction_not_operation_echo() { + let rp = Replay::new(); + let model = related_population().build(); + let ev = evidence(&model, &rp); + let q = query( + CausalMask::SPO, + Contract::Related, + Topology2::IndirectKnown, + ); + + let (_, down) = step(q, CausalMask::SPO, &ev, Edit::CutStep(1)); + let (_, up) = step(q, CausalMask::SPO, &ev, Edit::CutStep(0)); + let down = down.reaction().expect("cut 1 measured"); + let up = up.reaction().expect("cut 0 measured"); + + assert_eq!(activation(down), -3, "185 -> 120 inhibits"); + assert_eq!(activation(up), 2, "185 -> 225 excites"); + assert_ne!( + activation(down), + InferenceType::Counterfactual.to_mantissa(), + "activation is not the -6 counterfactual opcode" + ); + assert_ne!(activation(down).signum(), activation(up).signum()); + } + + /// Novelty is the width of the still-legal epistemic population, not a + /// synonym for causality. Hydrating the intermediate changes topology but + /// leaves four certification possibilities; the intervention collapses + /// those possibilities to one. + #[test] + fn novelty_measures_remaining_epistemic_population() { + let all = facts_population(0); + let unknown_related = facts_population(fact::IND_UNKNOWN | fact::RELATED); + let known_related = facts_population(fact::IND_KNOWN | fact::RELATED); + let known_causes = facts_population(fact::IND_KNOWN | fact::CAUSES); + + assert_eq!(all.count_ones(), 24); + assert_eq!(unknown_related.count_ones(), 4); + assert_eq!(known_related.count_ones(), 4); + assert_eq!(known_causes.count_ones(), 1); + + assert_eq!(population_novelty(0), 5); + assert_eq!(population_novelty(fact::IND_UNKNOWN | fact::RELATED), 2); + assert_eq!(population_novelty(fact::IND_KNOWN | fact::RELATED), 2); + assert_eq!(population_novelty(fact::IND_KNOWN | fact::CAUSES), 0); + } + + /// Orientation is orthogonal to operator selection and certification in + /// this fixture. Every 3-bit direction reaches the same PO measurement, + /// and revision preserves the chosen orientation bit-for-bit. + #[test] + fn orientation_does_not_secretly_select_the_pearl_operator() { + let rp = Replay::new(); + let mut b = related_population(); + add_positive_trial(&mut b); + let model = b.build(); + let ev = evidence(&model, &rp); + + let baseline_q = query(CausalMask::PO, Contract::Related, Topology2::IndirectKnown); + let baseline = reason(baseline_q, &ev, Edit::None); + + for direction in 0u8..8 { + let mut q = baseline_q; + q.set_direction(direction); + let measured = reason(q, &ev, Edit::None); + assert_eq!(measured, baseline, "direction {direction:03b}"); + let out = revise(q, &measured).unwrap(); + assert_eq!(out.direction(), direction); + assert_eq!(certification(out), Certification3::Causes); + } + } + } From e46c38f8ad29738f5cb43876e83b5d347d6f6406 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Wed, 7 Oct 2026 23:27:12 +0200 Subject: [PATCH 2/5] D-CE64-SEM-0: tighten signed activation quantization --- crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs b/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs index a2dc6b4d9..d8c65cd3f 100644 --- a/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs +++ b/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs @@ -598,7 +598,7 @@ mod semantic_upper_half { if delta == 0 { return 0; } - let magnitude = if delta < 0 { -delta } else { delta } as u16; + let magnitude = (if delta < 0 { -delta } else { delta }) as u16; let q = ((magnitude + 31) / 32).clamp(1, 7) as i8; if delta > 0 { q } else { -q } } From 97789b2ed7a6a16d307e38972c6dd66ea61f9a9e Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Wed, 7 Oct 2026 23:28:57 +0200 Subject: [PATCH 3/5] D-CE64-SEM-0: keep alternate readings test-only --- .../cognitive-shader-driver/examples/pearl_ladder_probe.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs b/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs index d8c65cd3f..46b60d4f2 100644 --- a/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs +++ b/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs @@ -66,7 +66,9 @@ use causal_edge::pearl::CausalMask; use causal_edge::plasticity::PlasticityState; use causal_edge::tables::NarsTables; use lance_graph_contract::causal_audit::SupportBasis; -use lance_graph_contract::epistemic_state5::{fact, facts_population, Certification3, Topology2}; +use lance_graph_contract::epistemic_state5::{Certification3, Topology2}; +#[cfg(test)] +use lance_graph_contract::epistemic_state5::{fact, facts_population}; use lance_graph_planner::dismech_counterfactual::{CutContext, DEFAULT_FREQUENCY_BAR}; use lance_graph_planner::dismech_replay::{ChainStep, ComposeTables}; @@ -551,6 +553,7 @@ fn topology(e: CausalEdge64) -> Topology2 { // // If these falsifiers survive, a later PR can decide which readings deserve // contract names. Until then the production accessors keep their current names. +#[cfg(test)] mod semantic_upper_half { use super::*; use causal_edge::layout::{PLAST_MASK, PLAST_SHIFT}; @@ -622,6 +625,7 @@ mod semantic_upper_half { } } +#[cfg(test)] use semantic_upper_half::*; // ── The script ──────────────────────────────────────────────────────────── From de0206544b68f0b6925e0bebe774b77761ecdd83 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 7 Oct 2026 21:35:10 +0000 Subject: [PATCH 4/5] D-CE64-SEM-0: an impossible population is not a settled one population_novelty returned 0 for both a single surviving EpistemicState5 and an empty population (contradictory facts such as DIRECT | INDIRECT), so a contradiction read as certainty (codex review). It now returns Option: None for no surviving state, Some(0) for one. The novelty test pins the contradiction case; a disable run mapping the empty population back to Some(0) turns it red. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0177nSSyQaXqbNuGR1vMXXN6 --- .../examples/pearl_ladder_probe.rs | 43 +++++++++++++------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs b/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs index e34f0f593..214bee7e0 100644 --- a/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs +++ b/crates/cognitive-shader-driver/examples/pearl_ladder_probe.rs @@ -276,12 +276,15 @@ mod semantic_upper_half { /// Quantize the maximum entropy of the surviving EpistemicState5 /// population: ceil(log2(popcount)). One surviving state is settled (0); /// all 24 meaningful V1 states fit in 5. Integer-only and deterministic. - pub fn population_novelty(required: u32) -> u8 { - let n = facts_population(required).count_ones(); - if n <= 1 { - 0 - } else { - (u32::BITS - (n - 1).leading_zeros()) as u8 + /// + /// `None` when no state survives: the required facts contradict each + /// other (for example `DIRECT | INDIRECT`). That is not a settled belief, + /// so it never shares the ordinal `0` with one surviving state. + pub fn population_novelty(required: u32) -> Option { + match facts_population(required).count_ones() { + 0 => None, + 1 => Some(0), + n => Some((u32::BITS - (n - 1).leading_zeros()) as u8), } } @@ -482,7 +485,10 @@ mod tests { Topology2::IndirectUnknown, ) .with_w_slot(0); - start = with_novelty3(start, population_novelty(fact::IND_UNKNOWN | fact::RELATED)); + start = with_novelty3( + start, + population_novelty(fact::IND_UNKNOWN | fact::RELATED).expect("consistent facts"), + ); assert_eq!(novelty3(start), 2, "four certification cells still survive"); // A real A -> B -> Y hydration moves topology, so it earns breadcrumb 1. @@ -491,7 +497,7 @@ mod tests { let mut hydrated = record_belief_update(start, hydrated, 1); hydrated = with_novelty3( hydrated, - population_novelty(fact::IND_KNOWN | fact::RELATED), + population_novelty(fact::IND_KNOWN | fact::RELATED).expect("consistent facts"), ); assert_eq!(hydrated.w_slot(), 1); assert_eq!(novelty3(hydrated), 2); @@ -505,7 +511,10 @@ mod tests { let (causal, m) = step(hydrated, CausalMask::PO, &ev, Edit::None); assert_eq!(m.earned(), Some(Certification3::Causes)); let mut causal = record_belief_update(hydrated, causal, 2); - causal = with_novelty3(causal, population_novelty(fact::IND_KNOWN | fact::CAUSES)); + causal = with_novelty3( + causal, + population_novelty(fact::IND_KNOWN | fact::CAUSES).expect("consistent facts"), + ); assert_eq!(causal.w_slot(), 2); assert_eq!(novelty3(causal), 0, "one epistemic state survives"); assert_eq!( @@ -569,10 +578,18 @@ mod tests { assert_eq!(known_related.count_ones(), 4); assert_eq!(known_causes.count_ones(), 1); - assert_eq!(population_novelty(0), 5); - assert_eq!(population_novelty(fact::IND_UNKNOWN | fact::RELATED), 2); - assert_eq!(population_novelty(fact::IND_KNOWN | fact::RELATED), 2); - assert_eq!(population_novelty(fact::IND_KNOWN | fact::CAUSES), 0); + assert_eq!(population_novelty(0), Some(5)); + assert_eq!( + population_novelty(fact::IND_UNKNOWN | fact::RELATED), + Some(2) + ); + assert_eq!(population_novelty(fact::IND_KNOWN | fact::RELATED), Some(2)); + assert_eq!(population_novelty(fact::IND_KNOWN | fact::CAUSES), Some(0)); + + // Codex #1393: contradictory facts leave no state at all. That is not + // the settled single state above, so it must not read as 0. + assert_eq!(facts_population(fact::DIRECT | fact::INDIRECT), 0); + assert_eq!(population_novelty(fact::DIRECT | fact::INDIRECT), None); } /// Orientation is orthogonal to operator selection and certification in From 6c980155dbf8e003e007e2918842f3ea3a1e5e61 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 7 Oct 2026 21:36:45 +0000 Subject: [PATCH 5/5] Board: regenerate the entries index (stale on main since #1391/#1392) Same regeneration as #1394, so regenerate-and-diff passes on this PR; it no-ops once main carries #1394. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0177nSSyQaXqbNuGR1vMXXN6 --- .claude/board/entries/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.claude/board/entries/README.md b/.claude/board/entries/README.md index ffefe8476..ed88b724a 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. -256 entries, 2026-08-06 .. 2026-10-07. +257 entries, 2026-08-06 .. 2026-10-07. | date | entry id | finding | file | |---|---|---|---|