diff --git a/.claude/board/EPIPHANIES.md b/.claude/board/EPIPHANIES.md index ff4c21b5d..618c90238 100644 --- a/.claude/board/EPIPHANIES.md +++ b/.claude/board/EPIPHANIES.md @@ -1,3 +1,13 @@ +## 2026-07-23 — E-S10-COHERENCE-CLOSURE-DENSITY-1 — the S10 insight/mush null falsifier (D-DIA-V2-A) did its job on the FIRST build: it scored real=null=0 under the plan's draft formula and forced a two-part correction, converting a plausible-but-broken detector into a working one. The plan's S10 was `insight = clamp(Δcoherence + Δwonder − Δentropy, 0, 1) · [yield>θ]` with `coherence = (derived/total)·mean_expectation(derived)`. The mandatory size-preserving null (`insight_beats_size_preserving_null`: three deep `is_a` chains vs a SplitMix64 same-edge-count random rewiring) scored **real insight 0, null insight 0** — zero discrimination. The falsifier isolated TWO independent confounds, both fixed + +**Status:** FINDING (measured: the null falsifier now passes real 0.82 > null; 3 insight tests + 46 nars-module tests green, clippy -D warnings clean). **Confidence:** High on the correction; the detector is now a WORKING discriminator on the synthetic chain-vs-random control, not yet exercised on a whole-book step (that is the V2-A→whole-book wire, next). + +**Confound 1 — the `·mean_exp` coherence multiplier (deduction-attenuation inversion).** NAL deduction *correctly* attenuates confidence with chain depth (`c = c₁c₂f₁f₂`), so the DEEPEST, most-coherent transitive chains earn the LOWEST mean expectation. Multiplying closure by `mean_exp` therefore dragged coherence DOWN exactly when the graph closed MOST — the metric fought the very structure it was meant to reward. **Fix:** `coherence = closure density = derived/total` — a size-invariant ratio (coherent chains close densely: 30 edges → 135 derived → 0.82; random rewiring closes sparsely). This is the size-invariant structural signal S10 must key on. + +**Confound 2 — the `−Δentropy` insight term (a VSA-world import that doesn't transfer to term-logic).** `truth_entropy` = confidence-distribution Shannon spread. On EVERY productive term-logic step it RISES (premises peak at one confidence bin; deduction spreads derivations across all bins) — measured `Δent = +0.88` on the coherent step, swamping `Δcoh = +0.82` → clamp to 0. The free-energy "entropy descends on insight" pole is real in the **VSA-codebook world** (where `likelihood = cosine-vs-codebook` and a good match sharpens the distribution), but it does NOT transfer to the pure **term-logic arena**: there is no codebook, and any confidence-based surprise measure *anti-correlates* with coherent depth for a CORRECT epistemic reason (deep transitive conclusions genuinely ARE weakly held — "Abraham's father's…'s father is a man" is uncertain after many hops). **Fix:** `−Δent` is REMOVED from insight (`insight = clamp(Δcoh + Δwonder, 0, 1)·gate`); entropy stays in the mush **stall** term (`stall = entropy·(1−|Δcoh|)`) where its sign is CORRECT — entropy WITH a coherence change is attenuated (low stall), entropy WITHOUT coherence change IS the stall pole of mush. The asymmetry is the resolution: entropy-paired-with-coherence = insight; entropy-alone = mush. + +**The lesson banked.** (1) The size-preserving null is not ceremony — it caught a detector that scored identically on structured and random input, the exact D-SRS-3b "composite = size" failure shape, and forced the fix before the code shipped. (2) **Free-energy poles are substrate-specific:** a term borrowed from the VSA-codebook free-energy compose (`(1−likelihood)+kl`) can invert sign in the term-logic arena; port the CONCEPT (surprise descends on insight), re-derive the PROXY per substrate, and let the null falsifier arbitrate. Refs: `E-BASIN-WIDTH` (the size-preserving-null discipline), `E-WHOLE-BOOK-REASONING-RUN-1` (the arena this scores steps over), `nars/insight.rs` (`Snapshot`/`InsightMush`/`detect`/`flow_state`), `dialectic-engine-v1.md` §1 S10, `dialectic-engine-v1.md` §4 (D-DIA-V2-A). + ## 2026-07-23 — E-WHOLE-BOOK-REASONING-RUN-1 — the whole KJV ran through the ACTUAL reasoning layer (not the encode) for the first time, via the SoC seam, and it falsified two real things while validating the core. `deepnsm-v2 bible_wave --export` (inbound leg) emitted the whole-book belief stream (31,327 SPO → 21,714 distinct statements: 3,072 `is_a`/copular rows, 28,255 verb rows); `lance-graph-planner --example reason_whole_book` (reasoning layer) ingested it into a `BeliefArena` and ran copula-gated `close_transitive` + the five tactics. This is the first time the dialectic engine reasoned over a whole real corpus **Status:** FINDING (measured, reproducible: the two examples + `/tmp/pg10.txt` PG#10 KJV, local-only). **Confidence:** High on the measured results; the concept-lift and Morton-scale directions are next-work, not built. diff --git a/.claude/board/STATUS_BOARD.md b/.claude/board/STATUS_BOARD.md index 0de847105..84305b3db 100644 --- a/.claude/board/STATUS_BOARD.md +++ b/.claude/board/STATUS_BOARD.md @@ -6,7 +6,8 @@ Plan: `.claude/plans/dialectic-engine-v1.md` (six operator pillars + S1-S12 synt |---|---|---|---|---| | D-DIA-V0 | Belief arena falsifying slice (triple-keyed + in-place stamped revision + copula-gated transitivity) | lance-graph | Shipped (all 4 registered gates green first run) | `deepnsm-v2/src/belief.rs`; 90 tests + clippy clean; `E-DIALECTIC-ENGINE-SYNTHESIS-1` | | D-DIA-V1 | The five tactics (RCR/TR/ASC/CAS/CR) over the Belief arena + throttles + ReasoningGap | lance-graph | Shipped (PR #816; lance-graph-planner `nars/{belief,tactics}` over `TruthValue`; 17 nars + 233 planner tests) | plan §3, §4 | -| D-DIA-V2 | The loop: bias→recipe LUT, byte-lane council, texture window, insight/mush + null falsifier | lance-graph | Queued | plan §4 | +| D-DIA-V2-A | insight/mush S10 detector + size-preserving null falsifier | lance-graph | Shipped (`nars/insight.rs`; null falsifier caught + fixed 2 formula confounds — `E-S10-COHERENCE-CLOSURE-DENSITY-1`; 3 insight + 46 nars tests, clippy clean) | plan §1 S10, §4 | +| D-DIA-V2-B | The loop: bias→recipe tactic-LUT, byte-lane council, texture window | lance-graph | Queued | plan §4 | | D-DIA-V3 | Dissolution → field rung-elevation (the cathedral floors) + Staunen↔Wisdom flow accounting | lance-graph | Queued | plan §4 | | D-DIA-V4 | 64k SIMT lowering (Boolean-reachability semiring + second-pass truth) | lance-graph | Queued | plan §4, S1 | | D-DIA-V5 | Reach-out felt integration (dull shadow vs insight) + qualia ablation falsifier | lance-graph | Queued | plan §3.6, S12 | diff --git a/.claude/plans/dialectic-engine-v1.md b/.claude/plans/dialectic-engine-v1.md index c4c6bda39..37c157475 100644 --- a/.claude/plans/dialectic-engine-v1.md +++ b/.claude/plans/dialectic-engine-v1.md @@ -179,9 +179,49 @@ stamps) and felt form (Datapath, texture) are one event read from two buckets. > exploration), `FlowState`/`mul`, `kanban` (contract + planner > style_strategy) before wiring. Reuse the one engine; probe-first on any > "detects insight" claim. + > **✅ V2-A SHIPPED (2026-07-23):** `nars/insight.rs` — `Snapshot`/ + > `InsightMush`/`detect`/`flow_state`, reusing contract `GraphSignals` + + > `FlowState` (nothing invented). The MANDATORY null falsifier + > (`insight_beats_size_preserving_null`) did its job on the first build: + > it scored real=null=0 under the draft `clamp(Δcoh+Δwonder−Δent)` formula + > and forced a TWO-part correction (`E-S10-COHERENCE-CLOSURE-DENSITY-1`): + > (1) `coherence = closure density (derived/total)` — the `·mean_exp` + > multiplier inverted under NAL deduction attenuation (deep chains earn the + > lowest expectation); (2) `−Δentropy` REMOVED from insight (confidence- + > spread rises on every productive term-logic step — a VSA-codebook pole + > that does not transfer to term-logic); entropy's correct home is the mush + > `stall` term. Final: `insight = clamp(Δcoh+Δwonder,0,1)·[yield>θ]`. 3 + > insight + 46 nars tests green, clippy clean. NOT yet wired to a whole-book + > step (V2-A→whole-book measurement is next). THEN V2-B below. - **V3:** dissolution detection + field elevation (S11) — the cathedral floors; Staunen↔Wisdom flow accounting; epiphany attractors (rate-normalized, S9). - **V4:** the 64k SIMT lowering — Boolean-reachability semiring + truth second pass (S1), masks, sweeps — only after V0–V3 green at small scale. + > **Column size is a capacity knob, NOT a cache constant (operator, 2026-07-23).** + > The 64k column (64k×512 B = 32 MB) is a cache convenience (server-L3-resident + > working set), not an architectural constant — 256k/128 MB or 512k/256 MB are + > easily affordable. The knob to grow is column CAPACITY (rows in RAM); the + > INVARIANT knob is the Morton TILE (the swept, cache-resident unit). They + > DECOUPLE under Morton-tile top-k: you sweep one tile, never the whole column, + > so cache behavior is invariant to total column size. Morton width scales fine + > (64k axis = u16 → u32 code; 512k = u19 → u38, still u64). What growing the + > column DOES change: brute O(N²) pair enumeration goes 16×/64× worse + > (`close_transitive`'s book-scale 92k-derived / 12–17 s already shows the + > shape) — so a bigger column makes the Morton-tile top-k substrate MANDATORY, + > not optional. Column growth is affordable ONLY with the retrieval mechanism, + > which is exactly why V4 is the Morton lowering, not a wider brute sweep. + > (Distinct from the GUID cascade's per-tier 64k = 256×256 centroid tile, which + > is codebook cardinality / canon — untouched by column length.) + > **LAB ceiling = 4M rows / 2 GB (operator, 2026-07-23).** The three regimes: + > (1) **production** = 64k / 32 MB (L3-cache-resident, the hot canonical size); + > (2) **affordable growth** = 256k–512k / 128–256 MB (DRAM, still cheap); + > (3) **LAB PoC ceiling = 4M / 2 GB** (`4,194,304 × 512 B = 2 GiB` exactly) — + > the upper bound for an *exceptional* proof-of-concept, **correctness-first, + > optimize later** (the lab-vs-canonical posture applied to field size). A 4M + > field is fine to HOLD resident and prove a result over; it is NOT fine to + > brute-sweep (O(N²) = 1.6×10¹³ pairs), so even a lab PoC at 4M runs the sweep + > Morton-tiled — the ceiling raises CAPACITY, never licenses brute enumeration. + > Morton width still fits: 4M axis = u22 → u44 code (u64). The lab result is a + > falsifier; the Morton-tile top-k is the production optimization that follows. - **V5:** reach-out integration (spider/arXiv → §3.6 felt criterion) + the qualia ablation falsifier (S12). diff --git a/crates/lance-graph-planner/src/nars/insight.rs b/crates/lance-graph-planner/src/nars/insight.rs new file mode 100644 index 000000000..d70663272 --- /dev/null +++ b/crates/lance-graph-planner/src/nars/insight.rs @@ -0,0 +1,317 @@ +//! `insight` — the S10 insight-vs-mush detector over a `BeliefArena` reasoning +//! step (`.claude/plans/dialectic-engine-v1.md` §1 S10, D-DIA-V2-A). +//! +//! A reasoning STEP is a before→after pair of arena snapshots (e.g. bracketing a +//! `close_transitive` or a tactic-admit round). The detector scores whether the +//! step produced **insight** (free-energy descent — coherence and wonder rise +//! together while entropy falls, gated on a real derivation yield) or **mush** +//! (churn + stall — revision thrash with no yield, or entropy with no coherence +//! change). It **reuses the contract types** ([`GraphSignals`] for the signal +//! carrier, [`FlowState`] for the flow classification) — nothing invented. +//! +//! **This is a registered convention, NOT a proven detector.** Per the S10 +//! discipline (`E-BASIN-WIDTH`), "detects insight" is only promotable once the +//! discriminator BEATS a size-preserving null — the shuffle control in the +//! [`insight_beats_size_preserving_null`](tests) test. If a coherent arena does +//! not out-score a size-matched random rewiring, the honest finding is that S10 +//! measures SIZE, not insight (the D-SRS-3b "composite = size" collapse shape). + +use super::belief::BeliefArena; +use lance_graph_contract::mul::FlowState; +use lance_graph_contract::sensorium::GraphSignals; + +/// A snapshot of the arena's cognitive signals at one instant — the contract +/// [`GraphSignals`] (reused) plus the two scalars S10 needs that it does not +/// carry: `coherence` (how much the graph has closed into strong conclusions) +/// and `wonder` (committed contradiction depth, the Staunen/novelty pole). +#[derive(Debug, Clone, Copy)] +pub struct Snapshot { + /// The reused contract signal carrier (entropy, yield, revision-velocity, …). + pub signals: GraphSignals, + /// Coherence: **closure density** = `derived / total`. A step that closes + /// the graph into many transitive conclusions scores high; before any + /// derivation it is 0. + /// + /// **Why NOT `·mean_exp` (the null-falsifier correction, `E-S10-COHERENCE- + /// CLOSURE-DENSITY-1`):** the first draft multiplied by mean expectation + /// over the derived set. But NAL deduction *correctly* attenuates confidence + /// with chain depth, so the deepest, most-coherent chains earn the LOWEST + /// mean-expectation — the multiplier dragged coherence DOWN exactly when the + /// graph closed MOST. The `insight_beats_size_preserving_null` falsifier + /// scored real=null=0 under that proxy. Closure density is size-invariant + /// (a ratio) and discriminates chain-structure (dense closure) from random + /// rewiring (sparse closure) — which is what S10 must measure. + pub coherence: f32, + /// Wonder: mean committed contradiction depth (`|f₁−f₂|` preserved across + /// revisions) — the Staunen pole. + pub wonder: f32, +} + +impl Snapshot { + /// Read the arena into a snapshot. `revision_velocity` (revisions this step ÷ + /// steps) is supplied by the caller — it is a rate over the step, not a + /// static arena property. + #[must_use] + pub fn of(arena: &BeliefArena, revision_velocity: f32) -> Self { + Self { + signals: arena_graph_signals(arena, revision_velocity), + coherence: coherence(arena), + wonder: wonder(arena), + } + } +} + +/// Populate the contract [`GraphSignals`] from an arena read (reuse, not invent). +/// `truth_entropy` = normalized Shannon entropy of the confidence distribution; +/// `deduction_yield` = derived ÷ total; `contradiction_rate` = fraction with a +/// committed contradiction; `revision_velocity` is passed through. +#[must_use] +pub fn arena_graph_signals(arena: &BeliefArena, revision_velocity: f32) -> GraphSignals { + let n = arena.entries().len(); + let (derived, contradicted) = arena.entries().iter().fold((0usize, 0usize), |(d, c), b| { + ( + d + usize::from(b.rung >= 1), + c + usize::from(b.contradiction > 0.0), + ) + }); + GraphSignals { + contradiction_rate: ratio(contradicted, n), + truth_entropy: confidence_entropy(arena), + revision_velocity, + plasticity_flux: 0.0, + deduction_yield: ratio(derived, n), + episodic_saturation: 0.0, + } +} + +/// **Closure density** = `derived / total` (0 if none derived). Size-invariant: +/// coherent chains close densely (many transitive conclusions per observed +/// edge); random rewiring closes sparsely. See [`Snapshot::coherence`] for why +/// the `·mean_exp` multiplier was dropped (the null-falsifier confound). +#[must_use] +fn coherence(arena: &BeliefArena) -> f32 { + let n = arena.entries().len(); + if n == 0 { + return 0.0; + } + let derived = arena.entries().iter().filter(|b| b.rung >= 1).count(); + derived as f32 / n as f32 +} + +/// Mean committed contradiction depth (the Staunen/novelty pole). +#[must_use] +fn wonder(arena: &BeliefArena) -> f32 { + let n = arena.entries().len(); + if n == 0 { + return 0.0; + } + arena.entries().iter().map(|b| b.contradiction).sum::() / n as f32 +} + +/// Normalized Shannon entropy of the confidence distribution over 10 bins +/// (`[0, 1]`; 0 = a single peaked confidence, 1 = uniform spread). +#[must_use] +fn confidence_entropy(arena: &BeliefArena) -> f32 { + const BINS: usize = 10; + let n = arena.entries().len(); + if n == 0 { + return 0.0; + } + let mut hist = [0usize; BINS]; + for b in arena.entries() { + let idx = ((b.truth.confidence.clamp(0.0, 1.0) * BINS as f32) as usize).min(BINS - 1); + hist[idx] += 1; + } + let mut h = 0.0f32; + for &c in &hist { + if c > 0 { + let p = c as f32 / n as f32; + h -= p * p.log2(); + } + } + h / (BINS as f32).log2() // normalize to [0, 1] +} + +#[must_use] +fn ratio(num: usize, den: usize) -> f32 { + if den == 0 { + 0.0 + } else { + num as f32 / den as f32 + } +} + +/// The S10 score of one reasoning step. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct InsightMush { + /// `clamp(Δcoh + Δwonder, 0, 1) · [yield > θ]` — coherent closure with the + /// committed-contradiction (wonder) pole. **The `−Δent` term the plan's + /// draft carried is REMOVED** — see [`detect`] for the null-falsifier + /// correction (`E-S10-COHERENCE-CLOSURE-DENSITY-1`): confidence-spread + /// entropy RISES on every productive term-logic step, so subtracting it + /// double-penalized the reasoning insight is meant to reward. Entropy's + /// correct role is the mush `stall` term below (entropy WITHOUT coherence + /// change = mush). + pub insight: f32, + /// `0.5·churn + 0.5·stall` — `churn = revision_velocity·(1−yield)`, + /// `stall = entropy·(1−|Δcoh|)`. Entropy paired WITH a coherence change is + /// attenuated (low stall); entropy WITHOUT coherence change is the stall + /// pole of mush — the correct, asymmetric home for `truth_entropy`. + pub mush: f32, +} + +/// Score a reasoning step (S10). The `yield_theta` gate keeps insight from firing +/// on a step that produced no real derivation. +/// +/// **Null-falsifier correction (`E-S10-COHERENCE-CLOSURE-DENSITY-1`).** The +/// plan's first-draft insight was `clamp(Δcoh + Δwonder − Δent, 0, 1)·gate`. The +/// `insight_beats_size_preserving_null` probe scored real=null=0 under it, for +/// two reasons the falsifier isolated: +/// 1. coherence was `(derived/total)·mean_exp`, but NAL deduction attenuates +/// expectation with chain depth → the DEEPEST coherent chains earned the +/// LOWEST coherence. Fixed: coherence = closure density (`derived/total`). +/// 2. `−Δent` (confidence-spread Shannon) subtracts a large positive on every +/// productive step (deduction spreads confidence across bins) — a term-logic +/// confound, NOT the free-energy surprise-descent it modeled in the +/// VSA-codebook world (where likelihood = cosine-vs-codebook). REMOVED from +/// insight; entropy stays in the mush `stall` term where its sign is correct. +/// +/// The surviving discriminator is closure density: coherent chains close densely +/// (0.82 here), random rewiring sparsely — the size-invariant structural signal. +#[must_use] +pub fn detect(before: &Snapshot, after: &Snapshot, yield_theta: f32) -> InsightMush { + let d_coh = after.coherence - before.coherence; + let d_wonder = after.wonder - before.wonder; + let gate = f32::from(after.signals.deduction_yield > yield_theta); + let insight = (d_coh + d_wonder).clamp(0.0, 1.0) * gate; + + let churn = after.signals.revision_velocity * (1.0 - after.signals.deduction_yield); + let stall = after.signals.truth_entropy * (1.0 - d_coh.abs()); + let mush = 0.5 * churn + 0.5 * stall; + InsightMush { insight, mush } +} + +/// Classify a step into the contract [`FlowState`] (reused) from its S10 score. +#[must_use] +pub fn flow_state(im: &InsightMush) -> FlowState { + if im.insight > 0.5 && im.mush < 0.3 { + FlowState::Flow + } else if im.mush > 0.5 { + FlowState::Anxiety + } else if im.insight < 0.1 && im.mush < 0.2 { + FlowState::Boredom + } else { + FlowState::Transition + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::nars::{CStmt, Copula, Stamp, TruthValue}; + + fn inh(s: u16, p: u16) -> CStmt { + CStmt { + s, + cop: Copula::Inh, + p, + } + } + + /// A deterministic SplitMix64 — the size-preserving null needs reproducible + /// randomness (no clock/`rand`), like the certification-officer seed. + struct SplitMix64(u64); + impl SplitMix64 { + fn next(&mut self) -> u64 { + self.0 = self.0.wrapping_add(0x9E37_79B9_7F4A_7C15); + let mut z = self.0; + z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9); + z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB); + z ^ (z >> 31) + } + fn below(&mut self, n: u16) -> u16 { + (self.next() % n as u64) as u16 + } + } + + /// Snapshot a fresh arena over a set of `is_a` edges, run `close_transitive`, + /// and score the step (before = observed-only, after = closed). + fn score_step(edges: &[(u16, u16)]) -> InsightMush { + let mut arena = BeliefArena::new(); + for (i, &(s, p)) in edges.iter().enumerate() { + arena.observe( + inh(s, p), + TruthValue::new(0.95, 0.9), + Stamp::source(i as u32), + ); + } + let before = Snapshot::of(&arena, 0.0); + arena.close_transitive(64); + // revision_velocity ~ 0 here (pure derivation, no observation revision). + let after = Snapshot::of(&arena, 0.0); + detect(&before, &after, 0.02) + } + + /// The S10 MANDATORY gate (`E-BASIN-WIDTH`): a COHERENT arena (deep `is_a` + /// chains that close into strong conclusions) must score higher insight than + /// a SIZE-PRESERVING null (the same edge count, randomly rewired so chains + /// are destroyed). If it does not, S10 measures size, not insight. + #[test] + fn insight_beats_size_preserving_null() { + // Coherent: three long chains 0→1→…→10, 20→21→…→30, 40→41→…→50 — closure + // derives many strong transitive conclusions. + let mut coherent: Vec<(u16, u16)> = Vec::new(); + for base in [0u16, 20, 40] { + for k in 0..10u16 { + coherent.push((base + k, base + k + 1)); + } + } + let real = score_step(&coherent); + + // Size-preserving null: SAME number of edges, endpoints drawn from the + // SAME concept id pool, but randomly rewired (chains destroyed). + let n_nodes = 51u16; + let mut rng = SplitMix64(0x1234_5678); + let null_edges: Vec<(u16, u16)> = (0..coherent.len()) + .map(|_| (rng.below(n_nodes), rng.below(n_nodes))) + .collect(); + let null = score_step(&null_edges); + + // The discriminator must BEAT the size-preserving null. + assert!( + real.insight > null.insight, + "S10 must beat the size-preserving null: real insight {} vs null {} \ + (if this fails, S10 measures size, not insight)", + real.insight, + null.insight + ); + assert!(real.insight > 0.0, "a coherent step registers insight"); + } + + /// A step that derives nothing (no shared middle terms) is gated to zero + /// insight — the yield gate holds. + #[test] + fn no_yield_no_insight() { + // Disjoint edges: no chain composes. + let im = score_step(&[(1, 2), (3, 4), (5, 6)]); + assert_eq!(im.insight, 0.0, "no derivation → yield gate → 0 insight"); + assert_eq!( + flow_state(&im), + FlowState::Boredom, + "no insight, no mush → Boredom" + ); + } + + /// `arena_graph_signals` reuses the contract carrier and reads a real yield. + #[test] + fn signals_reuse_contract_carrier() { + let mut arena = BeliefArena::new(); + arena.observe(inh(1, 2), TruthValue::new(0.9, 0.9), Stamp::source(0)); + arena.observe(inh(2, 3), TruthValue::new(0.9, 0.9), Stamp::source(1)); + arena.close_transitive(8); + let sig: GraphSignals = arena_graph_signals(&arena, 0.0); + // 3 statements, 1 derived (1→3) → yield = 1/3. + assert!((sig.deduction_yield - 1.0 / 3.0).abs() < 1e-6); + assert!(sig.truth_entropy >= 0.0 && sig.truth_entropy <= 1.0); + } +} diff --git a/crates/lance-graph-planner/src/nars/mod.rs b/crates/lance-graph-planner/src/nars/mod.rs index 0a75ec198..483343a26 100644 --- a/crates/lance-graph-planner/src/nars/mod.rs +++ b/crates/lance-graph-planner/src/nars/mod.rs @@ -7,11 +7,13 @@ pub mod belief; pub mod inference; +pub mod insight; pub mod tactics; pub mod truth; pub use belief::{Belief, BeliefArena, CStmt, Copula, ReviseOutcome, Stamp}; pub use inference::NarsInference; +pub use insight::{arena_graph_signals, detect, flow_state, InsightMush, Snapshot}; pub use tactics::{ asc_challenge, cas_abstract, challenge_target, cr_synthesize, rcr_abduce, tr_diverge, AscOutcome, Candidate, Frontier, GapKind, ReasoningGap, Tactic, Throttle,