From e9ca00c5ec62a53d95011f5ddc91489ff13bdb29 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 2 Jul 2026 12:45:13 +0000 Subject: [PATCH 1/4] board: post-merge hygiene for PR #630 (LATEST_STATE row + PR_ARC entry) Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01MLBnPuScZy6w9di2QEjsXM --- .claude/board/LATEST_STATE.md | 1 + .claude/board/PR_ARC_INVENTORY.md | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/.claude/board/LATEST_STATE.md b/.claude/board/LATEST_STATE.md index 082cc44f..979eb8a8 100644 --- a/.claude/board/LATEST_STATE.md +++ b/.claude/board/LATEST_STATE.md @@ -100,6 +100,7 @@ Membrane consumers can now pull BOTH halves of a render `classid` BBB-safely fro | PR | Merged | Title | What it added | |---|---|---|---| +| **#630** | 2026-07-02 | V3 W1 START: preflight deltas + WAL writer probes + adoption scan + D-PERT-1 + temporal synthesis | Fable-5 ten-point preflight (M24 board=WAL, W6a baseline inversion, W3 oracle ratchet, W2 probe-first reorder) + operator rulings folded live: zero-copy sink (cast = descriptor never bytes, flush via NodeRowPacket::as_le_bytes), "melden macht frei" (stacked casts never refused — 4 ignored probes define W1b green), temporal.rs deinterlace = the READ side (replay = QueryReference::at + deinterlace; M24/M25/time-travel are ONE mechanism; ack carries LanceVersion). Landed code: batch_writer skeleton + 4 probes; contract::classid_scan (771 green); D-PERT-1 rename (462 green). Audits: planner-SoA type-real/wiring-dormant (M15 GateDecision rename BLOCKING before W2); M7 corrected (NodeRowPacket IS production SoaEnvelope, codex P2); graph-flow benched ~0.4-0.5us/step (two-speed confirmed); M25 KanbanSessionStorage design (graph-flow-kanban envelope exists — wire don't invent). Merge `9a6df2a1`. | | **#629** | 2026-07-02 | V3 SUBSTRATE consolidated entry point (`.claude/v3/`) + ractor ownership attestation | `.claude/v3/` tree shipped: README (orientation), INTEGRATION-PLAN (W0–W6), COMPONENT-MAP (reuse/repurpose/retire), ENTROPY-MILESTONES (N→1 ledger), MODULE-TABLE (per-file census core/contract/planner), soa_layout/ (LE contract, tenant lanes, consumer map, routing), knowledge/ (substrate primer, mailbox-kanban model, sonnet-worker-guardrails), agents/BOOT.md (4 V3 cards); `/v3` skill + `/v3-audit` command; CLAUDE.md/BOOT.md ★ entrypoint. Review sharpenings folded: LE byte-order range-scan caveat, 3-shape legacy corpus scanner (incl. `0xAAAA_DDCC`), ractor helper-scope ruling (NOT messaging — slow; helper only: spawn/supervision/occasional control RPC). Ownership compile attestation: `KanbanActor` `type State = O`, owner MOVES in at pre_start; 22 supervisor tests green on the AdaWorldAPI ractor fork. Merge `28f17cd7`. | | **#628** | 2026-07-02 | classid canon:custom half-order flip EXECUTED (P0+P1+P2) | `CLASSID_ORDER = CanonHigh` live: canon `domain:appid` HIGH / custom LOW (`0x0701_1000` = `0x07:01::1000`); ONE flippable composition + `classid_canon_compat` (mint-forward both-forms reader — RBAC authorizes pre-flip rows, no re-bake); new-form mint constants + `CLASSID_*_LEGACY` aliases; hhtl dual-form fold; OGAR#95 reconciled (prefix = custom half, values unchanged); ogar pin → `19373a2` (OGAR #147 lockstep). Fleet: OGAR #147 + MedCare #180 + woa-rs #177 merged; q2 #71 + op-nexgen #68 open. Merge `6858118b`. | | **#627** | 2026-07-02 | classid canon:custom flip TRIGGERED (doc-only) | Operator ruling recorded + `classid-canon-custom-flip-v1.md` ACTIVE: canon `domain:appid` → hi u16, custom (`0x1000` temporary marker) → lo; `0x0701_1000` / `0x07:01::1000`; OSINT low byte = appid space (zero vocab rows, OGAR #146 67→65 fuse balanced); q2 gate WAIVED; ISSUES ×4 resolved/ruled; codex P2 guards locked (class_id via `classid_canon(id)` never `as u16`; legacy keys demote not retire). Merge `c8e1ec4`. | diff --git a/.claude/board/PR_ARC_INVENTORY.md b/.claude/board/PR_ARC_INVENTORY.md index 5fb26428..1ba2ee68 100644 --- a/.claude/board/PR_ARC_INVENTORY.md +++ b/.claude/board/PR_ARC_INVENTORY.md @@ -35,6 +35,22 @@ --- +## #630 lance-graph: V3 W1 START — preflight deltas, WAL-shaped writer probes, adoption-scan baseline, D-PERT-1, temporal synthesis + +**Status:** MERGED 2026-07-02 (merge commit `9a6df2a1`), branch `claude/v3-substrate-migration-review-o0yoxv`. + +**Added:** `lance-graph-planner::batch_writer` skeleton (`BatchWriter

`, `CastId`; todo! bodies) + 4 ignored probes in `tests/w1_probes.rs` (ahead-ordering, kill-after-cast replay, delegation miss-then-hit, stacked-casts-never-refused) — W1b green = fill bodies + un-ignore; `contract::classid_scan` (`ClassidForm` mirroring `classid_canon_compat`, `count_adoption`, 10 tests, zero bit math); D-PERT-1 (`ResonanceDto` → `PerturbationDto`, 8 files, deprecated alias; perspectival awareness_dto untouched); plan Addenda 1-8 + entropy rows M24 (board = WAL) / M25 (KanbanSessionStorage); rs-graph-llm sibling branch carries `dispatch_bench.rs`. + +**Locked:** cast = DESCRIPTOR never bytes; sink flushes via `NodeRowPacket::as_le_bytes` (zero-copy incl. through the writer); **melden macht frei** — the writer NEVER refuses stacked casts (WAL entries, natural coalescing via live-store reads); **temporal.rs is the read side** — replay = `QueryReference::at(v, rung)` + `deinterlace` (M24 crash-replay = M25 session-replay = time-travel, ONE mechanism); W1b `ack` carries the assigned `LanceVersion` (CastId↔LanceVersion = the WAL↔temporal join); M15 GateDecision rename BLOCKING before any planner→kanban emission; rig = oracle-frequency only (2 history clones/call); graph-flow = replayable orchestration layer (~0.4-0.5 µs/step measured), ExecTarget keeps the hot path. + +**Corrections shipped in-arc:** M7 premise ("zero production SoaEnvelope impls") FALSE — `NodeRowPacket<'a>` (canonical_node.rs:1275) is the live Lance byte path (codex #630 P2; surfaces ruled complementary); Addendum-6 mutation-freeze retracted by operator ruling (Addendum-7). + +**Deferred:** W1b implementation (fill todo!s, un-ignore probes, ack-with-LanceVersion reshape); W6a CLI wrapper + real-corpus t₀ (no classid-keyed corpora in container); W2b real-owner KanbanActor probe; M21 canon-node-bytes extraction; KanbanSessionStorage impl (W3b). + +**Docs:** `.claude/v3/INTEGRATION-PLAN.md` Addenda 1-8; EPIPHANIES E-V3-PREFLIGHT-1 (+CORRECTION), E-V3-KANBAN-SESSION-1, E-V3-PLANNER-SOA-AUDIT-1, E-V3-GRAPHFLOW-BENCH-1, E-V3-TEMPORAL-DEINTERLACE-1; ops: AdaWorldAPI/burn 403 build wall on rs-graph-llm/rig workspace roots. + +**Confidence (2026-07-02):** HIGH — contract 771 + thinking-engine 362 + shader-driver 100 green; probes compile (4 ignored by design); codex threads resolved + reacted. + ## #629 lance-graph: V3 SUBSTRATE consolidated entry point — `.claude/v3/` tree + mailbox-kanban doctrine + ractor ownership attestation **Status:** MERGED 2026-07-02 (merge commit `28f17cd7`), branch `claude/v3-substrate-migration-review-o0yoxv`. From a9ed99cb1abe57db015151df9c4c7377ec0dbe52 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 2 Jul 2026 12:51:38 +0000 Subject: [PATCH 2/4] =?UTF-8?q?feat(planner):=20W1b/W1c=20live=20=E2=80=94?= =?UTF-8?q?=20WAL=20batch=20writer=20implemented,=204=20probes=20green;=20?= =?UTF-8?q?M15=20MulGateDecision=20rename?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit W1b: BTreeMap board (monotonic CastId = cast order), ack(cast, LanceVersion) with acked_version getter (the WAL<->temporal join, Addendum-8), delegation cache, never-refuses stacking. All 4 probes un-ignored and passing. M15 (blocking-before-W2): planner-local GateDecision{Proceed,Sandbox, Compass} -> MulGateDecision + deprecated alias; contract kanban gate {Flow,Hold,Block} keeps the name; zero internal alias usage. Kills the false friend before any planner->kanban emission. Planner lib 204 green; clippy clean on all six touched files (pre-existing nars_engine.rs:492 deprecated-CausalEdge64 debt noted, untouched). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01MLBnPuScZy6w9di2QEjsXM --- crates/lance-graph-planner/src/api.rs | 2 +- .../lance-graph-planner/src/batch_writer.rs | 98 ++++++++++++------- crates/lance-graph-planner/src/lib.rs | 8 +- crates/lance-graph-planner/src/mul/gate.rs | 30 ++++-- crates/lance-graph-planner/src/mul/mod.rs | 8 +- crates/lance-graph-planner/tests/w1_probes.rs | 22 ++--- 6 files changed, 101 insertions(+), 67 deletions(-) diff --git a/crates/lance-graph-planner/src/api.rs b/crates/lance-graph-planner/src/api.rs index 0126d871..915d1c45 100644 --- a/crates/lance-graph-planner/src/api.rs +++ b/crates/lance-graph-planner/src/api.rs @@ -74,7 +74,7 @@ use crate::selector::StrategySelector; use crate::traits::*; // Re-export key types for ergonomic API -pub use crate::mul::gate::GateDecision as Gate; +pub use crate::mul::gate::MulGateDecision as Gate; pub use crate::mul::SituationInput; pub use crate::thinking::style::{FieldModulation, ScanParams, ThinkingCluster, ThinkingStyle}; pub use crate::thinking::ThinkingContext; diff --git a/crates/lance-graph-planner/src/batch_writer.rs b/crates/lance-graph-planner/src/batch_writer.rs index 1b1e9b62..436973df 100644 --- a/crates/lance-graph-planner/src/batch_writer.rs +++ b/crates/lance-graph-planner/src/batch_writer.rs @@ -1,6 +1,8 @@ //! W1b ahead-firing batch writer — the kanban board IS the write-ahead log (M24). //! -//! `cast()` records intent moves AHEAD of any storage ack; `ack()` confirms; +//! `cast()` records intent moves AHEAD of any storage ack; `ack()` confirms +//! at the `LanceVersion` the sink assigned (the CastId↔LanceVersion join +//! wiring the WAL into the temporal classifier; see `crate::temporal`); //! `unacked()` is the crash-replay surface. Payload-generic: the writer never //! inspects `P` (DTO purity — ownership rides the cast pairing, never the DTO). //! @@ -22,13 +24,19 @@ //! mint a parallel `KanbanMove`; see the D-MBX-A6 Outcome adapter context in //! `crate::strategy::style_strategy`. -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use lance_graph_contract::collapse_gate::MailboxId; use lance_graph_contract::kanban::KanbanMove; +use crate::temporal::LanceVersion; + /// Identity of one `cast()` — a write-ahead intent record on the kanban board. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +/// +/// `next_id` is monotonically increasing, so `CastId`'s derived `Ord` gives +/// insertion order — this is what lets `board`/`acked` use `BTreeMap` and +/// have `unacked()` iterate in cast order for free. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct CastId(pub u64); /// Ahead-firing batch writer: intent (`cast`) is visible on the board before @@ -40,10 +48,15 @@ pub struct BatchWriter

{ /// Board: intent moves recorded per cast, keyed by `CastId`, alongside the /// mailbox the cast was recorded on behalf of. Visible between `cast()` /// and `ack()` (and beyond, for crash-replay via `unacked()`). - board: HashMap)>, - /// Casts that have been confirmed (acked). A cast present in `board` but - /// absent from `acked` is the crash-replay surface (`unacked()`). - acked: std::collections::HashSet, + /// `BTreeMap` (not `HashMap`) so iteration is in ascending `CastId` order + /// — i.e. cast (insertion) order, matching `unacked()`'s ordering contract. + board: BTreeMap)>, + /// Casts that have been confirmed (acked), mapped to the `LanceVersion` + /// the sink assigned when it flushed — the CastId↔LanceVersion join + /// wiring the WAL into the temporal classifier (see `crate::temporal`). + /// A cast present in `board` but absent from `acked` is the crash-replay + /// surface (`unacked()`). + acked: BTreeMap, /// W1c delegation cache: `on_behalf` mailbox -> resolved owner mailbox. delegation_cache: HashMap, /// Payloads recorded per cast (payload-generic; the writer never inspects `P`). @@ -61,8 +74,8 @@ impl

BatchWriter

{ pub fn new() -> Self { Self { next_id: 0, - board: HashMap::new(), - acked: std::collections::HashSet::new(), + board: BTreeMap::new(), + acked: BTreeMap::new(), delegation_cache: HashMap::new(), pending_payloads: Vec::new(), } @@ -71,47 +84,58 @@ impl

BatchWriter

{ /// AHEAD: records the intent (moves visible on the board) BEFORE any ack. /// Returns the cast id. /// - /// Probe-first skeleton (D-V3-W1e): body pending — see - /// `tests/w1_probes.rs::probe_ahead_update_ordering` / - /// `probe_kill_after_cast_replay`. - pub fn cast(&mut self, _on_behalf: MailboxId, _moves: Vec, _payload: P) -> CastId { - todo!("W1b") + /// "Melden macht frei" (plan Addendum-7): casting is REPORTING, never + /// refused because earlier casts on the same mailbox are still unacked — + /// stacked casts are stacked WAL entries, each with its own `CastId`. + pub fn cast(&mut self, on_behalf: MailboxId, moves: Vec, payload: P) -> CastId { + let cast = CastId(self.next_id); + self.next_id += 1; + self.board.insert(cast, (on_behalf, moves)); + self.pending_payloads.push((cast, payload)); + cast } - /// Confirmation — marks the cast acked. - /// - /// Probe-first skeleton (D-V3-W1e): body pending — see - /// `tests/w1_probes.rs::probe_ahead_update_ordering`. - pub fn ack(&mut self, _cast: CastId) { - todo!("W1b") + /// Confirmation — marks the cast acked at the Lance version the sink + /// assigned (the CastId↔LanceVersion join wiring the WAL into the + /// temporal classifier; see planner `temporal.rs`). + pub fn ack(&mut self, cast: CastId, version: LanceVersion) { + self.acked.insert(cast, version); } - /// Crash-replay surface (M24): casts recorded but not yet acked. - /// - /// Probe-first skeleton (D-V3-W1e): body pending — see - /// `tests/w1_probes.rs::probe_kill_after_cast_replay`. + /// The `LanceVersion` a cast was acked at, if it has been acked. + #[must_use] + pub fn acked_version(&self, cast: CastId) -> Option { + self.acked.get(&cast).copied() + } + + /// Crash-replay surface (M24): casts recorded but not yet acked, in + /// ascending `CastId` (cast) order. + #[must_use] pub fn unacked(&self) -> Vec { - todo!("W1b") + self.board + .keys() + .filter(|cast| !self.acked.contains_key(cast)) + .copied() + .collect() } /// Board read: intent moves recorded for a cast (visible between cast and ack). - /// - /// Probe-first skeleton (D-V3-W1e): body pending — see - /// `tests/w1_probes.rs::probe_ahead_update_ordering` / - /// `probe_kill_after_cast_replay`. - pub fn intent_moves(&self, _cast: CastId) -> Option<&[KanbanMove]> { - todo!("W1b") + #[must_use] + pub fn intent_moves(&self, cast: CastId) -> Option<&[KanbanMove]> { + self.board.get(&cast).map(|(_, moves)| moves.as_slice()) } /// W1c delegation cache: resolve an owner once, cache; returns `(owner, was_cache_hit)`. - /// - /// Probe-first skeleton (D-V3-W1e): body pending — see - /// `tests/w1_probes.rs::probe_delegation_miss_then_hit`. pub fn resolve_owner( &mut self, - _on_behalf: MailboxId, - _resolver: impl FnOnce(MailboxId) -> MailboxId, + on_behalf: MailboxId, + resolver: impl FnOnce(MailboxId) -> MailboxId, ) -> (MailboxId, bool) { - todo!("W1c") + if let Some(&owner) = self.delegation_cache.get(&on_behalf) { + return (owner, true); + } + let owner = resolver(on_behalf); + self.delegation_cache.insert(on_behalf, owner); + (owner, false) } } diff --git a/crates/lance-graph-planner/src/lib.rs b/crates/lance-graph-planner/src/lib.rs index 8e291668..d61c0aee 100644 --- a/crates/lance-graph-planner/src/lib.rs +++ b/crates/lance-graph-planner/src/lib.rs @@ -93,7 +93,7 @@ pub mod temporal; mod orchestration_impl; use ir::LogicalPlan; -use mul::{GateDecision, MulAssessment}; +use mul::{MulAssessment, MulGateDecision}; use selector::StrategySelector; use thinking::ThinkingContext; use traits::{PlanContext, PlanStrategy, QueryFeatures}; @@ -181,7 +181,7 @@ impl PlannerAwareness { let gate = mul::gate_check(&mul_assessment); match gate { - GateDecision::Proceed { free_will_modifier } => { + MulGateDecision::Proceed { free_will_modifier } => { // === LAYER 2: THINKING ORCHESTRATION === let thinking_ctx = thinking::orchestrate(query, &mul_assessment, &plan::PlannerConfig::default()); @@ -219,8 +219,8 @@ impl PlannerAwareness { emitted_edges: Vec::new(), }) } - GateDecision::Sandbox { reason } => Err(PlanError::GateBlocked { reason }), - GateDecision::Compass => { + MulGateDecision::Sandbox { reason } => Err(PlanError::GateBlocked { reason }), + MulGateDecision::Compass => { let compass = mul::compass::navigate(query, &mul_assessment); match compass.decision { mul::compass::CompassDecision::SurfaceToMeta => Err(PlanError::SurfaceToMeta { diff --git a/crates/lance-graph-planner/src/mul/gate.rs b/crates/lance-graph-planner/src/mul/gate.rs index ee3f4d95..f5e326a5 100644 --- a/crates/lance-graph-planner/src/mul/gate.rs +++ b/crates/lance-graph-planner/src/mul/gate.rs @@ -10,8 +10,13 @@ use super::{dk::DkPosition, homeostasis::FlowState, trust::TrustTexture, MulAssessment}; /// Gate decision. +/// +/// Renamed from `GateDecision` (M15) — this is the planner's +/// Meta-Uncertainty-Layer verdict (Proceed/Sandbox/Compass), NOT the +/// contract's kanban gate (`lance_graph_contract::mul::GateDecision +/// {Flow, Hold, Block}`) which `KanbanColumn::advance_on_gate` consumes. #[derive(Debug, Clone)] -pub enum GateDecision { +pub enum MulGateDecision { /// All checks pass. Proceed with free will modifier applied. Proceed { free_will_modifier: f64 }, /// Gate blocked. Need sandbox or human assistance. @@ -20,25 +25,32 @@ pub enum GateDecision { Compass, } +/// Renamed to `MulGateDecision` (M15); the unqualified name collided with +/// `lance_graph_contract::mul::GateDecision`. +#[deprecated( + note = "renamed to MulGateDecision (M15); the unqualified name collided with contract mul::GateDecision" +)] +pub type GateDecision = MulGateDecision; + /// Check the gate conditions. -pub fn check(assessment: &MulAssessment) -> GateDecision { +pub fn check(assessment: &MulAssessment) -> MulGateDecision { // Check 1: Not Mount Stupid if assessment.dk_position == DkPosition::MountStupid { - return GateDecision::Sandbox { + return MulGateDecision::Sandbox { reason: "Dunning-Kruger: Mount Stupid detected. Learn first.".into(), }; } // Check 2: Complexity mapped if !assessment.complexity_mapped { - return GateDecision::Sandbox { + return MulGateDecision::Sandbox { reason: "Complexity not mapped. Map dimensions before proceeding.".into(), }; } // Check 3: Not depleted if assessment.homeostasis.needs_recovery { - return GateDecision::Sandbox { + return MulGateDecision::Sandbox { reason: "Depleted. Recover homeostasis first.".into(), }; } @@ -46,10 +58,10 @@ pub fn check(assessment: &MulAssessment) -> GateDecision { // Check 4: Trust not murky/dissonant match assessment.trust.texture { TrustTexture::Murky => { - return GateDecision::Compass; // Can navigate with compass + return MulGateDecision::Compass; // Can navigate with compass } TrustTexture::Dissonant => { - return GateDecision::Sandbox { + return MulGateDecision::Sandbox { reason: "Trust dissonant. Resolve dissonance before proceeding.".into(), }; } @@ -58,11 +70,11 @@ pub fn check(assessment: &MulAssessment) -> GateDecision { // Check 5: If trust is fuzzy, use compass for navigation if assessment.trust.texture == TrustTexture::Fuzzy { - return GateDecision::Compass; + return MulGateDecision::Compass; } // All checks pass - GateDecision::Proceed { + MulGateDecision::Proceed { free_will_modifier: assessment.free_will_modifier, } } diff --git a/crates/lance-graph-planner/src/mul/mod.rs b/crates/lance-graph-planner/src/mul/mod.rs index 166ce020..c50e4a21 100644 --- a/crates/lance-graph-planner/src/mul/mod.rs +++ b/crates/lance-graph-planner/src/mul/mod.rs @@ -23,7 +23,7 @@ pub mod trust; pub use compass::{CompassDecision, CompassResult}; pub use dk::{DkDetector, DkPosition}; -pub use gate::GateDecision; +pub use gate::MulGateDecision; pub use homeostasis::{FlowState, Homeostasis}; pub use trust::{TrustQualia, TrustTexture}; @@ -123,7 +123,7 @@ pub fn assess(input: &SituationInput) -> MulAssessment { } /// Gate check: determine whether to proceed, sandbox, or use compass. -pub fn gate_check(assessment: &MulAssessment) -> GateDecision { +pub fn gate_check(assessment: &MulAssessment) -> MulGateDecision { gate::check(assessment) } @@ -152,7 +152,7 @@ mod tests { let gate = gate_check(&assessment); // Mount Stupid should block - matches!(gate, GateDecision::Sandbox { .. }); + matches!(gate, MulGateDecision::Sandbox { .. }); } #[test] @@ -171,6 +171,6 @@ mod tests { let assessment = assess(&input); let gate = gate_check(&assessment); - matches!(gate, GateDecision::Proceed { .. }); + matches!(gate, MulGateDecision::Proceed { .. }); } } diff --git a/crates/lance-graph-planner/tests/w1_probes.rs b/crates/lance-graph-planner/tests/w1_probes.rs index cff4b636..09e02373 100644 --- a/crates/lance-graph-planner/tests/w1_probes.rs +++ b/crates/lance-graph-planner/tests/w1_probes.rs @@ -1,9 +1,8 @@ -//! D-V3-W1e probe-first: three failing probes for the W1b ahead-firing batch -//! writer + W1c delegation cache, pinned against +//! D-V3-W1e probe-first: four probes for the W1b ahead-firing batch writer + +//! W1c delegation cache, pinned against //! `lance_graph_planner::batch_writer::BatchWriter`. //! -//! All three are `#[ignore]`d — the writer's methods are `todo!()` stubs. -//! Un-ignore in the W1b implementation commit once the bodies are filled in. +//! Live (W1b implementation landed) — all four run and pass. //! //! Uses the REAL shipped kanban contract types //! (`lance_graph_contract::kanban::{KanbanColumn, KanbanMove, ExecTarget}`, @@ -29,7 +28,6 @@ fn make_move(mailbox: u32, from: KanbanColumn, to: KanbanColumn, witness: u32) - /// Probe 1 (W1b): cast() makes intent moves visible on the board AHEAD of any /// ack; ack() then removes the cast from unacked(). #[test] -#[ignore = "probe-first: W1b mechanism pending — un-ignore in the W1b implementation commit"] fn probe_ahead_update_ordering() { let mut writer: BatchWriter<()> = BatchWriter::new(); @@ -44,16 +42,18 @@ fn probe_ahead_update_ordering() { // AHEAD: intent is visible on the board BEFORE any ack. assert_eq!(writer.intent_moves(cast), Some(moves.as_slice())); - writer.ack(cast); + writer.ack(cast, 1); // After ack, the cast is no longer in the unacked (crash-replay) surface. assert!(!writer.unacked().contains(&cast)); + + // The CastId<->LanceVersion join: the ack recorded the assigned version. + assert_eq!(writer.acked_version(cast), Some(1)); } /// Probe 2 (M24): a cast that is never acked stays on the crash-replay /// surface (`unacked()`), and its intent moves remain replayable. #[test] -#[ignore = "probe-first: W1b mechanism pending — un-ignore in the W1b implementation commit"] fn probe_kill_after_cast_replay() { let mut writer: BatchWriter<()> = BatchWriter::new(); @@ -81,7 +81,6 @@ fn probe_kill_after_cast_replay() { /// a mailbox (cache miss) and skips it on the second lookup for the same /// mailbox (cache hit), returning the same owner both times. #[test] -#[ignore = "probe-first: W1b mechanism pending — un-ignore in the W1b implementation commit"] fn probe_delegation_miss_then_hit() { let mut writer: BatchWriter<()> = BatchWriter::new(); @@ -113,7 +112,6 @@ fn probe_delegation_miss_then_hit() { /// for a row — is sink-side behavior, exercised in the W1b implementation /// tests, not at this API surface.) #[test] -#[ignore = "probe-first: W1b mechanism pending — un-ignore in the W1b implementation commit"] fn probe_stacked_casts_never_refused() { let mut writer: BatchWriter<()> = BatchWriter::new(); @@ -135,9 +133,9 @@ fn probe_stacked_casts_never_refused() { assert!(writer.intent_moves(c3).is_some()); // Acks retire independently and in any order. - writer.ack(c2); + writer.ack(c2, 1); assert_eq!(writer.unacked(), vec![c1, c3]); - writer.ack(c1); - writer.ack(c3); + writer.ack(c1, 2); + writer.ack(c3, 3); assert!(writer.unacked().is_empty()); } From 7842803ff243e013a6ac9cb427af3f076c537330 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 2 Jul 2026 12:51:39 +0000 Subject: [PATCH 3/4] board: W1b/W1c -> In PR; M15 resolved Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01MLBnPuScZy6w9di2QEjsXM --- .claude/board/STATUS_BOARD.md | 4 ++-- .claude/v3/ENTROPY-MILESTONES.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.claude/board/STATUS_BOARD.md b/.claude/board/STATUS_BOARD.md index a4e80035..32b68225 100644 --- a/.claude/board/STATUS_BOARD.md +++ b/.claude/board/STATUS_BOARD.md @@ -7,8 +7,8 @@ Plan: `.claude/v3/INTEGRATION-PLAN.md` (stub: `.claude/plans/v3-substrate-integr | D-V3-W0a | `.claude/v3/` tree (README, plan, COMPONENT-MAP, ENTROPY-MILESTONES, MODULE-TABLE, soa_layout/*) | docs | Shipped (this PR) | complete: 7/7 mappers synthesized; MODULE-TABLE = 304/304 files (21/21 census chunks); soa_layout 5/5 docs | | D-V3-W0b | V3 awareness layer (knowledge docs, v3-* agent cards, /v3 skill, /v3-audit command, CLAUDE.md+BOOT.md entrypoints) | docs | Shipped (this PR) | 4 knowledge docs, 4 cards, skill+command registered | | D-V3-W1a | SoaEnvelope::mailbox_owner() ownership stamp | lance-graph-contract | Shipped | this branch; 775 contract tests green | -| D-V3-W1b | Ahead-firing batch writer (cast pairing + AHEAD KanbanMove at cast) | planner-adjacent | In progress | W1 STARTED 2026-07-02; WAL-shaped per preflight addendum (M24: cast = intent record) | -| D-V3-W1c | Delegation cache (cast id vs envelope stamp) | batch writer | In progress | W1 STARTED 2026-07-02; collapses into W1b writer (M24) | +| D-V3-W1b | Ahead-firing batch writer (cast pairing + AHEAD KanbanMove at cast) | planner-adjacent | In PR | W1 STARTED 2026-07-02; WAL-shaped per preflight addendum (M24: cast = intent record) | +| D-V3-W1c | Delegation cache (cast id vs envelope stamp) | batch writer | In PR | W1 STARTED 2026-07-02; collapses into W1b writer (M24) | | D-V3-W1d | MailboxId minting path (non-zero owners, uniqueness debug_assert) | contract | In progress | W1 STARTED 2026-07-02 | | D-V3-W1e | Probes: ahead-update ordering + delegation miss | contract/planner | In PR | W1 STARTED 2026-07-02; probe lands FIRST (probe-first gate) + kill-after-cast replay test (M24) | | D-V3-W2a | Per-mailbox kanban board as TENANT | contract | Queued | field-isolation matrix mandatory | diff --git a/.claude/v3/ENTROPY-MILESTONES.md b/.claude/v3/ENTROPY-MILESTONES.md index 6eb43e9d..bbb822c6 100644 --- a/.claude/v3/ENTROPY-MILESTONES.md +++ b/.claude/v3/ENTROPY-MILESTONES.md @@ -37,7 +37,7 @@ | M12 | 2 budget concepts (elevation `PatienceBudget` per-strategy vs the −550_000 µs Libet anchor per-cycle) | one budget allocator (elevation extended as the 550 ms scheduler, W2d) | elevation reads/writes the Libet anchor; doc cross-ref both ways | QUEUED (W2d) | | M13 | 2 "OGAR action" concepts (elixir_template::OgarAction enum vs contract `action::ActionDef`+CapabilityExecutor RBAC gate) | keep BOTH (different jobs) — collapse the NAME ambiguity via explicit disambiguation in every doc/brief | guardrails §2 row (done) + compiled-templates.md disambiguation; grep unqualified "OGAR action" in briefs = zero | IN-FLIGHT (doc-side done this PR) | | M14 | 3 `BindSpace` concepts (shader-driver singleton SoA; ladybug 8:8 dispatch table; graph/spo/merkle store) + stale "BindSpace" prose | scoped names; shader singleton RETIRES (M4); prose sweep to MailboxSoA vocabulary | grep bare `BindSpace` in doc comments describing per-mailbox mechanisms = zero | QUEUED (doc sweep + W7) | -| M15 | 2 `GateDecision` types (mul::{Flow,Hold,Block} live kanban gate vs collapse_gate::{gate,merge} write-merge) — the documented GATE-1 clash + 3 "CollapseGate" vocabulary users | rename the write-merge one (e.g. `WriteMergeGate`) and/or the dispersion op (`ResonanceDispersionGate`); mul::GateDecision keeps the name | grep `GateDecision` resolves to ONE type per import; cycle_accumulator GATE-1 note closed | RULING-NEEDED (rename choice) | +| M15 | 2 `GateDecision` types (mul::{Flow,Hold,Block} live kanban gate vs collapse_gate::{gate,merge} write-merge) — the documented GATE-1 clash + 3 "CollapseGate" vocabulary users | rename the write-merge one (e.g. `WriteMergeGate`) and/or the dispersion op (`ResonanceDispersionGate`); mul::GateDecision keeps the name | grep `GateDecision` resolves to ONE type per import; cycle_accumulator GATE-1 note closed | RESOLVED 2026-07-02: planner-local renamed MulGateDecision + deprecated alias (M15 worker; contract kanban gate keeps name; collapse_gate FLOW_XOR confirmed a THIRD distinct type, engine_bridge consumer) — grep GateDecision now resolves uniquely per import | | M16 | 3 independently-invented fail-closed deferral patterns (RuntimeError::NotImplemented / EquivalenceClass::Failure-note / CompileError::NotImplemented) | one documented convention (not a new abstraction) | a §-note in compiled-templates.md naming the pattern; new deferrals cite it | QUEUED (doc-only) | | M17 | 2 control-flow vocabularies with a FALSE 1:1 claim (graph-flow NextAction×6 vs template linear-only) | honest mapping: Step↔Task + ogar_name()↔Task::id(); control flow closed by StepMask/ControlSignal (W3a/b) | adapter tests replay a template with WaitForInput/End/GoTo semantics; compiled-templates.md corrected (this PR) | IN-FLIGHT (doc corrected; code W3) | | M18 | 2 lifecycle vocabularies (planner sigma chain Ω→Δ→Φ→Θ→Λ vs KanbanColumn 6 phases) with no documented mapping | a documented mapping (or an explicit "orthogonal" ruling) | one table in mailbox-kanban-model.md; both modules cross-ref it | RULING-NEEDED | From 563f560a08d12cfc8b31cf80f09277f690dce83a Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 2 Jul 2026 13:18:45 +0000 Subject: [PATCH 4/4] =?UTF-8?q?docs(v3):=20W3c=20oracle=20measured=20live?= =?UTF-8?q?=20=E2=80=94=201-2=20ms=20framework=20overhead=20vs=208.4-8.7?= =?UTF-8?q?=20s=20LLM=20round=20trip=20(Addendum-9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Live rig(xai)->FlowRunner oracle-node run; self-hosted JITSON serve.rs test-bench delta recorded; rs-graph-llm design-intent + GraphRAG-rs references folded. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01MLBnPuScZy6w9di2QEjsXM --- .claude/board/EPIPHANIES.md | 5 +++++ .claude/v3/INTEGRATION-PLAN.md | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/.claude/board/EPIPHANIES.md b/.claude/board/EPIPHANIES.md index 839c1568..796865d5 100644 --- a/.claude/board/EPIPHANIES.md +++ b/.claude/board/EPIPHANIES.md @@ -1,3 +1,8 @@ +## 2026-07-02 — E-V3-ORACLE-LIVE-1: W3c oracle node measured LIVE — graph-flow overhead is 1-2 ms against an 8.4-8.7 s LLM round trip +**Status:** FINDING (live run, rig 0.39 xai provider, 3 calls ~$0.02; harness in session scratchpad, reproducible) + +Live numbers (this container, via HTTPS proxy, XAI_API_KEY): T1 direct grok-3-mini connectivity smoke 2958 ms ("OK"). T2/T3: the W3c oracle-node shape — a graph_flow::Task whose run() consults a rig agent (grok-4-0709, max_tokens 64, FailureTicket pronoun-disambiguation prompt) — executed through GraphBuilder + FlowRunner + InMemorySessionStorage: e2e 8660/8406 ms, API 8658/8405 ms, **framework overhead 2/1 ms**. Both runs Completed; the oracle answered the disambiguation correctly ("it" = the board, animacy reasoning). Verdict: the orchestration layer costs SIX orders of magnitude less than the oracle call it wraps — W3c's budget is purely the LLM round trip (seconds), reinforcing oracle-frequency-only (never per-transition) and the two-speed split. Ergonomics: the whole oracle node is ~30 lines; three frictions: rig-core's lib name is rig_core (not rig), .agent() needs the rig_core::client::CompletionClient trait in scope, errors map via graph_flow::GraphError::TaskExecutionFailed. Operator references folded: (a) rs-graph-llm IS the LangGraph-inspired Rig-integrated stateful/interruptible handler by design (author's framing; the queue-vs-state debate in that thread is answered in V3 by the kanban board being BOTH — WAL intent log + state); (b) GraphRAG-rs (automataIA/graphrag-rs) noted as RAG-side prior art with native LanceDB/Arrow support, Leiden, LightRAG, cAST tree-sitter chunking — candidate reference for the retrieval stages, not a dependency decision; (c) test-bench delta: planner serve.rs (Axum, OpenAI-compatible /v1/chat/completions, JITSON behind it) can serve as a LOCAL zero-cost oracle endpoint via rig's openai-compatible provider + graceful retry — the self-hosted langgraph test bench for CI (no external key, no spend). + ## 2026-07-02 — E-V3-TEMPORAL-DEINTERLACE-1: temporal.rs is the read side of the WAL ruling — replay = a read at a pinned QueryReference **Status:** FINDING (operator pointer to planner temporal.rs; unifies M24 + M25 with the deinterlace machinery) diff --git a/.claude/v3/INTEGRATION-PLAN.md b/.claude/v3/INTEGRATION-PLAN.md index 5bef919c..66d6f0c4 100644 --- a/.claude/v3/INTEGRATION-PLAN.md +++ b/.claude/v3/INTEGRATION-PLAN.md @@ -328,3 +328,20 @@ Operator: "check temporal.rs for a deeper understanding." Verified against dispatchable = time-admitted AND data-ready — the standing rule "updates reprioritize, never gate" holds because a data-blocked row is dropped from the PROJECTION, not refused at the writer. + +### Addendum-9 2026-07-02 — W3c oracle measured LIVE + the self-hosted test bench + +- **Live numbers** (rig xai, grok-4-0709 oracle through FlowRunner): + framework overhead **1-2 ms** vs **8.4-8.7 s** LLM round trip. W3c's + budget IS the LLM call; orchestration is free. Full data: + E-V3-ORACLE-LIVE-1. +- **Test-bench delta (operator):** wire rig's OpenAI-compatible provider + at the planner's serve.rs (`/v1/chat/completions`, JITSON behind it) + as the LOCAL oracle for CI — zero external spend, no key, graceful + retry wrapping for a typical langchain-style bench. Lands with W3b's + KanbanSessionStorage tests. +- **References:** rs-graph-llm's stated design (LangGraph-inspired, + Rig-integrated, interruptible-by-design, step-by-step default) matches + the W3b role exactly; the thread's queue-vs-stateful debate is resolved + in V3 by the kanban board being both (M24 WAL + state). GraphRAG-rs + noted as RAG prior art (native LanceDB/Arrow, Leiden, LightRAG, cAST).