From 7f32b02fb4f7c0ebffb16cce0b7004f713ac5afe Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 2 Jul 2026 05:07:46 +0000 Subject: [PATCH 01/13] board: post-merge hygiene for PR #625 (LATEST_STATE row + PR_ARC entry) Records the merged knowledge arc (brick-3 RAN / truncation-disallowed / DO-arm 3-bucket triage / ogar lock a0c7936) plus the immutable mid-arc supersession note: the OSINT mirror commits this branch briefly carried were dropped in the rebase per the OGAR #146 zero-vocabulary-rows ruling and never merged; main's ISSUES.md resolution is authoritative. --- .claude/board/LATEST_STATE.md | 1 + .claude/board/PR_ARC_INVENTORY.md | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/.claude/board/LATEST_STATE.md b/.claude/board/LATEST_STATE.md index 68d79495..56d553ac 100644 --- a/.claude/board/LATEST_STATE.md +++ b/.claude/board/LATEST_STATE.md @@ -117,6 +117,7 @@ Membrane consumers can now pull BOTH halves of a render `classid` BBB-safely fro | **#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`. | +| **#625** | 2026-07-02 | brick-3 RAN: truncation-disallowed / overflow-as-SoC-reroute + DO-arm 3-bucket triage | Knowledge tier: `ast-as-partof-isa-address.md` Status → PARTIALLY MEASURED (rank-minter brick-3 RAN via `ruff_csharp_spo` → `ruff_spo_address::{mint, mint_factored}` → `medcare_probe`; naive 6-tier mint FALSIFIED; truncation DISALLOWED — overflow = SoC-reroute trigger per OGAR `256-cap-is-a-lint` #130/#140; overflow *classification* shipped upstream as `ruff_spo_address::soc`, class-conditioned shapes 6×2/4×3/3×4). New `do-arm-triage-3-bucket.md` (fuzzy→canonicalize / standard-DO→one DTO adapter + codebook swiss-knife / random→hand-port-and-graduate; C#/C++ DO-extractor gap named). Proprietary numbers stay in private MedCare-rs archive. Lock: ogar → `a0c7936` (post-#146, fuse 65==65). Mid-arc OSINT mirror commits DROPPED per OGAR #146 ruling. Branch `claude/medcare-bridge-lance-graph-wmx76z`, merge `5561908`. | | **#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`. | | **#626** | 2026-07-02 | V3 convergence wiring: tenant-carve certification, RungElevator, P6 wave probe, seam-list plan | "Wire, don't invent": `RungLevel::{from_u8,elevate,de_elevate,pearl_level,causal_mask_bits}` + `RungElevator` (sustained-BLOCK policy over P2/P3-certified masks; converged with `escalation::rung_delta` via `apply_delta` — one ladder, two signal sources) wired through the driver (persistent elevator, `ctx.rung=1` proxy retired, grpc rung saturates-never-wraps per codex P2); BOTH V3 tenant carves matrix-certified (Cognitive + Compressed); P6 probe (wave dist == certified palette read, markov_soa verified); `[patch.crates-io] ndarray` → local sibling path (fetch deadlock gone; first in-sandbox core build, 925/925). Plan `v3-convergence-wiring-v1.md`; worker Rule 7. Branch `claude/v3-substrate-migration-review-o0yoxv`, merge `5aaee33`. | | **#542** | 2026-06-18 | E-OGAR-IS-FOUNDRY capstone + 5+3 council + the key→row baton | Foundry/Gotham = "write the OGAR class schema + inheritance"; everything else is generic machinery over it (ontology=`classid→ClassView`+inheritance, AR=DO/THINK, pipelines=`compute_dag`, apps=Jinja-over-classes, query=Cypher⇄SurrealQL one IR). Added `MailboxSoaView::row_for_local_key -> Option` (default `None`, deferred-binding — the key→row baton for a future `Backend::MailboxSoa` router). Epiphanies `E-OGAR-IS-FOUNDRY`/`E-CYPHER-IS-THE-KANBAN-AST`/`E-GUID-IS-THE-GRAPH`; plan `cypher-kanban-ast-unification-v1`. Council corrections: `from_guid_prefix` is on `NiblePath` not `NodeGuid`; "odoo proof" = CONJECTURE; `ogar-adapter-surrealql` not a crate. Branch `claude/q2-substrate-grounding`, merge `faca377f`. | diff --git a/.claude/board/PR_ARC_INVENTORY.md b/.claude/board/PR_ARC_INVENTORY.md index 90bd11b3..8f96bd85 100644 --- a/.claude/board/PR_ARC_INVENTORY.md +++ b/.claude/board/PR_ARC_INVENTORY.md @@ -108,6 +108,25 @@ **Docs:** plan `classid-canon-custom-flip-v1.md` (phases now P0/P1/P2 DONE, P3 in q2 #71, P4 open); EPIPHANIES `E-CLASSID-FLIP-P1-LANDED` + `E-CLASSID-COMPAT-READER`; fleet inventories in AGENT_LOG. Sibling merges: OGAR #147, MedCare-rs #180, woa-rs #177; open: q2 #71, openproject-nexgen-rs #68 (lock bumped `ff3777b`, gate closed). **Confidence (2026-07-02):** HIGH — 774 contract tests (guid-v3-tail) + 759 default + doctests + dependents (callcenter/shader-driver/planner/rbac/ogar) green; clippy -D warnings; fleet verified per-repo. +## #625 lance-graph: brick-3 RAN (truncation-disallowed / overflow-as-SoC-reroute) + DO-arm 3-bucket triage + +**Status:** MERGED 2026-07-02 (merge commit `5561908`), branch `claude/medcare-bridge-lance-graph-wmx76z`. Knowledge-tier PR — closes the record-vs-reality drift after #616/#617: the design record catches up to the measurement. + +**Added:** `.claude/knowledge/ast-as-partof-isa-address.md` corrections — Status CONJECTURE → PARTIALLY MEASURED (carrier #613/#614/#615 shipped AND the rank-minter brick-3 has RUN: `ruff_csharp_spo` harvest → `ruff_spo_address::{mint, mint_factored}` → `medcare_probe`); "The missing brick" → "The brick that ran"; Next-bricks checkmarked with the real open bricks (reroute *execution* in the mint pipeline, probe re-run blocked on harvest input data, classid Canon:Custom half-order, LSP serve end). New `.claude/knowledge/do-arm-triage-3-bucket.md` — the operator's 3-bucket DO-residue triage (fuzzy/order-varying → canonicalize-first; anticipated standard DO → ontologically-shaped landing zone as ONE DTO adapter + codebook swiss-knife `open`/`filter`/`reorder`/`apply_mask`; truly random → hand-port, recurrences graduate to bucket 2), refining OGAR's 85/15 split; records the C#/C++ DO-extractor gap (`ruff_python_dto_check` is Python-only). Lock: ogar pin `597ecb1 → a0c7936` (post-OGAR-#146). EPIPHANIES `E-BRICK3-RAN-TRUNCATION-DISALLOWED` (same-commit hygiene). + +**Locked:** the naive fixed-width 6-tier `(part_of:is_a)` mint is FALSIFIED at real-corpus scale (mass truncation + god-class collisions); `mint_factored` (base-255 positional path + `is_a`-from-`inherits`-only) is the corrected minter. **Truncation is DISALLOWED by policy** — bucket overflow (256-cap / 6-tier depth) is a separation-of-concerns REROUTE trigger (split the god-class or escalate a cascade level; never truncate, never field-widen — the OGAR `256-cap-is-a-lint` law #130/#140 made operational). Division of labour: `mint_factored` = addressing precision; overflow→SoC-reroute = structure. Overflow *classification* SHIPPED upstream as `ruff_spo_address::soc` (`soc_findings` → `SocVerdict`, `law_holds`; class-conditioned cascade shapes Rails `6×2` / other `4×3` / canonical GUID `3×4`, all `G·D = 12`). **Privacy split:** proprietary corpus numbers live ONLY in private MedCare-rs `.claude/archive/ruff-spo-address-medcare-probe/`; the lance-graph tree carries the design consequence, zero corpus identifiers. + +**Deferred:** overflow-reroute *execution* inside the mint pipeline (the lint flags, a human splits); `medcare_probe` re-run on the current minter (needs corpus/NDJSON access); C#/C++ DO harvester (bucket-2 landing-zone extractor); classid Canon:Custom half-order (superseded mid-arc by the #627 canon:custom flip plan). + +**Mid-arc supersession note (immutable history):** this branch briefly carried the OSINT mirror rows + a `SHIPPED_ROOT_SLOT_CONCEPTS = [0x0700]` zero-slot carve-out (the ISS-OGAR-OSINT-MIRROR-PENDING READY PATCH). OGAR #146 executed the operator ruling ("OSINT contributes ZERO vocabulary rows — low byte is APPID space, domain-wise"), removing both #145 mints; the fuse balances 65 == 65 with zero mirror-side changes, so those commits were DROPPED in the rebase onto #626/#627 and never merged. Main's ISSUES.md (`ISS-OSINT-SYSTEM-ROOT-SLOT-VIOLATION` RESOLVED 2026-07-02) is authoritative. + +**Docs/board:** EPIPHANIES ×1; the two knowledge docs above; PR comments record the scope arc + the dropped-commit correction. + +**Confidence (2026-07-02):** HIGH for the knowledge content (brick-3 findings mirror the private archive's measured record; re-fetch diff against ruff `b459ec3` confirmed `lib.rs` byte-identical + `soc.rs` as the movement). Lock verified: contract `ogar_codebook` 8/8 + `lance-graph-ogar` standalone green at `a0c7936` (compile-time COUNT_FUSE holds); consumer medcare-bridge (`--features ontology`) compiles clean. NOTE: merged BEFORE #628's P1 flip — the ast-address doc's classid examples predate `ClassidOrder::CanonHigh`; interpret per the flip (canon `domain:appid` = HIGH u16). + +**Cross-ref:** #616/#617 (the ast-address doc lineage); #623 (OGAR sink-in plan); OGAR #145/#146 (OSINT mint + zero-rows ruling); ruff `b459ec3` (`ruff_spo_address` + `soc`); `E-CODEBOOK-MINT-IS-A-CROSS-REPO-ARC`; MedCare-rs private archive (RESTORE-STATUS re-fetch log). + +--- ## #627 lance-graph: classid canon:custom flip TRIGGERED — migration plan v1 + operator ruling record (doc-only) From ffeb2f5bacf8efe17672983545e8fab79fc1361d Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 2 Jul 2026 12:00:46 +0000 Subject: [PATCH 02/13] =?UTF-8?q?board:=20correction=20=E2=80=94=20mint=5F?= =?UTF-8?q?factored=20is=20split-brain=20across=20ruff=20branches,=20not?= =?UTF-8?q?=20on=20main?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 2026-07-02 OGAR+ruff review fan-out falsified a claim in the #625 record: ruff main carries mint + soc.rs; mint_factored + RadixCodebook live only on claude/medcare-ruff-csharp-sync-4iahey (505fdc4), which diverged before the soc promotion and lacks soc.rs — no branch carries both. E-BRICK3-CORRECTION prepended; dated correction line appended to the #625 PR_ARC entry per the corrections-append rule. --- .claude/board/EPIPHANIES.md | 27 +++++++++++++++++++++++++++ .claude/board/PR_ARC_INVENTORY.md | 2 ++ 2 files changed, 29 insertions(+) diff --git a/.claude/board/EPIPHANIES.md b/.claude/board/EPIPHANIES.md index 3d74b326..b26dc7ed 100644 --- a/.claude/board/EPIPHANIES.md +++ b/.claude/board/EPIPHANIES.md @@ -342,6 +342,33 @@ Operator: rs-graph-llm under lance-graph "might need some kanban integration to **Status:** FINDING (plan deltas folded into INTEGRATION-PLAN.md Addendum 2026-07-02) Headline collapses: (1) the kanban board IS the write-ahead log — cast = move = intent, ack = confirmation; W1b/W1c are one object, crash recovery free (M24). (2) M7 ruling rec: SoaEnvelope re-scoped as spec/certification surface (verify_layout + field-isolation matrix are the value; zero production impls of the trait). (3) Baseline inversion: W6a scanner runs at W1 START — adoption-100% needs a measured t0 denominator. (4) W3 oracle ratchet: oracle-hit rate must trend down vs catalogue size or deterministic-first is silently dead. (5) W2 reorder probe→budget→arms; budget constants measured not guessed; probe at batch 1/64/4096; loser owns slow path. (6) Ractor batching by API shape (Vec per message). (7+8) Pull-forwards: D-PERT-1 and M21 canon-node-bytes ride W1. (9) Gate-run rule: wave PRs end with /v3-audit + touched M-row greps in AGENT_LOG. (10) Supervisor stays thin — the product is the compile-time ownership attestation, not runtime supervision. Test applied throughout: every item is a collapse/reorder of existing machinery, none invents a layer. +## 2026-07-02 — E-BRICK3-CORRECTION-MINT-FACTORED-IS-SPLIT-BRAIN — the "corrected minter" exists only as the UNION of two diverged ruff branches; no branch carries both mint_factored AND soc.rs + +**Status:** CORRECTION (of `E-BRICK3-RAN-TRUNCATION-DISALLOWED` + PR #625's +`ast-as-partof-isa-address.md` "brick that ran" section, both of which state +`mint_factored` shipped). + +**The finding (review agent, ruff @ b459ec3, verified via git show/diffstat):** +ruff main carries `ruff_spo_address::{mint, soc}` — the naive minter (with its +own falsification recorded in its doc header) plus the 256-cap-is-a-lint +classifier. **`mint_factored` + `RadixCodebook` + `ONTOLOGICAL-RADIX-TRIE.md` +live ONLY on branch `claude/medcare-ruff-csharp-sync-4iahey` (tip `505fdc4`)**, +which diverged BEFORE the soc promotion and therefore LACKS `soc.rs` (branch↔main +diffstat: `soc.rs | 335 ---`). A naive merge of that branch would delete the +lint. So: main ships the falsified minter; the corrected minter has never +coexisted with the lint that motivated it. + +**Consequence:** the single highest-leverage small move in the address stack is +rebasing `mint_factored`+`RadixCodebook` over main (conflict surface ≈ the +`pub mod` line + doc header) so the corrected state exists on ONE branch. +Until then, "brick-3's corrected form is shipped" is true only of the private +probe run, not of public ruff main. + +**Process note:** my #625 record propagated the claim from the private archive's +RESTORE-STATUS without re-verifying WHICH branch carried the code — the same +verify-by-reading-not-by-inheriting failure mode as the stale-doc-comment +episode (E-BRICK3 arc). Corrections cite their pass: surfaced by the 2026-07-02 +OGAR+ruff review fan-out. ## 2026-07-02 — E-V3-PLANNER-TWO-NATURES-AND-SPEED-PROBE (operator: planner too slow for sub-µs; resonance-based thinking is not DataFusion) **Status:** FINDING (operator-ruled; speed claim probe-gated per truth-architect discipline) diff --git a/.claude/board/PR_ARC_INVENTORY.md b/.claude/board/PR_ARC_INVENTORY.md index 8f96bd85..a6a2d7b3 100644 --- a/.claude/board/PR_ARC_INVENTORY.md +++ b/.claude/board/PR_ARC_INVENTORY.md @@ -126,6 +126,8 @@ **Cross-ref:** #616/#617 (the ast-address doc lineage); #623 (OGAR sink-in plan); OGAR #145/#146 (OSINT mint + zero-rows ruling); ruff `b459ec3` (`ruff_spo_address` + `soc`); `E-CODEBOOK-MINT-IS-A-CROSS-REPO-ARC`; MedCare-rs private archive (RESTORE-STATUS re-fetch log). +**Correction (2026-07-02, from the OGAR+ruff review fan-out):** the Locked line's "`mint_factored` … is the corrected minter" overstates its location — on public ruff main only `mint` + `soc.rs` exist; `mint_factored`+`RadixCodebook` are stranded on branch `claude/medcare-ruff-csharp-sync-4iahey` (`505fdc4`), which predates and LACKS `soc.rs`. The corrected-minter state exists only as the union of two diverged branches. See `E-BRICK3-CORRECTION-MINT-FACTORED-IS-SPLIT-BRAIN`. + --- ## #627 lance-graph: classid canon:custom flip TRIGGERED — migration plan v1 + operator ruling record (doc-only) From bba92277c1b3bd1c0d0a68316defdab11c8536b5 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 2 Jul 2026 13:36:07 +0000 Subject: [PATCH 03/13] =?UTF-8?q?handover:=20cross-session=20wishlist=20sy?= =?UTF-8?q?nthesis=20=E2=80=94=20convergence=20ratification,=20dedups,=20t?= =?UTF-8?q?he=20ruff=20sync=20arc,=20one=20byte-truth=20ruling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Synthesizes three sessions' wishlists (this session's E-sweep, the coverage session's grounded list, op-nexgen's R/L/O/X list): ratifies the >=2-session convergences (two-sided fuses, test-pinned counts, zero-dep metric folds, F17, board-collision fix), records two dedup decisions (E2-ruby yields to R1 D-AR-3.5; disposition ledger == 3-bucket triage, one doctrine), proposes the single ruff integration order + minimal ruff governance, merges E7 + EdgeBlock into one operator byte-truth ruling, guards the columnar interchange against a second dialect split, and names the unclaimed probe-corpus archival gap. --- ...-07-02-cross-session-wishlist-synthesis.md | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 .claude/handovers/2026-07-02-cross-session-wishlist-synthesis.md diff --git a/.claude/handovers/2026-07-02-cross-session-wishlist-synthesis.md b/.claude/handovers/2026-07-02-cross-session-wishlist-synthesis.md new file mode 100644 index 00000000..81474c1f --- /dev/null +++ b/.claude/handovers/2026-07-02-cross-session-wishlist-synthesis.md @@ -0,0 +1,76 @@ +# Cross-session wishlist synthesis — 2026-07-02 (post-#630/#631) + +> From: the medcare-bridge session (branch `claude/medcare-bridge-lance-graph-wmx76z`). +> Inputs: this session's E1–E10 sweep (OGAR@19373a2 + ruff@b459ec3 review fan-out), +> the coverage session's grounded wishlist (ruff/OGAR/V3 items with acceptance +> tests), op-nexgen's R/L/O/X wishlist (2026-07-02). Operator relayed all three. +> APPEND-ONLY once committed; corrections cite their pass. + +## Ratified-by-convergence (≥2 sessions independently) + +1. **Two-sided fuses** — OGAR-side flip/COUNT_FUSE pinning test; "a dependency + contract named on one side is a slogan." (this session #1 ≡ coverage #7) +2. **Counts pinned by tests, never prose** — predicate-count pin (62), MethodSig + existence/parity pin, post-flip prose sweep. (E8 ≡ coverage #1/#2) +3. **Governance metrics = zero-dep contract folds** — classid_scan (#630) → + emission_scan (op-nexgen L2) is a design language now; name it in EPIPHANIES + so the next metric follows it (never a grep). +4. **F17 body triage** — unblocked since 06-30, consumed by nothing; flagged by + all three sessions. Most-agreed next move on the DO path. (mine #9 ≡ R6) +5. **Board prepend-collision fix** — per-entry board files (coverage #8) + + COORDINATION.md per repo (op-nexgen X1). Measured cost datapoint: 3 of this + session's rebases conflicted ONLY on board prepends. + +## Dedup decisions (avoid parallel work) + +- **E2-ruby DROPPED in favor of op-nexgen R1** (D-AR-3.5 column stratum from + the migration DSL — better Rails truth source than model-body extract_fields; + measured 99/65/27-typed on the real corpus). E2-python (`inherits_from` + emission in ruff_python_spo) STANDS — uncovered elsewhere; gates + mint_factored's is_a axis on Odoo. +- **"Disposition ledger" (coverage #5) ≡ the 3-bucket DO triage** + (`do-arm-triage-3-bucket.md`, #625): buckets = the routing decision, + disposition ledger = its conservation accounting. Cross-reference as ONE + doctrine; do not let two vocabularies grow. + +## ruff needs ONE sync arc (and minimal governance) + +Pending ruff work from three sessions: mint_factored split-brain rebase (E1), +coverage items 1–5, nexgen R1–R8 (incl. a vendored diff targeting "pristine +main" and R7's already-failing branch fixture). Proposed integration order: +(1) mint_factored rebase (smallest, oldest, ruff_spo_address only) → +(2) R1 D-AR-3.5 while main is pristine for the diff → +(3) R2 curated fixes + R7 fixture reconciliation → +(4) predicate-manifest parity test LAST (pins the union, guards forever). +Plus: give ruff a COORDINATION.md + 20-line LATEST_STATE before the arc starts. + +## One operator ruling covers two byte-truth conflicts + +E7 (hi-u16: `domain:appid` in le-contract vs `domain:concept-slot` in OGAR +canon) and coverage #9 (EdgeBlock: OGAR `key16+value496` vs lance-graph CANON +`key16|edges16|value480`) are the same defect class: byte layout stated +divergently in two append-only ledgers. Settle both in one ruling; the form of +the settlement: one set of consts + size asserts both repos PIN, both +CLAUDE.mds POINTING, not restating (#630 M7 is the in-repo precedent). + +## Columnar-interchange guard + +op-nexgen L3 (Arrow triples, 5 columns s p o f c) and this session's E5 (Mint → +Arrow facets batch) MUST share one `ruff-interchange` record-batch schema +family + one provenance header (R5), and the provenance stamp must include +`minter@sha` — E1's split-brain proved an artifact that doesn't name its +minter is unverifiable. Two adjacent Arrow schemas defined independently would +recreate the field_type three-dialect problem at the columnar layer. + +## Gap no list claimed + +**Probe-corpus archival rule, operationally:** F17, count_adoption-vs-bake, and +the medcare probe re-run will each produce a number quoted for months — archive +the reproduction (input + generation recipe + hash) WITH the run, or we +re-create "last measured, can't re-verify." + +## Kept by this session + +E1 mint_factored rebase (step 1 of the ruff arc), E2-python inherits_from, +C#-golden vs Predicate::ALL, E5 Mint emission (pending the shared interchange +schema decision), predicate-manifest test (step 4). From 2345a6cc1f60f1322679831b0104d95dee1d8607 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 3 Jul 2026 10:43:27 +0000 Subject: [PATCH 04/13] handover: entropy-reduction pass + epiphany ledger (F1-F7 process findings + wishlist claim-of-record) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Durable home for the F-pass process epiphanies (pin-propagation is the third leg of the cross-repo arc; unpinned environments falsify true states — verified live; CI-invisible fuses fire in consumers' builds; claim-of-record prevents near-collisions, proven by the mint_factored near-redo) and a status-annotated ledger converting the wishlist synthesis from proposal to claim-of-record. Committed durability-first under an observed churning environment before the rebase. --- ...2-entropy-reduction-and-epiphany-ledger.md | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 .claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md diff --git a/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md b/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md new file mode 100644 index 00000000..d81b34ba --- /dev/null +++ b/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md @@ -0,0 +1,102 @@ +# Entropy-reduction pass + epiphany ledger — 2026-07-02 + +> From: the `claude/medcare-bridge-lance-graph-wmx76z` session (medcare-bridge / +> ruff-harvester / cross-session synthesis). Companion to +> `2026-07-02-cross-session-wishlist-synthesis.md` — this file adds the +> **process epiphanies** (durable, fleet-wide) and turns the wishlist into a +> **status-annotated ledger** (claim-of-record) so executed items stop being +> re-derived. APPEND-ONLY; status lines updatable. + +## Why this file exists (the entropy diagnosis) + +Three entropies force re-derivation of reality every turn: +1. **Stale local state** — a session's branch lags a fast-moving main. +2. **Ephemeral epiphanies** — insights live in chat, evaporate at session end. +3. **No claim-of-record** — executed wishlist items have no done-marks; work + gets nearly re-done (proven this session — see F7). + +This file kills #2 and #3 durably; the paired rebase kills #1. + +## Process epiphanies (F-pass, durable — the fleet needs these) + +- **F1 — Pin propagation is the third leg of the cross-repo arc.** The mint + + mirror rows + **lock pin** land in ONE arc, never split. An arc that ships the + mirror-row change without bumping its own `Cargo.lock` pin ships a + fuse-broken contract to every consumer while both sides' own tests stay green. + (Root of the recurring "OGAR concept count changed, consumer build E0080s".) +- **F2 — Unpinned environments falsify TRUE states.** Verified live this + session: a local `origin/main` remote-tracking ref read #636 then #631 then + #636 across three commands (container re-provisioned to an older clone + snapshot mid-turn). A verification whose environment isn't pinned can raise a + false alarm on a correct state. Discipline: `git -C ` + explicit + re-`fetch` + echo the resolved SHA **before** concluding; never trust a + remote-tracking ref you haven't refreshed this turn. +- **F3 — A gitignored lockfile is an *undecided* design, not a neutral one.** + `lance-graph-ogar`'s own `Cargo.lock` is untracked → fresh checkouts build its + `COUNT_FUSE` against OGAR **HEAD** (a floating canary) while the workspace + lock pins. Canary or pin are both defensible; *accidental* is not. One doc + sentence deciding it removes a "works here, breaks there" class. +- **F4 — Executed wishlists need a claim-of-record.** Convergent multi-session + execution without a shared done-ledger risks double-work AND silently-dropped + halves (e.g. a two-part item where only part 1 is confirmed). This ledger is + the fix. +- **F5 — CI-invisible fuses only fire in *other people's* builds.** Main's CI + never compiles the workspace-`exclude`d `lance-graph-ogar`, so lance-graph + learns its own mirror broke the contract only when a *consumer* (medcare, + twice) hits E0080. A single CI job that `cargo check`s the excluded crate + makes the fuse fire where the change is made. +- **F6 — Rebase economics inverted.** At ~5 fleet-merges/day the board-prepend + conflicts (EPIPHANIES/LATEST_STATE/PR_ARC) are the only recurring rebase cost; + that's 30–60 min/day per parallel session. Per-entry board files (one file per + entry + generated index) make the conflict structurally impossible — graduated + from nice-to-have to cheapest recoverable overhead in the system. +- **F7 — Claim-of-record prevents near-collisions (proven).** I was one command + from re-doing the `mint_factored`+`RadixCodebook`+`soc.rs` union — it was + already unified on ruff branch `claude/medcare-ruff-csharp-sync-4iahey` + (`94f919a`, "public-safe", −308 the medcare probe), just unmerged to ruff main. + Only incidental fetch output revealed it. Without this ledger the collision + recurs. + +## Wishlist status ledger (claim-of-record) + +Legend: **VERIFIED** (I read the code/count) · **CLAIMED-BY-COMMIT** (merge +message asserts it; not independently verified) · **OPEN** · **UNVERIFIED**. + +### OGAR-lane items (forwarded → executed by #148 `75d955b`) +| # | Item | Status | +|---|---|---| +| 1 | OGAR-side flip fuse (`app_of/concept_of` vs contract `ClassidOrder`) | CLAIMED-BY-COMMIT (#148 "flip fuse") — verify test exists | +| 2 | Genetics `0x0E` domain + reserve `0x1000` + q2 APP_PREFIX row | PARTIAL — `0x1000` reservation + Genetics domain CLAIMED-BY-COMMIT (#148); **q2 APP_PREFIX row UNVERIFIED** | +| 4 | OGAR post-flip prose sweep | CLAIMED-BY-COMMIT (#148 "post-flip prose sweep") | +| 6 | Fill `0x08XX` OCR slots (`unicharset`/`recoder`/`charset`) | **VERIFIED** — 3 rows, codebook 65→68 | +| 7 | Two-sided `COUNT_FUSE` | CLAIMED-BY-COMMIT (#148 "COUNT_FUSE" two-sided) | +| — | Main's own ogar lock propagated to #148 | **VERIFIED** — main `Cargo.lock` pin = `75d955b`, mirror = 68 (F1 resolved on main) | + +### Byte-truth / contract items +| # | Item | Status | +|---|---|---| +| 4b | `Facet`↔`FacetCascade` byte-parity test (cross-repo) | **UNVERIFIED (B4)** — flip fuse confirmed, byte-parity half not confirmed present | +| — | `emission_scan` / `RouteBucketTyped` (op-nexgen L1/L2) | CLAIMED-BY-COMMIT (#632) | + +### ruff-lane items (this session's kept work — HELD by operator "don't start yet") +| # | Item | Status | +|---|---|---| +| E1 | `mint_factored`+`RadixCodebook`+`soc.rs` union | **DONE on branch** `94f919a` (F7) — UNMERGED to ruff main. Phase 1 shrinks to "verify + PR". | +| E2-py | `inherits_from` emission in `ruff_python_spo` | OPEN (gates mint_factored is_a axis on Odoo) | +| E2-ruby | ruby `extract_fields` | CEDED to op-nexgen R1 (migration-DSL column stratum is the better Rails truth source) | +| E3 | predicate-manifest parity test + C# `Program.cs`-vs-`Predicate::ALL` golden | OPEN | +| E5 | `Mint` → ndjson (now) / Arrow (after shared interchange-schema decision) | OPEN — landing zone is the #630/#631 WAL batch writer | + +## Open operator decisions (unblock the fleet) +- **One authoritative high-half naming** — le-contract `domain:appid` vs OGAR + general canon `domain:concept-slot`; settle once, pin as shared consts both + repos reference (merges with the EdgeBlock `value480` vs `value496` divergence + — same defect class, one ruling). +- **Probe-ledger Wave A green-light** (OGAR PROBE-SUBSTRATE-PROPOSAL §9). +- **F3** — `lance-graph-ogar` lockfile: canary or pin? + +## This session's immediate next (guided by the epiphanies) +1. ~~Commit this ledger~~ (durability-first under unstable env — F2). +2. Rebase onto #636 (kills B1; F1 says verify+fix the lock IN the arc). +3. Verify B4 (byte-parity test present?) + item-1/2/7 CLAIMED→VERIFIED. +4. THEN await operator green-light on ruff Phase 1 (merge `94f919a`) vs W5. From 002313098fb274aa98ba53128b79c391cb7c3134 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 3 Jul 2026 10:45:14 +0000 Subject: [PATCH 05/13] =?UTF-8?q?board:=20F-pass=20hygiene=20=E2=80=94=20E?= =?UTF-8?q?-FLEET-CADENCE=20epiphany=20+=20TD-FLEET-CADENCE=20debts=20(F1-?= =?UTF-8?q?F7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepend the process/meta epiphany (pin-propagation is the third leg of the cross-repo arc; unpinned envs falsify true states, verified live; CI-invisible fuses fire in consumers' builds; claim-of-record prevents near-collisions, proven) to EPIPHANIES.md, and file the three concrete debts (CI-excluded fuse, undecided ogar lockfile, board-prepend conflicts) in TECH_DEBT.md. Full text + wishlist claim-of-record ledger in the paired entropy-reduction handover. --- .claude/board/EPIPHANIES.md | 41 +++++++++++++++++++++++++++++++++++++ .claude/board/TECH_DEBT.md | 5 +++++ 2 files changed, 46 insertions(+) diff --git a/.claude/board/EPIPHANIES.md b/.claude/board/EPIPHANIES.md index b26dc7ed..d0d4c293 100644 --- a/.claude/board/EPIPHANIES.md +++ b/.claude/board/EPIPHANIES.md @@ -260,6 +260,47 @@ Two firsts + one correction: (1) FIRST binary format — `TFile` LE: `u32 count` **Pattern holds (E-CPP-KEYSTONE-1).** A new Core type, but the SAME shape: content-store tier (zero-dep, rides the keystone), one `diff` per mode, no Core gap. +10 contract tests. Consumed by `tesseract-core::{Recoder, recoded_to_text}` (codes→decode→ids→`ids_to_text`; +1 boundary test, 8/8). The recoder keystone (`invoke_recoder`, the E-CPP-KEYSTONE-1 analog) is UNBLOCKED — OGAR #148 minted concept `recoder`=0x0802 (mirrored in `ogar_codebook`) — but DEFERRED: the `classid→ClassView→content` dispatch is already proven generically, so a recoder keystone would re-prove a pattern with no new byte-parity information. Routing re-verified LIVE against OGAR (not the plan's cached answers): SURREAL-AST-TRAP-PREFLIGHT 5Q (data-shaped table, zero lifecycle vocabulary → content-store is honest) + OGAR-AS-IR §3 (adds no `Class`/`ActionDef`/`KausalSpec` → rerouted to the content tier, NOT `emit_rust`). ndarray and `ruff_cpp_spo` were correctly NOT used: the recoder is zero-SIMD data, and `UnicharCompress`/`RecodedCharID` have no inheritance/vtable for the harvest to resolve. Cross-ref: `E-CPP-PARITY-1..6`, `E-CPP-KEYSTONE-1`, `.claude/knowledge/core-first-transcode-doctrine.md`, OGAR #148 (0x08 OCR mint). Branch `claude/happy-hamilton-0azlw4`, lance-graph + tesseract-rs. +## 2026-07-02 — E-FLEET-CADENCE-PROCESS-FINDINGS (F1-F7) — pin-propagation is the new bottleneck; unpinned envs falsify true states; claim-of-record prevents near-collisions + +**Status:** FINDING (process/meta; durable full text + +wishlist claim-of-record ledger in +`.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md`). +Surfaced by the `medcare-bridge` session across the #625→#636 fleet arc. + +The bottleneck moved from analysis/implementation to **mechanical +propagation** — the fleet executes forwarded wishlist items within hours, +so the failure modes are now coordination-shaped: + +- **F1 — pin propagation is the third leg of the cross-repo arc.** OGAR + entry + contract mirror rows + **`Cargo.lock` pin** land in ONE arc. + An arc that ships the mirror-row change without bumping its own lock + pin ships a fuse-broken contract to every consumer while both sides' + own tests stay green. (Root of the recurring consumer-side E0080.) +- **F2 — unpinned environments falsify TRUE states.** Verified live: a + local `origin/main` ref read #636→#631→#636 across three commands + (container re-provisioned to an older clone snapshot mid-turn). A + verification whose env isn't pinned can raise a false alarm on correct + state. Discipline: re-`fetch` + echo the resolved SHA before concluding. +- **F3 — a gitignored lockfile is an *undecided* design.** + `lance-graph-ogar`'s untracked `Cargo.lock` builds its `COUNT_FUSE` + against OGAR HEAD (floating canary) while the workspace lock pins. + Canary or pin both fine; accidental is not — needs one doc sentence. +- **F4 — executed wishlists need a claim-of-record.** Convergent + multi-session execution without shared done-marks risks double-work + AND silently-dropped halves. (The ledger handover is the fix.) +- **F5 — CI-invisible fuses fire only in *consumers'* builds.** Main's CI + never compiles the `exclude`d `lance-graph-ogar`, so lance-graph learns + its own mirror broke the contract only when medcare (twice) hits E0080. + One CI job that `cargo check`s the excluded crate closes the asymmetry. +- **F6 — rebase economics inverted.** At ~5 fleet-merges/day the + board-prepend conflicts (EPIPHANIES/LATEST_STATE/PR_ARC) are the only + recurring rebase cost — 30–60 min/day per parallel session. Per-entry + board files make the conflict structurally impossible. +- **F7 — claim-of-record prevents near-collisions (proven).** Was one + command from re-doing the `mint_factored`+`RadixCodebook`+`soc.rs` + union — already unified on ruff `claude/medcare-ruff-csharp-sync-4iahey` + (`94f919a`, unmerged); only incidental fetch output revealed it. + ## 2026-07-02 — E-1BRC-GRIDLAKE-SWEETSPOT-1: the 64×64 gridlake SoA is the measured sweet spot — the batch pipeline at tile scale equals the best streamed topology while carrying the double-WAL **Status:** FINDING (measured, onebrc-probe lane J t7; closes the operator's four follow-up questions and the t4→t7 kanban-update arc) diff --git a/.claude/board/TECH_DEBT.md b/.claude/board/TECH_DEBT.md index 3b14c6d5..cdecec09 100644 --- a/.claude/board/TECH_DEBT.md +++ b/.claude/board/TECH_DEBT.md @@ -2946,3 +2946,8 @@ bijection needs re-seeding. Pair: D-IDENTITY-4. ## TD-CALLCENTER-QUERY-CLIPPY — 2026-06-20 — OPEN **Owed:** `cargo clippy -p lance-graph-callcenter --features query --lib --tests -- -D warnings` fails on PRE-EXISTING debt unrelated to the graph-adapter work: `oxrdf::Subject` deprecation (`src/edge.rs`, use `NamedOrBlankNode`), doc-list overindent + misc in `savant_reasoners.rs` / `vsa_udfs.rs` / `ttl_parse.rs` / `transcode/zerocopy.rs` / `hydrators/owl.rs`. Surfaced (not caused) by the 16-family-adapter PR, whose own files (`graph_table.rs`, `graph_gremlin.rs`) are clippy-clean (verified: zero errors originate in them). **Why deferred:** out of scope — fixing the oxrdf deprecation + doc lints across 6 unrelated modules is its own sweep; this PR is the OSINT graph adapter. **Pay when:** a callcenter-clippy-hardening pass, or opportunistically when those modules are next touched. + +## 2026-07-02 — TD-FLEET-CADENCE (F3/F5/F6, from E-FLEET-CADENCE-PROCESS-FINDINGS) +- **TD-CI-EXCLUDED-FUSE (F5):** main's CI never compiles the workspace-`exclude`d `lance-graph-ogar`, so its compile-time `COUNT_FUSE` fires only in *consumers'* builds (medcare hit E0080 twice). Fix: one CI job `cargo check`-ing the excluded crate against OGAR main. Effort S. +- **TD-OGAR-LOCK-UNDECIDED (F3):** `lance-graph-ogar/Cargo.lock` is gitignored → fresh checkouts build the fuse against OGAR HEAD (floating canary) while the workspace lock pins. Decide canary-vs-pin; document in one sentence. Effort S. +- **TD-BOARD-PREPEND-CONFLICTS (F6):** at fleet cadence the append-only board files (EPIPHANIES/LATEST_STATE/PR_ARC) are the only recurring rebase-conflict cost (~30-60 min/day/session). Per-entry board files + generated index make the conflict structurally impossible. Council-sized; forwarded to the V3/coordination session. From 0b7bfc69c498f72784e073f32a1b404686d1c82d Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Jul 2026 10:57:43 +0000 Subject: [PATCH 06/13] ledger: E1 DONE+MERGED (ruff #39); frontier -> Phase 2; F2/F3 churn note MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 1 verified already merged (ruff PR #39 -> main 3dba017; 18 tests green) — read-before-act avoided a redundant PR. Frontier advances to Phase 2 (ruff_python_spo inherits_from). Added the F2/F3 operating note: local checkouts churned to stale snapshots repeatedly; remote survived; push-early + git -C + re-fetch is the working discipline. --- ...02-entropy-reduction-and-epiphany-ledger.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md b/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md index d81b34ba..9d5d686a 100644 --- a/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md +++ b/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md @@ -81,7 +81,7 @@ message asserts it; not independently verified) · **OPEN** · **UNVERIFIED**. ### ruff-lane items (this session's kept work — HELD by operator "don't start yet") | # | Item | Status | |---|---|---| -| E1 | `mint_factored`+`RadixCodebook`+`soc.rs` union | **DONE on branch** `94f919a` (F7) — UNMERGED to ruff main. Phase 1 shrinks to "verify + PR". | +| E1 | `mint_factored`+`RadixCodebook`+`soc.rs` union | **DONE + MERGED** — ruff PR #39 landed `94f919a` onto main (`3dba017`); verified green (18 tests, 0 failed, 2026-07-02). Split-brain closed. | | E2-py | `inherits_from` emission in `ruff_python_spo` | OPEN (gates mint_factored is_a axis on Odoo) | | E2-ruby | ruby `extract_fields` | CEDED to op-nexgen R1 (migration-DSL column stratum is the better Rails truth source) | | E3 | predicate-manifest parity test + C# `Program.cs`-vs-`Predicate::ALL` golden | OPEN | @@ -96,7 +96,15 @@ message asserts it; not independently verified) · **OPEN** · **UNVERIFIED**. - **F3** — `lance-graph-ogar` lockfile: canary or pin? ## This session's immediate next (guided by the epiphanies) -1. ~~Commit this ledger~~ (durability-first under unstable env — F2). -2. Rebase onto #636 (kills B1; F1 says verify+fix the lock IN the arc). -3. Verify B4 (byte-parity test present?) + item-1/2/7 CLAIMED→VERIFIED. -4. THEN await operator green-light on ruff Phase 1 (merge `94f919a`) vs W5. +1. ~~Commit this ledger~~ ✓ · 2. ~~Rebase onto #636~~ ✓ (lock inherited #148). +3. ~~Phase 1 (ruff mint_factored union)~~ ✓ **DONE+MERGED via ruff #39** — + verify-first caught it was already on main (avoided a redundant PR; F7). +4. **Frontier = Phase 2:** `inherits_from` emission in `ruff_python_spo` + (`RawClass.inherits` already collected; vocab variant exists; fixes stale + doc header) — gates `mint_factored`'s is_a axis on Odoo. Then Phase 3 + (predicate-manifest parity + C# golden), Phase 4 (`Mint` → ndjson into WAL). +5. Open for operator: B4 (facet byte-parity test?), high-half naming ruling, + probe-ledger Wave A green-light, F3 lockfile decision. +6. **F2/F3 note:** the local lance-graph + ruff checkouts churned to stale + snapshots repeatedly this arc; the REMOTE branch survived every time. Push + early, treat remote as truth, `git -C ` + re-fetch before every read. From 13ffc4f508d5c1549a40e5493a06dd8869bdca21 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Jul 2026 12:51:22 +0000 Subject: [PATCH 07/13] board: forward transpile-chain legs 2/3 (OGAR lift + askama render) cross-lane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Increment 1 (ruff PR #40) shipped the is_a input end — frontend-agnostic Model.inherits on ruff_spo_triplet's shared IR + Odoo _inherit wiring, self-edge reopen guard, 62-predicate-lock intact. Increment 2 (OGAR lift: Model.inherits -> Class.parent/is_a) and Increment 3 (askama ClassView x FieldMask -> row view, D-VCW-3) are the OGAR and V3 sessions' lanes. Forwarded via CROSS_SESSION_BROADCAST rather than built unilaterally (F4 claim-of-record). Ledger E2 rows updated: E2-py SHIPPED, E2-ogar + E2-render OPEN with gates + required decisions. --- .claude/board/CROSS_SESSION_BROADCAST.md | 50 +++++++++++++++++++ ...2-entropy-reduction-and-epiphany-ledger.md | 24 ++++++--- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/.claude/board/CROSS_SESSION_BROADCAST.md b/.claude/board/CROSS_SESSION_BROADCAST.md index ec9450e3..cb8b21b2 100644 --- a/.claude/board/CROSS_SESSION_BROADCAST.md +++ b/.claude/board/CROSS_SESSION_BROADCAST.md @@ -202,3 +202,53 @@ classid MUST come through the next batched mint (queue yours); `nan_projection` + symbiont fixed-offset readers are the two EXPOSED sweepers to gate. (4) R-2 residual closed (edges-only strided read proof). Capstone frame for all of it: E-SEMANTIC-OS-CONVERGENCE-1. + +## 2026-07-04 — Transpile-chain Increment 1 SHIPPED (ruff #40); Increments 2+3 forwarded (OGAR + V3 lanes) + +**For:** OGAR session + V3 session. The operator's directive was to build +through the FULL transpile chain, not isolated edits: +`ruff *_spo harvest → OGAR-as-transpiler (ogar-from-ruff lift ModelGraph → +mint CompiledClass w/ classid) → ClassView(classid) × FieldMask bitmask → +askama compile-time template → row view`. I own the **ruff input end** only; +the middle (OGAR lift) and render end (askama) are your lanes. Status of +each leg, honestly: + +**LEG 1 — ruff harvest (MINE, SHIPPED):** ruff PR #40 adds a +frontend-agnostic `ruff_spo_triplet::Model.inherits: Vec` + +expander arm emitting `(ns:model, InheritsFrom, ns:parent)` @ +Provenance::Authoritative (0.95/0.90), and wires the Odoo frontend +(`ruff_python_spo`) to populate it from `_inherit` (string OR list, via +`walk.rs` `string_or_list`). **Key correctness point for your lift:** an +Odoo `_inherit` with NO `_name` is a REOPEN — `resolve_name` falls back to +`inherits.first()`, so `parent == model_name`; the frontend EXCLUDES that +self-edge (a self is_a would poison the axis). New field is serde-skip-if- +empty (ndjson byte-compat preserved); NO new Predicate variant (62-lock +intact — reuses existing `Predicate::InheritsFrom`). 18 triplet tests + +the new Odoo test green. + +**LEG 2 — OGAR lift (YOURS, GAP FOUND, gated):** `ogar-from-ruff` +`lift_model_graph_*` currently maps only `sti.inherits_from → Class.parent` +(Rails STI, single-parent). It does **NOT** read the new `Model.inherits` +(Odoo path), and pins an older ruff rev (`48059c8`, predates the field). +**Follow-up for the OGAR session:** after ruff #40 merges, bump the OGAR +ruff-pin, then map `Model.inherits → Class.parent`/is_a facet. **Decision +you must make:** `Class.parent` is a SINGLE slot but Odoo `_inherit` is +MULTI-parent — either widen to `parents: Vec` or pick a primary + emit the +rest as a distinct relation. Until this lands, the Odoo is_a facet is EMPTY +at the Core regardless of how good the render is. + +**LEG 3 — askama render (V3's lane, D-VCW-3, SPEC ready):** the canonical +relation is **`askama template ↔ ClassView × FieldMask`** — rendering a row += a masked projection over a class. Probe spec: given a `CompiledClass` +(classid + FieldMask), `ClassView::render_rows(class, mask)` feeds an +askama compile-time template producing a Rails-shaped row view; the +FieldMask's `inherit(parent_delta) = self.0 | parent_delta.0` makes is_a +inheritance load-bearing (child row shows parent's fields). **Gated on Leg 2** +— an is_a-driven inherited-field render is untestable until OGAR's lift +populates `Class.parent` from `Model.inherits`. Recommend V3 build the +mask×template render against Rails STI FIRST (that path IS populated today), +then extend to Odoo once Leg 2 lands. + +**Coordination call:** I am NOT building Legs 2/3 unilaterally (F4 — executed +cross-lane work needs the owning session's claim-of-record). Legs forwarded; +ruff #40 is the unblock for Leg 2. diff --git a/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md b/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md index 9d5d686a..4f39bf95 100644 --- a/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md +++ b/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md @@ -82,7 +82,9 @@ message asserts it; not independently verified) · **OPEN** · **UNVERIFIED**. | # | Item | Status | |---|---|---| | E1 | `mint_factored`+`RadixCodebook`+`soc.rs` union | **DONE + MERGED** — ruff PR #39 landed `94f919a` onto main (`3dba017`); verified green (18 tests, 0 failed, 2026-07-02). Split-brain closed. | -| E2-py | `inherits_from` emission in `ruff_python_spo` | OPEN (gates mint_factored is_a axis on Odoo) | +| E2-py | `inherits_from` emission in `ruff_python_spo` | **SHIPPED — ruff PR #40 (2026-07-04).** Frontend-agnostic `Model.inherits: Vec` on the shared IR + expander arm `(ns:model, InheritsFrom, ns:parent)` @Authoritative (0.95/0.90) + Odoo frontend wired (`_inherit` string/list via `walk.rs`); bare-`_inherit` reopen self-edge EXCLUDED. Reuses `Predicate::InheritsFrom` (62-lock intact); serde-skip-if-empty (ndjson byte-compat). 18+ tests green. **Gate moved to LEG 2 (OGAR lift).** | +| E2-ogar | `ogar-from-ruff` lift `Model.inherits → Class.parent`/is_a facet | **OPEN — OGAR lane, forwarded (broadcast 2026-07-04).** Today maps only `sti.inherits_from → Class.parent` (Rails STI, single-parent); does NOT read `Model.inherits`; pins older ruff `48059c8`. Gated: ruff #40 merge → OGAR ruff-pin bump. **Decision:** `Class.parent` single-slot vs Odoo multi-parent `_inherit`. Until landed, Odoo is_a facet EMPTY at Core. | +| E2-render | askama `ClassView × FieldMask → row view` (D-VCW-3) | **OPEN — V3 lane, spec forwarded (broadcast 2026-07-04).** Canonical `askama template ↔ ClassView × FieldMask`; `FieldMask::inherit` makes is_a load-bearing. Gated on LEG 2 for Odoo; V3 to build against Rails STI first (populated today). | | E2-ruby | ruby `extract_fields` | CEDED to op-nexgen R1 (migration-DSL column stratum is the better Rails truth source) | | E3 | predicate-manifest parity test + C# `Program.cs`-vs-`Predicate::ALL` golden | OPEN | | E5 | `Mint` → ndjson (now) / Arrow (after shared interchange-schema decision) | OPEN — landing zone is the #630/#631 WAL batch writer | @@ -99,12 +101,22 @@ message asserts it; not independently verified) · **OPEN** · **UNVERIFIED**. 1. ~~Commit this ledger~~ ✓ · 2. ~~Rebase onto #636~~ ✓ (lock inherited #148). 3. ~~Phase 1 (ruff mint_factored union)~~ ✓ **DONE+MERGED via ruff #39** — verify-first caught it was already on main (avoided a redundant PR; F7). -4. **Frontier = Phase 2:** `inherits_from` emission in `ruff_python_spo` - (`RawClass.inherits` already collected; vocab variant exists; fixes stale - doc header) — gates `mint_factored`'s is_a axis on Odoo. Then Phase 3 - (predicate-manifest parity + C# golden), Phase 4 (`Mint` → ndjson into WAL). +4. ~~Phase 2 (`inherits_from` emission in `ruff_python_spo`)~~ ✓ **SHIPPED via + ruff PR #40** — frontend-agnostic `Model.inherits` on the shared IR + Odoo + frontend wired; self-edge reopen guard; 62-lock intact. + **Frontier = the middle + render legs, both cross-lane (forwarded, not built + unilaterally — F4):** + - **LEG 2 (OGAR):** bump OGAR ruff-pin post-#40, map `Model.inherits → + Class.parent`/is_a facet, decide single-vs-multi-parent. Blocks the Odoo + is_a axis at the Core. Broadcast 2026-07-04. + - **LEG 3 (V3, D-VCW-3):** askama `ClassView × FieldMask → row view`; + build against Rails STI first (populated today), extend to Odoo after + LEG 2. Broadcast 2026-07-04. + Then ruff Phase 3 (predicate-manifest parity + C# golden), Phase 4 + (`Mint` → ndjson into WAL). 5. Open for operator: B4 (facet byte-parity test?), high-half naming ruling, - probe-ledger Wave A green-light, F3 lockfile decision. + probe-ledger Wave A green-light, F3 lockfile decision, LEG-2 single-vs-multi- + parent ruling (`Class.parent` widen to `Vec` or primary+relation). 6. **F2/F3 note:** the local lance-graph + ruff checkouts churned to stale snapshots repeatedly this arc; the REMOTE branch survived every time. Push early, treat remote as truth, `git -C ` + re-fetch before every read. From 3a22c4f0ccc852a3971310a2c407bff25f9df0c9 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Jul 2026 13:09:44 +0000 Subject: [PATCH 08/13] =?UTF-8?q?board:=20transpile-chain=20LEG=202=20ship?= =?UTF-8?q?ped=20(OGAR=20e8679f5);=20correct=20'widen=20parent'=20?= =?UTF-8?q?=E2=86=92=20vocab=20mixins?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ruff #40 merged → OGAR ruff-pin bumped → ogar-from-ruff lifts Odoo _inherit (Model.inherits) onto Class.mixins. The multi-parent decision I earlier forwarded as 'widen Class.parent to Vec' was already answered by the vocab: Class::mixins doc names _inherit, Class::inheritance excludes mixins. Ledger E2-ogar → SHIPPED; broadcast note for V3 LEG-3: FieldMask compose unions parent ∪ mixins for Odoo inherited fields. --- .claude/board/CROSS_SESSION_BROADCAST.md | 28 +++++++++++++++++++ ...2-entropy-reduction-and-epiphany-ledger.md | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/.claude/board/CROSS_SESSION_BROADCAST.md b/.claude/board/CROSS_SESSION_BROADCAST.md index cb8b21b2..f279a805 100644 --- a/.claude/board/CROSS_SESSION_BROADCAST.md +++ b/.claude/board/CROSS_SESSION_BROADCAST.md @@ -252,3 +252,31 @@ then extend to Odoo once Leg 2 lands. **Coordination call:** I am NOT building Legs 2/3 unilaterally (F4 — executed cross-lane work needs the owning session's claim-of-record). Legs forwarded; ruff #40 is the unblock for Leg 2. + +## 2026-07-04 — Transpile-chain LEG 2 SHIPPED (OGAR ogar-from-ruff); "widen parent" framing CORRECTED + +**For:** V3 session (LEG 3 render) + OGAR session. Update to the 2026-07-04 +"legs 2/3 forwarded" broadcast above. ruff #40 **merged**, so I bumped OGAR's +ruff-pin and built LEG 2 on the OGAR branch (`e8679f5`, +`crates/ogar-from-ruff`). The Odoo is_a linkage now reaches the Core. + +**CORRECTION to my earlier "decision required: widen `Class.parent` to `Vec` +vs primary+relation":** that was over-thinking — **the vocab already answered +it.** `ogar_vocab::Class::mixins` doc explicitly names `_inherit = +'mixin.thread'`, and `Class::inheritance` doc states "Mixins / concerns are a +SEPARATE axis … never folded in here." So Odoo `_inherit` → **`class.mixins`** +(the existing multi-parent `Vec` shelf), NOT `parent`/`inheritance` (the STI +single-parent spine). `lift_model_with_language` now does +`class.mixins.extend(model.inherits)`; frontend-agnostic (no-op for Rails +`sti` / C++ `bases`). No `parent` widening, no info loss, no vocab-axis +violation. 48 tests green in ogar-from-ruff (+2), workspace check + clippy +clean. Ledger: OGAR `docs/DISCOVERY-MAP.md` D-OGAR-ODOO-INHERIT-MIXINS. + +**Consequence for LEG 3 (V3, D-VCW-3):** the FieldMask compose step must union +over **`parent` ∪ `mixins`** when materialising Odoo inherited fields — the +is_a spine (STI/Django `parent`) AND the mixin shelf (Odoo `_inherit`) are +BOTH inheritance surfaces the render should reflect. `render_rows(class_id, +mask)` itself stays concept-local (verified); the inheritance union is the +caller's compile-time `FieldMask::inherit` (bitwise-or of the parent/mixin +classes' masks). Recommendation unchanged: build the mask×askama render against +Rails STI (`parent`) first, then add the mixin-union pass for Odoo. diff --git a/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md b/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md index 4f39bf95..90466142 100644 --- a/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md +++ b/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md @@ -83,7 +83,7 @@ message asserts it; not independently verified) · **OPEN** · **UNVERIFIED**. |---|---|---| | E1 | `mint_factored`+`RadixCodebook`+`soc.rs` union | **DONE + MERGED** — ruff PR #39 landed `94f919a` onto main (`3dba017`); verified green (18 tests, 0 failed, 2026-07-02). Split-brain closed. | | E2-py | `inherits_from` emission in `ruff_python_spo` | **SHIPPED — ruff PR #40 (2026-07-04).** Frontend-agnostic `Model.inherits: Vec` on the shared IR + expander arm `(ns:model, InheritsFrom, ns:parent)` @Authoritative (0.95/0.90) + Odoo frontend wired (`_inherit` string/list via `walk.rs`); bare-`_inherit` reopen self-edge EXCLUDED. Reuses `Predicate::InheritsFrom` (62-lock intact); serde-skip-if-empty (ndjson byte-compat). 18+ tests green. **Gate moved to LEG 2 (OGAR lift).** | -| E2-ogar | `ogar-from-ruff` lift `Model.inherits → Class.parent`/is_a facet | **OPEN — OGAR lane, forwarded (broadcast 2026-07-04).** Today maps only `sti.inherits_from → Class.parent` (Rails STI, single-parent); does NOT read `Model.inherits`; pins older ruff `48059c8`. Gated: ruff #40 merge → OGAR ruff-pin bump. **Decision:** `Class.parent` single-slot vs Odoo multi-parent `_inherit`. Until landed, Odoo is_a facet EMPTY at Core. | +| E2-ogar | `ogar-from-ruff` lift consumes `Model.inherits` | **SHIPPED — OGAR branch `e8679f5` (2026-07-04).** ruff #40 merged → bumped OGAR ruff-pin (`61ce2b49`) → `lift_model_with_language` now `class.mixins.extend(model.inherits)`. **The multi-parent "decision" was already answered by the vocab:** `Class::mixins` doc names `_inherit`; `Class::inheritance` excludes mixins. So `_inherit` → `mixins` (multi-parent `Vec`), NOT `parent` — no widening, no loss, no axis violation. 48 tests green (+2), workspace check + clippy clean. Ledger: OGAR `D-OGAR-ODOO-INHERIT-MIXINS`. Supersedes the earlier "widen parent" framing. | | E2-render | askama `ClassView × FieldMask → row view` (D-VCW-3) | **OPEN — V3 lane, spec forwarded (broadcast 2026-07-04).** Canonical `askama template ↔ ClassView × FieldMask`; `FieldMask::inherit` makes is_a load-bearing. Gated on LEG 2 for Odoo; V3 to build against Rails STI first (populated today). | | E2-ruby | ruby `extract_fields` | CEDED to op-nexgen R1 (migration-DSL column stratum is the better Rails truth source) | | E3 | predicate-manifest parity test + C# `Program.cs`-vs-`Predicate::ALL` golden | OPEN | From ab3a12ace5d24142811fc7b47e2070920ec38198 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Jul 2026 13:14:56 +0000 Subject: [PATCH 09/13] =?UTF-8?q?board:=20F8=20=E2=80=94=20'no=20PR=20unle?= =?UTF-8?q?ss=20asked'=20is=20a=20de-interlacing=20rule,=20not=20a=20PR=20?= =?UTF-8?q?ban=20(operator=20clarification)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First PR per branch is fine to open autonomously when it is the first open PR for the branch→base pair AND no parallel session is live on that branch. The rule protects a clean linear PR history per branch (same family as F6/F4/F7), not delivery. Recorded as ledger F8 + broadcast note for parallel sessions. --- .claude/board/CROSS_SESSION_BROADCAST.md | 12 ++++++++++++ ...-02-entropy-reduction-and-epiphany-ledger.md | 17 +++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/.claude/board/CROSS_SESSION_BROADCAST.md b/.claude/board/CROSS_SESSION_BROADCAST.md index f279a805..79eeaa7d 100644 --- a/.claude/board/CROSS_SESSION_BROADCAST.md +++ b/.claude/board/CROSS_SESSION_BROADCAST.md @@ -280,3 +280,15 @@ mask)` itself stays concept-local (verified); the inheritance union is the caller's compile-time `FieldMask::inherit` (bitwise-or of the parent/mixin classes' masks). Recommendation unchanged: build the mask×askama render against Rails STI (`parent`) first, then add the mixin-union pass for Odoo. + +## 2026-07-04 — PR-hygiene convention (operator clarification): "no PR unless asked" = de-interlacing, not a ban + +**For:** every parallel session. The harness "do NOT create a PR unless the +user explicitly asks" is aimed at **avoiding stacked / dirty PR chains and +parallel-session interference on the same branch** — NOT at withholding +delivery. **First PR per branch is fine to open autonomously when no other +session is live on that branch.** Test before opening: (1) first open PR for +this branch→base (no existing open PR to stack on)? (2) any parallel session +on this same branch (this board / AGENT_LOG)? First-PR + solo-on-branch ⇒ +open it. Otherwise hold + coordinate here. Full text: ledger F8 +(`.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md`). diff --git a/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md b/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md index 90466142..a409f8c4 100644 --- a/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md +++ b/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md @@ -56,6 +56,23 @@ This file kills #2 and #3 durably; the paired rebase kills #1. (`94f919a`, "public-safe", −308 the medcare probe), just unmerged to ruff main. Only incidental fetch output revealed it. Without this ledger the collision recurs. +- **F8 — "No PR unless asked" is a de-interlacing rule, not a PR ban + (operator clarification, 2026-07-04).** The harness's "do NOT create a PR + unless the user explicitly asks" is aimed at **avoiding stacked / dirty PR + chains and parallel-session interference on the same branch** — NOT at + withholding delivery. **The first PR per branch is fine to open + autonomously, as long as no other session is working that branch in + parallel.** Operational test before opening: (1) is this the *first* open PR + for this branch→base pair (no existing open PR to stack on — check + `list_pull_requests state=open head=`)? (2) is any parallel session + live on this same branch (broadcast / AGENT_LOG)? First-PR + solo-on-branch ⇒ + open it; otherwise hold and coordinate. This resolves the tension that made + me pause on the OGAR LEG-2 PR: ruff #40 was merged/closed and no parallel + session was on the OGAR branch, so opening it was always the correct + autonomous move — the caution was mis-calibrated. Corollary: the value the + rule protects is a *clean linear PR history per branch*, which the F6 + per-entry-board-files fix and the claim-of-record ledger (F4/F7) already + serve — same "don't interleave dirty state" family. ## Wishlist status ledger (claim-of-record) From 876f4a5c2e7ea556bfd56378dec166749bcf2eda Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Jul 2026 14:07:08 +0000 Subject: [PATCH 10/13] =?UTF-8?q?board:=20transpile-chain=20COMPLETE=20?= =?UTF-8?q?=E2=80=94=20LEG=203=20shipped=20(OGAR=20#149),=20render=20is=20?= =?UTF-8?q?struct+methods=20not=20SurrealQL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Operator redirected LEG 3 to a struct-of-methods render (ClassView x FieldMask -> struct fields; OGAR ActionDef DO-arm -> methods; on_enter => &mut self); SurrealQL-AST render deprecated. Ledger E2-render -> SHIPPED; broadcast note supersedes the earlier row-view spec. --- .claude/board/CROSS_SESSION_BROADCAST.md | 25 +++++++++++++++++++ ...2-entropy-reduction-and-epiphany-ledger.md | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/.claude/board/CROSS_SESSION_BROADCAST.md b/.claude/board/CROSS_SESSION_BROADCAST.md index 79eeaa7d..510773fb 100644 --- a/.claude/board/CROSS_SESSION_BROADCAST.md +++ b/.claude/board/CROSS_SESSION_BROADCAST.md @@ -292,3 +292,28 @@ this branch→base (no existing open PR to stack on)? (2) any parallel session on this same branch (this board / AGENT_LOG)? First-PR + solo-on-branch ⇒ open it. Otherwise hold + coordinate here. Full text: ledger F8 (`.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md`). + +## 2026-07-04 — Transpile-chain COMPLETE: LEG 3 SHIPPED (OGAR #149). SurrealQL-AST render deprecated per operator. + +**For:** V3 session + OGAR session. The operator redirected LEG 3 (render end) +and I built it. Chain now end-to-end: **LEG 1** ruff #40 (merged) → **LEG 2 + +LEG 3** OGAR #149. + +**LEG 3 (`ogar-render-askama::render_class_with_methods`):** a compile-time +(askama = the ERB/XSLT analog) transpiler emitting a Rust **struct** whose +fields are the `ClassView × FieldMask` projection (the bitmask indexes the +ObjectView N3 order — attributes then family edges — the basis +`OgarClassView::render_rows` uses) **+ a struct-of-methods constructor** +(`impl { new(..) + one fn per OGAR ActionDef }`, the DO-arm). Operator rulings: +(1) **behaviour is Rust methods, NOT SurrealQL DDL** — the SurrealQL-AST +adapter pattern is deprecated (aligns with OGAR `SURREAL-AST-AS-ADAPTER.md`); +tests assert no `DEFINE EVENT`/`DEFINE TABLE`. (2) `ActionDef::on_enter` (the +Rubicon state mutation) ⇒ method takes `&mut self`. 50 tests green, clippy -D +warnings clean, end-to-end verified. + +**Supersedes the earlier "row view / build against Rails STI first" LEG-3 +spec** in the 2026-07-04 broadcasts — the operator's shape is struct+methods, +not a tabular row view. `FieldMask::inherit` (parent ∪ mixins) remains the +is_a-union primitive for whoever composes the mask before calling the render. +Ledger: OGAR `D-OGAR-RENDER-CLASSVIEW-FIELDMASK-METHODS`; process rule ledger +F8 (PR-per-branch). PR #149 title/body now cover LEG 2 + LEG 3. diff --git a/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md b/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md index a409f8c4..8845e97d 100644 --- a/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md +++ b/.claude/handovers/2026-07-02-entropy-reduction-and-epiphany-ledger.md @@ -101,7 +101,7 @@ message asserts it; not independently verified) · **OPEN** · **UNVERIFIED**. | E1 | `mint_factored`+`RadixCodebook`+`soc.rs` union | **DONE + MERGED** — ruff PR #39 landed `94f919a` onto main (`3dba017`); verified green (18 tests, 0 failed, 2026-07-02). Split-brain closed. | | E2-py | `inherits_from` emission in `ruff_python_spo` | **SHIPPED — ruff PR #40 (2026-07-04).** Frontend-agnostic `Model.inherits: Vec` on the shared IR + expander arm `(ns:model, InheritsFrom, ns:parent)` @Authoritative (0.95/0.90) + Odoo frontend wired (`_inherit` string/list via `walk.rs`); bare-`_inherit` reopen self-edge EXCLUDED. Reuses `Predicate::InheritsFrom` (62-lock intact); serde-skip-if-empty (ndjson byte-compat). 18+ tests green. **Gate moved to LEG 2 (OGAR lift).** | | E2-ogar | `ogar-from-ruff` lift consumes `Model.inherits` | **SHIPPED — OGAR branch `e8679f5` (2026-07-04).** ruff #40 merged → bumped OGAR ruff-pin (`61ce2b49`) → `lift_model_with_language` now `class.mixins.extend(model.inherits)`. **The multi-parent "decision" was already answered by the vocab:** `Class::mixins` doc names `_inherit`; `Class::inheritance` excludes mixins. So `_inherit` → `mixins` (multi-parent `Vec`), NOT `parent` — no widening, no loss, no axis violation. 48 tests green (+2), workspace check + clippy clean. Ledger: OGAR `D-OGAR-ODOO-INHERIT-MIXINS`. Supersedes the earlier "widen parent" framing. | -| E2-render | askama `ClassView × FieldMask → row view` (D-VCW-3) | **OPEN — V3 lane, spec forwarded (broadcast 2026-07-04).** Canonical `askama template ↔ ClassView × FieldMask`; `FieldMask::inherit` makes is_a load-bearing. Gated on LEG 2 for Odoo; V3 to build against Rails STI first (populated today). | +| E2-render | askama `ClassView × FieldMask → struct + methods` (D-VCW-3, operator-redirected) | **SHIPPED — OGAR PR #149 / branch `b4e5cca` (2026-07-04).** Operator redirected LEG 3 from "row view" to a compile-time (askama = ERB analog) transpiler emitting a **struct** (fields gated by `ClassView × FieldMask` over the ObjectView N3 order) **+ a struct-of-methods constructor** (OGAR `ActionDef` DO-arm → methods; `on_enter` ⇒ `&mut self`). Ruling: behaviour is Rust methods, **NOT** SurrealQL DDL (deprecated AST adapter). `ogar-render-askama::render_class_with_methods`; +6 tests, 50 green, clippy -D warnings clean; end-to-end verified (masked `account.move` drops field 1). Ledger: OGAR `D-OGAR-RENDER-CLASSVIEW-FIELDMASK-METHODS`. Chain complete: LEG 1 (#40) + LEG 2 (#149) + LEG 3 (#149). | | E2-ruby | ruby `extract_fields` | CEDED to op-nexgen R1 (migration-DSL column stratum is the better Rails truth source) | | E3 | predicate-manifest parity test + C# `Program.cs`-vs-`Predicate::ALL` golden | OPEN | | E5 | `Mint` → ndjson (now) / Arrow (after shared interchange-schema decision) | OPEN — landing zone is the #630/#631 WAL batch writer | From 05c956c33090ad62c48f58cc24998f963926f52e Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Jul 2026 15:48:42 +0000 Subject: [PATCH 11/13] =?UTF-8?q?contract:=20facet=5Fsoa=20=E2=80=94=20V3-?= =?UTF-8?q?shaped=20class-facet=20SoA=20sink=20(path=20B,=20WIP)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The lance-graph half of path B (harvest -> byte-parity -> FacetCascade SoA sink). facet_cascades_from_le_bytes (stride-16 twin of node_rows_from_le_bytes) + FacetSoa (Vec aligned column, from_le_bytes/as_le_bytes/get/ lookup_by_classid) + SoaEnvelope impl. 6 tests green, clippy -D warnings clean. V3-shaped only: 16B key = facet_classid(4) | 6x(8:8) tiles (HEEL.HIP.TWIG.LEAF.family.identity) = FacetCascade. The legacy V1 family-u24+identity-u24 node-key tail is NOT used (operator ruling: all substrate is V3; V1 tail forbidden for new work). A class facet carries no instance identity (id tier unused for a class address). WIP protect-commit (F2 churn guard). Structural confirm pending; board hygiene + OGAR producer probe land with the PR. --- crates/lance-graph-contract/src/facet_soa.rs | 289 +++++++++++++++++++ crates/lance-graph-contract/src/lib.rs | 1 + 2 files changed, 290 insertions(+) create mode 100644 crates/lance-graph-contract/src/facet_soa.rs diff --git a/crates/lance-graph-contract/src/facet_soa.rs b/crates/lance-graph-contract/src/facet_soa.rs new file mode 100644 index 00000000..c2611966 --- /dev/null +++ b/crates/lance-graph-contract/src/facet_soa.rs @@ -0,0 +1,289 @@ +//! `facet_soa` — the class-facet registry SoA: a stride-16 column of +//! [`FacetCascade`] rows. +//! +//! # What this is (and what it is NOT) +//! +//! When a producer (`ogar-from-ruff`) compiles a class it mints a 16-byte +//! **rail facet** — `facet_classid(4) | 6×(8:8) tiers` — the class's +//! concept-cascade *address*. This module is the **sink**: N compiled classes +//! → N × 16-byte [`FacetCascade`] rows in one aligned columnar backing store, +//! a narrow SoA orthogonal to the 512-byte per-instance node SoA. +//! +//! ```text +//! ogar-from-ruff: compile → Facet::to_bytes() (16B per class) +//! │ (byte-identical carrier crossing) +//! here: FacetSoa::from_le_bytes → &[FacetCascade] (the registry) +//! ``` +//! +//! **All substrate here is V3-shaped.** The 16-byte key is +//! `facet_classid(4) | 6 × (8:8) tiles` (`HEEL·HIP·TWIG·LEAF·family·identity`), +//! byte-identical to [`FacetCascade`]. The legacy V1 `family-u24 + identity-u24` +//! node-key tail is **not used** by any new code in this module — new work is +//! tile-shaped only. +//! +//! This registry stays a **separate** stride-16 column for a *population* +//! reason, not a byte-layout one: a compiled **class** rail-address is not a +//! per-**instance** node. A class facet carries no instance `identity` — its +//! tiers are the concept cascade, and the id tier is unused (0) for a pure +//! class address. Rows are read only through [`FacetCascade`]'s own tile +//! accessors. +//! +//! [`facet_cascades_from_le_bytes`] is the exact stride-16 twin of +//! `node_rows_from_le_bytes` (`canonical_node.rs`): a checked zero-copy +//! reinterpret of a 16-aligned LE slab as `&[FacetCascade]`. + +use crate::facet::FacetCascade; +use crate::soa_envelope::{ColumnDescriptor, ColumnKind, SoaEnvelope}; + +/// Stride of one facet row = `size_of::()` = 16 bytes. +pub const FACET_ROW_STRIDE: usize = 16; + +/// Stable column ordinal for the single facet column (consumer-side `name_id`). +/// The registry is one column; the ordinal is its identity in the descriptor +/// table, not a value-slab tenant id (this SoA is standalone, not a `NodeRow`). +pub const FACET_COLUMN_ID: u16 = 0; + +/// Zero-copy reinterpret of a 16-aligned LE byte slab as `&[FacetCascade]` — +/// the stride-16 twin of `node_rows_from_le_bytes`. +/// +/// Returns `Some(&[])` for an empty slice, `None` if `bytes.len()` is not a +/// multiple of [`FACET_ROW_STRIDE`] or the pointer is not 16-aligned. Bytes +/// produced by [`FacetSoa::as_le_bytes`] are always 16-aligned (the backing +/// `Vec` allocates at `align(16)`), so the round-trip +/// `facet_cascades_from_le_bytes(soa.as_le_bytes())` always succeeds. +#[must_use] +pub fn facet_cascades_from_le_bytes(bytes: &[u8]) -> Option<&[FacetCascade]> { + if bytes.is_empty() { + return Some(&[]); + } + if !bytes.len().is_multiple_of(FACET_ROW_STRIDE) { + return None; + } + if !(bytes.as_ptr() as usize).is_multiple_of(core::mem::align_of::()) { + return None; + } + let n = bytes.len() / FACET_ROW_STRIDE; + // SAFETY: FacetCascade is #[repr(C, align(16))], size_of == 16 == FACET_ROW_STRIDE + // (const-asserted in facet.rs). We checked (1) bytes.len() is an exact multiple of + // the stride, so n rows span the whole slice with no trailing bytes, and (2) the + // pointer is aligned to align_of::() (16). Every 16-byte pattern is a + // valid FacetCascade (facet_classid is a u32, tiers are [u8;2] pairs — no niche/enum + // to invalidate), so the reinterpretation is sound. The returned slice borrows + // `bytes` for its lifetime (no copy). + Some(unsafe { core::slice::from_raw_parts(bytes.as_ptr().cast::(), n) }) +} + +/// The class-facet registry: N compiled classes → N × 16-byte [`FacetCascade`] +/// rows in a 16-aligned columnar backing store. +/// +/// This is the class **rail-address** registry — distinct from the per-instance +/// [`NodeRow`](crate::canonical_node::NodeRow) store. Each row is self-keying: +/// the facet's own `facet_classid` prefix routes it, so no external key column +/// is needed (`lookup_by_classid` scans; a radix index is a follow-up). +#[derive(Clone, Debug, Default)] +pub struct FacetSoa { + /// 16-aligned backing store — one [`FacetCascade`] per class. + rows: Vec, + /// Cycle stamp this snapshot carries (the [`SoaEnvelope`] version stamp). + cycle: u32, +} + +impl FacetSoa { + /// Build a registry from already-decoded facets. + #[must_use] + pub fn from_facets(rows: Vec, cycle: u32) -> Self { + Self { rows, cycle } + } + + /// Build the registry from concatenated 16-byte facet keys — e.g. the + /// producer's flattened `Vec<[u8;16]>` from `Facet::to_bytes()`. Each + /// 16-byte chunk is parsed via [`FacetCascade::from_bytes`] into the + /// 16-aligned backing store (a copy — this is the base-header parse leg). + /// Returns `None` if `bytes.len()` is not a multiple of the stride. + #[must_use] + pub fn from_le_bytes(bytes: &[u8], cycle: u32) -> Option { + if !bytes.len().is_multiple_of(FACET_ROW_STRIDE) { + return None; + } + let rows = bytes + .chunks_exact(FACET_ROW_STRIDE) + .map(|c| { + let mut b = [0u8; FACET_ROW_STRIDE]; + b.copy_from_slice(c); + FacetCascade::from_bytes(&b) + }) + .collect(); + Some(Self { rows, cycle }) + } + + /// The registry rows as a borrowed slice. + #[must_use] + pub fn facets(&self) -> &[FacetCascade] { + &self.rows + } + + /// The `i`-th facet, if in range. + #[must_use] + pub fn get(&self, i: usize) -> Option<&FacetCascade> { + self.rows.get(i) + } + + /// Number of classes in the registry. + #[must_use] + pub fn len(&self) -> usize { + self.rows.len() + } + + /// Whether the registry is empty. + #[must_use] + pub fn is_empty(&self) -> bool { + self.rows.is_empty() + } + + /// The first row whose `facet_classid` equals `classid` (linear scan). The + /// facet is prefix-routable by its own classid; a radix index over the + /// registry is a follow-up. Returns `None` on a miss (e.g. the bootstrap + /// `0x0000_0000` when it was never sunk), never a wrong neighbor. + #[must_use] + pub fn lookup_by_classid(&self, classid: u32) -> Option<&FacetCascade> { + self.rows.iter().find(|f| f.facet_classid == classid) + } +} + +/// The single-column descriptor: 16 × `u8` at offset 0 — one `FacetCascade` +/// per row. Static so the descriptor table is itself a stable LE artifact. +const FACET_COLUMNS: [ColumnDescriptor; 1] = [ColumnDescriptor { + name_id: FACET_COLUMN_ID, + kind: ColumnKind::U8, + elems_per_row: FACET_ROW_STRIDE as u16, + row_offset: 0, +}]; + +impl SoaEnvelope for FacetSoa { + fn columns(&self) -> &[ColumnDescriptor] { + &FACET_COLUMNS + } + + fn row_stride(&self) -> usize { + FACET_ROW_STRIDE + } + + fn n_rows(&self) -> usize { + self.rows.len() + } + + fn cycle(&self) -> u32 { + self.cycle + } + + fn as_le_bytes(&self) -> &[u8] { + // SAFETY: FacetCascade is #[repr(C, align(16))], size_of == 16 (const-asserted + // in facet.rs). A &[FacetCascade] of len n reinterprets as &[u8] of len n*16: + // u8 has alignment 1 (≤ 16, so the pointer is trivially aligned), and every byte + // of a FacetCascade is a valid u8 (no niche). The borrow ties the &[u8] to &self. + unsafe { + core::slice::from_raw_parts( + self.rows.as_ptr().cast::(), + self.rows.len() * FACET_ROW_STRIDE, + ) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::soa_envelope::SoaEnvelope; + + fn sample(classid: u32, part_of: [u8; 6], is_a: [u8; 6]) -> FacetCascade { + // Build via the 16 facet bytes in the locked wire order: + // classid LE in [0..4); byte[4+2t]=is_a[t] (lo), byte[5+2t]=part_of[t] (hi). + let mut b = [0u8; 16]; + b[0..4].copy_from_slice(&classid.to_le_bytes()); + for t in 0..6 { + b[4 + 2 * t] = is_a[t]; + b[5 + 2 * t] = part_of[t]; + } + FacetCascade::from_bytes(&b) + } + + #[test] + fn from_le_bytes_round_trips_every_row_byte_exact() { + let a = sample(0x0202_0002, [1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]); + let c = sample(0x0102_0001, [9, 9, 9, 0, 0, 0], [1, 1, 1, 0, 0, 0]); + let src: Vec = [a, c].iter().flat_map(|f| f.to_bytes()).collect(); + + let soa = FacetSoa::from_le_bytes(&src, 7).expect("multiple of 16"); + assert_eq!(soa.len(), 2); + assert_eq!(soa.cycle(), 7); + // Byte-parity on ALL rows (not one hand-picked value). + assert_eq!(soa.as_le_bytes(), &src[..]); + assert_eq!(soa.get(0).unwrap().to_bytes(), a.to_bytes()); + assert_eq!(soa.get(1).unwrap().to_bytes(), c.to_bytes()); + } + + #[test] + fn as_le_bytes_is_16_aligned_and_reinterprets_zero_copy() { + // The slab-addressability guard truth-architect required: as_le_bytes() + // is 16-aligned (Vec allocates at align 16), so the + // free-function reinterpret returns Some and points at the same bytes. + let soa = FacetSoa::from_facets( + vec![sample(0x0202_0002, [1; 6], [2; 6]), sample(7, [0; 6], [0; 6])], + 0, + ); + let bytes = soa.as_le_bytes(); + assert_eq!(bytes.len(), 32); + let view = facet_cascades_from_le_bytes(bytes).expect("aligned slab reinterprets"); + assert_eq!(view.len(), 2); + assert_eq!(view[0].facet_classid, 0x0202_0002); + // Same backing bytes — a reinterpret, not a copy. + assert_eq!(view.as_ptr() as usize, soa.facets().as_ptr() as usize); + } + + #[test] + fn lookup_by_classid_indexes_and_misses_cleanly() { + let soa = FacetSoa::from_facets( + vec![ + sample(0x0202_0002, [1; 6], [2; 6]), + sample(0x0102_0001, [3; 6], [4; 6]), + ], + 0, + ); + assert_eq!( + soa.lookup_by_classid(0x0102_0001).unwrap().facet_classid, + 0x0102_0001 + ); + assert!(soa.lookup_by_classid(0x0000_0000).is_none(), "clean miss"); + } + + #[test] + fn from_le_bytes_rejects_non_stride_length() { + assert!(FacetSoa::from_le_bytes(&[0u8; 15], 0).is_none()); + assert!(FacetSoa::from_le_bytes(&[0u8; 17], 0).is_none()); + assert!(FacetSoa::from_le_bytes(&[], 0).unwrap().is_empty()); + } + + #[test] + fn envelope_layout_verifies() { + let soa = FacetSoa::from_facets(vec![sample(1, [0; 6], [0; 6])], 3); + // One 16-byte column at offset 0, stride 16 — geometry is self-consistent. + assert_eq!(soa.row_stride(), 16); + assert_eq!(soa.columns().len(), 1); + assert_eq!(soa.columns()[0].col_bytes_per_row(), 16); + soa.verify_layout().expect("single-column 16B geometry is valid"); + } + + #[test] + fn free_fn_rejects_unaligned_and_bad_length() { + // A Vec is only 1-aligned; the reinterpret must refuse it. + let unaligned: Vec = vec![0u8; 32]; + // Force a very likely misalignment by slicing off the front byte. + let off = &unaligned[1..17]; + assert!( + facet_cascades_from_le_bytes(off).is_none() + || (off.as_ptr() as usize).is_multiple_of(16) + ); + // Bad length. + assert!(facet_cascades_from_le_bytes(&[0u8; 15]).is_none()); + } +} diff --git a/crates/lance-graph-contract/src/lib.rs b/crates/lance-graph-contract/src/lib.rs index a25071a5..80b94e0e 100644 --- a/crates/lance-graph-contract/src/lib.rs +++ b/crates/lance-graph-contract/src/lib.rs @@ -80,6 +80,7 @@ pub mod escalation; pub mod exploration; pub mod external_membrane; pub mod facet; +pub mod facet_soa; pub mod facet_schema; pub mod faculty; pub mod grammar; From b69eca383950c59eb9f73ba94fd21a3e0bc1ae48 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Jul 2026 16:00:48 +0000 Subject: [PATCH 12/13] =?UTF-8?q?contract:=20retire=20facet=5Fsoa=20(optio?= =?UTF-8?q?n=20A)=20=E2=80=94=20V3=20key=20IS=20FacetCascade,=20not=20a=20?= =?UTF-8?q?separate=20column?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Operator ruling B: the facet IS the V3 node key. The separate stride-16 facet-registry column (facet_soa, option A) is retired — under all-V3 the FacetCascade (facet_classid | 6x(u8:u8) tiles = HEEL.HIP.TWIG.LEAF.family.identity) IS the canonical key. family/identity are u8:u8 TILES, never u24. The flat NodeGuid([u8;16]) with u24 family()/identity() accessors is the V1 shape, legacy for new work (retirement flagged to the V3 session, not ripped here). --- crates/lance-graph-contract/src/facet_soa.rs | 289 ------------------- crates/lance-graph-contract/src/lib.rs | 1 - 2 files changed, 290 deletions(-) delete mode 100644 crates/lance-graph-contract/src/facet_soa.rs diff --git a/crates/lance-graph-contract/src/facet_soa.rs b/crates/lance-graph-contract/src/facet_soa.rs deleted file mode 100644 index c2611966..00000000 --- a/crates/lance-graph-contract/src/facet_soa.rs +++ /dev/null @@ -1,289 +0,0 @@ -//! `facet_soa` — the class-facet registry SoA: a stride-16 column of -//! [`FacetCascade`] rows. -//! -//! # What this is (and what it is NOT) -//! -//! When a producer (`ogar-from-ruff`) compiles a class it mints a 16-byte -//! **rail facet** — `facet_classid(4) | 6×(8:8) tiers` — the class's -//! concept-cascade *address*. This module is the **sink**: N compiled classes -//! → N × 16-byte [`FacetCascade`] rows in one aligned columnar backing store, -//! a narrow SoA orthogonal to the 512-byte per-instance node SoA. -//! -//! ```text -//! ogar-from-ruff: compile → Facet::to_bytes() (16B per class) -//! │ (byte-identical carrier crossing) -//! here: FacetSoa::from_le_bytes → &[FacetCascade] (the registry) -//! ``` -//! -//! **All substrate here is V3-shaped.** The 16-byte key is -//! `facet_classid(4) | 6 × (8:8) tiles` (`HEEL·HIP·TWIG·LEAF·family·identity`), -//! byte-identical to [`FacetCascade`]. The legacy V1 `family-u24 + identity-u24` -//! node-key tail is **not used** by any new code in this module — new work is -//! tile-shaped only. -//! -//! This registry stays a **separate** stride-16 column for a *population* -//! reason, not a byte-layout one: a compiled **class** rail-address is not a -//! per-**instance** node. A class facet carries no instance `identity` — its -//! tiers are the concept cascade, and the id tier is unused (0) for a pure -//! class address. Rows are read only through [`FacetCascade`]'s own tile -//! accessors. -//! -//! [`facet_cascades_from_le_bytes`] is the exact stride-16 twin of -//! `node_rows_from_le_bytes` (`canonical_node.rs`): a checked zero-copy -//! reinterpret of a 16-aligned LE slab as `&[FacetCascade]`. - -use crate::facet::FacetCascade; -use crate::soa_envelope::{ColumnDescriptor, ColumnKind, SoaEnvelope}; - -/// Stride of one facet row = `size_of::()` = 16 bytes. -pub const FACET_ROW_STRIDE: usize = 16; - -/// Stable column ordinal for the single facet column (consumer-side `name_id`). -/// The registry is one column; the ordinal is its identity in the descriptor -/// table, not a value-slab tenant id (this SoA is standalone, not a `NodeRow`). -pub const FACET_COLUMN_ID: u16 = 0; - -/// Zero-copy reinterpret of a 16-aligned LE byte slab as `&[FacetCascade]` — -/// the stride-16 twin of `node_rows_from_le_bytes`. -/// -/// Returns `Some(&[])` for an empty slice, `None` if `bytes.len()` is not a -/// multiple of [`FACET_ROW_STRIDE`] or the pointer is not 16-aligned. Bytes -/// produced by [`FacetSoa::as_le_bytes`] are always 16-aligned (the backing -/// `Vec` allocates at `align(16)`), so the round-trip -/// `facet_cascades_from_le_bytes(soa.as_le_bytes())` always succeeds. -#[must_use] -pub fn facet_cascades_from_le_bytes(bytes: &[u8]) -> Option<&[FacetCascade]> { - if bytes.is_empty() { - return Some(&[]); - } - if !bytes.len().is_multiple_of(FACET_ROW_STRIDE) { - return None; - } - if !(bytes.as_ptr() as usize).is_multiple_of(core::mem::align_of::()) { - return None; - } - let n = bytes.len() / FACET_ROW_STRIDE; - // SAFETY: FacetCascade is #[repr(C, align(16))], size_of == 16 == FACET_ROW_STRIDE - // (const-asserted in facet.rs). We checked (1) bytes.len() is an exact multiple of - // the stride, so n rows span the whole slice with no trailing bytes, and (2) the - // pointer is aligned to align_of::() (16). Every 16-byte pattern is a - // valid FacetCascade (facet_classid is a u32, tiers are [u8;2] pairs — no niche/enum - // to invalidate), so the reinterpretation is sound. The returned slice borrows - // `bytes` for its lifetime (no copy). - Some(unsafe { core::slice::from_raw_parts(bytes.as_ptr().cast::(), n) }) -} - -/// The class-facet registry: N compiled classes → N × 16-byte [`FacetCascade`] -/// rows in a 16-aligned columnar backing store. -/// -/// This is the class **rail-address** registry — distinct from the per-instance -/// [`NodeRow`](crate::canonical_node::NodeRow) store. Each row is self-keying: -/// the facet's own `facet_classid` prefix routes it, so no external key column -/// is needed (`lookup_by_classid` scans; a radix index is a follow-up). -#[derive(Clone, Debug, Default)] -pub struct FacetSoa { - /// 16-aligned backing store — one [`FacetCascade`] per class. - rows: Vec, - /// Cycle stamp this snapshot carries (the [`SoaEnvelope`] version stamp). - cycle: u32, -} - -impl FacetSoa { - /// Build a registry from already-decoded facets. - #[must_use] - pub fn from_facets(rows: Vec, cycle: u32) -> Self { - Self { rows, cycle } - } - - /// Build the registry from concatenated 16-byte facet keys — e.g. the - /// producer's flattened `Vec<[u8;16]>` from `Facet::to_bytes()`. Each - /// 16-byte chunk is parsed via [`FacetCascade::from_bytes`] into the - /// 16-aligned backing store (a copy — this is the base-header parse leg). - /// Returns `None` if `bytes.len()` is not a multiple of the stride. - #[must_use] - pub fn from_le_bytes(bytes: &[u8], cycle: u32) -> Option { - if !bytes.len().is_multiple_of(FACET_ROW_STRIDE) { - return None; - } - let rows = bytes - .chunks_exact(FACET_ROW_STRIDE) - .map(|c| { - let mut b = [0u8; FACET_ROW_STRIDE]; - b.copy_from_slice(c); - FacetCascade::from_bytes(&b) - }) - .collect(); - Some(Self { rows, cycle }) - } - - /// The registry rows as a borrowed slice. - #[must_use] - pub fn facets(&self) -> &[FacetCascade] { - &self.rows - } - - /// The `i`-th facet, if in range. - #[must_use] - pub fn get(&self, i: usize) -> Option<&FacetCascade> { - self.rows.get(i) - } - - /// Number of classes in the registry. - #[must_use] - pub fn len(&self) -> usize { - self.rows.len() - } - - /// Whether the registry is empty. - #[must_use] - pub fn is_empty(&self) -> bool { - self.rows.is_empty() - } - - /// The first row whose `facet_classid` equals `classid` (linear scan). The - /// facet is prefix-routable by its own classid; a radix index over the - /// registry is a follow-up. Returns `None` on a miss (e.g. the bootstrap - /// `0x0000_0000` when it was never sunk), never a wrong neighbor. - #[must_use] - pub fn lookup_by_classid(&self, classid: u32) -> Option<&FacetCascade> { - self.rows.iter().find(|f| f.facet_classid == classid) - } -} - -/// The single-column descriptor: 16 × `u8` at offset 0 — one `FacetCascade` -/// per row. Static so the descriptor table is itself a stable LE artifact. -const FACET_COLUMNS: [ColumnDescriptor; 1] = [ColumnDescriptor { - name_id: FACET_COLUMN_ID, - kind: ColumnKind::U8, - elems_per_row: FACET_ROW_STRIDE as u16, - row_offset: 0, -}]; - -impl SoaEnvelope for FacetSoa { - fn columns(&self) -> &[ColumnDescriptor] { - &FACET_COLUMNS - } - - fn row_stride(&self) -> usize { - FACET_ROW_STRIDE - } - - fn n_rows(&self) -> usize { - self.rows.len() - } - - fn cycle(&self) -> u32 { - self.cycle - } - - fn as_le_bytes(&self) -> &[u8] { - // SAFETY: FacetCascade is #[repr(C, align(16))], size_of == 16 (const-asserted - // in facet.rs). A &[FacetCascade] of len n reinterprets as &[u8] of len n*16: - // u8 has alignment 1 (≤ 16, so the pointer is trivially aligned), and every byte - // of a FacetCascade is a valid u8 (no niche). The borrow ties the &[u8] to &self. - unsafe { - core::slice::from_raw_parts( - self.rows.as_ptr().cast::(), - self.rows.len() * FACET_ROW_STRIDE, - ) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::soa_envelope::SoaEnvelope; - - fn sample(classid: u32, part_of: [u8; 6], is_a: [u8; 6]) -> FacetCascade { - // Build via the 16 facet bytes in the locked wire order: - // classid LE in [0..4); byte[4+2t]=is_a[t] (lo), byte[5+2t]=part_of[t] (hi). - let mut b = [0u8; 16]; - b[0..4].copy_from_slice(&classid.to_le_bytes()); - for t in 0..6 { - b[4 + 2 * t] = is_a[t]; - b[5 + 2 * t] = part_of[t]; - } - FacetCascade::from_bytes(&b) - } - - #[test] - fn from_le_bytes_round_trips_every_row_byte_exact() { - let a = sample(0x0202_0002, [1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]); - let c = sample(0x0102_0001, [9, 9, 9, 0, 0, 0], [1, 1, 1, 0, 0, 0]); - let src: Vec = [a, c].iter().flat_map(|f| f.to_bytes()).collect(); - - let soa = FacetSoa::from_le_bytes(&src, 7).expect("multiple of 16"); - assert_eq!(soa.len(), 2); - assert_eq!(soa.cycle(), 7); - // Byte-parity on ALL rows (not one hand-picked value). - assert_eq!(soa.as_le_bytes(), &src[..]); - assert_eq!(soa.get(0).unwrap().to_bytes(), a.to_bytes()); - assert_eq!(soa.get(1).unwrap().to_bytes(), c.to_bytes()); - } - - #[test] - fn as_le_bytes_is_16_aligned_and_reinterprets_zero_copy() { - // The slab-addressability guard truth-architect required: as_le_bytes() - // is 16-aligned (Vec allocates at align 16), so the - // free-function reinterpret returns Some and points at the same bytes. - let soa = FacetSoa::from_facets( - vec![sample(0x0202_0002, [1; 6], [2; 6]), sample(7, [0; 6], [0; 6])], - 0, - ); - let bytes = soa.as_le_bytes(); - assert_eq!(bytes.len(), 32); - let view = facet_cascades_from_le_bytes(bytes).expect("aligned slab reinterprets"); - assert_eq!(view.len(), 2); - assert_eq!(view[0].facet_classid, 0x0202_0002); - // Same backing bytes — a reinterpret, not a copy. - assert_eq!(view.as_ptr() as usize, soa.facets().as_ptr() as usize); - } - - #[test] - fn lookup_by_classid_indexes_and_misses_cleanly() { - let soa = FacetSoa::from_facets( - vec![ - sample(0x0202_0002, [1; 6], [2; 6]), - sample(0x0102_0001, [3; 6], [4; 6]), - ], - 0, - ); - assert_eq!( - soa.lookup_by_classid(0x0102_0001).unwrap().facet_classid, - 0x0102_0001 - ); - assert!(soa.lookup_by_classid(0x0000_0000).is_none(), "clean miss"); - } - - #[test] - fn from_le_bytes_rejects_non_stride_length() { - assert!(FacetSoa::from_le_bytes(&[0u8; 15], 0).is_none()); - assert!(FacetSoa::from_le_bytes(&[0u8; 17], 0).is_none()); - assert!(FacetSoa::from_le_bytes(&[], 0).unwrap().is_empty()); - } - - #[test] - fn envelope_layout_verifies() { - let soa = FacetSoa::from_facets(vec![sample(1, [0; 6], [0; 6])], 3); - // One 16-byte column at offset 0, stride 16 — geometry is self-consistent. - assert_eq!(soa.row_stride(), 16); - assert_eq!(soa.columns().len(), 1); - assert_eq!(soa.columns()[0].col_bytes_per_row(), 16); - soa.verify_layout().expect("single-column 16B geometry is valid"); - } - - #[test] - fn free_fn_rejects_unaligned_and_bad_length() { - // A Vec is only 1-aligned; the reinterpret must refuse it. - let unaligned: Vec = vec![0u8; 32]; - // Force a very likely misalignment by slicing off the front byte. - let off = &unaligned[1..17]; - assert!( - facet_cascades_from_le_bytes(off).is_none() - || (off.as_ptr() as usize).is_multiple_of(16) - ); - // Bad length. - assert!(facet_cascades_from_le_bytes(&[0u8; 15]).is_none()); - } -} diff --git a/crates/lance-graph-contract/src/lib.rs b/crates/lance-graph-contract/src/lib.rs index 80b94e0e..a25071a5 100644 --- a/crates/lance-graph-contract/src/lib.rs +++ b/crates/lance-graph-contract/src/lib.rs @@ -80,7 +80,6 @@ pub mod escalation; pub mod exploration; pub mod external_membrane; pub mod facet; -pub mod facet_soa; pub mod facet_schema; pub mod faculty; pub mod grammar; From 19d1b3aab7f8d67fa2629e9e3754370283db2e33 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Jul 2026 23:07:56 +0000 Subject: [PATCH 13/13] contract: mirror OSM/Geo codebook concepts (fuse 79==79, OGAR #152) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sync lance_graph_contract::ogar_codebook::CODEBOOK to OGAR #152 so the compile-time COUNT_FUSE in lance-graph-ogar holds against the OSM harvest: - +10 Geo (0x0FXX) OSM concepts: osm_node/way/relation/changeset/ element_tag/relation_member/way_node/note/gpx_trace/user. - ConceptDomain += Geo; canonical_concept_domain 0x0F => Geo; the 0x0F00 → Geo parity assert (0x1000 stays Unassigned). - domains_agree() += Geo and Genetics arms (Genetics was latently missing — no 0x0E codebook entry had exercised it; the new 0x0F entries would have tripped it). The mirror already carried network_layer (0x0804, an OCR concept wire-declared here first); OGAR #152 now mints its authoritative counterpart, so both sides land at class_ids::ALL = CODEBOOK.len() = 79. TEMP-PIN ogar-vocab/class-view/ontology/adapter-surrealql to OGAR rev 58a64d4 (the #152 tip, ALL = 79). OGAR main is still 68 until #152 merges; revert the four git deps to branch = "main" once it lands so the golden image resolves to one source again. Verified: lance-graph-ogar builds (COUNT_FUSE 79==79) + parity test passes (forward mirror⊆OGAR, reverse OGAR⊆mirror, domain agreement); lance-graph-contract ogar_codebook tests 13/13. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01EYvNjD8M8LMNYbRy3gq2FP --- Cargo.lock | 10 +++---- .../lance-graph-contract/src/ogar_codebook.rs | 27 +++++++++++++++++-- crates/lance-graph-ogar/Cargo.toml | 17 ++++++++---- crates/lance-graph-ogar/src/lib.rs | 2 ++ 4 files changed, 44 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3ecf60db..1a89f02e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4932,7 +4932,7 @@ dependencies = [ [[package]] name = "lance-graph-contract" version = "0.1.0" -source = "git+https://github.com/AdaWorldAPI/lance-graph?branch=main#df367471df8cc74464733554b4c2338f90eae7d4" +source = "git+https://github.com/AdaWorldAPI/lance-graph?branch=main#b74378c7853a9b03b48adb29537e45af6524728c" dependencies = [ "glob", "serde", @@ -6043,7 +6043,7 @@ dependencies = [ [[package]] name = "ogar-adapter-surrealql" version = "0.1.0" -source = "git+https://github.com/AdaWorldAPI/OGAR?branch=main#75d955bd3bfd1b97987ab9e4c2c1cedfcda1adfe" +source = "git+https://github.com/AdaWorldAPI/OGAR?rev=58a64d4701eaf70ff67fe53a5e2087d5d0c48c0d#58a64d4701eaf70ff67fe53a5e2087d5d0c48c0d" dependencies = [ "ogar-vocab", ] @@ -6051,7 +6051,7 @@ dependencies = [ [[package]] name = "ogar-class-view" version = "0.1.0" -source = "git+https://github.com/AdaWorldAPI/OGAR?branch=main#75d955bd3bfd1b97987ab9e4c2c1cedfcda1adfe" +source = "git+https://github.com/AdaWorldAPI/OGAR?rev=58a64d4701eaf70ff67fe53a5e2087d5d0c48c0d#58a64d4701eaf70ff67fe53a5e2087d5d0c48c0d" dependencies = [ "lance-graph-contract 0.1.0 (git+https://github.com/AdaWorldAPI/lance-graph?branch=main)", "ogar-vocab", @@ -6060,12 +6060,12 @@ dependencies = [ [[package]] name = "ogar-ontology" version = "0.1.0" -source = "git+https://github.com/AdaWorldAPI/OGAR?branch=main#75d955bd3bfd1b97987ab9e4c2c1cedfcda1adfe" +source = "git+https://github.com/AdaWorldAPI/OGAR?rev=58a64d4701eaf70ff67fe53a5e2087d5d0c48c0d#58a64d4701eaf70ff67fe53a5e2087d5d0c48c0d" [[package]] name = "ogar-vocab" version = "0.1.0" -source = "git+https://github.com/AdaWorldAPI/OGAR?branch=main#75d955bd3bfd1b97987ab9e4c2c1cedfcda1adfe" +source = "git+https://github.com/AdaWorldAPI/OGAR?rev=58a64d4701eaf70ff67fe53a5e2087d5d0c48c0d#58a64d4701eaf70ff67fe53a5e2087d5d0c48c0d" [[package]] name = "once_cell" diff --git a/crates/lance-graph-contract/src/ogar_codebook.rs b/crates/lance-graph-contract/src/ogar_codebook.rs index 4f83a9aa..b60e33c4 100644 --- a/crates/lance-graph-contract/src/ogar_codebook.rs +++ b/crates/lance-graph-contract/src/ogar_codebook.rs @@ -80,7 +80,13 @@ pub enum ConceptDomain { /// `ogar_vocab::ConceptDomain::Genetics` — OGAR catches up under the drift /// guard (the parity tests pin `0x0E00 → Genetics`). Genetics, - /// Any high-byte slot not yet assigned a domain (`0x03XX`–`0x06XX`, `0x0FXX`+). + /// `0x0FXX` — Geo (OpenStreetMap geodata: node / way / relation / changeset / + /// element-tag / member / note / GPX trace / user). Public spatial reference + /// data; the Geo domain binds the HHTL tier axes to literal (x, y) tiles + /// (OGAR canon "256×256 centroid tile", D-BOTHCASC). Mirrors OGAR + /// `ogar_vocab::ConceptDomain::Geo`; the parity tests pin `0x0F00 → Geo`. + Geo, + /// Any high-byte slot not yet assigned a domain (`0x03XX`–`0x06XX`, `0x10XX`+). Unassigned, } @@ -102,6 +108,7 @@ pub fn canonical_concept_domain(id: u16) -> ConceptDomain { 0x0C => ConceptDomain::Automation, 0x0D => ConceptDomain::HR, 0x0E => ConceptDomain::Genetics, + 0x0F => ConceptDomain::Geo, _ => ConceptDomain::Unassigned, } } @@ -533,6 +540,20 @@ pub const CODEBOOK: &[(&str, u16)] = &[ ("action_handler", 0x0C07), ("action_applicability", 0x0C08), ("automation_trigger", 0x0C09), + // ── 0x0FXX — Geo domain (OpenStreetMap geodata; OGAR OSM harvest, PR #152). + // The core OSM graph — node / way / relation / changeset — plus element tags, + // relation members, way nodes, notes, GPX traces, and the user. `Old*` + // versioned rows ground to the same concept (temporal axis, not a new id). ── + ("osm_node", 0x0F01), + ("osm_way", 0x0F02), + ("osm_relation", 0x0F03), + ("osm_changeset", 0x0F04), + ("osm_element_tag", 0x0F05), + ("osm_relation_member", 0x0F06), + ("osm_way_node", 0x0F07), + ("osm_note", 0x0F08), + ("osm_gpx_trace", 0x0F09), + ("osm_user", 0x0F0A), ]; /// Resolve a **canonical-concept** string to its stable `u16` codebook id via @@ -613,7 +634,9 @@ mod tests { assert_eq!(canonical_concept_domain(0x0500), ConceptDomain::Unassigned); // Genetics (0x0E) operator-allocated 2026-06-26 for CPIC-V3 (was Unassigned). assert_eq!(canonical_concept_domain(0x0E00), ConceptDomain::Genetics); - assert_eq!(canonical_concept_domain(0x0F00), ConceptDomain::Unassigned); + // Geo (0x0F) allocated with the OSM harvest (OGAR #152; was Unassigned). + assert_eq!(canonical_concept_domain(0x0F00), ConceptDomain::Geo); + assert_eq!(canonical_concept_domain(0x1000), ConceptDomain::Unassigned); } #[test] diff --git a/crates/lance-graph-ogar/Cargo.toml b/crates/lance-graph-ogar/Cargo.toml index a076c598..82cba2ea 100644 --- a/crates/lance-graph-ogar/Cargo.toml +++ b/crates/lance-graph-ogar/Cargo.toml @@ -78,14 +78,21 @@ lance-graph-contract = { path = "../lance-graph-contract" } # against live in lance-graph-ontology (OGIT). OGIT does NOT depend on OGAR. lance-graph-ontology = { path = "../lance-graph-ontology" } -# ── OGAR Active-Record forks: git deps @ main (the canonical superset; matches +# ── OGAR Active-Record forks: git deps (the canonical superset; matches # symbiont's pins so they resolve to ONE source in the golden image) ── -ogar-vocab = { git = "https://github.com/AdaWorldAPI/OGAR", branch = "main" } -ogar-class-view = { git = "https://github.com/AdaWorldAPI/OGAR", branch = "main" } -ogar-ontology = { git = "https://github.com/AdaWorldAPI/OGAR", branch = "main" } +# +# TEMP-PIN to OGAR #152 rev (Geo/OSM + network_layer codebook mint: +# class_ids::ALL 68→79). The mirror in lance-graph-contract carries the same +# concepts, so COUNT_FUSE (mirror::CODEBOOK.len() == ogar_vocab::class_ids::ALL +# .len()) requires BOTH sides at 79. OGAR main is still 68 until #152 merges — +# pinning to the pushed rev keeps the lockstep green now. REVERT the four deps +# to branch = "main" once OGAR #152 lands on main (one source in the golden image). +ogar-vocab = { git = "https://github.com/AdaWorldAPI/OGAR", rev = "58a64d4701eaf70ff67fe53a5e2087d5d0c48c0d" } +ogar-class-view = { git = "https://github.com/AdaWorldAPI/OGAR", rev = "58a64d4701eaf70ff67fe53a5e2087d5d0c48c0d" } +ogar-ontology = { git = "https://github.com/AdaWorldAPI/OGAR", rev = "58a64d4701eaf70ff67fe53a5e2087d5d0c48c0d" } # default features only = the light emit() DDL formatter (no surrealdb tree); # the parser half is opt-in via this crate's `surrealql-parser` feature. -ogar-adapter-surrealql = { git = "https://github.com/AdaWorldAPI/OGAR", branch = "main" } +ogar-adapter-surrealql = { git = "https://github.com/AdaWorldAPI/OGAR", rev = "58a64d4701eaf70ff67fe53a5e2087d5d0c48c0d" } # Fold ogar-class-view's transitive `lance-graph-contract` (git # AdaWorldAPI/lance-graph#main) onto the SAME path copy this crate uses, so there diff --git a/crates/lance-graph-ogar/src/lib.rs b/crates/lance-graph-ogar/src/lib.rs index bf9abde8..ee4b75d9 100644 --- a/crates/lance-graph-ogar/src/lib.rs +++ b/crates/lance-graph-ogar/src/lib.rs @@ -144,6 +144,8 @@ pub mod parity { | (O::Auth, C::Auth) | (O::Automation, C::Automation) | (O::HR, C::HR) + | (O::Genetics, C::Genetics) + | (O::Geo, C::Geo) | (O::Unassigned, C::Unassigned) ) }