|
| 1 | +# Migration — OGAR `ogar-vocab` codebook ⇄ `lance-graph-contract` classid (v1) |
| 2 | + |
| 3 | +> **Status:** PROPOSED (2026-06-20). Surfaces a **canon conflict** between merged |
| 4 | +> `lance-graph-contract` classids and OGAR's `ogar-vocab` codebook; the |
| 5 | +> reconciliation rewrites merged canon (`CLASSID_OSINT`/`CLASSID_FMA`) and so is |
| 6 | +> gated on operator sign-off. |
| 7 | +> **The triangle:** ontology (OGAR `ogar-vocab`) → contract (`NodeGuid`/`ClassId`) |
| 8 | +> → q2 (Quadro-2 cockpit consuming `GraphSnapshot`). |
| 9 | +
|
| 10 | +--- |
| 11 | + |
| 12 | +## 1 — The seam, grounded (file:line) |
| 13 | + |
| 14 | +OGAR's `crates/ogar-vocab/src/lib.rs` already defines the canonical class |
| 15 | +identity layer, and **its own doc-comment says where it belongs**: |
| 16 | + |
| 17 | +- **`CODEBOOK`** (`lib.rs:1073`) — curated `(canonical_concept, u16)` table, ids |
| 18 | + assigned (never hashed). Domain-encoded `0xDDCC` (high byte = domain). |
| 19 | +- **`ConceptDomain`** (`lib.rs:1141`) + **`canonical_concept_domain(id)→ConceptDomain`** |
| 20 | + (`lib.rs:1163`, routes on `id >> 8`, O(1) no-lookup). |
| 21 | +- **`source_domain_concept("project"|"erp"|"german-erp")→ConceptDomain`** |
| 22 | + (`lib.rs:1186`) — the seam from `Class::source_domain` (the coarse curator tag, |
| 23 | + `lib.rs:193`) to the typed domain. |
| 24 | +- **`canonical_concept_id(concept)→Option<u16>`** (`lib.rs:1214`) + |
| 25 | + `Class::canonical_id()/canonical_id_le()` (`lib.rs:1026/1034`). |
| 26 | +- **`LabelDTO { label, id: u16, canonical }`** (`lib.rs:1476`) + `from_alias()` — |
| 27 | + consumer alias → shared codebook id. **`lib.rs:1208`:** *"The contract type |
| 28 | + (`LabelDTO`) lives in `ogar-vocab` today; **long-term it belongs in |
| 29 | + `lance-graph-contract`** alongside `ClassId` and the `NodeGuid` LE layout. Wire |
| 30 | + is the source of truth: any encoder/decoder agreeing on `u16` LE is compatible |
| 31 | + regardless of which crate exports the DTO."* And `lib.rs:1204-1206`: *"codebook |
| 32 | + ids and the `NodeGuid.classid` u16 low half are wire-compatible."* |
| 33 | + |
| 34 | +So **the OGAR codebook id IS the contract classid (low u16)** — one wire value, |
| 35 | +two crates. Contract has none of it yet (grep: no `ogar-vocab` reference in |
| 36 | +`lance-graph-contract`). |
| 37 | + |
| 38 | +## 2 — The conflict (the migration gap) |
| 39 | + |
| 40 | +OGAR's `0xDDCC` domain layout vs the classids contract minted this session |
| 41 | +(#557/#560, merged): |
| 42 | + |
| 43 | +| Domain | OGAR `ConceptDomain` block | contract today | Aligned? | |
| 44 | +|---|---|---|---| |
| 45 | +| project-mgmt (OP↔Redmine) | `0x01XX` | — (un-minted) | n/a — **mint** | |
| 46 | +| commerce/ERP (OSB↔Odoo) | `0x02XX` | — (un-minted) | n/a — **mint** | |
| 47 | +| OSINT | **`0x07XX`** | `CLASSID_OSINT = 0x0007` | ❌ `0x0007 >> 8 = 0x00` = **Reserved**, not OSINT | |
| 48 | +| OCR | `0x08XX` | `CLASSID_FMA = 0x0008` | ❌ `0x0008` is in OGAR's **OCR** block | |
| 49 | +| Health (clinical) | `0x09XX` | (FMA anatomy ≈ Health) | ❌ FMA/anatomy is medical → belongs `0x09XX`, not `0x0008` | |
| 50 | + |
| 51 | +Root cause: `CLASSID_OSINT=0x0007` was minted from the early guess "OSINT is |
| 52 | +0x0007" before `ogar-vocab`'s domain-encoded layout was consulted. Under OGAR, |
| 53 | +the OSINT *domain* is the high byte `0x07`, so an OSINT class is `0x07CC` |
| 54 | +(e.g. `0x0700`), and `0x0007` is a Reserved-domain slot. `0x0008` collides with |
| 55 | +the OCR domain; FMA (Foundational Model of Anatomy) is clinical → Health |
| 56 | +`0x09XX` (or a dedicated anatomy domain) — never `0x0008`. |
| 57 | + |
| 58 | +## 3 — Target state (single source of truth) |
| 59 | + |
| 60 | +Per OGAR's own note, **`lance-graph-contract` is the long-term home** for the |
| 61 | +class-identity codebook. Reconcile onto OGAR's `0xDDCC` scheme: |
| 62 | + |
| 63 | +1. **Codebook + domain types live in contract.** Move (or mirror, wire-compat) |
| 64 | + `ConceptDomain`, `canonical_concept_domain`, `source_domain_concept`, |
| 65 | + `canonical_concept_id`, the `CODEBOOK`, and `LabelDTO` into |
| 66 | + `lance-graph-contract` (next to `ClassId`/`NodeGuid`). `ogar-vocab` |
| 67 | + re-exports them (OGAR→contract dep) **OR** both keep a copy and the **wire |
| 68 | + (`u16` LE) is the contract** (no new dep). *Decision needed — see §5.* |
| 69 | +2. **classids follow `0xDDCC`.** `NodeGuid.classid` low u16 == the codebook id. |
| 70 | + - project-mgmt: `0x01XX` (mint `CLASSID_PROJECT = 0x0100` block). |
| 71 | + - commerce/ERP: `0x02XX` (mint `CLASSID_ERP/COMMERCE = 0x0200` block). |
| 72 | + - OSINT: realign `CLASSID_OSINT` → `0x0700` (Gotham domain). |
| 73 | + - anatomy/FMA: realign `CLASSID_FMA` → Health `0x09XX` (or a new anatomy |
| 74 | + domain block, reserved appended — never `0x0008`). |
| 75 | +3. **`canonical_concept_domain` becomes the `ReadMode`/domain router** — the |
| 76 | + `classid → ReadMode` registry keys off `id >> 8` (the domain), so OSINT/FMA/ |
| 77 | + project/ERP all resolve by the same O(1) high-byte rule. |
| 78 | +4. **The per-family codebook (D-GV2-2) is the FINER scope of the SAME idea.** |
| 79 | + OGAR `CODEBOOK` = the *concept/classid* codebook (domain `0xDDCC`); the |
| 80 | + `guid-v2-tail` `FamilyCodebookRegistry` (`contract::codebook`) = the |
| 81 | + *within-family* label vocab. They compose: classid (domain) selects the |
| 82 | + coarse codebook; family selects the sub-codebook. Longest-prefix-wins, one |
| 83 | + rule (OGAR `CLAUDE.md` "Codebook scoping = the class routing prefix"). |
| 84 | + |
| 85 | +## 4 — Deliverables (gated on §5 decisions) |
| 86 | + |
| 87 | +- **D-OVC-1** Move/mirror `ConceptDomain` + `canonical_concept_domain` + |
| 88 | + `source_domain_concept` + `canonical_concept_id` + `CODEBOOK` + `LabelDTO` |
| 89 | + into `lance-graph-contract` (e.g. `contract::ogar_codebook`); `ogar-vocab` |
| 90 | + re-exports (or wire-compat duplicate). Round-trip test: `LabelDTO::from_alias` |
| 91 | + parity across both crates. |
| 92 | +- **D-OVC-2** Mint `CLASSID_PROJECT` (`0x0100`) + `CLASSID_ERP` (`0x0200`) in |
| 93 | + `canonical_node.rs` + `ReadMode`s, registered in `BUILTIN_READ_MODES`. Add |
| 94 | + `soa_graph::{PROJECT, ERP}` `DomainSpec`s (siblings of `OSINT_GOTHAM`/`FMA_ANATOMY`). |
| 95 | +- **D-OVC-3** **Canon realign (SIGN-OFF):** `CLASSID_OSINT 0x0007 → 0x0700`, |
| 96 | + `CLASSID_FMA 0x0008 → 0x09xx` (Health) or a minted anatomy domain. Field-isolation |
| 97 | + / version-gate per `I-LEGACY-API-FEATURE-GATED`; update `aiwar.rs`, `soa_graph.rs`, |
| 98 | + tests, and the canon block in `lance-graph/CLAUDE.md` + OGAR `CODEBOOK`. |
| 99 | +- **D-OVC-4** Route `classid → ReadMode` (and the domain ClassView) through |
| 100 | + `canonical_concept_domain(classid_lo)`; q2 reads `LabelDTO`/`canonical` for |
| 101 | + display labels (the contract→q2 leg of the triangle). |
| 102 | + |
| 103 | +## 5 — Decisions needed (operator) |
| 104 | + |
| 105 | +1. **Canon realign OSINT/FMA?** `CLASSID_OSINT 0x0007 → 0x0700`, `CLASSID_FMA |
| 106 | + 0x0008 → 0x09XX`. This rewrites merged canon (#557/#560) + the `lance-graph/ |
| 107 | + CLAUDE.md` canon block. Recommended (otherwise contract and OGAR disagree on |
| 108 | + what `0x07`/`0x08` mean), but it's your canon to change. Alternative: keep |
| 109 | + `0x0007/0x0008` and re-document OGAR's domain layout to match (worse — breaks |
| 110 | + the clean `id>>8` domain route). |
| 111 | +2. **Dependency direction for the shared types:** (a) move to contract, |
| 112 | + `ogar-vocab` `pub use`s from it (OGAR gains a `lance-graph-contract` dep); |
| 113 | + or (b) both define, wire (`u16` LE) is the only contract, a parity test |
| 114 | + guards drift (no new dep). OGAR's note leans (a) ("belongs in contract"); |
| 115 | + (b) is lighter and keeps OGAR dep-free. Recommend (b) now, (a) at a |
| 116 | + deliberate consolidation. |
| 117 | +3. **FMA/anatomy domain:** fold into Health `0x09XX`, or mint a dedicated |
| 118 | + anatomy domain block (append-only reserved high byte)? |
| 119 | + |
| 120 | +## Cross-refs |
| 121 | + |
| 122 | +OGAR `crates/ogar-vocab/src/lib.rs` (`CODEBOOK`/`ConceptDomain`/`LabelDTO`/ |
| 123 | +`source_domain`), OGAR `CLAUDE.md` "Tier interpretation 256×256 CENTROID TILE" + |
| 124 | +"Codebook scoping = the class routing prefix"; `contract::canonical_node` |
| 125 | +(`CLASSID_OSINT`/`CLASSID_FMA`/`BUILTIN_READ_MODES`), `contract::codebook` |
| 126 | +(D-GV2-2 per-family), `contract::soa_graph` (`OSINT_GOTHAM`/`FMA_ANATOMY`), |
| 127 | +`contract::aiwar`; `guid-v2-tail-per-family-codebook-v1.md`; |
| 128 | +`E-UNIFORM-MORTON-TILE-PYRAMID`. |
0 commit comments