From 8376a82789447e9797b9059fa2ce1d51b31b4222 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 1 Jun 2026 00:49:18 +0000 Subject: [PATCH 1/3] docs(board): record #447 merged (D-EW64-2 landed); loop continues https://claude.ai/code/session_012SorR8UbtEvYmbX8cXftj7 --- .claude/board/AGENT_LOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.claude/board/AGENT_LOG.md b/.claude/board/AGENT_LOG.md index 6d8ab0ca8..398b70b0b 100644 --- a/.claude/board/AGENT_LOG.md +++ b/.claude/board/AGENT_LOG.md @@ -1,3 +1,11 @@ +## [Main thread / Opus, autoattended] PR #447 MERGED — D-EW64-2 + white-matter findings landed + +**#447 merged → main** (EpisodicEdges64::{promote, strongest} MRU hot-tier + E-PLANNING-IS-WHITE-MATTER + E-EW64-STRENGTH-IS-CE64-PLASTICITY + MD001 fix). Loop iteration complete: drafted → Opus review (LAND, +2 coverage tests) → CodeRabbit (1 MD001, fixed) → CI green → merged. Session auto-unsubscribed. Branch synced onto main. + +**Loop continues:** spawned a Plan agent to sequence the next UNBLOCKED, offline-testable, firewall-clean slices toward the EW64↔CE64 white-matter prefetch seam. Surreal-side stays GATED (OQ-11.6); no live-pipeline rewrites unattended. Next: execute slice 1 from the plan → review → PR. + +--- + ## [Main thread / Opus, autoattended] D-EW64-2 review (LAND) + 2 coverage tests added **Branch:** claude/jolly-cori-clnf9 | **PR #447.** Opus review agent verdict: **LAND** — no P0/P1. It re-implemented `promote` and brute-forced all 0-4-edge words × every promote target: zero invariant violations (strongest==e, no dups, eviction only on full+new, coldest==slot 3, idempotence, order preserved); packing/shift correct; firewall clean; API consistent. Applied its 2 recommended P2 coverage tests: `promote_cross_family_local_collision_is_not_deduped` (dedup discriminates on family) + `promote_chains_mru_aging_and_appends_fresh_on_non_full` (multi-promote MRU aging + fresh-on-non-full append). Left the 3rd P2 (pre-existing `to_slot` masking on contract-violating `EdgeRef` input) as out-of-scope (module-wide decision; only triggers on invalid input). From 05ae8933ea4687748575e3608b41b36db33eea80 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 1 Jun 2026 00:58:28 +0000 Subject: [PATCH 2/3] feat(contract): EW64 cold-tier read surface + DemotionSink seam (D-EW64-3, D-EW64-4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plan-agent-sequenced unblocked slices toward the white-matter connectome. D-EW64-3: EpisodicEdges64::coldest() (the eviction victim, symmetric to strongest) + contains() (family-discriminating membership). Pure zero-dep bit-reads; coldest() == the edge promote() evicts (test ties the APIs). D-EW64-4: DemotionSink trait + promote_into(e, sink) — the hot->cold exit seam. promote routing the evicted (coldest) edge to the cold connectome; impls (surreal/LanceDB-LIVE wingman, E-SUBSTRATE-IS-THE-SCHEDULER) deferred + GATED on OQ-11.6 (same dependency-inversion idiom as MailboxSoaOwner). Tested with a fake VecSink: non-full -> empty; full+fresh -> exactly coldest; chain -> age order; refire-present -> untouched. Also prepends a factual CORRECTION: E-EW64-STRENGTH's "W15 0..3 plasticity" is high_heel::Heel (container field), NOT the 64-bit CausalEdge64 (3-bit-per-plane PlasticityState). The plasticity-WRITE co-fire stays GATED (model mismatch needs user decision + causal-edge offline + I-LEGACY v1/v2 minefield); the MRU slot-order strength (D-EW64-2) is unaffected. contract lib 545 green (+10); default clippy clean; episodic_edges.rs clean at pedantic+nursery. Board: EPIPHANIES correction + AGENT_LOG + STATUS_BOARD + LATEST_STATE. https://claude.ai/code/session_012SorR8UbtEvYmbX8cXftj7 --- .claude/board/AGENT_LOG.md | 10 + .claude/board/EPIPHANIES.md | 8 + .claude/board/LATEST_STATE.md | 2 + .claude/board/STATUS_BOARD.md | 7 + .../src/episodic_edges.rs | 182 ++++++++++++++++++ 5 files changed, 209 insertions(+) diff --git a/.claude/board/AGENT_LOG.md b/.claude/board/AGENT_LOG.md index 398b70b0b..9817909ee 100644 --- a/.claude/board/AGENT_LOG.md +++ b/.claude/board/AGENT_LOG.md @@ -1,3 +1,13 @@ +## [Main thread / Opus, autoattended] D-EW64-3 + D-EW64-4 — EpisodicEdges64 cold-tier read surface + DemotionSink seam + +**Branch:** claude/jolly-cori-clnf9. **Cargo:** contract lib **545 green** (+10 episodic_edges: 6 coldest/contains + 4 promote_into); default clippy `-D warnings` clean; `episodic_edges.rs` clean at pedantic+nursery. Plan-agent-sequenced (the 2 unblocked slices of 3; slice 3 + plasticity-write + comprehension↔arcuate are GATED/needs-design — flagged for user). + +**Shipped:** `EpisodicEdges64::coldest()` (the eviction victim, symmetric to `strongest`) + `contains()` (family-discriminating membership); `DemotionSink` trait + `promote_into()` (the hot→cold exit seam — promote routing the evicted edge to the cold connectome; surreal/LanceDB-LIVE impls deferred + GATED on OQ-11.6, same dependency-inversion idiom as `MailboxSoaOwner`). Prepended the `Heel`-vs-`PlasticityState` correction (Plan agent caught my E-EW64-STRENGTH imprecision). + +**Loop:** drafted → next: Opus review agent on the diff → PR (claude/jolly-cori-clnf9 → main) → subscribe. Accumulating for morning merge. + +--- + ## [Main thread / Opus, autoattended] PR #447 MERGED — D-EW64-2 + white-matter findings landed **#447 merged → main** (EpisodicEdges64::{promote, strongest} MRU hot-tier + E-PLANNING-IS-WHITE-MATTER + E-EW64-STRENGTH-IS-CE64-PLASTICITY + MD001 fix). Loop iteration complete: drafted → Opus review (LAND, +2 coverage tests) → CodeRabbit (1 MD001, fixed) → CI green → merged. Session auto-unsubscribed. Branch synced onto main. diff --git a/.claude/board/EPIPHANIES.md b/.claude/board/EPIPHANIES.md index 6aeeb5539..2430fe274 100644 --- a/.claude/board/EPIPHANIES.md +++ b/.claude/board/EPIPHANIES.md @@ -1,3 +1,11 @@ +## 2026-06-01 — E-EW64-STRENGTH CORRECTION — "W15 0..3 plasticity" is `high_heel::Heel` (128-byte container field), NOT the 64-bit `CausalEdge64`; the 64-bit edge's plasticity is the 3-bit-per-plane `PlasticityState` + +**Status:** CORRECTION (factual, Plan-agent-grounded against source 2026-06-01). Refines `E-EW64-STRENGTH-IS-CE64-PLASTICITY`'s mechanism claim; does NOT change D-EW64-2 (MRU slot-order strength stores NO plasticity — it stands regardless). + +The original said "strength = co-addressed `CausalEdge64` plasticity (W15 0=frozen..3=hot)." Source check: the W15 byte-3 scalar 0..3 is `high_heel::Heel` (`high_heel.rs:168`, a **128-byte container field**), NOT the 64-bit `CausalEdge64`. The 64-bit edge's plasticity is `causal-edge::PlasticityState` (`plasticity.rs`) = **3 bits, one per S/P/O plane** (heat/freeze/hot_count), not a 0..3 scalar. "Co-addressed CE64 plasticity" must pick ONE model — a **USER decision**. Consequence: the **plasticity-WRITE co-fire op is GATED** on 3 counts — (1) `causal-edge` doesn't build offline (anstream uncached); (2) the Heel-scalar-vs-PlasticityState-per-plane mismatch needs user design; (3) it hits `I-LEGACY-API-FEATURE-GATED` (the v1 PLAST_SHIFT=49 vs v2=50 boundary codex caught 5× in sprint-11). D-EW64-2's MRU (slot-order = recency, no stored weight) is unaffected. The Hebbian "wire together" weight-bump waits on the user's plasticity-model decision. Cross-ref: D-EW64-2/3/4, `causal-edge::edge.rs:471/483` (v2-gated getter/setter), `I-LEGACY-API-FEATURE-GATED`. + +--- + ## 2026-05-31 — E-EW64-STRENGTH-IS-CE64-PLASTICITY — EW64's "stronger immediate edges" need no new field (strength = co-addressed CE64 plasticity + MRU slot-order); the surreal LIVE wingman is the designed orchestrator but GATED + optional **Status:** FINDING (design resolution, register-lazy). User-stated 2026-05-31 ("episodicwitness64 needs the stronger immediate edges; wingman orchestration in surrealdb in same substrate is an option"). Resolves the strength gap in `EpisodicEdges64`; weighs the surreal-same-substrate option. Feeds the queued spec `episodic-witness64-ce64-prefetch.md`. diff --git a/.claude/board/LATEST_STATE.md b/.claude/board/LATEST_STATE.md index 8d5be1c52..f83920b46 100644 --- a/.claude/board/LATEST_STATE.md +++ b/.claude/board/LATEST_STATE.md @@ -496,3 +496,5 @@ PR sequence: #360 → #361 → post-#360 substrate-sweep (this PR). ### Current Contract Inventory — new entry - **`crates/lance-graph-arm-discovery`** (NEW, **excluded** standalone zero-dep crate; build via `cargo test --manifest-path crates/lance-graph-arm-discovery/Cargo.toml`). The **Aerial+** Rust transcode (Karabulut 2025, 2504.19354v1) — the upstream runtime-data proposer leg of `streaming-arm-nars-discovery-v1`. Public surface: `encode::{FeatureSpec, Dataset}`, `rule::{Item, CandidateRule, Proposer}`, `translator::{arm_to_nars, NarsTruth, CandidateTriple, FeedProjector, DebugProjector, NARS_PERSONALITY_K}`, `ndjson::to_ndjson`, and (feature `aerial`, default-on) `aerial::{Rng, AerialAutoencoder, AerialParams, AerialProposer, extract_rules, ExtractParams}`. 35/35 tests, clippy `-D warnings` clean. Emits the `{"s","p","o","f","c"}` ndjson the SPO store loader reads; `(f,c)` == `TruthValue::new(f,c)` == `ruff_spo_triplet::Triple{f,c}`. Determinism boundary: nondeterministic AE is seeded + feature-gated + emits *proposals* only. Synergy map: `.claude/knowledge/aerial-arm-ruff-spo-codegen-synergies.md`. Status board: D-ARM-13 (Shipped on branch) + D-ARM-SYN-1/2/3 (Queued). **Not** in `lance-graph-contract` yet — `rule`/`translator` are the local seam until D-ARM-1/2 land the shared carriers. + +> **2026-06-01 — PR-in-flight (autoattended)** (D-EW64-3/4): `lance_graph_contract::episodic_edges` gains `EpisodicEdges64::{coldest, contains, promote_into}` + the `DemotionSink` trait. `coldest()` = the eviction victim (symmetric to `strongest()`); `contains()` = family-discriminating membership; `promote_into(e, sink)` = `promote` routing the evicted (coldest) edge to a `DemotionSink` — the hot→cold connectome exit. `DemotionSink` impls (surreal/LanceDB-LIVE "wingman", `E-SUBSTRATE-IS-THE-SCHEDULER`) are deferred + GATED on OQ-11.6. Zero-dep; contract lib 545 green; default clippy clean; `episodic_edges.rs` pedantic+nursery clean. diff --git a/.claude/board/STATUS_BOARD.md b/.claude/board/STATUS_BOARD.md index a9b70b722..015bc858e 100644 --- a/.claude/board/STATUS_BOARD.md +++ b/.claude/board/STATUS_BOARD.md @@ -729,3 +729,10 @@ When a new deliverable is added to a plan: When a deliverable is abandoned: 1. Edit Status → **Abandoned**. Don't remove the row. 2. Cite the replacement in Notes. + +## D-EW64-3 / D-EW64-4 (2026-06-01, autoattended) + +| D-id | deliverable | status | evidence | +|---|---|---|---| +| D-EW64-3 | `EpisodicEdges64::{coldest, contains}` — MRU cold-tier read surface | In PR | contract lib 545 green; clippy clean | +| D-EW64-4 | `DemotionSink` trait + `promote_into` — hot→cold exit seam (impls gated OQ-11.6) | In PR | contract lib 545 green; clippy clean | diff --git a/crates/lance-graph-contract/src/episodic_edges.rs b/crates/lance-graph-contract/src/episodic_edges.rs index fc4c8daeb..594720a0d 100644 --- a/crates/lance-graph-contract/src/episodic_edges.rs +++ b/crates/lance-graph-contract/src/episodic_edges.rs @@ -190,6 +190,22 @@ impl EpisodicEdges64 { (Self(raw), evicted) } + /// [`promote`](Self::promote) `e`, routing any eviction to `sink` (the cold + /// connectome). Returns the new word. When a fresh edge displaces a full + /// word the sink receives exactly the coldest edge (= [`coldest`](Self::coldest)); + /// no eviction (non-full word, or re-firing a present edge) → sink untouched. + /// This is the hot tier's defined exit into the cold tier — the contract-side + /// half of `E-SUBSTRATE-IS-THE-SCHEDULER` (the surreal/LanceDB-LIVE wingman + /// implements [`DemotionSink`], gated on OQ-11.6). + #[must_use] + pub fn promote_into(self, e: EdgeRef, sink: &mut impl DemotionSink) -> Self { + let (next, evicted) = self.promote(e); + if let Some(victim) = evicted { + sink.demote(victim); + } + next + } + /// The strongest / most-immediate edge (slot 0 under the MRU invariant), or /// `None` if the word is empty. #[must_use] @@ -197,6 +213,38 @@ impl EpisodicEdges64 { self.edge(0) } + /// The coldest / least-immediate present edge — the **last** occupied slot + /// under the MRU invariant, i.e. exactly the edge [`promote`](Self::promote) + /// will evict when a fresh edge displaces a full word. `None` if empty. + /// Symmetric to [`strongest`](Self::strongest); the cold tier peeks the + /// victim here before it falls out. + #[must_use] + pub const fn coldest(self) -> Option { + let mut last = None; + let mut i = 0; + while i < Self::CAPACITY { + if let Some(e) = self.edge(i) { + last = Some(e); + } + i += 1; + } + last + } + + /// Is `e` present in any slot? Membership discriminates `family` (so + /// `cross(3, 3)` ≠ `intra(3)`), matching [`promote`](Self::promote)'s dedup. + #[must_use] + pub fn contains(self, e: EdgeRef) -> bool { + let mut i = 0; + while i < Self::CAPACITY { + if self.edge(i) == Some(e) { + return true; + } + i += 1; + } + false + } + /// Iterate the present edges in slot order. pub fn iter(self) -> impl Iterator { (0..Self::CAPACITY).filter_map(move |i| self.edge(i)) @@ -252,6 +300,19 @@ impl EpisodicEdges64 { } } +/// Receives an edge demoted out of the hot 4-slot tier — the **cold connectome** +/// (`E-EW64-STRENGTH-IS-CE64-PLASTICITY`, `E-SUBSTRATE-IS-THE-SCHEDULER`). +/// +/// This is the stable **zero-dep seam** between the hot tier (the `EpisodicEdges64` +/// MRU word, in the SoA) and the cold tier (the full connectome). Impls — the +/// surreal-LIVE / LanceDB-LIVE "wingman" that persists and re-prefetches demoted +/// edges — are deferred and GATED on OQ-11.6; the contract owns only the seam, +/// the same dependency-inversion idiom as [`crate::soa_view::MailboxSoaOwner`]. +pub trait DemotionSink { + /// An edge aged out of the hot tier; route it to the cold connectome. + fn demote(&mut self, evicted: EdgeRef); +} + #[cfg(test)] mod tests { use super::*; @@ -497,4 +558,125 @@ mod tests { ] ); } + + #[test] + fn coldest_of_empty_is_none() { + assert_eq!(EpisodicEdges64::empty().coldest(), None); + } + + #[test] + fn coldest_of_single_equals_strongest() { + let w = EpisodicEdges64::empty() + .push(EdgeRef::intra(7).unwrap()) + .unwrap(); + assert_eq!(w.coldest(), w.strongest()); + assert_eq!(w.coldest(), EdgeRef::intra(7)); + } + + #[test] + fn coldest_of_full_word_is_last_slot() { + let mut w = EpisodicEdges64::empty(); + for k in 1..=4u16 { + w = w.push(EdgeRef::intra(k).unwrap()).unwrap(); + } + assert_eq!(w.coldest(), EdgeRef::intra(4)); // slot 3 + } + + #[test] + fn coldest_equals_promote_eviction_victim() { + // The edge coldest() names is exactly the one promote evicts when a + // fresh edge displaces a full word — ties the read + write APIs. + let mut w = EpisodicEdges64::empty(); + for k in 1..=4u16 { + w = w.push(EdgeRef::intra(k).unwrap()).unwrap(); + } + let victim = w.coldest(); + let (_w2, evicted) = w.promote(EdgeRef::intra(9).unwrap()); + assert_eq!(evicted, victim); + } + + #[test] + fn contains_present_and_absent() { + let w = EpisodicEdges64::empty() + .push(EdgeRef::intra(1).unwrap()) + .unwrap() + .push(EdgeRef::cross(2, 5).unwrap()) + .unwrap(); + assert!(w.contains(EdgeRef::intra(1).unwrap())); + assert!(w.contains(EdgeRef::cross(2, 5).unwrap())); + assert!(!w.contains(EdgeRef::intra(2).unwrap())); + } + + #[test] + fn contains_discriminates_family() { + let w = EpisodicEdges64::empty() + .push(EdgeRef::intra(3).unwrap()) + .unwrap(); + assert!(w.contains(EdgeRef::intra(3).unwrap())); + assert!( + !w.contains(EdgeRef::cross(3, 3).unwrap()), + "family is discriminated" + ); + } + + /// Test sink that records demoted edges in arrival order. + struct VecSink(Vec); + impl DemotionSink for VecSink { + fn demote(&mut self, evicted: EdgeRef) { + self.0.push(evicted); + } + } + + #[test] + fn promote_into_non_full_leaves_sink_empty() { + let mut sink = VecSink(Vec::new()); + let w = EpisodicEdges64::empty() + .push(EdgeRef::intra(1).unwrap()) + .unwrap() + .promote_into(EdgeRef::intra(2).unwrap(), &mut sink); + assert!(sink.0.is_empty(), "no eviction on a non-full word"); + assert_eq!(w.strongest(), EdgeRef::intra(2)); + } + + #[test] + fn promote_into_full_routes_coldest_to_sink() { + let mut w = EpisodicEdges64::empty(); + for k in 1..=4u16 { + w = w.push(EdgeRef::intra(k).unwrap()).unwrap(); + } + let victim = w.coldest().unwrap(); + let mut sink = VecSink(Vec::new()); + let w2 = w.promote_into(EdgeRef::intra(9).unwrap(), &mut sink); + assert_eq!(sink.0, vec![victim], "exactly the coldest is demoted"); + assert_eq!( + w2, + w.promote(EdgeRef::intra(9).unwrap()).0, + "word equals promote().0; the sink only adds routing" + ); + } + + #[test] + fn promote_into_chain_accumulates_evictees_in_age_order() { + let mut sink = VecSink(Vec::new()); + let mut w = EpisodicEdges64::empty(); + // 1..=4 fill [4,3,2,1]; 5 evicts 1; 6 evicts 2. + for k in 1..=6u16 { + w = w.promote_into(EdgeRef::intra(k).unwrap(), &mut sink); + } + assert_eq!( + sink.0, + vec![EdgeRef::intra(1).unwrap(), EdgeRef::intra(2).unwrap()] + ); + } + + #[test] + fn promote_into_refire_present_leaves_sink_untouched() { + let mut w = EpisodicEdges64::empty(); + for k in 1..=4u16 { + w = w.push(EdgeRef::intra(k).unwrap()).unwrap(); + } + let mut sink = VecSink(Vec::new()); + let _ = w.promote_into(EdgeRef::intra(2).unwrap(), &mut sink); + assert!(sink.0.is_empty(), "re-firing a present edge never demotes"); + } } From e886dc211dcc9cba0a8d2eafe307919d89588aa0 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 1 Jun 2026 01:03:30 +0000 Subject: [PATCH 3/3] refactor(contract): contains() via iter().any (CodeRabbit #448) + log review LAND MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CodeRabbit nit (low value, sound): EpisodicEdges64::contains reuses the existing iter() — self.iter().any(|x| x == e) — instead of a manual index loop. Equivalent semantics (iter yields present edges in slot order; family-discriminating via EdgeRef PartialEq), more idiomatic. Opus review verdict was LAND (no P0/P1); the two optional editorial P2s are not applied. episodic_edges tests green; default clippy -D warnings clean. https://claude.ai/code/session_012SorR8UbtEvYmbX8cXftj7 --- .claude/board/AGENT_LOG.md | 6 ++++++ crates/lance-graph-contract/src/episodic_edges.rs | 9 +-------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.claude/board/AGENT_LOG.md b/.claude/board/AGENT_LOG.md index 9817909ee..6b8765da5 100644 --- a/.claude/board/AGENT_LOG.md +++ b/.claude/board/AGENT_LOG.md @@ -1,3 +1,9 @@ +## [Main thread / Opus, autoattended] D-EW64-3/4 review LAND + CodeRabbit contains nit applied (#448) + +Opus review agent: **LAND** — no P0/P1 (exhaustively verified: coldest == eviction victim for every word, no holes, promote_into word == promote().0 + sink gets exactly the eviction; firewall + API clean; 545 green). 2 optional editorial P2s NOT applied (don't block). CodeRabbit: 1 nit (💤 low value) — `contains` → `self.iter().any(|x| x == e)` (more idiomatic, reuses iter; equivalent) — APPLIED. episodic_edges tests still green; default clippy clean. #448 CI re-runs on this push. + +--- + ## [Main thread / Opus, autoattended] D-EW64-3 + D-EW64-4 — EpisodicEdges64 cold-tier read surface + DemotionSink seam **Branch:** claude/jolly-cori-clnf9. **Cargo:** contract lib **545 green** (+10 episodic_edges: 6 coldest/contains + 4 promote_into); default clippy `-D warnings` clean; `episodic_edges.rs` clean at pedantic+nursery. Plan-agent-sequenced (the 2 unblocked slices of 3; slice 3 + plasticity-write + comprehension↔arcuate are GATED/needs-design — flagged for user). diff --git a/crates/lance-graph-contract/src/episodic_edges.rs b/crates/lance-graph-contract/src/episodic_edges.rs index 594720a0d..c6daca2ab 100644 --- a/crates/lance-graph-contract/src/episodic_edges.rs +++ b/crates/lance-graph-contract/src/episodic_edges.rs @@ -235,14 +235,7 @@ impl EpisodicEdges64 { /// `cross(3, 3)` ≠ `intra(3)`), matching [`promote`](Self::promote)'s dedup. #[must_use] pub fn contains(self, e: EdgeRef) -> bool { - let mut i = 0; - while i < Self::CAPACITY { - if self.edge(i) == Some(e) { - return true; - } - i += 1; - } - false + self.iter().any(|x| x == e) } /// Iterate the present edges in slot order.