Skip to content

Commit f770e8e

Browse files
authored
Merge pull request #48 from AdaWorldAPI/claude/osint-soa-rebake
osint/fma: heart anatomy `/fma` cockpit view — 8:8 [container:identity] HHTL tiers
2 parents 61772c7 + a860351 commit f770e8e

4 files changed

Lines changed: 199 additions & 76 deletions

File tree

cockpit/public/fma.soa

0 Bytes
Binary file not shown.

cockpit/src/FmaGraph.tsx

Lines changed: 86 additions & 21 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,6 +36,44 @@ 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

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
49+
50+
/// the instance (low) byte of an 8:8 tier.
51+
const inst = (t: number) => t & 0xff;
52+
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;
73+
}
74+
return { x: ((lo + hi) / 2) * COL, y: soa.cls[i] * ROW };
75+
}
76+
3077
const OPTIONS: Options = {
3178
nodes: { shape: 'dot', borderWidth: 2.5, font: { color: '#d9e9f9', size: 13, strokeWidth: 3, strokeColor: PAGE_BG } },
3279
edges: {
@@ -36,11 +83,8 @@ const OPTIONS: Options = {
3683
smooth: { enabled: true, type: 'continuous', roundness: 0.2 },
3784
arrows: { to: { enabled: true, scaleFactor: 0.45 } },
3885
},
39-
physics: {
40-
solver: 'forceAtlas2Based',
41-
forceAtlas2Based: { gravitationalConstant: -70, centralGravity: 0.008, springLength: 130, springConstant: 0.04, damping: 0.5, avoidOverlap: 0.5 },
42-
stabilization: { iterations: 180, fit: true },
43-
},
86+
// positions are fixed 8:8-tier slots (see tierPos) — no force simulation.
87+
physics: { enabled: false },
4488
interaction: { hover: true, tooltipDelay: 90, dragNodes: true },
4589
layout: { improvedLayout: false },
4690
};
@@ -93,18 +137,40 @@ export function FmaGraph() {
93137
useEffect(() => {
94138
if (!hostRef.current || !soa || !rel) return;
95139
const ceiling = (i: number) => soa.ceiling[i] === 1 || soa.cls[i] === 5;
96-
const baseNode = (i: number) => ({
97-
id: i,
98-
label: soa.labels[i] || `#${i}`,
99-
shape: ceiling(i) ? 'diamond' : 'dot',
100-
color: {
101-
background: ceiling(i) ? 'rgba(255,209,102,0.14)' : 'rgba(10,14,23,0.88)',
102-
border: ceiling(i) ? CEILING_COLOR : classColor(soa.cls[i]),
103-
},
104-
size: ceiling(i) ? 22 : 13,
105-
font: { color: ceiling(i) ? '#ffe9b0' : '#d9e9f9' },
106-
title: `${soa.labels[i]}\n${ceiling(i) ? '◈ global type (leaf-limited, cross-cutting)' : FMA_CLASS[soa.cls[i]]?.name}`,
107-
});
140+
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.
145+
const poleNodes = Array.from({ length: soa.nodeCount }, (_, i) => i).filter(ceiling);
146+
const posOf = (i: number): { x: number; y: number; size: number } => {
147+
if (ceiling(i)) {
148+
const k = poleNodes.indexOf(i);
149+
const x = ((k + 0.5) / Math.max(poleNodes.length, 1)) * COL;
150+
return { x, y: POLE_Y, size: 22 };
151+
}
152+
const { x, y } = tierPos(soa, i);
153+
return { x, y, size: 30 - soa.cls[i] * 4 }; // coarser tier → larger dot
154+
};
155+
156+
const baseNode = (i: number) => {
157+
const p = posOf(i);
158+
return {
159+
id: i,
160+
label: soa.labels[i] || `#${i}`,
161+
x: p.x,
162+
y: p.y,
163+
fixed: { x: true, y: true }, // the address is the layout — pin it
164+
shape: ceiling(i) ? 'diamond' : 'dot',
165+
color: {
166+
background: ceiling(i) ? 'rgba(255,209,102,0.14)' : 'rgba(10,14,23,0.88)',
167+
border: ceiling(i) ? CEILING_COLOR : classColor(soa.cls[i]),
168+
},
169+
size: p.size,
170+
font: { color: ceiling(i) ? '#ffe9b0' : '#d9e9f9' },
171+
title: `${soa.labels[i]}\n${ceiling(i) ? '◈ global type (leaf-limited, cross-cutting)' : FMA_CLASS[soa.cls[i]]?.name}`,
172+
};
173+
};
108174
const baseEdge = (e: { s: number; t: number; r: number }, id: number) => ({
109175
id,
110176
from: e.s,
@@ -117,10 +183,9 @@ export function FmaGraph() {
117183
const visNodes = new DataSet<any>(Array.from({ length: soa.nodeCount }, (_, i) => baseNode(i)));
118184
const visEdges = new DataSet<any>(soa.edges.map((e, id) => baseEdge(e, id)));
119185
const net = new Network(hostRef.current, { nodes: visNodes, edges: visEdges }, OPTIONS);
120-
net.once('stabilizationIterationsDone', () => {
121-
net.setOptions({ physics: { enabled: false } });
122-
setStatus(`${soa.nodeCount} nodes · ${soa.edgeCount} edges — click a tissue to see its dual membership`);
123-
});
186+
// fixed 8:8-tier slots, no simulation — just frame the nested cascade.
187+
net.once('afterDrawing', () => net.fit({ animation: false }));
188+
setStatus(`${soa.nodeCount} nodes · ${soa.edgeCount} edges — Z-order tile pyramid; click a tissue for its dual membership`);
124189

125190
const dim = () => {
126191
visNodes.update(Array.from({ length: soa.nodeCount }, (_, i) => ({ id: i, color: { background: 'rgba(10,14,23,0.5)', border: '#26323f' }, font: { color: '#566779' } })));

cockpit/src/OsintGraph.tsx

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +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) — the stable node id.
93+
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;
92102
}
93103

94104
/** One readable step of the reasoning traversal, streamed into the readout. */
@@ -129,10 +139,24 @@ export function decodeSoa(buf: ArrayBuffer): Soa {
129139
// the node is a cross-cutting GLOBAL category (the dual-use axes), not
130140
// basin-local. Read straight off the 16-byte GUID (HEEL @4, HIP @6).
131141
const ceiling = new Uint8Array(nodeCount);
142+
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);
132150
for (let i = 0; i < nodeCount; i++) {
133151
const heel = dv.getUint16(off + 4, true);
134152
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);
135158
if (heel === 0xffff && hip === 0xffff) ceiling[i] = 1;
159+
identity[i] = dv.getUint16(off + 14, true);
136160
cls[i] = dv.getUint8(off + 16);
137161
off += 17;
138162
}
@@ -162,7 +186,10 @@ export function decodeSoa(buf: ArrayBuffer): Soa {
162186
tenants = new Uint8Array(buf, off, nodeCount * 6);
163187
off += nodeCount * 6;
164188
}
165-
return { nodeCount, edgeCount, cls, edges, labels, tenants, ceiling };
189+
return {
190+
nodeCount, edgeCount, cls, edges, labels, tenants, ceiling, identity,
191+
heel: heelA, hip: hipA, twig: twigA, leaf: leafA, family: familyA,
192+
};
166193
}
167194

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

0 commit comments

Comments
 (0)