Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added cockpit/public/fma.soa
Binary file not shown.
211 changes: 211 additions & 0 deletions cockpit/src/FmaGraph.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
// FMA anatomy slice — the "real test" of the dual-membership lattice. Decodes
// the baked /fma.soa (heart organ subtree + cross-cutting tissue TYPES) into the
// same vis-network renderer, and on click shows a node resolving to BOTH:
// · its part-of position (basin-local: organ → chamber → wall → structure)
// · its leaf-limited global TYPE (the 0xFFFF ceiling pole — cross-cutting,
// the same "Cardiac muscle tissue" shared by every chamber).
import { useEffect, useMemo, useRef, useState } from 'react';
import { Network, type Options } from 'vis-network';
import { DataSet } from 'vis-data';
import { decodeSoa, type Soa } from './OsintGraph';

const PAGE_BG = '#0a0e17';
const CEILING_COLOR = '#ffd166';

// class byte → colour/name (mirrors the C_* consts in src/bin/fma.rs).
const FMA_CLASS = [
{ name: 'Organ', color: '#ff637d' },
{ name: 'Chamber', color: '#ffb547' },
{ name: 'Wall', color: '#4dd0e1' },
{ name: 'Tissue', color: '#35d07f' },
{ name: 'Cell', color: '#9b8cff' },
{ name: 'Type · global', color: CEILING_COLOR },
];
const classColor = (c: number) => FMA_CLASS[c]?.color ?? '#8899aa';

// rel byte → name (REL_* in src/bin/fma.rs). 2 part-of, 3 is-a(global type).
const REL = ['member-of', 'interfaces', 'part-of', 'is-a'];
const REL_COLOR = ['#223040', '#223040', '#7fa6c4', CEILING_COLOR];

const OPTIONS: Options = {
nodes: { shape: 'dot', borderWidth: 2.5, font: { color: '#d9e9f9', size: 13, strokeWidth: 3, strokeColor: PAGE_BG } },
edges: {
color: { color: 'rgba(125,162,186,0.3)', inherit: false },
font: { color: 'rgba(147,169,191,0.55)', size: 9, strokeWidth: 0, align: 'middle' },
width: 1.1,
smooth: { enabled: true, type: 'continuous', roundness: 0.2 },
arrows: { to: { enabled: true, scaleFactor: 0.45 } },
},
physics: {
solver: 'forceAtlas2Based',
forceAtlas2Based: { gravitationalConstant: -70, centralGravity: 0.008, springLength: 130, springConstant: 0.04, damping: 0.5, avoidOverlap: 0.5 },
stabilization: { iterations: 180, fit: true },
},
interaction: { hover: true, tooltipDelay: 90, dragNodes: true },
layout: { improvedLayout: false },
};

interface Trace {
node: string;
partOf: string[];
type: string | null;
shared: number;
}

export function FmaGraph() {
const hostRef = useRef<HTMLDivElement>(null);
const [soa, setSoa] = useState<Soa | null>(null);
const [error, setError] = useState<string | null>(null);
const [status, setStatus] = useState('loading FMA slice…');
const [trace, setTrace] = useState<Trace | null>(null);

useEffect(() => {
let cancelled = false;
fetch('/fma.soa')
.then((r) => {
if (!r.ok) throw new Error(`HTTP ${r.status}`);
return r.arrayBuffer();
})
.then((buf) => !cancelled && setSoa(decodeSoa(buf)))
.catch((e: unknown) => !cancelled && setError(String(e)));
return () => {
cancelled = true;
};
}, []);

// part-of parent (rel 2) and is-a global type (rel 3) per node, + how many
// tissues each type gathers (its cross-cutting reach).
const rel = useMemo(() => {
if (!soa) return null;
const parentOf = new Map<number, number>();
const typeOf = new Map<number, number>();
const typeMembers = new Map<number, number>();
for (const e of soa.edges) {
if (e.r === 2) parentOf.set(e.s, e.t);
else if (e.r === 3) {
typeOf.set(e.s, e.t);
typeMembers.set(e.t, (typeMembers.get(e.t) ?? 0) + 1);
}
}
return { parentOf, typeOf, typeMembers };
}, [soa]);

useEffect(() => {
if (!hostRef.current || !soa || !rel) return;
const ceiling = (i: number) => soa.ceiling[i] === 1 || soa.cls[i] === 5;
const baseNode = (i: number) => ({
id: i,
label: soa.labels[i] || `#${i}`,
shape: ceiling(i) ? 'diamond' : 'dot',
color: {
background: ceiling(i) ? 'rgba(255,209,102,0.14)' : 'rgba(10,14,23,0.88)',
border: ceiling(i) ? CEILING_COLOR : classColor(soa.cls[i]),
},
size: ceiling(i) ? 22 : 13,
font: { color: ceiling(i) ? '#ffe9b0' : '#d9e9f9' },
title: `${soa.labels[i]}\n${ceiling(i) ? '◈ global type (leaf-limited, cross-cutting)' : FMA_CLASS[soa.cls[i]]?.name}`,
});
const baseEdge = (e: { s: number; t: number; r: number }, id: number) => ({
id,
from: e.s,
to: e.t,
label: REL[e.r] ?? '',
color: { color: `${REL_COLOR[e.r] ?? '#8fa6c4'}66`, highlight: REL_COLOR[e.r] ?? '#4dd0e1' },
dashes: e.r === 3 ? [4, 3] : false,
});

const visNodes = new DataSet<any>(Array.from({ length: soa.nodeCount }, (_, i) => baseNode(i)));
const visEdges = new DataSet<any>(soa.edges.map((e, id) => baseEdge(e, id)));
const net = new Network(hostRef.current, { nodes: visNodes, edges: visEdges }, OPTIONS);
net.once('stabilizationIterationsDone', () => {
net.setOptions({ physics: { enabled: false } });
setStatus(`${soa.nodeCount} nodes · ${soa.edgeCount} edges — click a tissue to see its dual membership`);
});

const dim = () => {
visNodes.update(Array.from({ length: soa.nodeCount }, (_, i) => ({ id: i, color: { background: 'rgba(10,14,23,0.5)', border: '#26323f' }, font: { color: '#566779' } })));
visEdges.update(soa.edges.map((_, id) => ({ id, color: { color: 'rgba(50,66,84,0.1)' } })));
};
const restore = () => {
visNodes.update(Array.from({ length: soa.nodeCount }, (_, i) => baseNode(i)));
visEdges.update(soa.edges.map((e, id) => baseEdge(e, id)));
setTrace(null);
};
const bright = (i: number) => visNodes.update({ id: i, color: { background: 'rgba(10,14,23,0.96)', border: ceiling(i) ? CEILING_COLOR : '#9fe8ff' }, font: { color: '#eaf4ff' } });
const litEdge = (from: number, to: number, c: string) => {
const hit = soa.edges.findIndex((e) => e.s === from && e.t === to);
if (hit >= 0) visEdges.update({ id: hit, color: { color: c }, width: 3 });
};

net.on('click', (p: { nodes: unknown[] }) => {
if (!p.nodes.length) {
restore();
return;
}
const seed = p.nodes[0] as number;
dim();
bright(seed);
// part-of chain up to the organ (basin-local position).
const partOf: string[] = [];
let cur = seed;
for (let hop = 0; hop < 12; hop++) {
const parent = rel.parentOf.get(cur);
if (parent == null) break;
litEdge(cur, parent, '#6cf0ff');
bright(parent);
partOf.push(soa.labels[parent]);
cur = parent;
}
// is-a leaf-limited global type (the ceiling pole, cross-cutting).
const ty = rel.typeOf.get(seed);
if (ty != null) {
litEdge(seed, ty, CEILING_COLOR);
bright(ty);
}
setTrace({
node: soa.labels[seed],
partOf,
type: ty != null ? soa.labels[ty] : null,
shared: ty != null ? rel.typeMembers.get(ty) ?? 0 : 0,
});
});

return () => net.destroy();
}, [soa, rel]);

return (
<div style={{ position: 'relative', width: '100%', height: '100vh', background: PAGE_BG, overflow: 'hidden' }}>
<div ref={hostRef} style={{ position: 'absolute', inset: 0, zIndex: 0 }} />
<div style={{ position: 'absolute', top: 16, left: 16, zIndex: 10, fontFamily: 'monospace', color: '#93a9bf', fontSize: 12, pointerEvents: 'none', textShadow: '0 0 4px #0a0e17' }}>
<div style={{ fontSize: 14, color: '#cfe7ff' }}>FMA heart slice · part-of basin × leaf-limited global type</div>
<div>{error ? <span style={{ color: '#ff637d' }}>load error: {error}</span> : status}</div>
</div>

{trace && (
<div style={{ position: 'absolute', left: 16, bottom: 56, width: 380, zIndex: 10, fontFamily: 'monospace', fontSize: 11, color: '#cfe7ff', background: 'rgba(8,12,20,0.88)', border: '1px solid #2a4a6a', borderRadius: 8, padding: '10px 12px' }}>
<div style={{ color: '#7fd1ff', marginBottom: 6 }}>◎ {trace.node}</div>
<div style={{ color: '#9fb4c8' }}>part-of (basin-local position):</div>
<div style={{ marginBottom: 6 }}>{trace.partOf.length ? trace.partOf.join(' › ') : '(root)'}</div>
<div style={{ color: '#9fb4c8' }}>is-a (leaf-limited global type — ceiling pole):</div>
<div style={{ color: trace.type ? CEILING_COLOR : '#566779' }}>
{trace.type ? `◈ ${trace.type} · cross-cuts ${trace.shared} chambers` : '— (no global type at this grain)'}
</div>
</div>
)}

{/* legend */}
<div style={{ position: 'absolute', bottom: 16, left: 16, zIndex: 10, fontFamily: 'monospace', fontSize: 11, color: '#93a9bf', pointerEvents: 'none', textShadow: '0 0 4px #0a0e17' }}>
{FMA_CLASS.map((k) => (
<span key={k.name} style={{ marginRight: 12, whiteSpace: 'nowrap' }}>
<span style={{ display: 'inline-block', width: 9, height: 9, borderRadius: k.name.startsWith('Type') ? 0 : 9, border: `2px solid ${k.color}`, marginRight: 5, verticalAlign: 'middle', transform: k.name.startsWith('Type') ? 'rotate(45deg)' : 'none' }} />
{k.name}
</span>
))}
</div>

<a href="/osint" style={{ position: 'absolute', top: 14, right: 16, zIndex: 10, fontFamily: 'monospace', fontSize: 12, color: '#cfe7ff', background: 'rgba(17,32,48,0.7)', border: '1px solid #2a4a6a', borderRadius: 6, padding: '6px 12px', textDecoration: 'none' }}>
← OSINT graph
</a>
</div>
);
}
44 changes: 37 additions & 7 deletions cockpit/src/OsintGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,11 @@ const facetColor = (code: number) =>
const DIM_NODE = { background: 'rgba(10,14,23,0.55)', border: '#26323f' };
const DIM_EDGE = 'rgba(50,66,84,0.12)';
const ACTIVE = '#6cf0ff';
// the cross-cutting global-category hubs (HEEL=HIP=0xFFFF ceiling pole) — drawn
// as bright diamonds so the dual-use axes read as global, not basin-local.
const CEILING_COLOR = '#ffd166';

interface Soa {
export interface Soa {
nodeCount: number;
edgeCount: number;
cls: Uint8Array;
Expand All @@ -84,6 +87,8 @@ interface Soa {
// per-node facet tenant: 6 codes (value[1..=6]) × nodeCount, or null if the
// asset predates the tenant tail. The dynamic attribute the facet lens groups by.
tenants: Uint8Array | null;
// per-node global-category flag (HEEL=HIP=0xFFFF ceiling pole): 1 = cross-cutting.
ceiling: Uint8Array;
}

/** One readable step of the reasoning traversal, streamed into the readout. */
Expand All @@ -110,7 +115,7 @@ interface GraphApi {
// Decode the OSO1 wire: magic(4) | nodeCount u32 | edgeCount u32 |
// nodeCount×[guid:16|class:1] | edgeCount×[src:u16|tgt:u16|rel:u8] |
// nodeCount×[len:u8|utf8 name] (the label tail is additive / may be absent).
function decodeSoa(buf: ArrayBuffer): Soa {
export function decodeSoa(buf: ArrayBuffer): Soa {
const dv = new DataView(buf);
const magicOk =
dv.getUint8(0) === 0x4f && dv.getUint8(1) === 0x53 &&
Expand All @@ -120,7 +125,14 @@ function decodeSoa(buf: ArrayBuffer): Soa {
const edgeCount = dv.getUint32(8, true);
let off = 12;
const cls = new Uint8Array(nodeCount);
// ceiling[i] = 1 when the GUID's HEEL and HIP are both the 0xFFFF sentinel —
// the node is a cross-cutting GLOBAL category (the dual-use axes), not
// basin-local. Read straight off the 16-byte GUID (HEEL @4, HIP @6).
const ceiling = new Uint8Array(nodeCount);
for (let i = 0; i < nodeCount; i++) {
const heel = dv.getUint16(off + 4, true);
const hip = dv.getUint16(off + 6, true);
if (heel === 0xffff && hip === 0xffff) ceiling[i] = 1;
cls[i] = dv.getUint8(off + 16);
off += 17;
}
Expand Down Expand Up @@ -150,7 +162,7 @@ function decodeSoa(buf: ArrayBuffer): Soa {
tenants = new Uint8Array(buf, off, nodeCount * 6);
off += nodeCount * 6;
}
return { nodeCount, edgeCount, cls, edges, labels, tenants };
return { nodeCount, edgeCount, cls, edges, labels, tenants, ceiling };
}

// vis-network options tuned to the Palantir look: hollow ring nodes (dark fill
Expand Down Expand Up @@ -348,22 +360,26 @@ export function OsintGraph() {
// code on that axis (categorical, computed live across every node); else the
// class colour. This is the dynamic group-by — no baked edges involved.
const nodeBorder = (i: number) => {
if (soa.ceiling[i]) return CEILING_COLOR; // global hubs stay prominent in every mode
const ax = facetAxisRef.current;
if (ax != null && soa.tenants) return facetColor(soa.tenants[i * 6 + ax]);
return classColor(soa.cls[i]);
};
const nodeKind = (i: number) =>
soa.ceiling[i] ? '◈ global category (cross-cutting)' : CLASS[soa.cls[i]]?.name ?? 'concept';
const baseNode = (i: number) => ({
id: i,
label: soa.labels[i] || `#${i}`,
shape: soa.ceiling[i] ? 'diamond' : 'dot',
color: {
background: 'rgba(10,14,23,0.88)',
background: soa.ceiling[i] ? 'rgba(255,209,102,0.14)' : 'rgba(10,14,23,0.88)',
border: nodeBorder(i),
highlight: { background: 'rgba(10,14,23,0.96)', border: '#9fe8ff' },
hover: { background: 'rgba(10,14,23,0.82)', border: nodeBorder(i) },
},
size: baseSize(i),
font: { color: '#d9e9f9' },
title: `${soa.labels[i] || `#${i}`}\n${CLASS[soa.cls[i]]?.name ?? 'concept'} · ${degree.get(i) ?? 0} links`,
size: baseSize(i) + (soa.ceiling[i] ? 7 : 0),
font: { color: soa.ceiling[i] ? '#ffe9b0' : '#d9e9f9' },
title: `${soa.labels[i] || `#${i}`}\n${nodeKind(i)} · ${degree.get(i) ?? 0} links`,
});
const baseEdge = (e: { id: number; s: number; t: number; r: number }) => ({
id: e.id,
Expand Down Expand Up @@ -993,6 +1009,20 @@ export function OsintGraph() {
{k.name}
</span>
))}
<span style={{ marginRight: 12, whiteSpace: 'nowrap' }}>
<span
style={{
display: 'inline-block',
width: 9,
height: 9,
border: `2px solid ${CEILING_COLOR}`,
marginRight: 5,
verticalAlign: 'middle',
transform: 'rotate(45deg)',
}}
/>
◈ global axis
</span>
</div>

{/* alternative-view link */}
Expand Down
3 changes: 3 additions & 0 deletions cockpit/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { NeuralDebuggerPage } from './NeuralDebuggerPage';
import { RenderPage, OrbitPage, FlightPage } from './RenderPage';
import { OsintScene3D } from './OsintScene3D';
import { OsintGraph } from './OsintGraph';
import { FmaGraph } from './FmaGraph';
import { ReasoningPage } from './ReasoningPage';
import { ErrorBoundary } from './components/ErrorBoundary';
import './styles/cockpit.css';
Expand Down Expand Up @@ -76,6 +77,8 @@ createRoot(document.getElementById('root')!).render(
<Route path="/" element={<OsintGraph />} />
<Route path="/osint" element={<OsintGraph />} />
<Route path="/osint3d" element={<OsintScene3D />} />
{/* FMA anatomy slice — part-of basin × leaf-limited global type (dual membership) */}
<Route path="/fma" element={<FmaGraph />} />
{/* The Palantir JSON-graph cockpit (221 aiwar nodes) stays reachable
at /palantir and as the catch-all for its own sub-routes. */}
<Route path="/palantir" element={<PalantirApp />} />
Expand Down
Binary file modified crates/cockpit-server/assets/osint_scene.soa
Binary file not shown.
Loading