Skip to content

Commit 7455c4e

Browse files
committed
osint/fma: Z-order tile-pyramid layout — the address is the position
Re-bake the FMA heart slice so each part-of node carries its Morton (Z-order) tile path in the GUID identity field: one 4×4 level per part-of step (heart → chamber quadrant → wall → tissue → cell), via osint_bake::morton::descend. Depth == class, so the path is fully recoverable from identity + class alone. FmaGraph deinterleaves that path nibble-by-nibble into a fixed nested tile centre (coarser tier → larger dot), pins every node (physics off), and lines the cross-cutting global types up along the pole above the body. /fma now renders as the literal nested tile pyramid the cascade descends, instead of a force-directed blob — position() is decode(). The walk reconstructs (x,y) level by level rather than flat-decoding the multi-level code (a flat decode spreads the per-level axis bits across nibbles and lands out of range). Edges reference the SoA array index, never the identity, so storing the Morton code there is layout-only and cannot perturb topology. decodeSoa now exposes the raw identity field (additive; OSINT ignores it). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TzqvDqbFRzyx17EkLKBoZF
1 parent 61772c7 commit 7455c4e

4 files changed

Lines changed: 129 additions & 32 deletions

File tree

cockpit/public/fma.soa

0 Bytes
Binary file not shown.

cockpit/src/FmaGraph.tsx

Lines changed: 76 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,41 @@ const classColor = (c: number) => FMA_CLASS[c]?.color ?? '#8899aa';
2727
const REL = ['member-of', 'interfaces', 'part-of', 'is-a'];
2828
const REL_COLOR = ['#223040', '#223040', '#7fa6c4', CEILING_COLOR];
2929

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+
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+
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);
60+
}
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 };
63+
}
64+
3065
const OPTIONS: Options = {
3166
nodes: { shape: 'dot', borderWidth: 2.5, font: { color: '#d9e9f9', size: 13, strokeWidth: 3, strokeColor: PAGE_BG } },
3267
edges: {
@@ -36,11 +71,8 @@ const OPTIONS: Options = {
3671
smooth: { enabled: true, type: 'continuous', roundness: 0.2 },
3772
arrows: { to: { enabled: true, scaleFactor: 0.45 } },
3873
},
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-
},
74+
// positions are fixed Z-order tiles (see tilePos) — no force simulation.
75+
physics: { enabled: false },
4476
interaction: { hover: true, tooltipDelay: 90, dragNodes: true },
4577
layout: { improvedLayout: false },
4678
};
@@ -93,18 +125,42 @@ export function FmaGraph() {
93125
useEffect(() => {
94126
if (!hostRef.current || !soa || !rel) return;
95127
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-
});
128+
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.
133+
const poleNodes = Array.from({ length: soa.nodeCount }, (_, i) => i).filter(ceiling);
134+
const gridSpan = (1 << MAX_DEPTH) * CELL;
135+
const posOf = (i: number): { x: number; y: number; size: number } => {
136+
if (ceiling(i)) {
137+
const k = poleNodes.indexOf(i);
138+
const x = ((k + 0.5) / Math.max(poleNodes.length, 1)) * gridSpan;
139+
return { x, y: POLE_Y, size: 22 };
140+
}
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
144+
};
145+
146+
const baseNode = (i: number) => {
147+
const p = posOf(i);
148+
return {
149+
id: i,
150+
label: soa.labels[i] || `#${i}`,
151+
x: p.x,
152+
y: p.y,
153+
fixed: { x: true, y: true }, // the address is the layout — pin it
154+
shape: ceiling(i) ? 'diamond' : 'dot',
155+
color: {
156+
background: ceiling(i) ? 'rgba(255,209,102,0.14)' : 'rgba(10,14,23,0.88)',
157+
border: ceiling(i) ? CEILING_COLOR : classColor(soa.cls[i]),
158+
},
159+
size: p.size,
160+
font: { color: ceiling(i) ? '#ffe9b0' : '#d9e9f9' },
161+
title: `${soa.labels[i]}\n${ceiling(i) ? '◈ global type (leaf-limited, cross-cutting)' : FMA_CLASS[soa.cls[i]]?.name}`,
162+
};
163+
};
108164
const baseEdge = (e: { s: number; t: number; r: number }, id: number) => ({
109165
id,
110166
from: e.s,
@@ -117,10 +173,9 @@ export function FmaGraph() {
117173
const visNodes = new DataSet<any>(Array.from({ length: soa.nodeCount }, (_, i) => baseNode(i)));
118174
const visEdges = new DataSet<any>(soa.edges.map((e, id) => baseEdge(e, id)));
119175
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-
});
176+
// fixed Z-order tiles, no simulation — just frame the nested pyramid.
177+
net.once('afterDrawing', () => net.fit({ animation: false }));
178+
setStatus(`${soa.nodeCount} nodes · ${soa.edgeCount} edges — Z-order tile pyramid; click a tissue for its dual membership`);
124179

125180
const dim = () => {
126181
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: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ 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.
95+
identity: Uint16Array;
9296
}
9397

9498
/** One readable step of the reasoning traversal, streamed into the readout. */
@@ -129,10 +133,14 @@ export function decodeSoa(buf: ArrayBuffer): Soa {
129133
// the node is a cross-cutting GLOBAL category (the dual-use axes), not
130134
// basin-local. Read straight off the 16-byte GUID (HEEL @4, HIP @6).
131135
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.
138+
const identity = new Uint16Array(nodeCount);
132139
for (let i = 0; i < nodeCount; i++) {
133140
const heel = dv.getUint16(off + 4, true);
134141
const hip = dv.getUint16(off + 6, true);
135142
if (heel === 0xffff && hip === 0xffff) ceiling[i] = 1;
143+
identity[i] = dv.getUint16(off + 14, true);
136144
cls[i] = dv.getUint8(off + 16);
137145
off += 17;
138146
}
@@ -162,7 +170,7 @@ export function decodeSoa(buf: ArrayBuffer): Soa {
162170
tenants = new Uint8Array(buf, off, nodeCount * 6);
163171
off += nodeCount * 6;
164172
}
165-
return { nodeCount, edgeCount, cls, edges, labels, tenants, ceiling };
173+
return { nodeCount, edgeCount, cls, edges, labels, tenants, ceiling, identity };
166174
}
167175

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

crates/osint-bake/src/bin/fma.rs

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
//! Run from the workspace root: `cargo run -p osint-bake --bin fma`
2020
2121
use lance_graph_contract::canonical_node::NodeGuid;
22+
use osint_bake::morton;
2223
use std::path::{Path, PathBuf};
2324

2425
/// The CEILING global-category pole (HEEL=HIP=0xFFFF; sentinel through TWIG = leaf-grain).
@@ -38,6 +39,15 @@ const C_TYPE: u8 = 5; // the leaf-limited global type categories (ceiling pole)
3839
const REL_PART_OF: u8 = 2; // structure → its container (basin-local hierarchy)
3940
const REL_IS_A: u8 = 3; // structure → its cross-cutting global type (ceiling)
4041

42+
/// Map a sibling index (0..4) to its 2×2 quadrant `(tx, ty)` inside one 4×4
43+
/// Morton level: 0→(0,0) 1→(1,0) 2→(0,1) 3→(1,1) — natural row-major placement.
44+
/// Every FMA branch is ≤4-way (4 chambers, 3 walls, 2 tissues, 2 cells), so each
45+
/// part-of step is exactly one `morton::descend`, and depth == class.
46+
fn quad(i: usize) -> (u16, u16) {
47+
let i = i as u16;
48+
(i & 1, (i >> 1) & 1)
49+
}
50+
4151
struct Node {
4252
label: String,
4353
class: u8,
@@ -55,6 +65,12 @@ impl Builder {
5565
}
5666

5767
/// A part-of (basin-local) node: HEEL=organ, HIP=chamber, TWIG=wall, LEAF=struct.
68+
/// `morton` is the node's Z-order tile path (one 4×4 level per part-of step);
69+
/// its low 16 bits land in the GUID identity field, so the address **is** the
70+
/// layout coordinate — `FmaGraph` deinterleaves it back into a fixed position.
71+
/// Edges reference the returned array index, never the identity, so storing the
72+
/// Morton code here is layout-only and can't perturb the graph topology.
73+
#[allow(clippy::too_many_arguments)]
5874
fn part_of_node(
5975
&mut self,
6076
label: &str,
@@ -64,16 +80,17 @@ impl Builder {
6480
wall: u16,
6581
leaf: u16,
6682
basin: u8,
83+
morton: u32,
6784
) -> usize {
6885
let i = self.nodes.len();
6986
let key = NodeGuid::new_v2(
7087
CLASSID_FMA,
71-
organ, // HEEL — organ tier
72-
chamber, // HIP — chamber tier
73-
wall, // TWIG — wall/region tier
74-
leaf, // LEAF — structure tier
88+
organ, // HEEL — organ tier
89+
chamber, // HIP — chamber tier
90+
wall, // TWIG — wall/region tier
91+
leaf, // LEAF — structure tier
7592
u16::from(basin),
76-
i as u16,
93+
morton as u16, // identity — the Z-order tile path (position == address)
7794
);
7895
self.nodes.push(Node { label: label.to_string(), class, key });
7996
i
@@ -129,18 +146,24 @@ fn build_heart() -> Builder {
129146
// a couple of cell types per tissue (depth + scale; part-of only).
130147
let cells: [&str; 2] = ["cell A", "cell B"];
131148

132-
// ── the heart organ (basin-local root) ──
133-
let heart = b.part_of_node("Heart", C_ORGAN, 1, 0, 0, 0, 0);
149+
// ── the heart organ (basin-local root, root of the Z-order pyramid) ──
150+
// Morton 0 = the whole 16×16 tile; each part-of step descends one 4×4 level.
151+
let heart_m: u32 = 0;
152+
let heart = b.part_of_node("Heart", C_ORGAN, 1, 0, 0, 0, 0, heart_m);
134153

135154
let chambers = ["left atrium", "right atrium", "left ventricle", "right ventricle"];
136155
for (ci, chamber) in chambers.iter().enumerate() {
137156
let cnum = (ci as u16) + 1; // HIP 1..4
138157
let basin = (ci as u8) + 1; // one basin per chamber
139-
let ch = b.part_of_node(chamber, C_CHAMBER, 1, cnum, 0, 0, basin);
158+
let (ctx, cty) = quad(ci); // chamber → one of the 4 heart quadrants
159+
let chamber_m = morton::descend(heart_m, ctx, cty);
160+
let ch = b.part_of_node(chamber, C_CHAMBER, 1, cnum, 0, 0, basin, chamber_m);
140161
b.edge(ch, heart, REL_PART_OF);
141162

142163
for (wi, (wall, tissues)) in walls.iter().enumerate() {
143164
let wnum = (wi as u16) + 1; // TWIG 1..3
165+
let (wtx, wty) = quad(wi); // wall → a sub-tile of the chamber quadrant
166+
let wall_m = morton::descend(chamber_m, wtx, wty);
144167
let w = b.part_of_node(
145168
&format!("{chamber} {wall}"),
146169
C_WALL,
@@ -149,11 +172,14 @@ fn build_heart() -> Builder {
149172
wnum,
150173
0,
151174
basin,
175+
wall_m,
152176
);
153177
b.edge(w, ch, REL_PART_OF);
154178

155179
for (ti, (tissue, gtype)) in tissues.iter().enumerate() {
156180
let leaf = (ti as u16) + 1;
181+
let (ttx, tty) = quad(ti); // tissue → a sub-tile of the wall
182+
let tissue_m = morton::descend(wall_m, ttx, tty);
157183
let t = b.part_of_node(
158184
&format!("{chamber} {tissue}"),
159185
C_TISSUE,
@@ -162,13 +188,16 @@ fn build_heart() -> Builder {
162188
wnum,
163189
leaf,
164190
basin,
191+
tissue_m,
165192
);
166193
b.edge(t, w, REL_PART_OF);
167194
// THE dual membership: this basin-local tissue is-a the global type.
168195
b.edge(t, type_idx[*gtype], REL_IS_A);
169196

170197
for (cells_i, cell) in cells.iter().enumerate() {
171198
let cleaf = (ti as u16) * 8 + (cells_i as u16) + 16;
199+
let (xtx, xty) = quad(cells_i); // cell → the finest sub-tile
200+
let cell_m = morton::descend(tissue_m, xtx, xty);
172201
let c = b.part_of_node(
173202
&format!("{chamber} {tissue} {cell}"),
174203
C_CELL,
@@ -177,6 +206,7 @@ fn build_heart() -> Builder {
177206
wnum,
178207
cleaf,
179208
basin,
209+
cell_m,
180210
);
181211
b.edge(c, t, REL_PART_OF);
182212
}
@@ -226,14 +256,18 @@ fn main() {
226256
let key = &b.nodes[tissue].key;
227257
println!("── FMA dual-membership proof ──");
228258
println!("node: {}", b.nodes[tissue].label);
259+
// identity now carries the node's Z-order tile path (one 4×4 level per
260+
// part-of step, coarsest in the high nibble). FmaGraph walks the nibbles to
261+
// recover the nested-tile position; a flat decode would mis-spread the bits.
262+
let morton_code = u32::from(key.identity_v2());
229263
println!(
230-
" part-of address (basin-local): HEEL={} HIP={} TWIG={} LEAF={} family={} identity={}",
264+
" part-of address (basin-local): HEEL={} HIP={} TWIG={} LEAF={} family={} morton=0x{:04x} (Z-order tile path)",
231265
key.heel(),
232266
key.hip(),
233267
key.twig(),
234268
key.leaf(),
235269
key.family_v2(),
236-
key.identity_v2()
270+
morton_code,
237271
);
238272
// its is-a edge → the leaf-limited global type (ceiling pole)
239273
let gtype = b

0 commit comments

Comments
 (0)