diff --git a/cockpit/src/BodyV3.tsx b/cockpit/src/BodyV3.tsx
index cde66ac04..435c4f9ef 100644
--- a/cockpit/src/BodyV3.tsx
+++ b/cockpit/src/BodyV3.tsx
@@ -21,7 +21,11 @@ import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const PAGE_BG = 0x0a0e17;
-const FMA_V3_CLASSID = 0x10000a01;
+// Post-flip form (canon 0x0A01 HIGH, V3 marker 0x1000 LOW — 2026-07-02).
+const FMA_V3_CLASSID = 0x0a011000;
+// Pre-flip stored form — the body.soa GitHub-Release asset
+// (fma-body-soa-v3-v1) still carries it until re-baked + re-released.
+const FMA_V3_CLASSID_LEGACY = 0x10000a01;
const LAYERS: { id: number; name: string; color: string }[] = [
{ id: 1, name: 'skin', color: '#dba88a' },
@@ -433,7 +437,7 @@ export function BodyV3() {
{d && (
{d.nConcepts.toLocaleString()} concepts ·{' '}
- {d.classid === FMA_V3_CLASSID
+ {(d.classid === FMA_V3_CLASSID || d.classid === FMA_V3_CLASSID_LEGACY)
? classid 0x{d.classid.toString(16)} ✓ V3 (part_of:is_a)
: classid 0x{d.classid.toString(16)}}
diff --git a/cpic/docs/INGEST.md b/cpic/docs/INGEST.md
index 321ab1948..5ba05c9cb 100644
--- a/cpic/docs/INGEST.md
+++ b/cpic/docs/INGEST.md
@@ -40,19 +40,32 @@ Both hierarchies are *already in the CPIC columns* — nothing is invented:
partonomy is the `part_of` axis, and ATC drug codes are a second ready-made `is_a`
cascade.
-## classid — pharmacogenomics domain `0x0C`
-
-`classid` prefix-routes the entity kind (the OGAR `ClassView` dispatch). We use domain
-`0x0C` (anatomy was `0x0A`):
+## classid — pharmacogenomics, Genetics domain `0x0E01` (re-minted 2026-07-02)
+
+> **Note (2026-07-02):** `SAMPLE_GUIDS.tsv` was regenerated from a fresh
+> `cargo run --release --bin ingest -- data out 4000` run against this
+> re-mint — every row's tail (HEEL/HIP/TWIG/family/identity) is byte-identical
+> to the pre-flip sample; only the classid prefix changed.
+
+`classid` prefix-routes the entity kind (the OGAR `ClassView` dispatch). The
+original local scheme used domain `0x0C`, which collides with the Automation
+domain (`lance-graph-contract::ogar_codebook::ConceptDomain::Automation`) and
+predates the operator's Genetics ruling. Re-minted as INTERIM canon-high
+Genetics:q2 ids, matching the `lance-graph-contract` classid half-order flip
+(canon HIGH / custom LOW): canon `0x0E01` = Genetics domain (`0x0E`) + appid
+`0x01` (q2); the LOW half is this crate's local kind slot. This crate is
+dep-free and does not pull the real `lance-graph-contract` ClassView
+catalogue — the full contract-pull re-mint that dissolves this local scheme
+entirely is the tracked follow-up.
| classid | entity | part_of (high) | is_a (low) |
|---|---|---|---|
-| `0x000C0001` | gene | `pharmacogenome / CYP / CYP2 / CYP2C / CYP2C19` | `entity / gene` |
-| `0x000C0002` | allele (`*2`) | gene partonomy ++ allele | `allele / no_function` |
-| `0x000C0003` | diplotype (`*2/*2`) | gene ++ `diplotypes` ++ dip | `diplotype / homozygous` |
-| `0x000C0004` | phenotype | gene ++ `phenotypes` ++ result | `phenotype / poor_metabolizer` |
-| `0x000C0005` | drug | `pharmacogenome / drugs / name` | `drug / N / N06 / N06A / N06AA` |
-| `0x000C0006` | recommendation | `recommendations / g{id} / drug` | `recommendation / strong` |
+| `0x0E010001` | gene | `pharmacogenome / CYP / CYP2 / CYP2C / CYP2C19` | `entity / gene` |
+| `0x0E010002` | allele (`*2`) | gene partonomy ++ allele | `allele / no_function` |
+| `0x0E010003` | diplotype (`*2/*2`) | gene ++ `diplotypes` ++ dip | `diplotype / homozygous` |
+| `0x0E010004` | phenotype | gene ++ `phenotypes` ++ result | `phenotype / poor_metabolizer` |
+| `0x0E010005` | drug | `pharmacogenome / drugs / name` | `drug / N / N06 / N06A / N06AA` |
+| `0x0E010006` | recommendation | `recommendations / g{id} / drug` | `recommendation / strong` |
- **family (u24)** = the basin: the gene symbol (gene/allele/diplotype/phenotype), the
ATC root letter (drug), or `rec:g{id}` (recommendation). Groups all of a gene's
@@ -66,10 +79,10 @@ cascade.
```text
allele guid HEEL HIP TWIG family
-CYP2C19 *2 000c0002-c358-ec6f-f76f-d69bfe558274 c358 ec6f f76f d69bfe (No function)
-CYP2C9 *2 000c0002-c358-ecd8-f7d8-fbd6cbd5c622 c358 ecd8 f7d8 fbd6cb (Decreased function)
-CYP2C19 *1 000c0002-c358-ec07-f707-d69bfe3c1176 c358 ec07 f707 d69bfe (Normal function)
-CYP2D6 *4 000c0002-c358-ec6f-f76f-1066f96f7ace c358 ec6f f76f 1066f9 (No function)
+CYP2C19 *2 0e010002-c358-ec6f-f76f-d69bfe558274 c358 ec6f f76f d69bfe (No function)
+CYP2C9 *2 0e010002-c358-ecd8-f7d8-fbd6cbd5c622 c358 ecd8 f7d8 fbd6cb (Decreased function)
+CYP2C19 *1 0e010002-c358-ec07-f707-d69bfe3c1176 c358 ec07 f707 d69bfe (Normal function)
+CYP2D6 *4 0e010002-c358-ec6f-f76f-1066f96f7ace c358 ec6f f76f 1066f9 (No function)
```
- **part_of HIGH bytes** `c3 / ec / f7` = `pharmacogenome → CYP → CYP2`, shared by all
diff --git a/cpic/docs/SAMPLE_GUIDS.tsv b/cpic/docs/SAMPLE_GUIDS.tsv
index b43c82c52..d2954cda8 100644
--- a/cpic/docs/SAMPLE_GUIDS.tsv
+++ b/cpic/docs/SAMPLE_GUIDS.tsv
@@ -1,26 +1,26 @@
guid kind label part_of is_a
-000c0001-c3fa-ec2a-f72a-fbd6cb3779b9 gene CYP2C9 pharmacogenome / CYP / CYP2 / CYP2C / CYP2C9 entity / gene
-000c0001-c3fa-ec2a-f72a-1066f93779b9 gene CYP2D6 pharmacogenome / CYP / CYP2 / CYP2D / CYP2D6 entity / gene
-000c0001-c3fa-1b2a-982a-61ef4f3779b9 gene HLA-B pharmacogenome / HLA / HLA-B entity / gene
-000c0001-c3fa-ec2a-f72a-d69bfe3779b9 gene CYP2C19 pharmacogenome / CYP / CYP2 / CYP2C / CYP2C19 entity / gene
-000c0001-c3fa-f92a-8f2a-ec80083779b9 gene TPMT pharmacogenome / TPMT / TPMT entity / gene
-000c0002-c358-ec6f-f76f-d69bfe4cda56 allele CYP2C19 *4 pharmacogenome / CYP / CYP2 / CYP2C / CYP2C19 / 4 allele / no_function
-000c0002-c358-ec6f-f76f-1066f96f7ace allele CYP2D6 *4 pharmacogenome / CYP / CYP2 / CYP2D / CYP2D6 / 4 allele / no_function
-000c0002-c358-1bd5-98d5-61ef4f6ef372 allele HLA-B *57:01 pharmacogenome / HLA / HLA-B / 57_01 allele / uncertain_function
-000c0002-c358-ec6f-f76f-d69bfe558274 allele CYP2C19 *2 pharmacogenome / CYP / CYP2 / CYP2C / CYP2C19 / 2 allele / no_function
-000c0002-c358-ecd8-f7d8-fbd6cbd5c622 allele CYP2C9 *2 pharmacogenome / CYP / CYP2 / CYP2C / CYP2C9 / 2 allele / decreased_function
-000c0002-c358-ec07-f707-d69bfe3c1176 allele CYP2C19 *1 pharmacogenome / CYP / CYP2 / CYP2C / CYP2C19 / 1 allele / normal_function
-000c0002-c358-ec6f-f76f-fbd6cb6b6a6d allele CYP2C9 *3 pharmacogenome / CYP / CYP2 / CYP2C / CYP2C9 / 3 allele / no_function
-000c0002-c358-ec07-f707-1066f9fd85b3 allele CYP2D6 *1 pharmacogenome / CYP / CYP2 / CYP2D / CYP2D6 / 1 allele / normal_function
-000c0004-c347-ecb1-f7b1-1066f93779b9 phenotype CYP2D6 Ultrarapid Metabolizer pharmacogenome / CYP / CYP2 / CYP2D / CYP2D6 / phenotypes / ultrarapid_metabolizer phenotype / ultrarapid_metabolizer
-000c0004-c347-ecb1-f7b1-1066f96ef372 phenotype CYP2D6 Ultrarapid Metabolizer pharmacogenome / CYP / CYP2 / CYP2D / CYP2D6 / phenotypes / ultrarapid_metabolizer phenotype / ultrarapid_metabolizer
-000c0004-c347-ec7a-f77a-1066f9a66d2b phenotype CYP2D6 Normal Metabolizer pharmacogenome / CYP / CYP2 / CYP2D / CYP2D6 / phenotypes / normal_metabolizer phenotype / normal_metabolizer
-000c0004-c347-f9a8-8fa8-ec80083779b9 phenotype TPMT Intermediate Metabolizer pharmacogenome / TPMT / TPMT / phenotypes / intermediate_metabolizer phenotype / intermediate_metabolizer
-000c0004-c347-f9e9-8fe9-ec80086ef372 phenotype TPMT Poor Metabolizer pharmacogenome / TPMT / TPMT / phenotypes / poor_metabolizer phenotype / poor_metabolizer
-000c0004-c347-f9db-8fdb-ec8008a66d2b phenotype TPMT Indeterminate pharmacogenome / TPMT / TPMT / phenotypes / indeterminate phenotype / indeterminate
-000c0005-c3af-cb3e-233c-1c839f6ef372 drug abacavir pharmacogenome / drugs / abacavir drug / J / J05 / J05A / J05AF / abacavir
-000c0005-c3af-cb0a-630d-1c7cd36ef372 drug amitriptyline pharmacogenome / drugs / amitriptyline drug / N / N06 / N06A / N06AA / amitriptyline
-000c0005-c3af-cba6-3010-1c9137a66d2b drug warfarin pharmacogenome / drugs / warfarin drug / B / B01 / B01A / B01AA / warfarin
-000c0005-c3af-cba6-b610-1c9137bbcdc8 drug clopidogrel pharmacogenome / drugs / clopidogrel drug / B / B01 / B01A / B01AC / clopidogrel
-000c0006-c7ee-454c-db4c-a2917a3779b9 recommendation g100421 RxNorm:190521 [HLA-B:*57:01 negative] -> Strong recommendations / g100421 / rxnorm_190521 recommendation / strong
-000c0006-c7ee-454c-db4c-a2917a6ef372 recommendation g100421 RxNorm:190521 [HLA-B:*57:01 positive] -> Strong recommendations / g100421 / rxnorm_190521 recommendation / strong
+0e010001-c3fa-ec2a-f72a-fbd6cb3779b9 gene CYP2C9 pharmacogenome / CYP / CYP2 / CYP2C / CYP2C9 entity / gene
+0e010001-c3fa-ec2a-f72a-1066f93779b9 gene CYP2D6 pharmacogenome / CYP / CYP2 / CYP2D / CYP2D6 entity / gene
+0e010001-c3fa-1b2a-982a-61ef4f3779b9 gene HLA-B pharmacogenome / HLA / HLA-B entity / gene
+0e010001-c3fa-ec2a-f72a-d69bfe3779b9 gene CYP2C19 pharmacogenome / CYP / CYP2 / CYP2C / CYP2C19 entity / gene
+0e010001-c3fa-f92a-8f2a-ec80083779b9 gene TPMT pharmacogenome / TPMT / TPMT entity / gene
+0e010002-c358-ec6f-f76f-d69bfe4cda56 allele CYP2C19 *4 pharmacogenome / CYP / CYP2 / CYP2C / CYP2C19 / 4 allele / no_function
+0e010002-c358-ec6f-f76f-1066f96f7ace allele CYP2D6 *4 pharmacogenome / CYP / CYP2 / CYP2D / CYP2D6 / 4 allele / no_function
+0e010002-c358-1bd5-98d5-61ef4f6ef372 allele HLA-B *57:01 pharmacogenome / HLA / HLA-B / 57_01 allele / uncertain_function
+0e010002-c358-ec6f-f76f-d69bfe558274 allele CYP2C19 *2 pharmacogenome / CYP / CYP2 / CYP2C / CYP2C19 / 2 allele / no_function
+0e010002-c358-ecd8-f7d8-fbd6cbd5c622 allele CYP2C9 *2 pharmacogenome / CYP / CYP2 / CYP2C / CYP2C9 / 2 allele / decreased_function
+0e010002-c358-ec07-f707-d69bfe3c1176 allele CYP2C19 *1 pharmacogenome / CYP / CYP2 / CYP2C / CYP2C19 / 1 allele / normal_function
+0e010002-c358-ec6f-f76f-fbd6cb6b6a6d allele CYP2C9 *3 pharmacogenome / CYP / CYP2 / CYP2C / CYP2C9 / 3 allele / no_function
+0e010002-c358-ec07-f707-1066f9fd85b3 allele CYP2D6 *1 pharmacogenome / CYP / CYP2 / CYP2D / CYP2D6 / 1 allele / normal_function
+0e010004-c347-ecb1-f7b1-1066f93779b9 phenotype CYP2D6 Ultrarapid Metabolizer pharmacogenome / CYP / CYP2 / CYP2D / CYP2D6 / phenotypes / ultrarapid_metabolizer phenotype / ultrarapid_metabolizer
+0e010004-c347-ecb1-f7b1-1066f96ef372 phenotype CYP2D6 Ultrarapid Metabolizer pharmacogenome / CYP / CYP2 / CYP2D / CYP2D6 / phenotypes / ultrarapid_metabolizer phenotype / ultrarapid_metabolizer
+0e010004-c347-ec7a-f77a-1066f9a66d2b phenotype CYP2D6 Normal Metabolizer pharmacogenome / CYP / CYP2 / CYP2D / CYP2D6 / phenotypes / normal_metabolizer phenotype / normal_metabolizer
+0e010004-c347-f9a8-8fa8-ec80083779b9 phenotype TPMT Intermediate Metabolizer pharmacogenome / TPMT / TPMT / phenotypes / intermediate_metabolizer phenotype / intermediate_metabolizer
+0e010004-c347-f9e9-8fe9-ec80086ef372 phenotype TPMT Poor Metabolizer pharmacogenome / TPMT / TPMT / phenotypes / poor_metabolizer phenotype / poor_metabolizer
+0e010004-c347-f9db-8fdb-ec8008a66d2b phenotype TPMT Indeterminate pharmacogenome / TPMT / TPMT / phenotypes / indeterminate phenotype / indeterminate
+0e010005-c3af-cb3e-233c-1c839f6ef372 drug abacavir pharmacogenome / drugs / abacavir drug / J / J05 / J05A / J05AF / abacavir
+0e010005-c3af-cb0a-630d-1c7cd36ef372 drug amitriptyline pharmacogenome / drugs / amitriptyline drug / N / N06 / N06A / N06AA / amitriptyline
+0e010005-c3af-cba6-3010-1c9137a66d2b drug warfarin pharmacogenome / drugs / warfarin drug / B / B01 / B01A / B01AA / warfarin
+0e010005-c3af-cba6-b610-1c9137bbcdc8 drug clopidogrel pharmacogenome / drugs / clopidogrel drug / B / B01 / B01A / B01AC / clopidogrel
+0e010006-c7ee-454c-db4c-a2917a3779b9 recommendation g100421 RxNorm:190521 [HLA-B:*57:01 negative] -> Strong recommendations / g100421 / rxnorm_190521 recommendation / strong
+0e010006-c7ee-454c-db4c-a2917a6ef372 recommendation g100421 RxNorm:190521 [HLA-B:*57:01 positive] -> Strong recommendations / g100421 / rxnorm_190521 recommendation / strong
diff --git a/cpic/src/lib.rs b/cpic/src/lib.rs
index ee9bad060..24a6deb13 100644
--- a/cpic/src/lib.rs
+++ b/cpic/src/lib.rs
@@ -6,13 +6,23 @@
//!
//! POC over published CPIC rules — NOT clinical decision support.
-// ── classid: pharmacogenomics domain 0x0C (cf. anatomy 0x0A used by fma/converge) ──
-pub const CID_GENE: u32 = 0x000C_0001;
-pub const CID_ALLELE: u32 = 0x000C_0002;
-pub const CID_DIPLOTYPE: u32 = 0x000C_0003;
-pub const CID_PHENOTYPE: u32 = 0x000C_0004;
-pub const CID_DRUG: u32 = 0x000C_0005;
-pub const CID_REC: u32 = 0x000C_0006;
+// ── classid: pharmacogenomics — re-minted 2026-07-02. The original local scheme
+// (`0x000C_000N`) predated the operator's Genetics ruling and collided with the
+// Automation domain (0x0C is Automation, not Genetics — see
+// `lance-graph-contract::ogar_codebook::ConceptDomain::Automation`). Re-minted as
+// INTERIM canon-high Genetics:q2 ids, matching the `lance-graph-contract` classid
+// half-order flip (canon in the HIGH half, custom in the LOW half): canon `0x0E01`
+// = Genetics domain (`0x0E`) + appid `0x01` (q2); the LOW half is this crate's
+// local kind slot (GENE=1, ALLELE=2, DIPLOTYPE=3, PHENOTYPE=4, DRUG=5, REC=6).
+// This is dep-free and does NOT pull the real `lance-graph-contract` ClassView
+// catalogue — the full contract-pull re-mint that dissolves this local scheme
+// entirely is the tracked follow-up (see `docs/INGEST.md`).
+pub const CID_GENE: u32 = 0x0E01_0001;
+pub const CID_ALLELE: u32 = 0x0E01_0002;
+pub const CID_DIPLOTYPE: u32 = 0x0E01_0003;
+pub const CID_PHENOTYPE: u32 = 0x0E01_0004;
+pub const CID_DRUG: u32 = 0x0E01_0005;
+pub const CID_REC: u32 = 0x0E01_0006;
// ── FNV-1a (the same prefix-cascade generator the fma converge bin uses) ──
const FNV_OFFSET: u64 = 0xcbf2_9ce4_8422_2325;
diff --git a/crates/aiwar-ingest/tests/fixtures/codebook_normalize.py b/crates/aiwar-ingest/tests/fixtures/codebook_normalize.py
index d3a1ad690..6eec49b2e 100644
--- a/crates/aiwar-ingest/tests/fixtures/codebook_normalize.py
+++ b/crates/aiwar-ingest/tests/fixtures/codebook_normalize.py
@@ -3,7 +3,10 @@
into ONE codebook-based, non-serialized Gotham/neo4j test fixture.
CANON model (lance-graph contract::aiwar + E-FAMILY-ADAPTER + OGAR codebook):
- - classid OSINT = 0x0700 (NodeGuid::CLASSID_OSINT, >>8 == 0x07)
+ - classid OSINT = 0x0700 (NodeGuid::CLASSID_OSINT, >>8 == 0x07) — this is the
+ bare u16 canon id, the HIGH half of the composed u32 classid since the
+ 2026-07-02 half-order flip (NodeGuid::CLASSID_OSINT == 0x0700_0000); this
+ fixture never composes the full u32, so no functional change from the flip.
- a node is its HEAD only: classid | family(mixin) | identity(u16) | edge-adapters
- mixin: an entity inherits its category by REFERENCE (family-node id), never a copy
- identity = 4 nibbles (u16)
@@ -13,6 +16,9 @@
import json, re, sys, glob, os
ROOT = os.environ.get("AIWAR_HARVEST", "/home/user/aiwar-neo4j-harvest")
+# u16 canon id — the HIGH half of the composed u32 classid since the
+# 2026-07-02 flip (NodeGuid::CLASSID_OSINT == 0x0700_0000). This script only
+# ever emits the bare u16 (see @meta below), never the composed u32.
OSINT_CLASSID = 0x0700
# JSON N_ -> canonical family label (matches the cypher node labels)
diff --git a/crates/cockpit-server/src/main.rs b/crates/cockpit-server/src/main.rs
index 19e50ef90..b137ae6f3 100644
--- a/crates/cockpit-server/src/main.rs
+++ b/crates/cockpit-server/src/main.rs
@@ -217,7 +217,8 @@ async fn main() {
// CPIC pharmacogenomics for the /cpic cockpit (cpic::reason over the baked CPIC tables)
.route("/api/cpic/reason", post(pgx::cpic_reason_handler))
.route("/api/cpic/catalog", get(pgx::cpic_catalog_handler))
- // OSINT domain (classid 0x0700): the harvest as a CANON family-basin graph
+ // OSINT domain (canon classid 0x0700 — HIGH half since the 2026-07-02
+ // flip): the harvest as a CANON family-basin graph
// (round→anchor basins, GUID-v2 tail), displayed via the OGAR ClassView.
.route("/api/graph/osint", get(osint_gotham::osint_graph_handler))
// Pre-baked enriched OSINT SoA bytes — the 3D view (/osint3d) fetches
diff --git a/crates/cockpit-server/src/osint_gotham.rs b/crates/cockpit-server/src/osint_gotham.rs
index 78a440b00..34f8bb80f 100644
--- a/crates/cockpit-server/src/osint_gotham.rs
+++ b/crates/cockpit-server/src/osint_gotham.rs
@@ -1,5 +1,9 @@
//! OSINT / Palantir-Gotham domain (classid `0x0700`) — the aiwar harvest as a
//! CANON family-basin graph, rendered through the OGAR Active-Record `ClassView`.
+//! `0x0700` is the canon concept id: since the 2026-07-02 half-order flip it is
+//! the HIGH u16 of the composed `u32` classid (`0x0700_0000`, `NodeGuid::CLASSID_OSINT`);
+//! the pre-flip stored form `0x0000_0700` still resolves via `CLASSID_OSINT_LEGACY`.
+//! Bare `0x0700` below always means the canon value, not the full composed classid.
//!
//! The corrected model (operator-locked this session):
//!
@@ -500,9 +504,12 @@ pub fn osint_graph() -> &'static Arc> {
OSINT_GRAPH.get_or_init(|| Arc::new(RwLock::new(GraphSnapshot::empty())))
}
-/// The ClassView ClassId for the OSINT domain (low u16 of `CLASSID_OSINT`).
+/// The ClassView ClassId for the OSINT domain — the concept id, i.e. the CANON
+/// half of `CLASSID_OSINT` (the HIGH u16 since the 2026-07-02 half-order flip;
+/// `classid & 0xFFFF` would now read the CUSTOM half and silently return the
+/// wrong value).
fn osint_class_id() -> u16 {
- (NodeGuid::CLASSID_OSINT & 0xFFFF) as u16
+ lance_graph_contract::classid_concept(NodeGuid::CLASSID_OSINT)
}
// ─────────────────────────────────────────────────────────────────────────────
@@ -826,7 +833,13 @@ pub fn build_osint_gotham(graph: &AiWarGraph, rounds: &[EncounterRound]) -> Grap
let class_label = label_of_order(order);
let mut props: HashMap = src.properties.clone();
props.insert("guid".to_string(), Value::String(r.key.to_hex_v2()));
- props.insert("classid".to_string(), Value::String("00000700".to_string()));
+ // Compose dynamically rather than hardcoding the stored form — the
+ // 2026-07-02 half-order flip moved canon 0x0700 into the HIGH half,
+ // so this now yields "07000000" (was "00000700" pre-flip).
+ props.insert(
+ "classid".to_string(),
+ Value::String(format!("{:08x}", NodeGuid::CLASSID_OSINT)),
+ );
props.insert("class_order".to_string(), Value::from(order));
props.insert("class".to_string(), Value::String(class_label.to_string()));
props.insert("basin".to_string(), Value::String(format!("{basin:02x}")));
@@ -1249,9 +1262,14 @@ mod tests {
let rows = osint_node_rows(&g, &plan);
assert_eq!(rows.len(), g.node_count(), "one OSINT row per entity");
for (i, row) in rows.iter().enumerate() {
- // classid 0x0700 (the OSINT domain byte is 0x07)
+ // classid 0x0700_0000 (canon 0x0700 sits in the HIGH half since
+ // the 2026-07-02 flip; route through the contract helper rather
+ // than deriving the domain byte via a raw shift).
assert_eq!(row.key.classid(), NodeGuid::CLASSID_OSINT);
- assert_eq!(row.key.classid() >> 8, 0x07);
+ assert_eq!(
+ lance_graph_contract::ogar_codebook::classid_canon(row.key.classid()) >> 8,
+ 0x07
+ );
// GUID-v2 tail: identity == index, family == basin byte (high byte 0)
assert_eq!(row.key.identity_v2(), i as u16);
assert_eq!(row.key.family_v2() >> 8, 0, "basin is an 8-bit byte");
diff --git a/crates/osint-bake/Cargo.toml b/crates/osint-bake/Cargo.toml
index 702a96f33..95b039257 100644
--- a/crates/osint-bake/Cargo.toml
+++ b/crates/osint-bake/Cargo.toml
@@ -15,7 +15,8 @@ path = "src/main.rs"
[dependencies]
aiwar-ingest = { path = "../aiwar-ingest" }
# osint-bake is the ONLY crate that mints on the V3 cascade tail (the FMA bake:
-# CLASSID_FMA_V3 0x1000_0A01 → ReadMode::FMA_V3, the part_of:is_a reading of the
+# CLASSID_FMA_V3 0x0A01_1000 (canon 0x0A01 HIGH, V3 marker 0x1000 LOW — 2026-07-02
+# half-order flip) → ReadMode::FMA_V3, the part_of:is_a reading of the
# SAME leaf·family·identity bytes). guid-v3-tail is requested here, NOT workspace-
# wide, so it doesn't force the feature onto cockpit-server's Railway build.
lance-graph-contract = { workspace = true, features = ["guid-v3-tail"] }
diff --git a/crates/osint-bake/src/bin/body.rs b/crates/osint-bake/src/bin/body.rs
index 11a92504b..4a81e1fe6 100644
--- a/crates/osint-bake/src/bin/body.rs
+++ b/crates/osint-bake/src/bin/body.rs
@@ -37,8 +37,10 @@
use lance_graph_contract::canonical_node::{classid_read_mode, NodeGuid};
use std::path::{Path, PathBuf};
-/// FMA V3 cascade key (`0x1000_0A01`) — same constant `bin/fma.rs` uses; the V3
-/// generation marker `0x1000` over the canon `anatomical_structure` concept `0x0A01`.
+/// FMA V3 cascade key (`0x0A01_1000` since the 2026-07-02 half-order flip; pre-flip
+/// stored form `0x1000_0A01`) — same constant `bin/fma.rs` uses; the canon
+/// `anatomical_structure` concept `0x0A01` (HIGH half) paired with the V3
+/// generation marker `0x1000` (LOW half).
const CLASSID_FMA: u32 = NodeGuid::CLASSID_FMA_V3;
/// One 8:8 HHTL tier: `[container-mixin : identity]` (mirrors `fma.rs::tier`).
diff --git a/crates/osint-bake/src/bin/fma.rs b/crates/osint-bake/src/bin/fma.rs
index 9485cac89..ddf96e8c9 100644
--- a/crates/osint-bake/src/bin/fma.rs
+++ b/crates/osint-bake/src/bin/fma.rs
@@ -58,16 +58,18 @@ use std::path::{Path, PathBuf};
/// The CEILING global-category pole (HEEL=HIP=0xFFFF; sentinel through TWIG = leaf-grain).
const CEILING: u16 = 0xFFFF;
-/// FMA classid — the **V3 cascade-key** `CLASSID_FMA_V3` (`0x1000_0A01`): the V3
-/// generation marker `0x1000` in the HIGH (custom) u16, the canon `anatomical_structure`
-/// concept `0x0A01` preserved in the LOW u16 (so `classid_concept_domain` still routes
-/// OGAR's `ConceptDomain::Anatomy`, high byte `0x0A`). V3 is a *reading* of the SAME
+/// FMA classid — the **V3 cascade-key** `CLASSID_FMA_V3` (`0x0A01_1000` since the
+/// 2026-07-02 half-order flip): the canon `anatomical_structure` concept `0x0A01`
+/// in the HIGH (canon) u16, the V3 generation marker `0x1000` preserved in the LOW
+/// (custom) u16 (so `classid_concept_domain` still routes OGAR's
+/// `ConceptDomain::Anatomy`, high byte `0x0A`). V3 is a *reading* of the SAME
/// leaf·family·identity tail v2 mints — the `(part_of:is_a)` cascade reinterprets the
/// 8:8 tiers, never re-carves — so the node still mints through `new_v2` (via
/// `mint_for`'s V3 arm), resolving to `ReadMode::FMA_V3`. Migrated from the legacy V2
/// `0x0000_0A01`; the heart slice is soft-tissue anatomy (universal-root concept;
/// OGAR reserves `0x0A02..0x0A04` for skeleton/bone/joint). See OGAR PR #116
/// (`docs/FMA-SKELETON-CONVERGENCE-ANCHOR.md`) and the V3 set in `canonical_node.rs`.
+/// Pre-flip stored form: `0x1000_0A01` (`CLASSID_FMA_V3_LEGACY`).
const CLASSID_FMA: u32 = NodeGuid::CLASSID_FMA_V3;
// class bytes → cockpit colour/label (see FmaGraph.tsx).
diff --git a/crates/osint-bake/src/lib.rs b/crates/osint-bake/src/lib.rs
index c9a3607f1..a5f9190ea 100644
--- a/crates/osint-bake/src/lib.rs
+++ b/crates/osint-bake/src/lib.rs
@@ -51,8 +51,10 @@ pub mod morton;
/// inside the one class (not sprinkled across classids). The function defined at
/// order *i* carries label *i*; an instance inherits its label by the order it
/// carries in its value tenant. This is the consumer-side home of the schema for
-/// the single OSINT class `0x0700`; the AR-native home is `ogar-vocab`'s `0x0700`
-/// `ObjectView` (an upstream OGAR change, out of this repo's push scope).
+/// the single OSINT class `0x0700` (the canon id — the HIGH half of the composed
+/// `u32` classid since the 2026-07-02 half-order flip); the AR-native home is
+/// `ogar-vocab`'s `0x0700` `ObjectView` (an upstream OGAR change, out of this
+/// repo's push scope).
/// The complete label↔order row: every label an item can carry has a slot, so
/// no item falls through to "Other" (an item with a label but no order would be
/// missing its label↔identity pairing). Orders 0-4 are the entity types; 5-6 are
@@ -604,7 +606,7 @@ pub fn osint_node_rows(graph: &AiWarGraph, plan: &BasinPlan) -> Vec {
NodeRow {
key: NodeGuid::new_v2(
- NodeGuid::CLASSID_OSINT, // classid 0x0700 — the ONE OSINT class
+ NodeGuid::CLASSID_OSINT, // classid 0x0700_0000 — canon 0x0700 (HIGH half) — the ONE OSINT class
heel, // HEEL — theme, or 0xFFFF ceiling for a dimension
hip, // HIP — anchor, or 0xFFFF ceiling for a dimension
twig, // TWIG — axis grain for a ceiling-pole dimension
@@ -898,9 +900,14 @@ mod tests {
let rows = osint_node_rows(&g, &plan);
assert_eq!(rows.len(), g.node_count(), "one OSINT row per entity");
for (i, row) in rows.iter().enumerate() {
- // classid 0x0700 (the OSINT domain byte is 0x07)
+ // classid 0x0700_0000 (canon 0x0700 sits in the HIGH half since
+ // the 2026-07-02 flip; route through the contract helper rather
+ // than deriving the domain byte via a raw shift).
assert_eq!(row.key.classid(), NodeGuid::CLASSID_OSINT);
- assert_eq!(row.key.classid() >> 8, 0x07);
+ assert_eq!(
+ lance_graph_contract::ogar_codebook::classid_canon(row.key.classid()) >> 8,
+ 0x07
+ );
// GUID-v2 tail: identity == index, family == basin byte (high byte 0)
assert_eq!(row.key.identity_v2(), i as u16);
assert_eq!(row.key.family_v2() >> 8, 0, "basin is an 8-bit byte");
diff --git a/crates/osint-bake/tools/body-soa-wire/src/main.rs b/crates/osint-bake/tools/body-soa-wire/src/main.rs
index 2ebc81956..db06a8c5e 100644
--- a/crates/osint-bake/tools/body-soa-wire/src/main.rs
+++ b/crates/osint-bake/tools/body-soa-wire/src/main.rs
@@ -24,7 +24,7 @@ use lance_graph_contract::canonical_node::{classid_read_mode, NodeGuid};
use ndarray::hpc::quantized::F16;
use ndarray::hpc::splat3d::helix_orient;
-const CLASSID_FMA: u32 = NodeGuid::CLASSID_FMA_V3; // 0x1000_0A01
+const CLASSID_FMA: u32 = NodeGuid::CLASSID_FMA_V3; // 0x0A01_1000 (canon HIGH, V3 marker LOW — 2026-07-02 flip; pre-flip 0x1000_0A01)
fn tile(part_of: u8, is_a: u8) -> u16 { ((part_of as u16) << 8) | is_a as u16 }
diff --git a/fma/README.md b/fma/README.md
index 376b24758..f7bc7403b 100644
--- a/fma/README.md
+++ b/fma/README.md
@@ -21,6 +21,11 @@ BodyParts3D meshes ──tissue (is_a tree)──► triangle rasterizer (z-buff
(prefix-routable cascade + golden-stride identity mint)
```
+> Order flipped 2026-07-02 — canon HIGH / custom LOW. The worked GUID examples
+> below use the post-flip classid form (`0x0A01_0000` soft tissue,
+> `0x0A02_0000` skeleton, printed as `0a010000…` / `0a020000…`), matching the
+> `lance-graph-contract` half-order flip even though this crate is dep-free.
+
- **Geometry** is the real mesh triangles (not gaussian splats): per-triangle
z-buffered fill with smooth per-vertex (Gouraud) normals, two-sided shading,
FMA-tissue color (bone ivory, muscle red, vessel red, nerve yellow, …).
@@ -40,7 +45,7 @@ BodyParts3D meshes ──tissue (is_a tree)──► triangle rasterizer (z-buff
| `serve` | dep-free std HTTP server, all routes under `/FMA` (binds `0.0.0.0:$PORT`) |
| `guid` | mint the part_of GUID per FMA node → `guid/guid_manifest.tsv`, `guid/fj_guid.tsv` |
| `converge` | **v3**: cascading-HHTL `(place:tissue)` **canonical NodeGuid** + `connected_to` edges → `guid/{guid_converged,nodes,edges}.tsv` |
-| `graph` | **v3 render**: SOLID triangle surface colored by `tissue`, with a GUID **prefix** that selects the subtree (`graph … 00000a02` = skeleton) → `graph/graph_.png` |
+| `graph` | **v3 render**: SOLID triangle surface colored by `tissue`, with a GUID **prefix** that selects the subtree (`graph … 0a020000` = skeleton) → `graph/graph_.png` |
| `cockpit_bake` | bake the full body → `cockpit/public/fma_body.mesh` (SPM1, opacity = layer id) for the **`/fma-body`** cockpit page (layer toggles + transparency) |
| `soa_scan` | 1M-row SoA scalability PoC: key-only **prefix-route** scan vs full **value-decode** scan (~90× at 1M — the canon's *"prerender with zero value decode"*) |
| `anchor` | compression study: cascade vs raw-cartesian vs Cartesian-Skeleton hybrid |
@@ -95,15 +100,15 @@ Three things make `place` and the render converge (`classid`-dispatched, OGAR `H
```text
Located skeleton (thoracic vertebrae T9/T10/T11, classid 0x0A02, mode Located):
- FMA10014 00000a02-ce01-fe02-7b02-… ↔ T10,T11,T12,… shared Morton HEEL ce = same spatial octant
- FMA10059 00000a02-ce01-d602-eb02-… ↔ T9,T10,T12,… HIP/TWIG descend as the centroid descends (z 1164→1107)
+ FMA10014 0a020000-ce01-fe02-7b02-… ↔ T10,T11,T12,… shared Morton HEEL ce = same spatial octant
+ FMA10059 0a020000-ce01-d602-eb02-… ↔ T9,T10,T12,… HIP/TWIG descend as the centroid descends (z 1164→1107)
Cascade soft tissue (aortic segments, 0x0A01, mode Cascade):
- FMA3736 ascending 00000a01-0901-0702-0e02-… ↔ arch, descending part_of siblings = the connected segments
+ FMA3736 ascending 0a010000-0901-0702-0e02-… ↔ arch, descending part_of siblings = the connected segments
```

-*`graph … 00000a02` — the canonical key SELECTS the geometry: the `0x0A02` (skeleton)
+*`graph … 0a020000` — the canonical key SELECTS the geometry: the `0x0A02` (skeleton)
classid prefix renders just the bones as solid triangles (922K), colored by the `tissue`
byte (is_a). The address is the render; the prefix is the query. `graph all` / `tissues`
/ `vessel` render the whole body / inner tissues / vascular tree.*
diff --git a/fma/docs/OGAR_CONSUMER_INTEGRATION.md b/fma/docs/OGAR_CONSUMER_INTEGRATION.md
index d536f6601..3c9b3876d 100644
--- a/fma/docs/OGAR_CONSUMER_INTEGRATION.md
+++ b/fma/docs/OGAR_CONSUMER_INTEGRATION.md
@@ -171,7 +171,10 @@ reimplements the canonical 16-byte layout byte-for-byte:
- It realizes the **two ontological axes in one key**: each 8:8 HHTL tier is
`(place : tissue)` — high byte = PLACE (Morton spatial cell for skeletal nodes
classid `0x0A02`, or `part_of` sibling-rank for soft tissue `0x0A01`); low byte
- = TISSUE (`is_a` taxonomy sibling-rank). The high-byte chain prefix-routes the
+ = TISSUE (`is_a` taxonomy sibling-rank). (Order flipped 2026-07-02 — canon HIGH
+ / custom LOW: `converge.rs` stores these as `0x0A02_0000` / `0x0A01_0000` in the
+ composed `u32` classid; see `V3_SOA_WIRING.md` §2.1 for the worked GUIDs.) The
+ high-byte chain prefix-routes the
body, the low-byte chain prefix-routes the type taxonomy — **both hierarchies,
one key**. `family` (u24) is the `(part_of:is_a)` level-3 ontological basin.
`connected_to` lands in the EdgeBlock shape: `part_of` siblings = in-family
diff --git a/fma/docs/V3_SOA_WIRING.md b/fma/docs/V3_SOA_WIRING.md
index 7a885f26a..1a0f167f8 100644
--- a/fma/docs/V3_SOA_WIRING.md
+++ b/fma/docs/V3_SOA_WIRING.md
@@ -125,9 +125,14 @@ as u32) << 8) | ia_rank3` — `(part_of:is_a)` one level deeper.
`converge.rs` classifies each FMA node into `ConceptDomain::Anatomy` (`0x0A`):
-- `classid 0x0000_0A02` — **skeleton** (bone / cartilage / vertebra / rib / femur /
+> Order flipped 2026-07-02 — canon HIGH / custom LOW (matches the
+> `lance-graph-contract` classid half-order flip; `converge.rs` is dep-free and
+> mints this order directly). The pre-flip stored form was `0x0000_0A01` /
+> `0x0000_0A02`; every worked example below uses the post-flip form.
+
+- `classid 0x0A02_0000` — **skeleton** (bone / cartilage / vertebra / rib / femur /
skull, via `is_skeletal()`).
-- `classid 0x0000_0A01` — **soft tissue** (everything else).
+- `classid 0x0A01_0000` — **soft tissue** (everything else).
The `place` bytes are then dispatched on classid:
@@ -158,8 +163,8 @@ Located skeleton — **thoracic vertebrae T9/T10/T11**, `classid 0x0A02`, mode
Located:
```text
- FMA10014 00000a02-ce01-fe02-7b02-… ↔ T10,T11,T12,… shared Morton HEEL ce = same spatial octant
- FMA10059 00000a02-ce01-d602-eb02-… ↔ T9,T10,T12,… HIP/TWIG descend as the centroid descends (z 1164→1107)
+ FMA10014 0a020000-ce01-fe02-7b02-… ↔ T10,T11,T12,… shared Morton HEEL ce = same spatial octant
+ FMA10059 0a020000-ce01-d602-eb02-… ↔ T9,T10,T12,… HIP/TWIG descend as the centroid descends (z 1164→1107)
```
Both vertebrae share `classid 0x0A02` and the **same HEEL high byte `ce`** — they
@@ -170,7 +175,7 @@ spatial group. HIP and TWIG diverge as the centroid descends. The low bytes (`01
Cascade soft tissue — **aortic segments**, `classid 0x0A01`, mode Cascade:
```text
- FMA3736 ascending aorta 00000a01-0901-0702-0e02-… ↔ arch, descending part_of siblings = the connected segments
+ FMA3736 ascending aorta 0a010000-0901-0702-0e02-… ↔ arch, descending part_of siblings = the connected segments
```
The ascending aorta, the arch, and the descending aorta are `part_of` siblings of
@@ -178,8 +183,8 @@ the same aorta; they share the leading `part_of` high-byte groups (`09`, `07`, `
…) and are connected to each other (§3). The `connected_to` column lists exactly the
sibling segments that physically continue the vessel.
-The upshot, made visible in `graph.rs`: a single key prefix `00000a01-0901-0702`
-selects "one `part_of`/`is_a` subtree" of triangles; `00000a02` selects the whole
+The upshot, made visible in `graph.rs`: a single key prefix `0a010000-0901-0702`
+selects "one `part_of`/`is_a` subtree" of triangles; `0a020000` selects the whole
skeleton. **The address is the query.**
---
@@ -216,8 +221,8 @@ value column (`Vec<[u8; 480]>`), separate allocations. Two scans over 1 M synthe
rows (seeded by the FMA distribution: ~25 % skeleton classid, the rest soft tissue):
- **key-only (prefix-route / render-select):** read only the key column; decode
- `classid` from bytes `[0..4)`; count the skeleton subtree (`== 0x0000_0A02`). This
- is exactly the work the `/fma-body` skeleton button and `graph 00000a02` do.
+ `classid` from bytes `[0..4)`; count the skeleton subtree (`== 0x0A02_0000`). This
+ is exactly the work the `/fma-body` skeleton button and `graph 0a020000` do.
- **value (decode the slab):** read the whole value column; sum all 480 bytes per
row — the work a value/tenant materialization does.
@@ -251,7 +256,7 @@ Why this falls out of the layout, not a trick:
`graph.rs` is the same routing at render time, not at scan time: it reads the
converged manifest, and a `sel` that is all-hex-or-dash is treated as a GUID prefix —
`guid.starts_with(&sel)` selects which meshes' triangles to rasterize. `graph …
-00000a02` renders ~922 K skeleton triangles; `graph all` / `tissues` / `vessel`
+0a020000` renders ~922 K skeleton triangles; `graph all` / `tissues` / `vessel`
render the whole body / inner tissues / vascular tree. The address selects the
geometry; the prefix is the query — and it never decodes a value slab to decide.
@@ -353,7 +358,7 @@ holds for mechanical/data-shaped leaf methods and remains CONJECTURE until
| value tenants / schemas / `classid → ReadMode` | same — `ValueTenant`, `ValueSchema`, `classid_read_mode` |
| `(place:tissue)` 8:8 tier, Located/Cascade, mint | `q2/fma/src/bin/converge.rs` |
| `connected_to` EdgeBlock from `part_of` siblings | `q2/fma/src/bin/converge.rs` (`siblings`, edge emit) |
-| prefix-routed render (`graph 00000a02`) | `q2/fma/src/bin/graph.rs` |
+| prefix-routed render (`graph 0a020000`) | `q2/fma/src/bin/graph.rs` |
| key-only vs value scan, 89–130×, flat | `q2/fma/src/bin/soa_scan.rs` |
| three coexisting v1/v2/v3 addressings | `q2/fma/README.md` |
| GUID-is-key, key-prerenders, classid adapters | `OGAR/CLAUDE.md`, `core-first-transcode-doctrine` |
diff --git a/fma/src/bin/converge.rs b/fma/src/bin/converge.rs
index 1a5e9183f..994fc9826 100644
--- a/fma/src/bin/converge.rs
+++ b/fma/src/bin/converge.rs
@@ -25,6 +25,11 @@
// `lance_graph_contract::canonical_node::NodeGuid::new(classid, heel, hip, twig,
// family, identity)` (OGAR canon, 2026-06-13). classid in ConceptDomain::Anatomy
// (0x0A): 0x0A01 soft tissue, 0x0A02 skeleton — same space as the other session's bake.
+// (Order flipped 2026-07-02 — canon HIGH / custom LOW: this crate stores the
+// canon 0x0A01/0x0A02 value directly in the classid `u32`'s high half, i.e.
+// `0x0A01_0000` / `0x0A02_0000`, matching `lance-graph-contract`'s
+// `CLASSID_ORDER = CanonHigh`. This crate is dep-free and mints the value
+// itself — it does not call the contract's `compose_classid`.)
//
// usage: converge [inclusion.txt] [isa_inclusion.txt] [out_dir] [parts_dir] [element_parts]
// (parts_dir optional — present ⇒ Located skeleton + spatial edges + render-ready
@@ -467,9 +472,9 @@ fn main() {
let names = po.dn(fma) + " " + &ia.dn(fma);
let skeletal_node = is_skeletal(&names);
let classid = if skeletal_node {
- 0x0000_0A02
+ 0x0A02_0000
} else {
- 0x0000_0A01
+ 0x0A01_0000
};
if skeletal_node {
skeletal += 1;
diff --git a/fma/src/bin/graph.rs b/fma/src/bin/graph.rs
index 5186c5da6..554281ded 100644
--- a/fma/src/bin/graph.rs
+++ b/fma/src/bin/graph.rs
@@ -5,9 +5,11 @@
// * COLOR — each mesh is colored by its FMA's `tissue` byte (the is_a low byte of
// the converged GUID), read straight from `converge`'s manifest.
// * SELECT — an optional GUID **prefix** picks which triangles to draw: pass
-// `00000a01-0901-0702` and only the parts whose canonical key starts with
+// `0a010000-0901-0702` and only the parts whose canonical key starts with
// it render (one part_of/is_a subtree). Prefix-routing the key, made
// visible — the address selects the geometry. `all` draws the whole body.
+// (Prefix example uses the post-2026-07-02-flip classid form — canon
+// 0x0A01 in the HIGH half; `converge.rs` mints this order.)
//
// This is "70k nodes connecting via relationships → 16M triangles": the relationships
// (part_of/is_a) ARE the address, and the address drives which triangles light up.
@@ -258,7 +260,7 @@ fn main() {
tris.len()
);
if tris.is_empty() {
- eprintln!("[graph] nothing matched '{sel}' — try `all`, a tissue (bone/vessel/...), or a guid prefix like 00000a01-0901");
+ eprintln!("[graph] nothing matched '{sel}' — try `all`, a tissue (bone/vessel/...), or a guid prefix like 0a010000-0901");
return;
}
diff --git a/fma/src/bin/soa_scan.rs b/fma/src/bin/soa_scan.rs
index 0731797fd..63ec1b58f 100644
--- a/fma/src/bin/soa_scan.rs
+++ b/fma/src/bin/soa_scan.rs
@@ -3,9 +3,11 @@
// Proves the OGAR canon's "the key prerenders nodes with ZERO value decode": when the
// canonical NodeRow (512 B = key 16 + edges 16 + value 480) is laid out COLUMNAR
// (struct-of-arrays) — a contiguous key column + a contiguous value column — a key-only
-// scan (prefix-route / render-select, e.g. "draw the skeleton subtree" = classid 0x0A02)
+// scan (prefix-route / render-select, e.g. "draw the skeleton subtree" = classid 0x0A02
+// — canon 0x0A02 in the HIGH half of the composed u32, `0x0A02_0000`, since the
+// 2026-07-02 half-order flip)
// touches ~30x less memory than materializing the value slab, and stays flat as N grows.
-// This is the same prefix routing the /fma-body skeleton button and `graph 00000a02` do,
+// This is the same prefix routing the /fma-body skeleton button and `graph 0a020000` do,
// measured at scale.
//
// 1M is SYNTHETIC — real FMA is ~1368 placed meshes / ~75K terms; the scan throughput is
@@ -17,8 +19,11 @@
use std::hint::black_box;
use std::time::Instant;
-const CLASSID_SOFT: u32 = 0x0000_0A01;
-const CLASSID_SKELETON: u32 = 0x0000_0A02;
+// Order flipped 2026-07-02 — canon HIGH / custom LOW (matches the
+// lance-graph-contract classid half-order flip; this crate is dep-free and
+// mints its own local scheme, kept consistent with the canonical order).
+const CLASSID_SOFT: u32 = 0x0A01_0000;
+const CLASSID_SKELETON: u32 = 0x0A02_0000;
/// Columnar SoA: the 16-byte GUID key column and the 480-byte value-slab column, kept
/// in separate contiguous allocations (the "SoA > tenant view" split).