Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions .claude/board/EPIPHANIES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,59 @@
## 2026-06-06 — E-DEINTERLACE-TWO-SCALES — deinterlace is one operation at two scales; no-cross-cycle-lag = byte-scale deinterlace

**Status:** FINDING (source-grounded; `temporal.rs` PR #468 confirms row-scale; byte-scale is a documented gap)
**Confidence:** High

**The synthesis:** temporal causality in the SoA system must be enforced at two
independent scales that share the same monotonic clock:

```text
Row/query scale → HLC tick + DependsClosure → temporal.rs::deinterlace() (SHIPPED, PR #468)
Byte/column scale → SoaEnvelope::cycle() stamp → MailboxSoA Arc-swap COW (GAP — plan written)
```

Both are the SAME operation — "sort by the causal clock and project the result
into the reader's reference frame" — but at different granularities.

**Row scale (PR #468 confirms):**
`temporal.rs:18-20` defines the standing wave correctly: "merge-sort by HLC
tick and every field's row lands on one timeline. The result IS the standing
wave / kanban SoA." The `deinterlace()` function + `EpistemicMode` (Strict /
Aware / Retro) + `DependsClosure` implement this. 8 tests pass.

**Byte scale (current gap):**
Nothing in the codebase prevents a reader from holding column data from SoA
cycle N and cycle N+1 in the same SIMD sweep. The `SoaEnvelope::cycle()` stamp
exists but is not enforced as a snapshot barrier.

**The fix (plan: `cycle-coherent-soa-snapshot-v1.md`):**
Arc-swap COW at column granularity in `MailboxSoa::advance_phase`:
1. Writer increments `cycle`, then swaps the `Arc<[u8]>` of each mutated column.
2. Reader snapshots all column Arcs under one cycle stamp (lock-free retry).
3. The resulting `MailboxSoaSnapshot { cycle, cols }` is structurally coherent.

**The boundary:**
`MultiLaneColumn` in ndarray stays layout-only. The Arc-swap policy lives in
lance-graph's `MailboxSoa`. ndarray does not learn that cycles exist.

**The clock is one clock:**
`SoaEnvelope::cycle()` (byte scale) and `QueryReference::ref_version` (row
scale) are the same monotonic sequence. Threading `snapshot.cycle` into
`QueryReference` closes the loop: row-scale and byte-scale deinterlace use
the same clock.

**Standing wave clarification (Q3 probe result):**
The "standing wave" is NOT a compute recurrence. It is the deinterlaced
projection over Lance versions — provided by Lance versioning itself (O(1)
90° lookup). Do not implement a standing wave in compute.

**Cross-ref:**
- PR #468 (`temporal.rs`) — row-scale (SHIPPED)
- PR #477 (`soa_envelope.rs`) — envelope contract (IN REVIEW)
- `.claude/plans/cycle-coherent-soa-snapshot-v1.md` — byte-scale fix plan
- `docs/probes/q3-standing-wave-falsification.md` — probe confirming no wave in compute

---

## 2026-06-04 — E-AUDIT-RETENTION-CAVEAT — substrate-b consumer doc Lance-versions-as-audit claim was overstated; corrected to retention-policy-gated (codex P1 on #465)

**Status:** CORRECTION (codex P1 on PR #465, 2026-06-04; merged + immediate follow-up correction per the no-silent-edit discipline — the FIX appends; the original epiphany E-SUBSTRATE-B-CAPABILITY-ROADMAP stands as the corrected reference now reads).
Expand Down
16 changes: 16 additions & 0 deletions .claude/board/INTEGRATION_PLANS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
## 2026-06-06 — cycle-coherent-soa-snapshot-v1 (Arc-swap COW at column granularity; byte-scale deinterlace; no-cross-cycle-lag guarantee)

**Status:** QUEUED. Design-spec only, no code. **Plan file:** `.claude/plans/cycle-coherent-soa-snapshot-v1.md`.
**Owns:** 6 deliverables D-SOA-SNAP-1..6.
- D-SOA-SNAP-1: `MailboxSoaSnapshot` type in lance-graph-contract
- D-SOA-SNAP-2: `SnapshotProvider` trait in lance-graph-contract
- D-SOA-SNAP-3: Arc-swap write path in `MailboxSoa::advance_phase`
- D-SOA-SNAP-4: `snapshot()` impl on `MailboxSoa`
- D-SOA-SNAP-5: No-cross-cycle-lag falsification test (writer thread + 8 reader threads)
- D-SOA-SNAP-6: Wire `snapshot.cycle` into `QueryReference` (close row-scale / byte-scale clock loop)
**Epiphany:** E-DEINTERLACE-TWO-SCALES (prepended 2026-06-06).
**Companion:** PR #468 (`temporal.rs`, row-scale, SHIPPED); PR #477 (`soa_envelope.rs`, IN REVIEW).
**Boundary:** ndarray stays layout-only (`MultiLaneColumn`); Arc-swap policy in lance-graph only.

---

## 2026-06-05 — cesium-osm-substrate-v1 (OpenStreetMap as 6th source class for the 3DGS-ArcGIS-Cesium ingestion plan; OSM PBF → Arrow → Lance → SPO → cesium tileset → splat renderer; substrate-reuse with splat-native-ultrasound-v1)

**Status:** PROPOSAL. Design-spec only, no code. **Plan file:** `.claude/plans/cesium-osm-substrate-v1.md` (~430 LOC). **Trigger:** user feasibility question on OSM × Cesium × Gaussian-splat coupling; cross-session coordination with OGAR.
Expand Down
11 changes: 11 additions & 0 deletions .claude/board/TECH_DEBT.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@

## Open Debt

### TD-UNBUNDLE-FROM-1 — `unbundle_from` is NOT the inverse of `bundle_into` (2026-06-07)

**Open.** `crates/lance-graph-planner/src/cache/kv_bundle.rs` — `unbundle_from`
uses `wrapping_sub` as the "undo" of `bundle_into`. But `bundle_into` is a
weighted average: `(old * w_self + new * w_new) / total`. Subtraction is not the
inverse. `AttentionMatrix::set` calls both in sequence, silently corrupting the
gestalt ~1 bit per epoch. Measurable after ~100 epochs. Function is marked
`#[deprecated]` with a doc warning; callers use `#[allow(deprecated)]` + FIXME.
**Paid by:** switch to raw-sum + count tracking so exact integer subtraction is
possible. Cross-ref: `kv_bundle.rs:28-33`.

### TD-HELIX-OVERLAP-1 (D-HELIX-1) — `helix` re-derives existing CERTIFIED primitives (clean-room by directive)

**Open.** `crates/helix` ships as a zero-dep clean-room codec per the user directive "scoped only to crate." ~80% of its pipeline duplicates existing, in-places-CERTIFIED workspace code: Fisher-Z/arctanh→i8 (`bgz-tensor::projection::Base17Fz`, `bgz-tensor::fisher_z::FamilyGamma` ρ≥0.999), golden-spiral azimuth (`jc::weyl`), stride-4 coupling (`thinking-engine::reencode_safety`, `highheelbgz`), EULER_GAMMA hand-off (`jc::precond`, `bgz-tensor::euler_fold`), 256-palette/L1 (`bgz17::palette`). Genuinely new = the `√u` equal-area hemisphere placement + the PLACE/RESIDUE doctrine. **Paid by** (when it graduates from clean-room): the consolidation path in `crates/helix/KNOWLEDGE.md` § Overlap & Consolidation — re-export `FamilyGamma` behind a feature; route coupling through the canonical `(i·11)%17`/stride-4 zipper; feed `ResidueEdge` into the existing HIP/TWIG CAKES tier. **Also owed:** a fidelity-vs-ground-truth probe (the naive-u8 floor gate ≥0.9980 Pearson is currently CONJECTURE — NOT RUN) before promotion. Cross-ref: E-HELIX-OVERLAP, `encoding-ecosystem.md`.
Expand Down
176 changes: 176 additions & 0 deletions .claude/plans/cycle-coherent-soa-snapshot-v1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# Plan: Cycle-Coherent SoA Snapshot — No-Cross-Cycle-Lag Guarantee

**Version:** v1
**Date:** 2026-06-06
**Status:** Queued
**D-ids:** D-SOA-SNAP-1 through D-SOA-SNAP-6

---

## The problem

`temporal.rs` (PR #468) closes the row-scale deinterlace gap: HLC tick →
`classify/deinterlace` → causally-coherent row sequence. But there is a
parallel byte-scale gap: nothing prevents a reader from holding a mix of
column data from cycle N and cycle N+1 within the same SIMD sweep. This is
the **cross-cycle lag problem** — a SIMD sweep that is not internally
single-cycle is not coherent.

The deinterlace operation is one operation at two scales:

```text
Row/query scale → HLC tick + DependsClosure → temporal.rs (SHIPPED, PR #468)
Byte/column scale → SoaEnvelope::cycle() stamp → MailboxSoA Arc-swap (THIS PLAN)
```

---

## The mechanism: Arc-swap COW at column granularity

The SoA mailbox carries its columns as `Arc<[u8]>` slices (via
`MultiLaneColumn` in ndarray). The invariant is:

> **A reader that snapshots all column Arcs at the same `cycle()` stamp sees
> a single coherent cycle. No column can be from a prior cycle.**

### Write path (in `lance-graph`, `MailboxSoa::advance_phase`)

On every `advance_phase(to: KanbanPhase)`:

1. Increment `cycle` counter on the envelope.
2. For each mutated column: swap the `Arc` pointer — `Arc::make_mut` on the
backing `Arc<[u8]>` of the `MultiLaneColumn`, write the new data, then
publish the new Arc via an `ArcSwap` (or `RwLock<Arc<MultiLaneColumn>>`).
3. The cycle increment is a `SeqCst` store (fence) BEFORE the column Arc
swaps. Readers who observe the new cycle will see the new column data.

### Read path (in `lance-graph`, `MailboxSoaView`)

On `snapshot()`:

1. Load cycle stamp.
2. Clone all column Arcs under the same cycle stamp (atomic snapshot loop:
re-read cycle after loading all Arcs; retry if it changed — lock-free
single-retry is sufficient because writers are serialized through
`advance_phase`).
3. Return `MailboxSoaSnapshot { cycle, cols: [...] }`.

The snapshot guarantees all column data is from the same cycle.

### Boundary: ndarray stays layout-only

`MultiLaneColumn` in ndarray is `Arc<[u8]>` with typed lane iterators —
**layout-only**. The Arc-swap policy (when to swap, how to snapshot, the
cycle fence) belongs in `lance-graph`'s `MailboxSoa`. ndarray never learns
that cycles or snapshots exist. The boundary is:

```text
ndarray::simd::MultiLaneColumn — Arc<[u8]>, lane iters, Send + Sync, zero-copy reads
lance-graph::MailboxSoa — Arc-swap on advance_phase, cycle fence, snapshot()
```

### Connection to temporal.rs

`SoaEnvelope::cycle()` is the byte-scale clock. `QueryReference::ref_version`
is the row-scale clock (a Lance version). They are the same monotonic clock
at different granularities — Lance version N corresponds to SoA cycle C(N).
When `temporal.rs::deinterlace` runs at query time, the `V_ref` it uses should
align with the `cycle()` of the snapshot being queried.

Wiring: `VersionScheduler::on_version(&view, at, exec)` provides the Lance
version; the `MailboxSoaSnapshot` that went into that version carries its
`cycle`. Threading `snapshot.cycle` into `QueryReference` closes the loop so
row-scale and byte-scale deinterlace use the same clock.

---

## Deliverables

### D-SOA-SNAP-1 — `MailboxSoaSnapshot` type in lance-graph-contract

A `MailboxSoaSnapshot` struct: `cycle: u32`, `cols: Vec<Arc<MultiLaneColumn>>`.
Snapshot is `Send + Sync`. No reference to the originating `MailboxSoa`.
This is a point-in-time read — immutable after creation.

### D-SOA-SNAP-2 — `SnapshotProvider` trait in lance-graph-contract

```rust
pub trait SnapshotProvider {
fn snapshot(&self) -> MailboxSoaSnapshot;
}
```

Zero deps in contract. `MailboxSoa` in lance-graph implements it.
Comment on lines +89 to +103

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical dependency architecture violation in D-SOA-SNAP-1 and D-SOA-SNAP-2.

D-SOA-SNAP-1 proposes placing MailboxSoaSnapshot with field cols: Vec<Arc<MultiLaneColumn>> in lance-graph-contract, and D-SOA-SNAP-2 claims "Zero deps in contract." However, MultiLaneColumn is from ndarray (lines 68, 176). This creates a lance-graph-contract → ndarray dependency, violating the zero-dependency contract architecture. Based on learnings, "Zero circular dependencies: lance-graph-contract (zero-dep) → ndarray/planner/n8n-rs/crewai-rust."

Proposed resolution options

Option 1 (recommended): Keep MailboxSoaSnapshot in lance-graph, not in lance-graph-contract. The contract provides only the SoaEnvelope trait; the concrete snapshot type lives in the implementation crate.

Option 2: Make the contract snapshot type generic/abstract:

// In lance-graph-contract
pub struct MailboxSoaSnapshot<C> {
    pub cycle: u32,
    pub cols: Vec<Arc<C>>,
}

pub trait SnapshotProvider {
    type Column;
    fn snapshot(&self) -> MailboxSoaSnapshot<Self::Column>;
}

Then lance-graph provides impl SnapshotProvider for MailboxSoa { type Column = MultiLaneColumn; }.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/plans/cycle-coherent-soa-snapshot-v1.md around lines 89 - 103, The
contract currently introduces a direct dependency on ndarray by placing
MailboxSoaSnapshot with cols: Vec<Arc<MultiLaneColumn>> into
lance-graph-contract; move the concrete MailboxSoaSnapshot type out of
lance-graph-contract into the implementation crate (lance-graph) and keep only
the abstract trait in the contract (SnapshotProvider or SoaEnvelope) so the
contract remains zero-dep, or alternatively change the trait in
lance-graph-contract to use an associated type/generic column (e.g.,
SnapshotProvider::Column and MailboxSoaSnapshot<C>) so lance-graph can implement
SnapshotProvider with Column = MultiLaneColumn without pulling ndarray into the
contract; update the implementation of MailboxSoa::snapshot and any references
to MailboxSoaSnapshot to the new location/type accordingly.

Source: Learnings


### D-SOA-SNAP-3 — Arc-swap write path in `MailboxSoa::advance_phase`

In lance-graph (not contract, not ndarray): implement the cycle fence +
column Arc-swap on every `advance_phase`. Use `std::sync::RwLock<Arc<MultiLaneColumn>>`
per column (no external arc-swap crate needed unless benchmarks show
contention; add as a feature flag if needed).

### D-SOA-SNAP-4 — `snapshot()` implementation on `MailboxSoa`

Lock-free snapshot: load cycle, clone all column Arcs, re-read cycle, retry
once if changed. Return `MailboxSoaSnapshot`.

### D-SOA-SNAP-5 — No-cross-cycle-lag falsification test

```rust
// Spawn a writer thread: advance_phase in a loop (100 cycles).
// Spawn 8 reader threads: each calls snapshot() in a loop.
// Assert: every snapshot has all columns reporting the same cycle.
// Assert: no snapshot mixes data from two different cycles.
```

The test is the formal statement of the guarantee. If it passes, the
invariant is mechanically enforced, not just documented.

### D-SOA-SNAP-6 — Wire `snapshot.cycle` into `QueryReference`

In the planner: when a query resolves a `MailboxSoaSnapshot`, thread
`snapshot.cycle` through `QueryReference::hlc_tick` (or a new
`QueryReference::soa_cycle: Option<u32>` field) so `deinterlace` at
row scale uses the same cycle boundary as the snapshot at byte scale.

---

## Prerequisite gap fixes (order matters)

These mechanical fixes should land before or alongside D-SOA-SNAP-1
(they settle the column shape):

1. Remove `MailboxSoA::emit()` + `CollapseGateEmission` from source.
2. Rename `last_emission_cycle` → `last_active_cycle` in MailboxSoA.
3. Drop `entity_type: u16` from SoA row — MailboxId IS NiblePath.
4. Fix `OntologyRegistry::enumerate_first_with_entity_type_id` linear scan.
5. Remove `MappingRow.thinking_style` — Kanban owns thinking styles.
6. Fix `unbundle_from` in `kv_bundle.rs:29` — `wrapping_sub` is not the
inverse of weighted-average `bundle_into`.

Items 1-5 settle the column shape before the Arc-swap schema is frozen.
Item 6 is independent but should not be deferred (correctness bug).

---

## Non-goals

- No recurrence / standing wave implementation. The standing wave is the
deinterlaced Lance version projection, provided by Lance versioning
(O(1) 90° lookup). Do not implement it in compute.
- No baton. No emission. No inter-mailbox handoff type. The snapshot is
consumed in-place; nothing is transmitted.
- ndarray does not learn about cycles, snapshots, or advance_phase.

---

## Cross-references

- `temporal.rs` (PR #468) — row-scale deinterlace (SHIPPED)
- `soa_envelope.rs` (PR #477) — envelope LE contract (IN REVIEW)
- `soa-three-tier-model.md` — three-tier lifecycle model
- `q3-standing-wave-falsification.md` — falsification: standing wave = Lance
versioning, not compute recurrence
- `.claude/board/EPIPHANIES.md` E-DEINTERLACE-TWO-SCALES — the synthesis
- `ndarray/src/simd_soa.rs` — `MultiLaneColumn` (layout-only; Arc-swap lives
in lance-graph, not here)
22 changes: 22 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# CLAUDE.md — lance-graph

## P0 — AdaWorldAPI forks ONLY, NEVER crates.io upstream

**Always depend on the AdaWorldAPI fork of any crate that has one. NEVER use the
upstream crates.io version of a forked crate.** Non-negotiable; applies to every
`Cargo.toml` and every dependency decision in this repo. Every repo in this
workspace is local — prefer the local/fork source over the registry, always.

- Crates with an `AdaWorldAPI/<name>` fork — e.g. `ndarray`, `lance` /
`lancedb` / `lance-index` / `lance-linalg` / `lance-namespace`, `surrealdb`,
and any other — MUST be wired via the fork (`path` / `git` / `[patch.crates-io]`),
never the registry version.
- If a fork's coordinates (git URL, branch/tag, feature flag) are unknown,
**STOP and ask**. Do NOT fall back to crates.io as a convenience or to make a
build pass.
- `"warning: Patch <crate> ... was not used in the crate graph"` is a policy
alert. It can indicate missing fork wiring OR a transitive semver mismatch
that prevents the patch from applying. Do not ignore it: verify direct
`Cargo.toml` patch entries and `Cargo.lock` wiring, then track/resolve any
transitive blocker explicitly before closing the issue.
- crates.io is permitted ONLY for crates that have no AdaWorldAPI fork / no local
source.

> **Updated**: 2026-04-21 (categorical-algebraic inference click)
> **Role**: The obligatory spine — query engine, codec stack, semantic transformer, and orchestration contract
> **Status**: 22 crates, 7 in workspace, 15 excluded (standalone/DTO), Phases 1-2 DONE, Phases 6-7 DONE (grammar + governance), Phase 3 IN PROGRESS
Expand Down
1 change: 1 addition & 0 deletions crates/lance-graph-contract/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ pub mod scheduler;
pub mod sensorium;
pub mod sigma_propagation;
pub mod sla;
pub mod soa_envelope;
pub mod soa_view;
pub mod splat;
pub mod tax;
Expand Down
Loading
Loading