Skip to content

Commit a860351

Browse files
committed
osint/fma: 8:8 [container:identity] HHTL tiers — the address IS the partonomy
Replace the synthetic Morton-in-identity scheme (which crammed a whole multi-level tile path into one u16 and nibble-walked it back — bad addressing) with the deterministic tier model: each HHTL tier is one 8:8 [container:identity] pair = [mixin-node : instance-on-it], 256×256 = 64k per tier. The high byte names the KIND mixin node (Organ/Chamber/Wall/ Tissue/Cell — the family things attach on), the low byte the instance. HEEL [Organ:Heart] HIP [Chamber:id] TWIG [Wall:id] LEAF [Tissue:id] family [Cell:id] The non-zero tiers ARE the partonomy path, so the address says where a node sits — no Morton decode, no edge lookup. This is the q2 Cascade reading of OGAR PR quarto-dev#116's [container:member] tier model (OGAR's skeleton is the Located/spatial sibling). Mirrors OGAR's [bodypart:bone] LeafTile and supersedes the 12+4 EdgeBlock with family-node grouping (the container byte = the mixin/family node). classid stays 0x0A01 = anatomical_structure in OGAR's ConceptDomain::Anatomy. decodeSoa now exposes the five tiers (heel/hip/twig/leaf/family); FmaGraph lays out straight from them (tierPos: y = depth, x = nested slot under the parent's instance) instead of the Morton treemap — so the HHTL block is finally load-bearing, not write-only ornamentation. Verified: the cockpit's read offsets match the Rust-written GUID byte for byte across organ→chamber→wall→tissue→cell; ceiling sentinel intact; cockpit tsc clean. Browser render not exercised (no browser here). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TzqvDqbFRzyx17EkLKBoZF
1 parent 7455c4e commit a860351

4 files changed

Lines changed: 159 additions & 133 deletions

File tree

cockpit/public/fma.soa

0 Bytes
Binary file not shown.

cockpit/src/FmaGraph.tsx

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@
44
// · its part-of position (basin-local: organ → chamber → wall → structure)
55
// · its leaf-limited global TYPE (the 0xFFFF ceiling pole — cross-cutting,
66
// the same "Cardiac muscle tissue" shared by every chamber).
7+
//
8+
// This is the `Cascade` (ontology / part-of) reading of OGAR PR #116's HhtlMode
9+
// FMA tier model: each node is a stack of 8:8 [container:identity] tiers —
10+
// HEEL=[Organ:Heart], HIP=[Chamber:id], TWIG=[Wall:id], LEAF=[Tissue:id] — where
11+
// the container byte is the KIND mixin node and the identity the instance, so the
12+
// partonomy IS the key and the layout reads straight off it. OGAR's
13+
// ogar-fma-skeleton is the `Located` (spatial) sibling (the same 8:8 tiers carry
14+
// coronal x:y / depth z Morton cells). classid 0x0A01 = anatomical_structure in
15+
// OGAR's ConceptDomain::Anatomy (0x0A).
716
import { useEffect, useMemo, useRef, useState } from 'react';
817
import { Network, type Options } from 'vis-network';
918
import { DataSet } from 'vis-data';
@@ -27,39 +36,42 @@ const classColor = (c: number) => FMA_CLASS[c]?.color ?? '#8899aa';
2736
const REL = ['member-of', 'interfaces', 'part-of', 'is-a'];
2837
const REL_COLOR = ['#223040', '#223040', '#7fa6c4', CEILING_COLOR];
2938

30-
// ── Z-order (Morton) tile layout ─────────────────────────────────────────────
31-
// The bake stores each part-of node's Morton tile path in the GUID identity (one
32-
// 4×4 level per part-of step, coarsest in the high nibble). Depth == class
33-
// (Organ 0 → Cell 4), so position is fully recoverable from identity + class:
34-
// walk the nibbles, decode each 4×4 cell, accumulate base-2, and the node lands
35-
// at the centre of its nested tile — the address literally *is* the coordinate.
36-
const MAX_DEPTH = 4; // cells are the deepest tier → a 2^4 = 16×16 finest grid
37-
const CELL = 90; // px per finest grid cell
38-
const POLE_Y = -2.4 * CELL; // the ceiling pole hovers above the body
39+
// ── 8:8 [container:identity] HHTL-tier layout ────────────────────────────────
40+
// The bake addresses each node as a stack of 8:8 tiers (see src/bin/fma.rs):
41+
// HEEL=[Organ:Heart] HIP=[Chamber:id] TWIG=[Wall:id] LEAF=[Tissue:id]
42+
// family=[Cell:id]. The container (high byte) is the KIND mixin node, the
43+
// identity (low byte) is the instance. The non-zero tier identities ARE the
44+
// partonomy path — so position is read straight off the tiers, no Morton decode:
45+
// y = depth (class), x = a nested slot that subdivides under each parent.
46+
const COL = 1500; // total layout width in vis units
47+
const ROW = 210; // vertical gap per depth level
48+
const POLE_Y = -1.7 * ROW; // the cross-cutting global types hover above the body
3949

40-
// inverse bit-interleave (gather even bits to the low half) — TS port of
41-
// `compact1by1` in osint-bake/src/morton.rs; decodes ONE 4×4 Morton cell.
42-
function compact1by1(n: number): number {
43-
n &= 0x55555555;
44-
n = (n | (n >> 1)) & 0x33333333;
45-
n = (n | (n >> 2)) & 0x0f0f0f0f;
46-
n = (n | (n >> 4)) & 0x00ff00ff;
47-
n = (n | (n >> 8)) & 0x0000ffff;
48-
return n >>> 0;
49-
}
50+
/// the instance (low) byte of an 8:8 tier.
51+
const inst = (t: number) => t & 0xff;
5052

51-
// Reconstruct a node's tile centre by walking its Morton path nibble-by-nibble
52-
// (NOT a flat decode — a multi-level code spreads the axis bits across nibbles).
53-
function tilePos(code: number, depth: number): { x: number; y: number; span: number } {
54-
let gx = 0;
55-
let gy = 0;
56-
for (let k = 0; k < depth; k++) {
57-
const nib = (code >> (4 * (depth - 1 - k))) & 0xf; // coarsest level first
58-
gx = gx * 2 + compact1by1(nib); // each FMA level is a 2×2 branch (quad 0..1)
59-
gy = gy * 2 + compact1by1(nib >> 1);
53+
// Nested horizontal slot from the [Chamber][Wall][Tissue][Cell] instance path:
54+
// each level subdivides its parent's slot (max-siblings per level: 4/3/2/2), so
55+
// children cluster under their parent. y is the depth band (class).
56+
function tierPos(
57+
soa: Soa,
58+
i: number,
59+
): { x: number; y: number } {
60+
const path: Array<[number, number]> = [
61+
[inst(soa.hip[i]), 4], // chamber 1..4
62+
[inst(soa.twig[i]), 3], // wall 1..3
63+
[inst(soa.leaf[i]), 2], // tissue 1..2
64+
[inst(soa.family[i]), 2], // cell 1..2
65+
];
66+
let lo = 0;
67+
let hi = 1;
68+
for (const [id, n] of path) {
69+
if (id <= 0) break;
70+
const w = (hi - lo) / n;
71+
lo += (id - 1) * w;
72+
hi = lo + w;
6073
}
61-
const span = 1 << (MAX_DEPTH - depth); // tile edge, in finest cells
62-
return { x: (gx * span + span / 2) * CELL, y: (gy * span + span / 2) * CELL, span };
74+
return { x: ((lo + hi) / 2) * COL, y: soa.cls[i] * ROW };
6375
}
6476

6577
const OPTIONS: Options = {
@@ -71,7 +83,7 @@ const OPTIONS: Options = {
7183
smooth: { enabled: true, type: 'continuous', roundness: 0.2 },
7284
arrows: { to: { enabled: true, scaleFactor: 0.45 } },
7385
},
74-
// positions are fixed Z-order tiles (see tilePos) — no force simulation.
86+
// positions are fixed 8:8-tier slots (see tierPos) — no force simulation.
7587
physics: { enabled: false },
7688
interaction: { hover: true, tooltipDelay: 90, dragNodes: true },
7789
layout: { improvedLayout: false },
@@ -126,21 +138,19 @@ export function FmaGraph() {
126138
if (!hostRef.current || !soa || !rel) return;
127139
const ceiling = (i: number) => soa.ceiling[i] === 1 || soa.cls[i] === 5;
128140

129-
// Fixed Z-order position per node: part-of nodes deinterleave their Morton
130-
// tile path (depth == class) into a nested tile centre; the cross-cutting
131-
// global types line up along the pole above the body. The grid width spans
132-
// 2^MAX_DEPTH finest cells, so the pole row is centred over that span.
141+
// Fixed position per node, read straight off the 8:8 [container:identity]
142+
// HHTL tiers: part-of nodes nest by their [Chamber][Wall][Tissue][Cell]
143+
// instance path (y = depth = class); the cross-cutting global types line up
144+
// along the pole above the body, spread across the same width.
133145
const poleNodes = Array.from({ length: soa.nodeCount }, (_, i) => i).filter(ceiling);
134-
const gridSpan = (1 << MAX_DEPTH) * CELL;
135146
const posOf = (i: number): { x: number; y: number; size: number } => {
136147
if (ceiling(i)) {
137148
const k = poleNodes.indexOf(i);
138-
const x = ((k + 0.5) / Math.max(poleNodes.length, 1)) * gridSpan;
149+
const x = ((k + 0.5) / Math.max(poleNodes.length, 1)) * COL;
139150
return { x, y: POLE_Y, size: 22 };
140151
}
141-
const depth = soa.cls[i]; // Organ 0 → Cell 4
142-
const { x, y } = tilePos(soa.identity[i], depth);
143-
return { x, y, size: 30 - depth * 4 }; // coarser tier → larger dot
152+
const { x, y } = tierPos(soa, i);
153+
return { x, y, size: 30 - soa.cls[i] * 4 }; // coarser tier → larger dot
144154
};
145155

146156
const baseNode = (i: number) => {
@@ -173,7 +183,7 @@ export function FmaGraph() {
173183
const visNodes = new DataSet<any>(Array.from({ length: soa.nodeCount }, (_, i) => baseNode(i)));
174184
const visEdges = new DataSet<any>(soa.edges.map((e, id) => baseEdge(e, id)));
175185
const net = new Network(hostRef.current, { nodes: visNodes, edges: visEdges }, OPTIONS);
176-
// fixed Z-order tiles, no simulation — just frame the nested pyramid.
186+
// fixed 8:8-tier slots, no simulation — just frame the nested cascade.
177187
net.once('afterDrawing', () => net.fit({ animation: false }));
178188
setStatus(`${soa.nodeCount} nodes · ${soa.edgeCount} edges — Z-order tile pyramid; click a tissue for its dual membership`);
179189

cockpit/src/OsintGraph.tsx

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,16 @@ export interface Soa {
8989
tenants: Uint8Array | null;
9090
// per-node global-category flag (HEEL=HIP=0xFFFF ceiling pole): 1 = cross-cutting.
9191
ceiling: Uint8Array;
92-
// per-node GUID identity field (bytes 14-15 LE). For basin-local nodes this is
93-
// the plain identity; the FMA bake stores the node's Z-order (Morton) tile path
94-
// here, so FmaGraph deinterleaves it into a fixed tile-pyramid position.
92+
// per-node GUID identity field (bytes 14-15 LE) — the stable node id.
9593
identity: Uint16Array;
94+
// the four 8:8 [container:identity] HHTL tiers + the family tier (each a u16:
95+
// high byte = mixin/kind node, low byte = instance-on-it). The FMA cockpit lays
96+
// out straight from these; OSINT ignores them.
97+
heel: Uint16Array;
98+
hip: Uint16Array;
99+
twig: Uint16Array;
100+
leaf: Uint16Array;
101+
family: Uint16Array;
96102
}
97103

98104
/** One readable step of the reasoning traversal, streamed into the readout. */
@@ -133,12 +139,22 @@ export function decodeSoa(buf: ArrayBuffer): Soa {
133139
// the node is a cross-cutting GLOBAL category (the dual-use axes), not
134140
// basin-local. Read straight off the 16-byte GUID (HEEL @4, HIP @6).
135141
const ceiling = new Uint8Array(nodeCount);
136-
// identity[i] = GUID bytes 14-15 (LE) — the basin-local identity, or the
137-
// node's Morton tile-path when the bake stores a Z-order address there.
138142
const identity = new Uint16Array(nodeCount);
143+
// the 8:8 [container:identity] HHTL tiers (high byte = mixin node, low byte =
144+
// instance). HEEL/HIP also carry the 0xFFFF/0xFFFF ceiling-pole sentinel.
145+
const heelA = new Uint16Array(nodeCount);
146+
const hipA = new Uint16Array(nodeCount);
147+
const twigA = new Uint16Array(nodeCount);
148+
const leafA = new Uint16Array(nodeCount);
149+
const familyA = new Uint16Array(nodeCount);
139150
for (let i = 0; i < nodeCount; i++) {
140151
const heel = dv.getUint16(off + 4, true);
141152
const hip = dv.getUint16(off + 6, true);
153+
heelA[i] = heel;
154+
hipA[i] = hip;
155+
twigA[i] = dv.getUint16(off + 8, true);
156+
leafA[i] = dv.getUint16(off + 10, true);
157+
familyA[i] = dv.getUint16(off + 12, true);
142158
if (heel === 0xffff && hip === 0xffff) ceiling[i] = 1;
143159
identity[i] = dv.getUint16(off + 14, true);
144160
cls[i] = dv.getUint8(off + 16);
@@ -170,7 +186,10 @@ export function decodeSoa(buf: ArrayBuffer): Soa {
170186
tenants = new Uint8Array(buf, off, nodeCount * 6);
171187
off += nodeCount * 6;
172188
}
173-
return { nodeCount, edgeCount, cls, edges, labels, tenants, ceiling, identity };
189+
return {
190+
nodeCount, edgeCount, cls, edges, labels, tenants, ceiling, identity,
191+
heel: heelA, hip: hipA, twig: twigA, leaf: leafA, family: familyA,
192+
};
174193
}
175194

176195
// vis-network options tuned to the Palantir look: hollow ring nodes (dark fill

0 commit comments

Comments
 (0)