From 9efaa341af891bdf2eb499e60e96f75042e78512 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 31 May 2026 23:23:57 +0000 Subject: [PATCH 1/5] =?UTF-8?q?docs(board):=20planning=20is=20white=20matt?= =?UTF-8?q?er=20=E2=80=94=20grey=20mailboxes=20vs=20white=20connectome=20(?= =?UTF-8?q?E-PLANNING-IS-WHITE-MATTER)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check (a): reframe the 64k-mailbox actor model. The mailboxes are GREY matter (compute) + PFC executive (MUL/planner); the CE64/EW64 plasticity connectome is WHITE matter, and planning lives THERE -- the Hebbian-wired path (fire together -> wire together) + prefetch + spreader, under PFC bias and head2head selection -- NOT OTP/BEAM scheduling (KanbanMove/VersionScheduler = grey-matter process coordination, not the planner). Unifies existing Hebbian findings (E-EW64-IS-PREDICTIVE-PREFETCH, plasticity_ counters, the §11.5 spreaders, high_heel W15 plasticity) under the grey/white lens. Honest: the white-matter mechanism is DESIGN (A3 witness_arc MISSING, OQ-11.1 spreader TBD). Seam = plasticity update + spread on the SoA EdgeColumn; arcuate.rs is the first explicit white-matter tract. https://claude.ai/code/session_012SorR8UbtEvYmbX8cXftj7 --- .claude/board/AGENT_LOG.md | 10 ++++++++++ .claude/board/EPIPHANIES.md | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/.claude/board/AGENT_LOG.md b/.claude/board/AGENT_LOG.md index c31bd9dc..4c78b29c 100644 --- a/.claude/board/AGENT_LOG.md +++ b/.claude/board/AGENT_LOG.md @@ -1,3 +1,13 @@ +## [Main thread / Opus] check (a): planning is white matter — grey mailboxes vs white connectome (E-PLANNING-IS-WHITE-MATTER) + +**Branch:** claude/jolly-cori-clnf9. Design-only check (no code) per user "check about (a)". **coexist** confirmed (512-bit ContextWindow internal + arcuate cross-boundary; wiring queued behind this check). #446 merged (LATEST_STATE/PR_ARC sweep + the few CodeRabbit comments deferred per "stay on track" — can sweep on request). + +**Finding:** the 64k mailboxes = GREY matter (compute) + PFC=MUL/planner; the CE64/EW64 plasticity connectome = WHITE matter (planning). Planning = Hebbian-wired path (fire→wire) + prefetch + spreader, under PFC/MUL bias + head2head selection — NOT OTP/`KanbanMove` scheduling. Unifies existing Hebbian findings (`E-EW64-IS-PREDICTIVE-PREFETCH`, `plasticity_counters`, §11.5 spreaders, `high_heel` W15 plasticity) under the grey/white lens and reframes the planner. + +**Honest:** the white-matter mechanism is DESIGN — A3 `witness_arc` MISSING, OQ-11.1 spreader radius/decay TBD, prefetch spine = the unbuilt EW64 reactive seam. **Seam:** plasticity update + spread on the SoA EdgeColumn. `arcuate.rs` is the first explicit white-matter tract. + +--- + ## [Main thread / Opus] arcuate connector — the Broca↔Wernicke cable carries signal (E-ARCUATE-CONDUCTION, first fix) **Branch:** claude/jolly-cori-clnf9. **Cargo:** deepnsm lib 99 green (+4 `arcuate`) + 4+8+1; `arcuate.rs` default-clippy-clean. User: "okay" → build the connector seam. diff --git a/.claude/board/EPIPHANIES.md b/.claude/board/EPIPHANIES.md index c8c822a6..96635c7e 100644 --- a/.claude/board/EPIPHANIES.md +++ b/.claude/board/EPIPHANIES.md @@ -1,3 +1,23 @@ +## 2026-05-31 — E-PLANNING-IS-WHITE-MATTER — the 64k mailboxes are GREY matter (compute); planning lives in the WHITE matter (the CE64/EW64 plasticity connectome), not in OTP/BEAM scheduling + +**Status:** FINDING (architecture reframe; unifies existing Hebbian/plasticity findings under the grey/white lens — the *mechanisms* are already on the board, the *framing* of planning is the new part). User-stated 2026-05-31 ("it doesn't make sense to have 64k OTP BEAM Erlang multithreading when you don't recognize the potential as grey vs white matter and BNN what fires together wires together"). Extends the language-network map (`E-ARCUATE-CONDUCTION`) into the cognitive substrate. Answers: "what can the mailbox SoA do about planning." + +**Grey vs white:** +- **Grey matter (compute / neurons)** = the 64k mailboxes (per-mailbox SoA: Fingerprint/Qualia/Meta columns + the `Think` compute) AND the PFC executive (`lance-graph-planner`: MUL / elevation / strategies — goal-setting + suppression). +- **White matter (connectome / axonal tracts)** = the CE64 (causal) + EW64 (episodic) EDGE columns + **plasticity** (`high_heel` W15 u8 `0=frozen..3=hot`; v2 `CausalEdge64` plasticity[2]; `sensorium.plasticity_flux`). `arcuate.rs` is the first explicit *named* tract. + +**Planning is a white-matter phenomenon, not OTP scheduling:** +- A plan = a trajectory through the mailbox population. The white matter encodes which trajectories are **myelinated** (high plasticity = well-worn = automatic). +- "Fire together → wire together" (already on board: `E-EW64-IS-PREDICTIVE-PREFETCH`, `plasticity_counters`, the prefetch spine): executing a path increments edge plasticity → consolidates it into **procedural memory** (a habit/skill). +- Planning = bias toward myelinated paths (exploitation) + the **spreader** recruiting adjacent low-plasticity edges when the goal isn't reached (exploration, OQ-11.1/§11.5) + **prefetch** making the next step resident before it's asked. NOT a DAG computed by `KanbanMove`/`VersionScheduler`. +- **Reframe:** `KanbanMove` / `VersionScheduler` / ractor = grey-matter process COORDINATION (necessary plumbing), **not the planner**. The planner IS the plasticity-weighted EW64/CE64 connectome, under PFC (MUL) bias + `head2head::SupportSpread` action-selection. + +**Why "64k OTP/BEAM concurrency" misses it:** Erlang treats processes as isolated units with explicit message passing (supervision trees). A BNN treats them as a connected population where the CONNECTIONS carry the computation. The brain is mostly white matter; a 64k-grey-node system with a thin connectome can compute in parallel but can't PLAN — planning lives in the wiring. The lever is the connectome (EW64/plasticity), not more grey-matter concurrency. + +**Honest state (the mechanism is DESIGN, not built):** A3 `witness_arc` MISSING; the Hebbian spreader radius/decay TBD (OQ-11.1, D-MBX-A4); `plasticity_counters` described not built; the prefetch spine = the unbuilt EW64 reactive seam ("every link shipped, the chain open at the joints"). The grey/white lens UNIFIES these and reframes the planner; the **buildable seam = the plasticity update + spread on the SoA EdgeColumn** (white-matter growth). Cross-ref: `E-EW64-IS-PREDICTIVE-PREFETCH`, `E-ARCUATE-CONDUCTION` (first tract), §11.5 plasticity-spreaders, OQ-11.1/11.2, `head2head`, `sensorium.plasticity_flux`, `high_heel` W15. + +--- + ## 2026-05-31 — E-ARCUATE-CONDUCTION — the stack has conduction aphasia: Broca+Wernicke intact, the arcuate cable (disambiguator_glue) carries no signal (the producer gap) — closing it IS the next wire **Status:** FINDING (diagnosis, grounded in source). Extends `E-BROCA-WERNICKE-HIPPO` to the full distributed language network (doc § "the full language network"). Names the single highest-value wire. From f396f5725c99c5242dcd9439bbedd722152d9ab6 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 1 Jun 2026 00:05:21 +0000 Subject: [PATCH 2/5] docs(board): EW64 stronger-immediate-edges = CE64 plasticity + MRU slots; surreal wingman weighed (E-EW64-STRENGTH-IS-CE64-PLASTICITY) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EpisodicEdges64 (4x EdgeRef{family,local}) has no strength field — and needs none. Strength = the co-addressed CausalEdge64 plasticity (EW64 shares CE64 low-40 bits; high_heel W15 0=frozen..3=hot); the 4 slots are an MRU hot set (slot 0 strongest, fire->promote, age->evict to cold). Register-lazy. The "wingman" = the existing E-SUBSTRATE-IS-THE-SCHEDULER: surreal LIVE over the version arc fires the promote/prefetch back into the mailbox, same substrate (cold connectome + orchestration). GATED on OQ-11.6 (surreal_container fork) but OPTIONAL — LanceDB-LIVE is the substrate-free fallback; the hot 4-edge EW64 stays in the deterministic SoA. Unblocked next = contract-side EW64 strength/MRU atom; surreal deferred to OQ-11.6. Feeds episodic-witness64-ce64-prefetch.md. https://claude.ai/code/session_012SorR8UbtEvYmbX8cXftj7 --- .claude/board/AGENT_LOG.md | 12 ++++++++++++ .claude/board/EPIPHANIES.md | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/.claude/board/AGENT_LOG.md b/.claude/board/AGENT_LOG.md index 4c78b29c..62b5ccfd 100644 --- a/.claude/board/AGENT_LOG.md +++ b/.claude/board/AGENT_LOG.md @@ -1,3 +1,15 @@ +## [Main thread / Opus] EW64 stronger-immediate-edges resolution + surreal-wingman weigh-in (E-EW64-STRENGTH-IS-CE64-PLASTICITY) + +**Branch:** claude/jolly-cori-clnf9. Design-only check (no code) per user floating the surreal-substrate option + "EW64 needs stronger immediate edges." + +**Resolution:** EW64 `EdgeRef{family,local}` has NO strength field — but needs none. Strength = the co-addressed `CausalEdge64` plasticity (W15 0=frozen..3=hot; EW64 shares CE64 low-40 bits); the 4 slots = an MRU hot set (slot 0 strongest, fire→promote, age→evict to cold). Register-lazy, no 16-bit change. + +**Surreal wingman:** = the EXISTING `E-SUBSTRATE-IS-THE-SCHEDULER` (surreal LIVE over the version arc fires the promote/prefetch back into the mailbox; same substrate holds the cold connectome + orchestration). GATED on OQ-11.6 (surreal_container fork) but OPTIONAL — LanceDB-LIVE is the substrate-free fallback. Hot 4-edge EW64 stays in the SoA (deterministic); surreal is cold+reactive only. + +**Honest:** E-ARIGRAPH-IS-AN-ISLAND gap — EW64 = 0 code symbols, Lance→surreal→kanban unbuilt, HotWitness = todo!(). Unblocked next = contract-side EW64 strength/MRU atom (no fork, offline, firewall-clean); surreal wingman deferred to OQ-11.6. Feeds queued spec episodic-witness64-ce64-prefetch.md. + +--- + ## [Main thread / Opus] check (a): planning is white matter — grey mailboxes vs white connectome (E-PLANNING-IS-WHITE-MATTER) **Branch:** claude/jolly-cori-clnf9. Design-only check (no code) per user "check about (a)". **coexist** confirmed (512-bit ContextWindow internal + arcuate cross-boundary; wiring queued behind this check). #446 merged (LATEST_STATE/PR_ARC sweep + the few CodeRabbit comments deferred per "stay on track" — can sweep on request). diff --git a/.claude/board/EPIPHANIES.md b/.claude/board/EPIPHANIES.md index 96635c7e..6aeeb553 100644 --- a/.claude/board/EPIPHANIES.md +++ b/.claude/board/EPIPHANIES.md @@ -1,3 +1,21 @@ +## 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`. + +**The gap (grounded):** `EpisodicEdges64` = 4×`EdgeRef{family:u8, local:u16}` (`episodic_edges.rs`) — NO strength / weight / recency field. "Stronger immediate edges" has no home today. + +**The register-lazy resolution (no 16-bit EdgeRef change):** EW64 already **shares CE64 low-40 bits (co-address)** — each EW64 edge co-addresses a `CausalEdge64` whose **plasticity** (`high_heel` W15 `0=frozen..3=hot`; v2 plasticity[2]) IS the edge strength. Two complementary orderings, both free: +- **strength = co-addressed CE64 plasticity** — the Hebbian weight is already there; EW64 inherits it by co-address. +- **the 4 slots = an MRU hot set** — slot 0 = strongest/most-immediate; fire → promote to slot 0 (strengthen); age → demote → evict slot 3 to the cold connectome. Slot ORDER is the ranking. No new field. + +**The wingman = the surreal LIVE scheduler (already `E-SUBSTRATE-IS-THE-SCHEDULER`):** witness fires → Lance append → surreal LIVE → promote the EW64 edge + prefetch the next into the SoA; the mailbox runs no planner loop. "Same substrate" = SurrealDB holds the **cold connectome** (all edges as graph RELATE + strength/recency) AND orchestrates the hot EW64 refresh (LIVE). The **hot 4-edge EW64 stays in the SoA** (resident, deterministic, zero-copy); SurrealDB is the cold+reactive tier, never the hot compute. + +**The option, weighed:** surreal-same-substrate is the DESIGNED goal and the right fit for cold+wingman — but GATED on `surreal_container` (OQ-11.6: fork dep + Lance 6 pin) and OPTIONAL: the design is substrate-free, so a **LanceDB-LIVE trigger is the fallback** (surreal is the goal, not a dependency). Adopting surreal is a free upgrade when OQ-11.6 clears, not a blocker. + +**Honest state + the unblocked next:** this is the `E-ARIGRAPH-IS-AN-ISLAND` gap — EW64/`SpoWitness64` = 0 code symbols; the Lance→surreal→kanban subscription unbuilt; `HotWitness` = `todo!()`. The surreal side is blocked (OQ-11.6). The UNBLOCKED, firewall-clean, offline-testable next = the **contract-side EW64 strength/ordering atom**: the hot-4 MRU semantics + CE64-plasticity-mirror strength on `EpisodicEdges64` (no fork), deferring the surreal wingman to wire when OQ-11.6 clears. **Firewall:** EW64 stores opaque `(family,local)` + co-addressed CE64; surreal would store opaque handles + strength — never COCA. Cross-ref: `E-SUBSTRATE-IS-THE-SCHEDULER`, `E-EW64-IS-PREDICTIVE-PREFETCH`, `E-PLANNING-IS-WHITE-MATTER`, `E-ARIGRAPH-IS-AN-ISLAND`, `episodic-witness64-ce64-prefetch.md` (queued spec), OQ-11.6. + +--- + ## 2026-05-31 — E-PLANNING-IS-WHITE-MATTER — the 64k mailboxes are GREY matter (compute); planning lives in the WHITE matter (the CE64/EW64 plasticity connectome), not in OTP/BEAM scheduling **Status:** FINDING (architecture reframe; unifies existing Hebbian/plasticity findings under the grey/white lens — the *mechanisms* are already on the board, the *framing* of planning is the new part). User-stated 2026-05-31 ("it doesn't make sense to have 64k OTP BEAM Erlang multithreading when you don't recognize the potential as grey vs white matter and BNN what fires together wires together"). Extends the language-network map (`E-ARCUATE-CONDUCTION`) into the cognitive substrate. Answers: "what can the mailbox SoA do about planning." From 4628132cbc2855f39f8343d346dfeb3a131eff0f Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 1 Jun 2026 00:29:23 +0000 Subject: [PATCH 3/5] =?UTF-8?q?feat(contract):=20EpisodicEdges64=20MRU=20p?= =?UTF-8?q?romote=20=E2=80=94=20Hebbian=20hot-tier=20strength=20(D-EW64-2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "Stronger immediate edges" (E-EW64-STRENGTH-IS-CE64-PLASTICITY) need no new field. EpisodicEdges64::promote(e) moves a fired edge to slot 0 (strongest / most-immediate); survivors shift down; a new edge on a full word evicts the coldest (slot 3, returned for demotion to the cold connectome); idempotent on the already-hottest edge. strongest() reads slot 0. Slot ORDER is the strength ranking — no per-edge weight stored; the co-addressed CausalEdge64 plasticity carries the Hebbian weight, recency is the slot index. This is the substrate-agnostic hot-tier mechanism the surreal-LIVE "wingman" (E-SUBSTRATE-IS-THE-SCHEDULER) will drive; that orchestration stays gated on OQ-11.6 (LanceDB-LIVE fallback exists). Zero-dep; opaque (family,local) only, no COCA. contract lib 533 green (+5); default clippy clean; episodic_edges.rs clean at pedantic+nursery. Board: STATUS_BOARD D-EW64-2 + LATEST_STATE PR-in-flight note + AGENT_LOG. https://claude.ai/code/session_012SorR8UbtEvYmbX8cXftj7 --- .claude/board/AGENT_LOG.md | 12 ++ .claude/board/LATEST_STATE.md | 4 + .claude/board/STATUS_BOARD.md | 6 + .../src/episodic_edges.rs | 132 ++++++++++++++++++ 4 files changed, 154 insertions(+) diff --git a/.claude/board/AGENT_LOG.md b/.claude/board/AGENT_LOG.md index 62b5ccfd..f5bd12ef 100644 --- a/.claude/board/AGENT_LOG.md +++ b/.claude/board/AGENT_LOG.md @@ -1,3 +1,15 @@ +## [Main thread / Opus, autoattended] D-EW64-2 — EpisodicEdges64 MRU promote (Hebbian hot-tier "stronger immediate edges") + +**Branch:** claude/jolly-cori-clnf9 (synced onto merged main; #446 merged the bifurcation+faculties+arcuate wave). **Cargo:** `cargo test -p lance-graph-contract --lib` → 533 green (+5 promote); default clippy `-D warnings` CLEAN; episodic_edges.rs clean at pedantic+nursery (the 3 pedantic errors are pre-existing in free_energy/escalation/thinking/sigma_propagation/scenario, NOT mine). Autoattended (user asleep: "draft, review, fix, PR, subscribe, repeat"). + +**Shipped:** `EpisodicEdges64::promote(self, EdgeRef) -> (Self, Option)` + `strongest()`. MRU: a fired edge moves to slot 0 (strongest/most-immediate); survivors shift down; a new edge on a full word evicts the coldest (slot 3, returned for demotion to the cold connectome); idempotent on the already-hottest edge. **Slot order IS strength** — no per-edge weight stored (co-addressed CausalEdge64 plasticity carries the Hebbian weight; recency = slot index). Realizes `E-EW64-STRENGTH-IS-CE64-PLASTICITY`. + +**Firewall:** opaque (family,local) only; no COCA; zero-dep; the surreal-LIVE wingman that will drive promote stays gated on OQ-11.6 (LanceDB-LIVE fallback) — this is the substrate-agnostic hot-tier mechanism. + +**Loop state:** drafted+committed; next = review agent (Opus) on the diff → fix → open PR (claude/jolly-cori-clnf9 → main) → subscribe. Board: STATUS_BOARD D-EW64-2 row + LATEST_STATE PR-in-flight note. + +--- + ## [Main thread / Opus] EW64 stronger-immediate-edges resolution + surreal-wingman weigh-in (E-EW64-STRENGTH-IS-CE64-PLASTICITY) **Branch:** claude/jolly-cori-clnf9. Design-only check (no code) per user floating the surreal-substrate option + "EW64 needs stronger immediate edges." diff --git a/.claude/board/LATEST_STATE.md b/.claude/board/LATEST_STATE.md index 30690c4e..8d5be1c5 100644 --- a/.claude/board/LATEST_STATE.md +++ b/.claude/board/LATEST_STATE.md @@ -10,6 +10,10 @@ --- +> **2026-06-01 — PR-in-flight (autoattended)** (D-EW64-2): `lance_graph_contract::episodic_edges::EpisodicEdges64::{promote, strongest}` — MRU "promote" strengthens an edge to slot 0 (the hot / most-immediate position); fire→front, un-refired ages toward slot 3 and evicts to the cold connectome; **slot order IS the strength ranking** (no per-edge weight stored — the co-addressed `CausalEdge64` plasticity carries the Hebbian weight, recency is the slot index). Realizes `E-EW64-STRENGTH-IS-CE64-PLASTICITY` (the user's "stronger immediate edges"). Zero-dep; contract lib 533 green (+5), default clippy clean, episodic_edges.rs pedantic+nursery clean. The surreal-LIVE "wingman" that drives `promote` stays GATED on OQ-11.6 (LanceDB-LIVE fallback exists) — this is the substrate-agnostic hot-tier mechanism it calls. + +--- + ## Recently Shipped PRs (reverse chronological) | PR | Merged | Title | What it added | diff --git a/.claude/board/STATUS_BOARD.md b/.claude/board/STATUS_BOARD.md index b8bc12b5..50c41964 100644 --- a/.claude/board/STATUS_BOARD.md +++ b/.claude/board/STATUS_BOARD.md @@ -10,6 +10,12 @@ --- +### D-EW64-2 — EpisodicEdges64 MRU promote (Hebbian hot-tier "stronger immediate edges") + +| D-id | deliverable | status | PR / evidence | +|---|---|---|---| +| D-EW64-2 | `EpisodicEdges64::{promote, strongest}` — MRU slot-order = strength; fire→slot 0, evict coldest (`E-EW64-STRENGTH-IS-CE64-PLASTICITY`) | In PR (claude/jolly-cori-clnf9) | contract lib 533 green (+5); default clippy clean | + ## Status Legend | Status | Meaning | diff --git a/crates/lance-graph-contract/src/episodic_edges.rs b/crates/lance-graph-contract/src/episodic_edges.rs index 2e3f94f5..bd6f79ec 100644 --- a/crates/lance-graph-contract/src/episodic_edges.rs +++ b/crates/lance-graph-contract/src/episodic_edges.rs @@ -145,6 +145,58 @@ impl EpisodicEdges64 { None } + /// MRU **promote** — strengthen `e` by moving it to slot 0, the *strongest / + /// most-immediate* position (`E-EW64-STRENGTH-IS-CE64-PLASTICITY`). + /// + /// If `e` is already present it moves to the front; otherwise it is inserted + /// at the front and the survivors shift down by one. When 4 *distinct* edges + /// are already present and `e` is new, the **coldest** (slot 3) is evicted — + /// demoted to the cold connectome (returned as the second tuple element). + /// + /// This is the Hebbian "fire together → wire together" at the hot tier: a + /// fired edge becomes the strongest; un-refired edges age toward slot 3 and + /// out. **Slot order is the strength ranking** (slot 0 = hottest); no per-edge + /// weight is stored here — the co-addressed `CausalEdge64` plasticity carries + /// the Hebbian weight, recency is the slot index. Idempotent on the already- + /// hottest edge (re-firing slot 0 of a full word changes nothing). + #[must_use] + pub fn promote(self, e: EdgeRef) -> (Self, Option) { + let mut slots = [0u16; Self::CAPACITY]; + slots[0] = e.to_slot(); + let mut filled = 1usize; + let mut evicted = None; + let mut i = 0; + while i < Self::CAPACITY { + if let Some(x) = self.edge(i) { + if x != e { + if filled < Self::CAPACITY { + slots[filled] = x.to_slot(); + filled += 1; + } else { + // Word was full of distinct edges and `e` is new: the + // coldest survivor (encountered last, slot 3) is evicted. + evicted = Some(x); + } + } + } + i += 1; + } + let mut raw = 0u64; + let mut s = 0; + while s < Self::CAPACITY { + raw |= u64::from(slots[s]) << (s * 16); + s += 1; + } + (Self(raw), evicted) + } + + /// The strongest / most-immediate edge (slot 0 under the MRU invariant), or + /// `None` if the word is empty. + #[must_use] + pub const fn strongest(self) -> Option { + self.edge(0) + } + /// Iterate the present edges in slot order. pub fn iter(self) -> impl Iterator { (0..Self::CAPACITY).filter_map(move |i| self.edge(i)) @@ -303,4 +355,84 @@ mod tests { assert_eq!(w.to_le_bytes()[0], 0x01); assert_eq!(w.to_le_bytes()[1], 0x00); } + + #[test] + fn promote_into_empty_sets_strongest() { + let (w, evicted) = EpisodicEdges64::empty().promote(EdgeRef::intra(7).unwrap()); + assert_eq!(w.strongest(), EdgeRef::intra(7)); + assert_eq!(w.count(), 1); + assert_eq!(evicted, None); + } + + #[test] + fn promote_existing_moves_to_front_no_evict() { + let w = EpisodicEdges64::empty() + .push(EdgeRef::intra(1).unwrap()) + .unwrap() + .push(EdgeRef::intra(2).unwrap()) + .unwrap() + .push(EdgeRef::intra(3).unwrap()) + .unwrap(); + // Promote the middle edge → moves to slot 0, survivors preserved in order. + let (w2, evicted) = w.promote(EdgeRef::intra(2).unwrap()); + assert_eq!(evicted, None); + assert_eq!(w2.strongest(), EdgeRef::intra(2)); + assert_eq!( + w2.iter().collect::>(), + vec![ + EdgeRef::intra(2).unwrap(), + EdgeRef::intra(1).unwrap(), + EdgeRef::intra(3).unwrap(), + ] + ); + } + + #[test] + fn promote_new_on_full_evicts_coldest() { + // Fill 1,2,3,4 (slot 3 = intra 4 = coldest); promote a new edge → evict it. + let mut w = EpisodicEdges64::empty(); + for k in 1..=4u16 { + w = w.push(EdgeRef::intra(k).unwrap()).unwrap(); + } + let (w2, evicted) = w.promote(EdgeRef::intra(9).unwrap()); + assert_eq!(evicted, EdgeRef::intra(4), "coldest (slot 3) is evicted"); + assert_eq!(w2.strongest(), EdgeRef::intra(9)); + assert_eq!( + w2.iter().collect::>(), + vec![ + EdgeRef::intra(9).unwrap(), + EdgeRef::intra(1).unwrap(), + EdgeRef::intra(2).unwrap(), + EdgeRef::intra(3).unwrap(), + ] + ); + } + + #[test] + fn promote_refire_hottest_is_idempotent() { + let w = EpisodicEdges64::empty() + .push(EdgeRef::intra(1).unwrap()) + .unwrap() + .push(EdgeRef::intra(2).unwrap()) + .unwrap(); + let (w2, evicted) = w.promote(EdgeRef::intra(1).unwrap()); + assert_eq!(evicted, None); + assert_eq!(w2, w, "re-firing the already-strongest edge is a no-op"); + } + + #[test] + fn promote_dedups_when_present_on_full_word() { + let mut w = EpisodicEdges64::empty(); + for k in 1..=4u16 { + w = w.push(EdgeRef::intra(k).unwrap()).unwrap(); + } + // Promote an edge already present → no eviction, no duplicate slot. + let (w2, evicted) = w.promote(EdgeRef::intra(3).unwrap()); + assert_eq!(evicted, None); + assert_eq!(w2.count(), 4, "no duplicate slot created"); + assert_eq!(w2.strongest(), EdgeRef::intra(3)); + for k in 1..=4u16 { + assert!(w2.iter().any(|e| e == EdgeRef::intra(k).unwrap())); + } + } } From 4ed17b2a9534f7bcbb945c41f955fd7af248788e Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 1 Jun 2026 00:34:36 +0000 Subject: [PATCH 4/5] test(contract): add D-EW64-2 promote coverage (cross-family dedup + MRU chain) per review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Opus review verdict LAND (no P0/P1; brute-forced all 0-4-edge words). Added its two recommended P2 coverage tests: - promote_cross_family_local_collision_is_not_deduped: dedup compares family too, so cross(3,3) and intra(3) are distinct (no dedup) despite shared local. - promote_chains_mru_aging_and_appends_fresh_on_non_full: 4 fresh promotes → [4,3,2,1]; re-fire coldest → [1,4,3,2]; fresh-on-non-full appends to front. episodic_edges 16/16 green; default clippy clean. Left the pre-existing to_slot-on-invalid-EdgeRef nit out of scope (module-wide decision; valid inputs constructed via new/intra/cross are unaffected). https://claude.ai/code/session_012SorR8UbtEvYmbX8cXftj7 --- .claude/board/AGENT_LOG.md | 8 +++ .../src/episodic_edges.rs | 62 +++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/.claude/board/AGENT_LOG.md b/.claude/board/AGENT_LOG.md index f5bd12ef..6d8ab0ca 100644 --- a/.claude/board/AGENT_LOG.md +++ b/.claude/board/AGENT_LOG.md @@ -1,3 +1,11 @@ +## [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). + +**Cargo:** episodic_edges 16/16 (+2); contract lib green; default clippy `-D warnings` clean. CI on #447 was in_progress at push; re-runs on this commit. Awaiting CI green + CodeRabbit. + +--- + ## [Main thread / Opus, autoattended] D-EW64-2 — EpisodicEdges64 MRU promote (Hebbian hot-tier "stronger immediate edges") **Branch:** claude/jolly-cori-clnf9 (synced onto merged main; #446 merged the bifurcation+faculties+arcuate wave). **Cargo:** `cargo test -p lance-graph-contract --lib` → 533 green (+5 promote); default clippy `-D warnings` CLEAN; episodic_edges.rs clean at pedantic+nursery (the 3 pedantic errors are pre-existing in free_energy/escalation/thinking/sigma_propagation/scenario, NOT mine). Autoattended (user asleep: "draft, review, fix, PR, subscribe, repeat"). diff --git a/crates/lance-graph-contract/src/episodic_edges.rs b/crates/lance-graph-contract/src/episodic_edges.rs index bd6f79ec..fc4c8dae 100644 --- a/crates/lance-graph-contract/src/episodic_edges.rs +++ b/crates/lance-graph-contract/src/episodic_edges.rs @@ -435,4 +435,66 @@ mod tests { assert!(w2.iter().any(|e| e == EdgeRef::intra(k).unwrap())); } } + + #[test] + fn promote_cross_family_local_collision_is_not_deduped() { + // Dedup compares `family` too: cross(3,3) and intra(3) share `local` + // but differ in family → distinct edges, both present, no dedup. + let w = EpisodicEdges64::empty() + .push(EdgeRef::intra(1).unwrap()) + .unwrap() + .push(EdgeRef::intra(3).unwrap()) + .unwrap(); + let (w2, evicted) = w.promote(EdgeRef::cross(3, 3).unwrap()); + assert_eq!(evicted, None); + assert_eq!(w2.count(), 3, "cross(3,3) is distinct from intra(3)"); + assert_eq!(w2.strongest(), EdgeRef::cross(3, 3)); + assert!(w2.iter().any(|e| e == EdgeRef::intra(3).unwrap())); + } + + #[test] + fn promote_chains_mru_aging_and_appends_fresh_on_non_full() { + // A fresh edge on a non-full word appends to the front (no eviction). + let (w, evicted) = EpisodicEdges64::empty() + .push(EdgeRef::intra(1).unwrap()) + .unwrap() + .push(EdgeRef::intra(2).unwrap()) + .unwrap() + .promote(EdgeRef::intra(5).unwrap()); + assert_eq!(evicted, None); + assert_eq!( + w.iter().collect::>(), + vec![ + EdgeRef::intra(5).unwrap(), + EdgeRef::intra(1).unwrap(), + EdgeRef::intra(2).unwrap(), + ] + ); + // Chain 4 fresh promotes → newest-first [4,3,2,1]; then re-fire the + // coldest (1) → it jumps to the front: [1,4,3,2], no eviction. + let mut m = EpisodicEdges64::empty(); + for k in 1..=4u16 { + m = m.promote(EdgeRef::intra(k).unwrap()).0; + } + assert_eq!( + m.iter().collect::>(), + vec![ + EdgeRef::intra(4).unwrap(), + EdgeRef::intra(3).unwrap(), + EdgeRef::intra(2).unwrap(), + EdgeRef::intra(1).unwrap(), + ] + ); + let (m2, evicted2) = m.promote(EdgeRef::intra(1).unwrap()); + assert_eq!(evicted2, None, "re-firing a present edge never evicts"); + assert_eq!( + m2.iter().collect::>(), + vec![ + EdgeRef::intra(1).unwrap(), + EdgeRef::intra(4).unwrap(), + EdgeRef::intra(3).unwrap(), + EdgeRef::intra(2).unwrap(), + ] + ); + } } From f5183b00ede253d01e798933516f1518e01bd22f Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 1 Jun 2026 00:35:20 +0000 Subject: [PATCH 5/5] docs(board): fix MD001 heading increment on D-EW64-2 row (CodeRabbit #447) STATUS_BOARD section heading was ### (h3) directly under the # (h1) title, skipping h2. CodeRabbit markdownlint MD001. Demote to ## (h2). Trivial. https://claude.ai/code/session_012SorR8UbtEvYmbX8cXftj7 --- .claude/board/STATUS_BOARD.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.claude/board/STATUS_BOARD.md b/.claude/board/STATUS_BOARD.md index 50c41964..a9b70b72 100644 --- a/.claude/board/STATUS_BOARD.md +++ b/.claude/board/STATUS_BOARD.md @@ -10,7 +10,7 @@ --- -### D-EW64-2 — EpisodicEdges64 MRU promote (Hebbian hot-tier "stronger immediate edges") +## D-EW64-2 — EpisodicEdges64 MRU promote (Hebbian hot-tier "stronger immediate edges") | D-id | deliverable | status | PR / evidence | |---|---|---|---|