From a7e075d36078b6d3105abf6adc936104c57dd4ae Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 20:11:16 +0000 Subject: [PATCH 1/3] d-rmap, act-r CI: bind thoughts to the palette generation; rebuild on toolchain changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ThoughtMapPaletteBinding now records the palette generation it bound and refuses resolution when the palette's generation has moved, so §6a's stale-binding refusal is enforceable; the §4 example shows it. The act-r job also runs on rust-toolchain.toml changes, since no workspace job builds the excluded crate. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VyWZYKycy6MoYDxHRVnV5K --- .../plans/d-rmap-separate-tables-thought-palettes-v1.md | 8 ++++---- .github/workflows/act-r.yml | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.claude/plans/d-rmap-separate-tables-thought-palettes-v1.md b/.claude/plans/d-rmap-separate-tables-thought-palettes-v1.md index 1064dca03..1cf9708c9 100644 --- a/.claude/plans/d-rmap-separate-tables-thought-palettes-v1.md +++ b/.claude/plans/d-rmap-separate-tables-thought-palettes-v1.md @@ -10,7 +10,7 @@ | --- | --- | --- | | OGAR Class / ClassView / DTO-IR | Types, fields, associations, actions, compiled class vocabulary, generated field masks and DTO projection descriptors | Persistent relationship index pages, RelAlg evaluator, runtime DTO copies | | RelationshipMapStore | Separate relation-fact tables, sorted index permutations, global relationship-map identity, seal/version, eligible physical capabilities and optional relation tiles | Datalog syntax/AST, CE64 fields, per-thought graph copies | -| ThoughtMapPaletteBinding | Thought slot and incarnation -> MapPaletteId under a witnessed frame; selected subset and order of maps | Relation-fact payload, evidence roots | +| ThoughtMapPaletteBinding | Thought slot and incarnation -> MapPaletteId **and the palette generation it bound** under a witnessed frame; selected subset and order of maps | Relation-fact payload, evidence roots | | MapPalette | Palette ID **and its own palette generation**, plus 0..255 local map selectors -> globally stable MapId + map generation | Global relationship truth or per-object row materialization | | FocusBinding | Source/target global identities -> focus-local slots; lifetime, version and ACL attestation | Persistent semantic facts | | BIND | Resolves metadata and borrows native spans, masks, indexed ranges or permutations with a mapping witness | RelAlg rewrite rules, storage ownership, separate runtime evaluator | @@ -31,7 +31,7 @@ The following are proposed **logical tables**, not physical record layouts or ma | RelationOrder | Sealed indexed permutations of original fact row references: e.g. predicate-subject-object, object-predicate-subject | Derived ordering; no source payload copy | | **RelationshipMap** | Separate MapId, map generation, underlying relation-order view handles, constraints and capability metadata | **Global shared table** | | **MapPalette** | MapPaletteId + **palette generation**, local map ordinal 0..255 to MapId and map generation. Reassigning any slot bumps the palette generation (or mints a new palette; palettes may also be immutable) | **Shared palette table** | -| **ThoughtMapPaletteBinding** | (thought slot, incarnation, frame witness) to MapPaletteId; optional sparse palette visibility override | **Separate thought map** | +| **ThoughtMapPaletteBinding** | (thought slot, incarnation, frame witness) to MapPaletteId + the palette generation it bound; resolution refuses when the palette's current generation differs; optional sparse palette visibility override | **Separate thought map** | | FocusBinding | Frame witness, source/target slot-to-global identity maps and authorization | Local map binding | | RelationTile | Optional cached source-slot to local target mask, keyed by **global MapId + map generation (or index seal digest)** + FocusBinding generation + authorization scope. A frame id or local palette slot alone is never a sufficient key | Disposable derived bits | | RelationDelta | Separately typed fact changes, binding changes, tile invalidations, speculative thought claims | Incremental witnesses | @@ -68,9 +68,9 @@ OGAR's DTO plans can provide an ergonomically tiny API over this binding, but OG ~~~text ThoughtMapPaletteBinding - (thought_slot=7, incarnation=41, frame=9) -> map_palette=23 + (thought_slot=7, incarnation=41, frame=9) -> map_palette=23, palette generation 5 -MapPalette[23] +MapPalette[23], palette generation 5 slot 0 -> global MapId(is_a), map generation 12 slot 1 -> global MapId(part_of), map generation 8 slot 2 -> global MapId(mentioned_in), map generation 3 diff --git a/.github/workflows/act-r.yml b/.github/workflows/act-r.yml index c682e4ec3..6d0640f1a 100644 --- a/.github/workflows/act-r.yml +++ b/.github/workflows/act-r.yml @@ -7,11 +7,13 @@ on: paths: - 'crates/lance-graph-act-r/**' - '.github/workflows/act-r.yml' + - 'rust-toolchain.toml' push: branches: [main] paths: - 'crates/lance-graph-act-r/**' - '.github/workflows/act-r.yml' + - 'rust-toolchain.toml' workflow_dispatch: permissions: contents: read From 59ff8508a299e5de23f6ffa47e84ee1f6506d569 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 20:53:57 +0000 Subject: [PATCH 2/3] d-rmap: derive map, palette and binding generations from Thought Git and #1605 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit D-RMAP-1A §7 maps each of its generation concepts onto the identities D-TGA and #1605 already specify. Map and palette generation become readings of DurableRef (sealed) or ThoughtCommitId (speculative); the thought-palette binding is (ThoughtCommitId, palette generation) instead of (slot, incarnation). Focus generation stays an ephemeral witness, the index seal stays separate unless RelationFacts uses stable row ids, and authorization scope stays its own key component. D-RMAP adds no durable counter. Read in code: no version type carries a dataset or branch, versioned.rs::commit_encounter_round returns only the nodes version of a three-dataset write, AlphaStamp.visits saturates and is not a generation, and D-TGA defines no thought incarnation. Falsifiers X1-X9 are specified with their disables; none are run. Gaps recorded in thought-git-api-v1 and the causal-pickaxe plan: ThoughtCommitId must be never-reused, a dirty bit, and one DurableRef per dataset for a multi-dataset write. ENTROPY-MILESTONES M28, STATUS_BOARD D-RMAP-1A-V, board entry, entries index regenerated. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VyWZYKycy6MoYDxHRVnV5K --- .claude/board/STATUS_BOARD.md | 1 + ...026-10-19-d-rmap-thought-git-versioning.md | 17 +++ .claude/board/entries/README.md | 3 +- ...ickaxe-resident-git-lance13-temporal-v1.md | 19 ++++ ...map-separate-tables-thought-palettes-v1.md | 105 ++++++++++++++++++ .claude/plans/thought-git-api-v1.md | 17 +++ .claude/v3/ENTROPY-MILESTONES.md | 1 + 7 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 .claude/board/entries/2026-10-19-d-rmap-thought-git-versioning.md diff --git a/.claude/board/STATUS_BOARD.md b/.claude/board/STATUS_BOARD.md index 8f8877377..f16dfcc55 100644 --- a/.claude/board/STATUS_BOARD.md +++ b/.claude/board/STATUS_BOARD.md @@ -8,6 +8,7 @@ These PRs merged with no board rows. Every row below is a PROPOSAL (documents an | **graph_hop quarantine** (#1616) | `lance-graph-mask-risc::graph_hop::OutgoingHop` (two `MaskOp::Gather` + `ScatterOrU32`) | BLOCKED — compiled only under the off-by-default `quarantined-gather-hop` feature | default build: `compile_fail` doctest proves `OutgoingHop` unreachable (disable-verified); `ISS-GATHER-HOP-1616` | | D-RMAP-1 | implicit RelationshipMap and focus-relative registers (`d-rmap-implicit-relationship-register-v1.md`) | PROPOSAL (superseded on ownership by D-RMAP-1A) | falsifier matrix F0–F10 in the plan | | D-RMAP-1A | separate map tables, borrowed projections, thought-selected palettes (`d-rmap-separate-tables-thought-palettes-v1.md`) | PROPOSAL; generation witnesses corrected 2026-10-19 (§6a) | refusal on map regeneration, palette-slot reassignment, focus-slot reuse, incarnation reuse, stale tile, cross-tenant change | +| D-RMAP-1A-V | versioning crosswalk: map/palette/binding generations derived from D-TGA `ThoughtCommitId` + #1605 `DurableRef`; focus generation and index seal retained (`d-rmap-separate-tables-thought-palettes-v1.md` §7) | PROPOSED; no code, no type; falsifiers specified, none run | X1–X9 in §7.4 (cross-dataset, compaction, palette ABA, slot reuse, uncommitted change, rebase, authorization, squash+replay, deletion/DRed) | | D-RMAP-2 | context-declaration reuse and GraphBLAS/BF16 tile probe (`d-rmap-2-context-tile-algebra-probe-v1.md`) | PROPOSAL; not run | arms 1–5 in the plan; 297× (D-GTM-0j) is not evidence | | D-SRAM-0 | inventory Soufflé AST/ast2ram/RAM passes against D-ASM/D-RA/D-TGA owners | Queued | evidence per mapped pass; no code imported | | D-SRAM-1 | bound AST → RAM-like schedule for pure conjunctive selection | Queued | same answers and read sets on hand-built fixtures; unsupported ops typed-refused | diff --git a/.claude/board/entries/2026-10-19-d-rmap-thought-git-versioning.md b/.claude/board/entries/2026-10-19-d-rmap-thought-git-versioning.md new file mode 100644 index 000000000..d87487967 --- /dev/null +++ b/.claude/board/entries/2026-10-19-d-rmap-thought-git-versioning.md @@ -0,0 +1,17 @@ +# 2026-10-19 — D-RMAP-1A §7: RelationshipMap versioning reads Thought Git and #1605 + +**Status:** PROPOSED. Documentation only; no code, no type, no falsifier run. + +**Plan:** [d-rmap-separate-tables-thought-palettes-v1.md §7](../../plans/d-rmap-separate-tables-thought-palettes-v1.md) + +**Decision (PROPOSED):** D-RMAP keeps no durable revision counter. Map generation and palette generation are readings of `DurableRef{dataset, branch, version}` (sealed) or `ThoughtCommitId` (speculative); the thought-palette binding is `(ThoughtCommitId, palette generation)`, replacing `(slot, incarnation)`. Focus generation stays an ephemeral frame-local witness. The index seal stays separate unless RelationFacts uses stable row ids (H14c-5: compaction moved 3 510 of 3 510 `_rowid`s without them, 0 with them). Authorization scope stays its own key component. Replay reads `QueryReference::at(v, rung)` with `Strict`, never `QueryReference::default()`. + +**Measured in code (read 2026-10-19):** no version type carries a dataset or branch (`temporal.rs:72`, `temporal_pov.rs:49`, `scheduler.rs:36`); `versioned.rs::commit_encounter_round` writes three datasets and returns only the nodes version; `AlphaStamp.visits` saturates and is not a generation; D-TGA has no thought incarnation. + +**Gaps filed into the source plans:** `ThoughtCommitId` must be never-reused (thought-git-api-v1, causal-pickaxe); a dirty bit for writes after the last commit (thought-git-api-v1); multi-dataset writes need one `DurableRef` per dataset or a refusal (both). + +**Falsifiers specified:** X1–X9 (§7.4), each a named refusal with the disable that must turn it red. + +**Entropy:** ENTROPY-MILESTONES M28 (version spellings → `DurableRef` + `ThoughtCommitId`). + +**Unchanged:** no CE64 change, no new executor or store, no per-fold commit, the no-gather ruling stands. diff --git a/.claude/board/entries/README.md b/.claude/board/entries/README.md index baac29fee..0d86f9634 100644 --- a/.claude/board/entries/README.md +++ b/.claude/board/entries/README.md @@ -25,11 +25,12 @@ index row, (3) no duplicate entry id. Checks 1 and 2 are deliberately opposite directions; the stranding this convention prevents shows up in exactly one of them, never both. -370 entries, 2026-08-06 .. 2026-10-19. +371 entries, 2026-08-06 .. 2026-10-19. | date | entry id | finding | file | |---|---|---|---| | 2026-10-19 | `post-merge-recovery-1601-1617` | | [2026-10-19-post-merge-recovery-1601-1617.md](2026-10-19-post-merge-recovery-1601-1617.md) | +| 2026-10-19 | `D-RMAP-1A` | | [2026-10-19-d-rmap-thought-git-versioning.md](2026-10-19-d-rmap-thought-git-versioning.md) | | 2026-10-19 | `D-RMAP-1` | | [2026-10-19-d-rmap-implicit-relationship-register.md](2026-10-19-d-rmap-implicit-relationship-register.md) | | 2026-10-17 | `thinking-tables-wiring` | | [2026-10-17-thinking-tables-wiring.md](2026-10-17-thinking-tables-wiring.md) | | 2026-10-17 | `D-ASM-11` | | [2026-10-17-pgring-idea-catalogue.md](2026-10-17-pgring-idea-catalogue.md) | diff --git a/.claude/plans/causal-pickaxe-resident-git-lance13-temporal-v1.md b/.claude/plans/causal-pickaxe-resident-git-lance13-temporal-v1.md index af170f7b9..9b6dc4db8 100644 --- a/.claude/plans/causal-pickaxe-resident-git-lance13-temporal-v1.md +++ b/.claude/plans/causal-pickaxe-resident-git-lance13-temporal-v1.md @@ -304,3 +304,22 @@ The JSON preregistration adds `CPG-18`–`CPG-25` and **does not constitute exec **Review gate:** treat the porcelain feature as **DESIGN-ONLY** until D-TGA's falsifiers, H14c/H14d operators, strict temporal horizon enforcement, source-root policy, and stable-row/branch API probes have actual passing fixtures. A presentable CLI is not evidence of a correct reasoning engine. **Summary:** **One porcelain, one typed meaning, one mask execution substrate, one evidence policy, one durable writer.** Git makes epistemic algebra approachable precisely because it does not replace that algebra. + +## Gaps found by D-RMAP-1A §7 (2026-10-19, PROPOSED) + +D-RMAP-1A §7 keys every relation-map binding on `ThoughtCommitId` and +`DurableRef` from §1. Three points this plan leaves open: + +1. **`ThoughtCommitId` reuse.** "Stable while retained" does not say whether + an id can return after its thought is discarded. A binding keyed on it + needs *never reused*. +2. **No version in code is dataset-scoped.** `temporal.rs` and + `temporal_pov.rs` both define `LanceVersion = u64`, `scheduler.rs` has + `DatasetVersion(u64)`, and `QueryReference` has no dataset or branch. The + read coordinate is the pair (`DurableRef`, `QueryReference`); neither + alone is a generation. +3. **`versioned.rs` writes three datasets and returns one version.** + `commit_encounter_round` returns the nodes version and drops the edges and + fingerprints versions. CPG-2's `DurableRef` adapter has to cover a write + that spans datasets, or refuse one. + diff --git a/.claude/plans/d-rmap-separate-tables-thought-palettes-v1.md b/.claude/plans/d-rmap-separate-tables-thought-palettes-v1.md index 1cf9708c9..bcb2c8a1e 100644 --- a/.claude/plans/d-rmap-separate-tables-thought-palettes-v1.md +++ b/.claude/plans/d-rmap-separate-tables-thought-palettes-v1.md @@ -2,6 +2,8 @@ > **Status: PROPOSAL / ARCHITECTURE ONLY (2026-10-19).** Clarifies [D-RMAP-1](d-rmap-implicit-relationship-register-v1.md). This amendment **supersedes** earlier suggestions that CE64 P could identify a relationship map. No code, persisted data format, wire/ABI change, opcode or performance claim. > +> **Versioning (2026-10-19):** §7 derives map, palette and binding generations from Thought Git (D-TGA) and #1605's `ThoughtCommitId` / `DurableRef`; D-RMAP adds no durable counter. PROPOSED. +> > **Operator ruling for this proposal:** RelationshipMaps live in separate explicit tables, expose a zero-copy map of existing indexed values, and are not stored inside RelAlg. Each thought selects a *palette of global RelationshipMaps* using another independent table. Nothing is crammed into CausalEdge64. ## 1. Ownership contract @@ -121,6 +123,109 @@ Falsifiers, each a refusal (never a plausible stale answer): Status: PROPOSED. Nothing here is implemented; RelationshipMap storage stays a proposal until a separately approved implementation establishes its legality (co-addressed operands, not a gather) and its economics. Map identity never enters CausalEdge64, and RelAlg never owns map tables. +## 7. Versioning: one logical history, borrowed from Thought Git and #1605 + +> **Status: PROPOSED (2026-10-19).** Nothing in this section is implemented. It decides which of the identities named in §2, §4 and §6a are *new* and which are readings of identities that D-TGA ([thought-git-api-v1](thought-git-api-v1.md)) and D-CPG ([causal-pickaxe, #1605](causal-pickaxe-resident-git-lance13-temporal-v1.md)) already define. D-TGA-0..6 and CPG-00..06 are themselves unbuilt, so every "existing authority" below is a *specified* authority, not running code, unless marked otherwise. + +### 7.1 Ownership + +| Owner | Owns | Source | +| --- | --- | --- | +| Thought Git (D-TGA) | logical revision of speculative state: `branch`, `write`, `rebase`, `land`, `squash_into`, `blame` | thought-git-api-v1 §Surface, Rules 1–5 | +| `ThoughtCommitId` (D-CPG §1) | identity of one in-memory thought commit and its parents | #1605 §1, "speculative" row | +| Lance, through `DurableRef{dataset, branch, version}` | sealed snapshots; one `land` = one next version (D-TGA "versions as PR entries") | #1605 §1 "durable" row, §5.2 | +| `temporal.rs` | epistemic reading of a version: `QueryReference::at(v, rung)`; replay and blame use an explicit `EpistemicMode::Strict` | `crates/lance-graph-planner/src/temporal.rs:134,188` (code) | +| Physical index seal | validity of a sorted permutation against the row-address map it points into | this plan, §7.3 row 5 | +| Binding witness | the ephemeral tuple BIND checks before it borrows a span (§7.5) | this plan | + +D-RMAP owns **relational binding**, and nothing else: which maps a thought selected, under which focus and scope, and the witness that the borrowed spans are still the ones it selected. It does not own a revision counter of its own. + +### 7.2 What is code today (measured 2026-10-19, read in full) + +- **Version identity is never dataset-scoped.** `temporal.rs:72` `LanceVersion = u64`; `temporal_pov.rs:49` `LanceVersion = u64`; `scheduler.rs:36` `DatasetVersion(pub u64)` (also `LanceCycleWriter::head()`); `versioned.rs` returns bare `u64`. `QueryReference` (`temporal.rs:134`) has `server_id, ref_version, hlc_tick, mode, rung` and no dataset or branch. No `DurableRef` or `ThoughtCommitId` exists in `crates/` (search: `DurableRef|ThoughtCommitId|dataset_id` over `crates/**/*.rs`, 0 hits; a negative over that named space only). +- **`versioned.rs` already shows the collision this section guards against.** `commit_encounter_round` (`versioned.rs:255`) writes three datasets (nodes, edges, fingerprints) in three separate commits and returns only the nodes version; the edges and fingerprints versions are dropped. `at_version`, `current_version`, `versions` and `tag` read the nodes dataset only. A caller holding that `u64` cannot name the edges snapshot it was written with. (Its doc says each write "appends"; `write_batch` uses `WriteMode::Overwrite`.) +- **`QueryReference::default()` is unbounded** (`ref_version = u64::MAX`), the dangerous default #1605 names. A witness must never be built from it. +- **The alpha overlay's `visits` is not a generation.** `AlphaStamp.visits: u16` counts revisits of one address and saturates (`alpha.rs` `claim`, `saturating_add`); `seq`/`rung`/`cycle` keep the first claim. A palette rewritten A→B→A at one address is two revisits, not a version, and stops counting at 65 535. +- **D-TGA has no thought incarnation.** Slots 1..63 are reused after `squash`/`discard` (D-TGA Rule 4: "the thought number does not survive"). §2's `(thought slot, incarnation)` therefore needs an identity D-TGA does not define; #1605's `ThoughtCommitId` is the only specified candidate. + +### 7.3 N→1: each D-RMAP identity against the authority that already exists + +| D-RMAP concept (§2/§6a) | Existing authority | Derived or retained | Falsifier (§7.4) | +| --- | --- | --- | --- | +| **Map generation** | `DurableRef` of the sealed RelationshipMap/RelationFacts version | **Derived.** Equality of `DurableRef`, never of a bare version. A new Lance version (append, delete, compaction, reseal) is a new generation, so nothing needs counting | X1 cross-dataset, X2 compaction, X9 deletion | +| **Palette generation** | sealed palette: `DurableRef` of the palette table version. Speculative palette edit inside a thought: the `ThoughtCommitId` of the commit that made it | **Derived.** Versions and commit ids are never reused, so A→B→A cannot reproduce an old generation | X3 palette ABA | +| **Thought-palette binding** | `(ThoughtCommitId, palette generation)` | **Derived.** `ThoughtCommitId` replaces `(slot, incarnation)`; the slot (CE64 W) is a register, not an identity. Only the binding *row* is new | X4 slot reuse, X6 rebase | +| **Focus generation** | none. A focus is a frame-local lens; changing it is a binding delta, which D-RMAP-1 §5 already separates from fact and thought deltas | **Retained**, ephemeral: dies with the frame, never persisted, never recovered | §6a focus-slot reuse | +| **RelationTile seal** (index seal) | `DurableRef` of the RelationOrder version **plus** the row-address map it was built against | **Retained** unless RelationFacts is written with stable row ids (opt-in, per dataset). With them it collapses to the RelationOrder `DurableRef` (H14c-5 measured 0 of 3 510 `_rowid`s moved by compaction); without them compaction moved 3 510 of 3 510 and a stale map omitted 160 of 160 live rows silently | X2 compaction | +| **Durable revision** | `DurableRef{dataset, branch, version}`, read through `QueryReference::at(v, rung)` with `Strict` for replay | **Existing** (specified by #1605; no type yet) | X1, X8 | +| **Authorization scope** | the existing RBAC decision at bind time | **Retained**, separate key component; no revision carries it | X7 | + +Result: of the six D-RMAP generation concepts, four are readings of two existing identities (`ThoughtCommitId`, `DurableRef`), and two stay as witnesses (focus generation: ephemeral; index seal: unless stable row ids). D-RMAP adds **no durable counter**. + +### 7.4 Falsifiers (specified, none run) + +Each is a refusal with a named reason. A plausible stale answer is the failure. Each lists the disable that must turn it red. + +| # | Case | Fixture | Must | Disable | +| --- | --- | --- | --- | --- | +| X1 | Cross-dataset collision | two datasets both at version 7; a tile keyed on map A at v7 | refuse a read against map B at v7 | key on `version` alone | +| X2 | Compaction | compact RelationFacts without stable row ids; tile and RelationOrder built before | refuse the stale permutation (new `DurableRef`, new seal); never return the H14c-5 160/160 omission | key the seal on RelationOrder's `DurableRef` only | +| X3 | Palette ABA | palette slot 3: MapId P → Q → P across three sealed versions; binding taken at the first | refuse at the third (version differs although the content repeats) | use a content hash or `visits` as the generation | +| X4 | Thought slot reuse | thought in slot 7 binds palette 23, is squashed; a new thought takes slot 7 | the new thought does not inherit the binding (different `ThoughtCommitId`) | key the binding on the slot | +| X5 | Uncommitted change | thought writes a speculative claim after its last commit; tile built from that commit | refuse the accelerated path while dirty; a reader holding only a `DurableRef` never sees the claim | drop the dirty check | +| X6 | Rebase | thought bound map M at `merge_base` v; main lands v+1 changing M; rebase | bindings to M at v revalidate or refuse; D-TGA Rule 2 retraction applies to tiles derived from M | keep the bound generation across rebase | +| X7 | Authorization change | same thought, same versions, scope revoked for one map | refuse; no payload span is borrowed before the check | omit scope from the key | +| X8 | Squash + historical replay | land, squash, reuse slot, then blame and replay the landed fact | blame returns `(landing DurableRef, source bitset)`; replay reads `Strict` at that version; a request for erased micro-steps returns `LineageUnavailable` | resolve blame through the slot; replay with `QueryReference::default()` | +| X9 | Deletion / DRed | thought derived B from A; main deletes A | the tile over A's map is refused (new `DurableRef`) and B is retracted before re-derivation (D-TGA Rule 2) | invalidate tiles without retracting derived cells | + +### 7.5 Minimal sketches (not code) + +```rust +// Reused, unchanged: temporal_pov::LanceVersion, planner::temporal::QueryReference. +pub struct DurableRef { dataset: DatasetId, branch: BranchId, version: LanceVersion } // #1605 §1; DatasetId/BranchId representation open until CPG-00 +pub struct ThoughtCommitId(u64); // #1605 §1; must be never-reused (see 7.6) +pub enum PaletteRevision { Sealed(DurableRef), Speculative(ThoughtCommitId) } +pub struct IndexSeal { order: DurableRef, addresses: DurableRef } // addresses dropped when RelationFacts uses stable row ids +pub struct FocusGeneration(u32); // frame-local, never persisted + +/// What BIND checks, every time, before borrowing a span. Ephemeral; never stored. +pub struct BindingWitness<'a> { + thought: ThoughtCommitId, + palette: PaletteRevision, + maps: &'a [(MapId, DurableRef, IndexSeal)], + focus: FocusGeneration, + scope: AuthorizationReceipt, // existing RBAC owner; type not chosen here + read: QueryReference, // concrete ref_version; Strict for replay; never Default +} +``` + +`MapId` and `MapPaletteId` remain the §2 identities. No field reaches CausalEdge64. + +### 7.6 Gaps this section finds in D-TGA and #1605 + +1. **`ThoughtCommitId` reuse is undefined.** #1605 says "stable while retained". X3 and X4 need *never reused*, including after `discard` and `squash`. Until that is specified, a binding keyed on it cannot be trusted after a discard. +2. **`QueryReference` has no dataset or branch.** It is a correct epistemic coordinate and an incomplete durable one. The read coordinate is the pair (`DurableRef`, `QueryReference`); `QueryReference` alone must not be accepted as a map or palette generation. +3. **A multi-dataset write has no single version.** `versioned.rs` is the measured instance; D-TGA's "one land = one version" holds only if a landed thought writes one dataset, or if the PR record (D-TGA open item "where the PR record lives") names the `DurableRef` of every dataset it wrote. +4. **Dirty state has no witness.** No authority says whether a thought has writes after its last `ThoughtCommitId`; X5 needs one bit, and #1605 §5.8 forbids a commit per fold. + +### 7.7 Cost and entropy: A (independent generations) vs B (derived from Thought Git and Lance) + +No timings exist for either; none are given. + +| | A: D-RMAP keeps its own counters | B: readings of `ThoughtCommitId` / `DurableRef` | +| --- | --- | --- | +| Identity spaces | map gen, palette gen, incarnation, focus gen, tile seal, plus `ThoughtCommitId` and `DurableRef`: 7 | `ThoughtCommitId`, `DurableRef`, plus focus gen and index seal: 4 | +| Durable counters D-RMAP must persist and recover | 3 (map gen, palette gen, incarnation) | 0 | +| Consistency checks between spaces | every counter against the version it shadows (a bumped map gen with an unchanged `DurableRef` has no meaning) | none: the derived ones are the authority | +| Wrap / reuse rules to write | one per counter | inherited: Lance versions never reuse; `ThoughtCommitId` needs gap 7.6.1 | +| Cost B pays that A does not | a `DurableRef` is wider than a counter in every key, and compaction invalidates every tile on the map even when content is unchanged (a refusal, then a rebuild) | | + +A adds a second ledger beside Lance and Thought Git, the duplicated truth this plan's §1 rules out. B is chosen. Its known cost is the compaction rebuild; whether that matters is measured with the §6 economics, not assumed. + +### 7.8 Schnellverschluss (#1620) + +The MORK/PathMap probe ([#1620](https://github.com/AdaWorldAPI/lance-graph/pull/1620)) binds a `RelationView { rows, generation: u64 }` and refuses `Stale { bound, current }`. That `u64` is a stand-in: under §7 it becomes the `(DurableRef, IndexSeal, QueryReference)` part of the binding witness. The backend switch (MORK, PathMap, native) does not touch the witness: the witness is about the data, the backend is a physical capability BIND attests. No new executor, store, or per-fold commit; the no-gather ruling is unchanged. + **Stop condition:** any design that requires copying canonical map facts per thought, using RelAlg as a table store, or allocating new CE64 bits to identify MapId/MapPaletteId has chosen the wrong boundary. **Short form: RelationshipMapStore stores. OGAR types. ThoughtMapPalette selects. BIND borrows. RelAlg describes. Quack lowers. Mask-RISC executes. CE64 remains opaque.** diff --git a/.claude/plans/thought-git-api-v1.md b/.claude/plans/thought-git-api-v1.md index b23dd4eb5..008f92265 100644 --- a/.claude/plans/thought-git-api-v1.md +++ b/.claude/plans/thought-git-api-v1.md @@ -231,3 +231,20 @@ carry has to be checked before choosing. - Timings: v4 only, ns per cell, tier printed by the program. - The dense/sparse crossover that picks presence masks or leapfrog seek per operand (catalogue P3/P11); measured, not assumed. + +## Gaps found by D-RMAP-1A §7 (2026-10-19, PROPOSED) + +D-RMAP-1A §7 derives its map, palette and binding generations from this plan +and #1605 instead of keeping its own counters. Two things it needs are not +specified here yet: + +- **A thought identity that survives slot reuse.** Slots are reused (Rule 4), + and nothing here names the thought that occupied a slot. #1605's + `ThoughtCommitId` is the candidate; it must never be reused, including after + `discard` and `squash` (D-RMAP X4). +- **A dirty bit.** Whether a thought has writes after its last commit. A + cached projection built from the last commit must be refused while it is + set (D-RMAP X5); a commit per fold is ruled out (#1605 §5.8). + +The PR-record open item above also decides whether a landed thought that +writes several datasets has one `DurableRef` per dataset (D-RMAP §7.6.3). diff --git a/.claude/v3/ENTROPY-MILESTONES.md b/.claude/v3/ENTROPY-MILESTONES.md index 49c8694cc..d24fe7ef3 100644 --- a/.claude/v3/ENTROPY-MILESTONES.md +++ b/.claude/v3/ENTROPY-MILESTONES.md @@ -50,6 +50,7 @@ | M25 | 2 persistence surfaces for orchestration state (graph-flow SessionStorage backend vs mailbox kanban board) | ONE: KanbanSessionStorage — Session transitions ARE KanbanMoves via the W1b writer; replay = rebuild from board | kill-mid-graph replay test: session resumes identically from board-recorded moves; grep non-kanban SessionStorage impls in lance-graph = zero | SHIPPED v1 2026-07-02 (rs-graph-llm graph-flow `kanban` feature: KanbanSessionStorage, snapshot+move-log; kill-mid-graph replay test GREEN — no repeats/gaps, pinned Rubicon column sequence; grep gate holds: no non-kanban SessionStorage impl in lance-graph) | | M26 | 2 belief representations (D-DIA reasoning arena `Belief`{CStmt+TruthValue, `belief.rs`} risks a NEW persistent belief store parallel to the M20 awareness carrier) | ONE: a `Belief` PERSISTS as a **reading across the M20 autopoiesis triangle** — statement→`awareness_facet::SpoFacet` semantic triple, witness→`SpoFacet` witness triple, truth→`cognitive_palette`/NARS; the in-memory arena stays the ephemeral working-set (data-flow cat-2), NO new SoA belief schema | a `Belief ↔ SpoFacet` mapping with a semantic-triple round-trip parity test (codebook-mediated: term-id→palette256² pair, gated on `PROBE-CODEBOOK-44`/M1); grep new belief-storage types in the SoA layer = zero | MECHANISM SHIPPED 2026-07-23 (`E-DIA-V4-FIELD-SEARCH-LOOP-1`): the `Belief↔SpoFacet` lossless byte round-trip is built + green (`planner/nars/facet_fold.rs`, `to_spo_facet`/`cstmt_from_spo_facet`, round-trip parity across all copulas incl. `Rel(65535)` + boundary term-ids) — a Belief IS a reading of the M20 awareness register, no new store. Remaining: the lossy codebook-mediated SEMANTIC placement (term→centroid, needs term embeddings). Was QUEUED (D-DIA; the codebook dependency PROBE-CODEBOOK-44 is now **mechanism-GREEN** 2026-07-23 `E-PROBE-CODEBOOK-44-MECHANISM-1` — the term→palette256² hierarchy is real, real-data ρ pending; remaining M26 work = the `Belief↔SpoFacet` round-trip mapping itself. The foveated field-search reads the persisted `SpoFacet`, not the arena — `E-FOVEATED-HHTL-TRIE-FIELD-SEARCH-1` fold correction) | | M27 | ≥5 threshold/band vocabularies over ONE distance column: `ndarray::hpc::cascade::Band` (quarters of t), `perturbation-sim::FloorBand`, holograph `QualityTracker` buckets + `HdrCascade` `threshold_l0/l1/l2` / `DEFAULT_EXCITE/INHIBIT`, OGAR `residue_band`, and the `mu + kσ` reject floor (`.claude/nexgen/harvest/01-cascade-rolling-floor-hdr.md`) | ONE sealed `NestedBands` per `(classid, version)` (the plan's TARGET key, room 26 — the shipped struct is version-keyed over one column, no classid): `bucket_index(row) = partition_point(masks, row)`; bucket i = `mask_ternlog::` BY NAME; Prozentrang = the index; rollover = a version-keyed mask split, never a rewrite (`.claude/nexgen/plans/nexgen-mask-histogram-thresholds-v1.md` rooms 0–4, §2 T1/T2) | production callers of the five vocabularies = calls into `planner::nested_bands` only; PROBE-NXG-HIST-1/ROLL-1/FLOOR-1 stay green; no numeric threshold parameter on a T3 signature (room 19 reflective fence); `E-NXG-20` bounds it — the rank floor is the best ACHIEVABLE boundary, exact only without ties | mechanism SHIPPED (`crates/lance-graph-planner/src/nested_bands.rs`, D-NXG-1/4/5, `E-NXG-21`, 2026-09-05); the collapse of the callers is D-NXG-6/7/8 — QUEUED. Row added 2026-09-07 (plan inventory: this folder had no reference to the nexgen work) | +| M28 | 4 version spellings, none dataset-scoped (`temporal.rs` `LanceVersion = u64`, `temporal_pov.rs` `LanceVersion = u64`, `scheduler.rs` `DatasetVersion(u64)`, `versioned.rs` bare `u64` of the nodes dataset only) plus D-RMAP-1A's own map/palette/incarnation counters (proposed, unbuilt) | `DurableRef{dataset, branch, version}` (#1605 §1) for durable identity, `ThoughtCommitId` for speculative, read through `QueryReference::at(v, rung)`; D-RMAP generations are readings of these (D-RMAP-1A §7) | D-RMAP-1A §7.4 X1 (two datasets at one version refused) green; grep: no map/palette generation counter outside `DurableRef`/`ThoughtCommitId` | PROPOSED 2026-10-19 (no `DurableRef` type yet; CPG-00 unrun). Row added with D-RMAP-1A §7 | ## The meta-rule (why this ledger exists) From 79baa045112bdf2ddbf85794027d53d4c0184de9 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 20:58:21 +0000 Subject: [PATCH 3/3] =?UTF-8?q?d-rmap=20=C2=A77:=20cite=20symbols,=20not?= =?UTF-8?q?=20line=20numbers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit citation-decay flagged temporal.rs:134 as anchorless. Every §7 and board-entry citation into source now names the symbol instead of a line. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VyWZYKycy6MoYDxHRVnV5K --- .../entries/2026-10-19-d-rmap-thought-git-versioning.md | 2 +- .claude/plans/d-rmap-separate-tables-thought-palettes-v1.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.claude/board/entries/2026-10-19-d-rmap-thought-git-versioning.md b/.claude/board/entries/2026-10-19-d-rmap-thought-git-versioning.md index d87487967..40b9f55f1 100644 --- a/.claude/board/entries/2026-10-19-d-rmap-thought-git-versioning.md +++ b/.claude/board/entries/2026-10-19-d-rmap-thought-git-versioning.md @@ -6,7 +6,7 @@ **Decision (PROPOSED):** D-RMAP keeps no durable revision counter. Map generation and palette generation are readings of `DurableRef{dataset, branch, version}` (sealed) or `ThoughtCommitId` (speculative); the thought-palette binding is `(ThoughtCommitId, palette generation)`, replacing `(slot, incarnation)`. Focus generation stays an ephemeral frame-local witness. The index seal stays separate unless RelationFacts uses stable row ids (H14c-5: compaction moved 3 510 of 3 510 `_rowid`s without them, 0 with them). Authorization scope stays its own key component. Replay reads `QueryReference::at(v, rung)` with `Strict`, never `QueryReference::default()`. -**Measured in code (read 2026-10-19):** no version type carries a dataset or branch (`temporal.rs:72`, `temporal_pov.rs:49`, `scheduler.rs:36`); `versioned.rs::commit_encounter_round` writes three datasets and returns only the nodes version; `AlphaStamp.visits` saturates and is not a generation; D-TGA has no thought incarnation. +**Measured in code (read 2026-10-19):** no version type carries a dataset or branch (`temporal.rs` and `temporal_pov.rs` `LanceVersion = u64`, `scheduler.rs` `DatasetVersion(u64)`); `versioned.rs::commit_encounter_round` writes three datasets and returns only the nodes version; `AlphaStamp.visits` saturates and is not a generation; D-TGA has no thought incarnation. **Gaps filed into the source plans:** `ThoughtCommitId` must be never-reused (thought-git-api-v1, causal-pickaxe); a dirty bit for writes after the last commit (thought-git-api-v1); multi-dataset writes need one `DurableRef` per dataset or a refusal (both). diff --git a/.claude/plans/d-rmap-separate-tables-thought-palettes-v1.md b/.claude/plans/d-rmap-separate-tables-thought-palettes-v1.md index bcb2c8a1e..988c32701 100644 --- a/.claude/plans/d-rmap-separate-tables-thought-palettes-v1.md +++ b/.claude/plans/d-rmap-separate-tables-thought-palettes-v1.md @@ -134,7 +134,7 @@ Status: PROPOSED. Nothing here is implemented; RelationshipMap storage stays a p | Thought Git (D-TGA) | logical revision of speculative state: `branch`, `write`, `rebase`, `land`, `squash_into`, `blame` | thought-git-api-v1 §Surface, Rules 1–5 | | `ThoughtCommitId` (D-CPG §1) | identity of one in-memory thought commit and its parents | #1605 §1, "speculative" row | | Lance, through `DurableRef{dataset, branch, version}` | sealed snapshots; one `land` = one next version (D-TGA "versions as PR entries") | #1605 §1 "durable" row, §5.2 | -| `temporal.rs` | epistemic reading of a version: `QueryReference::at(v, rung)`; replay and blame use an explicit `EpistemicMode::Strict` | `crates/lance-graph-planner/src/temporal.rs:134,188` (code) | +| `temporal.rs` | epistemic reading of a version: `QueryReference::at(v, rung)`; replay and blame use an explicit `EpistemicMode::Strict` | `crates/lance-graph-planner/src/temporal.rs`, `QueryReference` and `QueryReference::at` (code) | | Physical index seal | validity of a sorted permutation against the row-address map it points into | this plan, §7.3 row 5 | | Binding witness | the ephemeral tuple BIND checks before it borrows a span (§7.5) | this plan | @@ -142,8 +142,8 @@ D-RMAP owns **relational binding**, and nothing else: which maps a thought selec ### 7.2 What is code today (measured 2026-10-19, read in full) -- **Version identity is never dataset-scoped.** `temporal.rs:72` `LanceVersion = u64`; `temporal_pov.rs:49` `LanceVersion = u64`; `scheduler.rs:36` `DatasetVersion(pub u64)` (also `LanceCycleWriter::head()`); `versioned.rs` returns bare `u64`. `QueryReference` (`temporal.rs:134`) has `server_id, ref_version, hlc_tick, mode, rung` and no dataset or branch. No `DurableRef` or `ThoughtCommitId` exists in `crates/` (search: `DurableRef|ThoughtCommitId|dataset_id` over `crates/**/*.rs`, 0 hits; a negative over that named space only). -- **`versioned.rs` already shows the collision this section guards against.** `commit_encounter_round` (`versioned.rs:255`) writes three datasets (nodes, edges, fingerprints) in three separate commits and returns only the nodes version; the edges and fingerprints versions are dropped. `at_version`, `current_version`, `versions` and `tag` read the nodes dataset only. A caller holding that `u64` cannot name the edges snapshot it was written with. (Its doc says each write "appends"; `write_batch` uses `WriteMode::Overwrite`.) +- **Version identity is never dataset-scoped.** `temporal.rs` `pub type LanceVersion = u64`; `temporal_pov.rs` `pub type LanceVersion = u64`; `scheduler.rs` `pub struct DatasetVersion(pub u64)` (also `LanceCycleWriter::head()`); `versioned.rs` returns bare `u64`. `QueryReference` (`temporal.rs`) has `server_id, ref_version, hlc_tick, mode, rung` and no dataset or branch. No `DurableRef` or `ThoughtCommitId` exists in `crates/` (search: `DurableRef|ThoughtCommitId|dataset_id` over `crates/**/*.rs`, 0 hits; a negative over that named space only). +- **`versioned.rs` already shows the collision this section guards against.** `commit_encounter_round` (`versioned.rs`) writes three datasets (nodes, edges, fingerprints) in three separate commits and returns only the nodes version; the edges and fingerprints versions are dropped. `at_version`, `current_version`, `versions` and `tag` read the nodes dataset only. A caller holding that `u64` cannot name the edges snapshot it was written with. (Its doc says each write "appends"; `write_batch` uses `WriteMode::Overwrite`.) - **`QueryReference::default()` is unbounded** (`ref_version = u64::MAX`), the dangerous default #1605 names. A witness must never be built from it. - **The alpha overlay's `visits` is not a generation.** `AlphaStamp.visits: u16` counts revisits of one address and saturates (`alpha.rs` `claim`, `saturating_add`); `seq`/`rung`/`cycle` keep the first claim. A palette rewritten A→B→A at one address is two revisits, not a version, and stops counting at 65 535. - **D-TGA has no thought incarnation.** Slots 1..63 are reused after `squash`/`discard` (D-TGA Rule 4: "the thought number does not survive"). §2's `(thought slot, incarnation)` therefore needs an identity D-TGA does not define; #1605's `ThoughtCommitId` is the only specified candidate.