Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .claude/board/LATEST_STATE.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 2026-11-02 — main after #1925 (merged `e89e61790`)

- dt64: `BindStore::check_route` (read-only route check).
- Codegraph: the lab `WalSink` for the G10 × G11 publication lab; closure caches filled between prepare and commit are dropped at commit.

## 2026-11-02 — main after #1924 (merged `78f9996af`)

- Codegraph refresh splits into a fenced prepare / commit (crate-private); the F-LAND / F-DISCARD lab tests pin it, in debug and release.
Expand Down
11 changes: 11 additions & 0 deletions .claude/board/PR_ARC_INVENTORY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
## 2026-11-02 — lance-graph PR #1925 (merged `e89e61790`, branch `claude/clone-repositories-71a5sw`) — D-TGL-PUB steps 1–2: `check_route`, lab `WalSink`; stale-closure fix

- **Added:**
- dt64 `BindStore::check_route`, the read-only form of `route`; `route` runs the same `RouteLog::check`.
- Codegraph lab `WalSink` (`LabWal`, test-only): fence, reconcile, `HashConflict`, payload-free scan, image read, injected faults.
- Fix: commit drops a closure cache filled between prepare and commit (Codex P2 on #1924).
- Post-merge record for #1924.
- **Locked:** a checked route intent stays valid; `scan_sealed` carries no payload, so land records are read from the image.
- **Deferred:** the L1–L6 lab test (two commits after the merge point, carried by the next PR).
- **Confidence:** dt64 25 + 29, codegraph 12 lib tests; 3 + 4 + 1 disables red; planner is a dev-dependency only, with one ndarray via `[patch]`.

## 2026-11-02 — lance-graph PR #1924 (merged `78f9996af`, branch `claude/clone-repositories-71a5sw`) — F-LAND / F-DISCARD lab, D-TGL lifecycle contract, G10 × G11 lab spec

- **Added:**
Expand Down
2 changes: 1 addition & 1 deletion .claude/board/STATUS_BOARD.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ Plan: [d-codegraph-0-resident-codegraph-v1.md](../plans/d-codegraph-0-resident-c
| **D-TGL-G10** | atomic publication: prepare all, durable commit first, then infallible in-memory apply from the land record, replay after crash | OPEN (production); named gap: no prepare/validate route API on `BindStore` | a `Fenced` leaves no published partial state |
| **D-TGL-G11** | branch-local routing; no branch-minted DR position as durable routing key | OPEN (production) | a branch route leaves `BindStore::current_version()` unchanged until land |
| **D-TGL-G12** | identities apart: W-slot, generation, ThoughtCommitId, DurableRef, RouteVersion, Lance version, source SHA (provenance only) | OPEN (production) | joins only through receipt / CommitWitness / MetaKey / land record |
| **D-TGL-PUB** | G10 × G11 lab: prepared land (Codegraph + DT64 route intent), fenced durable commit through a test `WalSink`, crash recovery from the durable record, branch-local routing | SPEC: plan `g10-g11-atomic-publication-lab-v1.md`; boundaries B1–B5 located. Step 1 SHIPPED (lab-ready): `BindStore::check_route` (read-only; `route` runs the same `RouteLog::check`), 3 tests, 3 disables red. Step 2 SHIPPED (lab): `LabWal` in `lance-graph-codegraph/src/lab_wal.rs` (test-only `WalSink`: fence, one version per commit, reconcile, `HashConflict`, payload-free scan, image read, injected I/O / Ambiguous faults), 4 tests, 4 disables red; planner is a dev-dependency, one ndarray via `[patch]`. Step 3 (L1–L6) open | L1–L6, each with a disable; L4 shows route re-application ticks `RouteVersion` without a watermark |
| **D-TGL-PUB** | G10 × G11 lab: prepared land (Codegraph + DT64 route intent), fenced durable commit through a test `WalSink`, crash recovery from the durable record, branch-local routing | SPEC: plan `g10-g11-atomic-publication-lab-v1.md`; boundaries B1–B5 located. Step 1 SHIPPED (lab-ready): `BindStore::check_route` (read-only; `route` runs the same `RouteLog::check`), 3 tests, 3 disables red. Step 2 SHIPPED (lab): `LabWal` in `lance-graph-codegraph/src/lab_wal.rs` (test-only `WalSink`: fence, one version per commit, reconcile, `HashConflict`, payload-free scan, image read, injected I/O / Ambiguous faults), 4 tests, 4 disables red; planner is a dev-dependency, one ndarray via `[patch]`. Step 3 SHIPPED (lab): `graph/publication.rs`, L1–L6 green, 5 disables red at the intended assertion (L4: Codegraph unchanged, `RouteVersion` 1 → 2; L6 without the canonical sort silently loses cycle 1). EXO-148 locked; no production land | L1–L6, each with a disable; L4 shows route re-application ticks `RouteVersion` without a watermark |
| **D-TGL-EXO148** | `DurableRef` + never-reused `ThoughtCommitId` before any durable land, replay or PR record | OPEN (production, EXO-148) | reuse test (D-RST-1) |
| **D-DT64-AUTH** | DT64 / F### as the one method authority: census of production words with a two-way exception ratchet; parallel identities (`MethodSignature`, tract `Registry`, XLOG `Word`, ogar-loco `FnIndex`) stay as listed `LAB` adapters | QUEUED: plan `d-dt64-method-authority-census-v1.md` (operator decision 2026-11-02); egglog pinned to one commit in `egglog-r2il-probe`, `dr-math-binding-probe`, `xlog-relcomp-probe` | undeclared production word → red; stale exception → red; current tree green |
| **D-CODEGRAPH-0-D** | local stdio MCP over C | QUEUED | only after B and C gates |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,29 @@ OPEN: `check_route`, the lab `WalSink`, and the L1–L6 test are three separate
- a fault before publish and one after publish leave different durable states.
- **Disables (each red on its own test):** drop the fence; leak the payload through `scan`; skip the reconcile lookup; make `Ambiguous` publish nothing.
- **Gates:** codegraph suites green (12 lib tests); clippy and fmt clean.

## Step 3 done: L1–L6 (2026-11-02, MEASURED in the lab)
- **Code:** `crates/lance-graph-codegraph/src/graph/publication.rs` (`#[cfg(test)]`).
- A branch revises one Codegraph source and carries DT64 route intents. It lands in the G10 order:
1. prepare (`prepare_refresh` + `check_route`);
2. durable commit through `LabWal`, with the land record (source + route intents, no positions, no `RouteVersion`) as payload;
3. an infallible publication (`commit_refresh`, `route`, watermark).
- Recovery reads records from the durable image above the watermark, in canonical cycle order. The record codec refuses truncated or padded bytes.
- **Results (all green):**
- **L1/L5:** prepare and discard leave the Codegraph snapshot, `RouteVersion`, `routed_at(P)` and `claimed` unchanged.
- **L2:** `Fenced` publishes nothing; the branch lands after re-preparing against the new head.
- **L3:** after a crash between the durable commit and publication, recovery restores exactly the confirmed state: clean-open equality, `RouteVersion` +1, `P → C1`.
- **L4:** a second recovery changes nothing.
- **L6:** a rebuild from the base with reversed physical order equals the live state.
- **Disables (each red at the intended assertion):**
- **L1/L5 eager `route`:** L1, L2 and L3 red.
- **L2 publish before the durable commit:** "nothing published" red.
- **L3 read records from `scan_sealed`:** "land record in the durable image" red.
- **L4 drop the watermark:** the Codegraph snapshot stays equal (digest skip) while `RouteVersion` goes 1 → 2. This is the predicted non-idempotence of `route`, now measured.
- **L6 drop the canonical sort:** the rebuild replays cycle 2 first, then the watermark skips cycle 1. The record is lost, not merely reordered (`RouteVersion` 1, `P → C2` only). **Physical-order replay plus a watermark loses data silently.**
- **Gates:** codegraph suites green (17 lib tests); clippy and fmt clean.
- **Limits:**
- The lab `prepare` takes `&mut` only so the L1 disable can call `route`. A production prepare should take `&self`.
- The `WalSink` is in memory; no 512-byte ABI and no `LanceCycleWriter`.
- EXO-148 stays locked.
- Lab results satisfy no production gate.
2 changes: 1 addition & 1 deletion .claude/plans/g10-g11-atomic-publication-lab-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,6 @@ The in-memory publication is one infallible step (Codegraph `commit_refresh` + t
- it agrees with `route` on accept and refuse for every case;
- it leaves `current_version()` unchanged.
2. **DONE (2026-11-02):** a lab-only test `WalSink` (`LabWal`, `crates/lance-graph-codegraph/src/lab_wal.rs`) beside the Codegraph test (dev-dependency on `lance-graph-planner`; test `WalSink` impls exist in ten places, for example `lance-graph-planner/examples/blw_fusion.rs` `MemWal`). No production edge from Codegraph to the planner.
3. The lab test itself, in-crate, because `prepare_refresh` / `commit_refresh` are crate-private.
3. **DONE (2026-11-02):** the lab test itself (`crates/lance-graph-codegraph/src/graph/publication.rs`), in-crate, because `prepare_refresh` / `commit_refresh` are crate-private.

Out of scope: `LanceCycleWriter` (needs the 512-byte ABI and real Lance), `ThoughtCommitId`/`DurableRef` (EXO-148), MergeQueue, review gates.
17 changes: 10 additions & 7 deletions crates/lance-graph-codegraph/src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1271,6 +1271,9 @@ mod atomic {
/// two branches over one W0 base, each a revision of one source; landing
/// recomputes against the current W0; discarding leaves W0 untouched. Lab
/// only: no Thought-Git wiring, no persistence, no routing.
#[cfg(test)]
mod publication;

#[cfg(test)]
mod lifecycle {
use super::*;
Expand All @@ -1281,7 +1284,7 @@ mod lifecycle {

const HEAD: &str = "#version 2\n#schema predicate\tsubject\tobject\tgrade\tfile\tstart\tend\n";

fn dir(tag: &str) -> PathBuf {
pub(super) fn dir(tag: &str) -> PathBuf {
static NEXT: AtomicU32 = AtomicU32::new(0);
let n = NEXT.fetch_add(1, Ordering::Relaxed);
let d = std::env::temp_dir().join(format!("cg_lifecycle_{}_{tag}_{n}", std::process::id()));
Expand Down Expand Up @@ -1310,34 +1313,34 @@ mod lifecycle {
}

// W0: m::a calls m::b at two sites; n::c calls m::b once.
fn m_v1() -> String {
pub(super) fn m_v1() -> String {
rows(
"m.rs",
&["m::a", "m::b"],
&[("m::a", "m::b"), ("m::a", "m::b")],
)
}
fn n_v1() -> String {
pub(super) fn n_v1() -> String {
rows("n.rs", &["n::c"], &[("n::c", "m::b")])
}
// Branch A revises source m: a new symbol m::x calling m::b.
fn m_v2() -> String {
pub(super) fn m_v2() -> String {
rows(
"m.rs",
&["m::a", "m::b", "m::x"],
&[("m::a", "m::b"), ("m::a", "m::b"), ("m::x", "m::b")],
)
}
// Branch B revises source n: a new symbol n::y; n::c now calls it too.
fn n_v2() -> String {
pub(super) fn n_v2() -> String {
rows(
"n.rs",
&["n::c", "n::y"],
&[("n::c", "m::b"), ("n::c", "n::y"), ("n::y", "m::b")],
)
}

fn store(tag: &str, m: &str, n: &str) -> PathBuf {
pub(super) fn store(tag: &str, m: &str, n: &str) -> PathBuf {
let d = dir(tag);
fs::write(d.join("m.rows.tsv"), m).expect("write");
fs::write(d.join("n.rows.tsv"), n).expect("write");
Expand All @@ -1355,7 +1358,7 @@ mod lifecycle {

/// Every symbol's callers (names + call-site count), callees and
/// impact, by name, so two graphs with different positions compare.
fn answers(g: &mut Codegraph) -> BTreeMap<String, String> {
pub(super) fn answers(g: &mut Codegraph) -> BTreeMap<String, String> {
let all: Vec<String> = (0..g.words() * 64)
.filter_map(|p| g.symbol(p as Pos).map(str::to_string))
.collect();
Expand Down
Loading
Loading