mirror of
https://github.com/ruvnet/RuVector.git
synced 2026-07-10 01:38:44 +00:00
* feat(sonic_ct): acoustic digital human workbench — Rust/WASM USCT + R3F UI Add `sonic_ct`, a research-grade Ultrasound Computed Tomography (USCT) simulator and reconstruction workbench. Core (crates/sonic-ct, pure Rust, zero deps, 17 tests): - procedural z-varying torso phantom (fat/muscle/organ shells, spine, ribs, pelvis, liver/spleen/kidneys/aorta, heart+lungs in thorax) - circular ring acquisition with straight-ray travel-time + attenuation - SART time-of-flight reconstruction (1 sweep == delay backprojection) - transparent speed-band segmentation with per-cell uncertainty - coordinate-ascent threshold training (mean Dice ~0.30 -> ~0.63) - RuVector-style acoustic memory: NSW vector index, longitudinal drift, warm-start, anatomical graph-coherence checks, .rvf-style serialization - 3-D volume sweep (truth / recon / error / confidence channels) - mock Butterfly Embedded acquisition boundary (trait, no hardware SDK) WASM (crates/sonic-ct-wasm): raw C-ABI cdylib (no wasm-bindgen, ~39 KB) exposing the single-slice + progressive volume pipeline. UI (examples/sonic-ct): React Three Fiber "Sonic Chamber" — water chamber, transducer ring(s), holographic torso with internal organ glows and class-tinted contour slices, live HUD (acoustic paths, phantom fidelity, path confidence, body composition), cranio-caudal scrubber. Driven entirely by real reconstruction data. Docs (docs/sonic-ct): 8 ADRs, SOTA research map, market brief, SPARC. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(sonic_ct ui): welcome modal + GLB body-model loader with procedural fallback - WelcomeModal: Simulate/Reconstruct/Analyze/Validate intro, Get Started cards, "show on startup" preference, research-only disclaimer. - BodyModel: loads a supplied GLB anatomy model (GLB_URL) and applies a ghost material override + per-organ tinting from organ_manifest.json; cleanly falls back to the procedural violet ghost (torso + internal organ glows) when no asset is supplied or it fails to load. GLB is a visual prior only — the Rust phantom stays the physics ground truth. - Refined holographic ghost: violet volumetric glow, class-tinted contour slices, twin transducer rings, glowing base, internal organ volumes. - docs/sonic-ct/BODY-MODELS.md: researched model sources (Zygote, BioDigital, SMPL/Meshcapade, Z-Anatomy, BodyParts3D) + GLB integration pipeline. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(sonic_ct ui): load open-source CesiumMan GLB as the ghost body shell - Ship CesiumMan (Khronos glTF Sample Assets, CC-BY 4.0) as public/models/human.glb, loaded via useGLTF, auto-fit to the chamber, and styled with the ghost-material override; procedural internal organ glows render inside it. - GLB_URL now points at the bundled model; missing/broken asset still falls back to the procedural torso shell via the error boundary. - Attribution recorded in organ_manifest.json and docs/sonic-ct/BODY-MODELS.md. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(metabiohacker): organ-hypothesis detector, Darwin optimizer, rebrand Rename the app to MetaBioHacker (Acoustic Digital Human Workbench · Sonic Chamber) across HUD, welcome modal, and metadata. Organ inference (ADR-0009/0010): new `crates/sonic-ct/src/organ.rs` detects liver, spleen, kidneys, aorta, heart, and lungs from the reconstructed volume using anatomical priors (zone, side, size, posterior adjacency, slice-consistency) — never from speed alone. Each hypothesis carries a confidence and an evidence bitmask. Exposed via WASM (sct_organ_*, sct_quality_flag) and surfaced in a new HUD panel with per-organ confidence bars + quality flags (bone shadowing / sparse coverage / boundary uncertainty / gas). 18 Rust tests pass; clippy clean. Harness optimization (examples/sonic-ct/optimize.mjs): uses @metaharness/darwin ("freeze the model, evolve the harness") with cheap->frontier tiering and Pareto selection over the frozen WASM engine to evolve {elements, fan, iters}; lifts phantom fidelity ~0.53 -> ~0.59. Documented in docs/sonic-ct/OPTIMIZATION.md. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(metabiohacker): faithful Darwin harness evolution + OpenRouter write layer - crates/sonic-ct/src/bin/serve.rs: the frozen acoustic engine as a JSON-over- stdio process (sonic_ct_serve) — the physics truth layer for the evolver. - examples/sonic-ct/src/optimizer/reconstructionEvolution.ts: typed genome (reconstruction/routing/scoring/safety), runFrozenRustEngine (spawns the real binary), cheap->frontier routeReconstruction (augments engine output, never rewrites anatomy), multi-objective scoreCandidate, mutateGenome, and evolveMetaBioHarness using Darwin mapLimit + paretoFront + an archive. - optimize.mjs: OpenRouter LLM "write layer" proposes harness mutations (cheap gpt-4o-mini / frontier gpt-4o), gated by routing policy, bounded budget, key read from env only; archive-based acceptance gate now PASSES (latency -92.8%, no regression). probeDarwin.mjs verifies the export surface. - Tests (npm test, Node type-stripping): mapLimit bounds concurrency; paretoFront keeps accurate+cheap trade-offs and drops dominated; frontier never bypasses the frozen engine. docs/sonic-ct/OPTIMIZATION.md updated. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * docs(metabiohacker): ADRs 0009-0019 — organ inference, harness evolution, multimodal data + governance Add 11 ADRs and an index covering the layers built and the medical-data architecture roadmap: Organ/inference layer (grounded in organ.rs / segmentation.rs / Hud.jsx): - 0009 five acoustic classes canonical (no organ identity from speed alone) - 0010 organ identity inferred from anatomical priors (evidence + confidence) - 0011 organ function requires dynamic/multiparametric channels ("not measured") - 0012 explainability mandatory (evidence bitmask surfaced in the UI) - 0013 no disease labels — research mode only Harness + data architecture: - 0014 freeze the physics engine, evolve the reconstruction harness (Darwin) - 0015 patient data as a graph of typed observations (MedicalObservation, provenance + uncertainty + consent scope) - 0016 adopt DICOM / FHIR / LOINC / SNOMED CT / OMOP + RuVector similarity index - 0017 typed multimodal fusion patterns (monitoring/research, not diagnosis) - 0018 governance & SaMD boundary (FDA GMLP/PCCP, Health Canada, Ontario PHIPA) - 0019 a medical signal operating system, not an AI doctor Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(metabiohacker): benchmark harness on real CT data + synthetic corpus - Real-data ingestion: Grid::from_pgm (P5 parser), Phantom::from_intensity_grid (band a grayscale CT slice into the five acoustic classes), and pipeline::run_with_phantom (reconstruct a supplied phantom — engine unchanged). - sonic_ct_serve gains a phantomPgm path: reconstruct a real anatomical slice instead of a procedural one and emit the same score schema. - tools/fetchRealSlice.mjs: fetch a public-domain abdominal CT slice (Wikimedia Commons) and convert to a grayscale PGM (image not committed; fetched on demand, derived PGM gitignored). - benchmark.mjs (npm run benchmark): baseline vs Darwin-evolved harness over 12 reproducible synthetic phantoms + 1 real CT slice; writes docs/sonic-ct/ BENCHMARK.md + benchmark.report.json. Representative: evolved harness ~157% faster at equal Dice; real CT honestly harder (Dice ~0.27). - New integration test exercises the PGM/real-phantom reconstruction path (19 Rust tests pass). Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(metabiohacker): scale benchmark — 40 synthetic seeds + multiple real CT slices, 95% CI - fetchRealSlice.mjs fetches several public-domain CT slices (abdomen, thorax, pelvis) resiliently, skipping unavailable ones. - benchmark.mjs now runs N synthetic seeds (default 40) + every fetched real slice, reports mean ± 95% CI, and writes docs/sonic-ct/BENCHMARK.md. Representative: 42 samples, evolved harness ~149% faster at equal Dice (±0.002 CI); real CT slices honestly harder (Dice ~0.30). Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(metabiohacker): Multimodal Ingest V0 — observations, graph, fusion, ledger, ruvn evidence gate New package packages/metabiohacker (@metabiohacker/core, TS, 14 tests pass): - ingest/: canonical MedicalObservation + lab (CSV→LOINC), imaging (DICOM sidecar), and pathology adapters with provenance/uncertainty/consent. - graph/: auditable patient state graph + rule-based contradiction detection (low-quality, ≥2x same-test disagreement, unflagged review modalities). - fusion/: prior builder (data shapes priors, never forces conclusions), multimodal scoring (acoustic residual passed through unchanged), contradiction penalty, and a Darwin harness (mapLimit + paretoFront) selecting fusion policy. - evidence/: ruvn as the evidence-intelligence layer (off the hot path) — provider interface, A/B-or-blocked claim gate, deterministic cached provider + optional @ruvnet/ruvn CLI adapter (never a hard dep). Claims ship only on grade A/B with citations; pathology/biopsy/Pap/HPV/cytology force human review. - ledger/ + output/: stable-hash reconstruction run ledger (tamper-evident, verifiable) and the safe UI packet (uncertainty overlay, diagnosis blocked). Benchmark: +10% stability, ~37% uncertainty drop, residual unchanged, ledger verified, clinical-review mode forced by pathology. Docs: ADR-0020 (canonical observation), 0021 (graph+contradictions), 0022 (run ledger), 0023 (ruvn evidence layer); ADR index updated. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(metabiohacker): real-slice calibration, domain-gap honesty gate, evidence refresh, CI gates Attacks the synthetic→real Dice gap honestly rather than hiding it. - Engine: sonic_ct_serve emits per-class (region) Dice on real slices. - calibration/: region-level Dice (diceByRegion), domain-gap scoring + honesty gate (classifyRealSliceResult: headline/researchOnly/exclude), centroid registration-error + boundary-complexity proxies. Real CT slices are calibration targets, not USCT. - benchmark.mjs: 3-section report (synthetic / real region-level / governance); headline separates speed from real fidelity. Real slices now classify as exclude/researchOnly and stay out of headline metrics (abdomen~0.30). - evidence:refresh (OpenRouter): grades modality evidence into docs/evidence/*.md + a candidate cache; promotion to the curated cache stays a reviewed step. Live run graded acoustic USCT = C (research-only), MRI = B. - CI gates (ciGates.test.ts + .github/workflows/metabiohacker-ci.yml): residual invariant, pathology review forced, A/B-only claims, real-slice honesty gate. 23 metabiohacker tests + 12 Rust integration tests pass. ADR-0024 added. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(sonic_ct): method comparison vs BP/SART/Landweber on Shepp-Logan with RMSE/PSNR/SSIM Bench reconstruction against recognised algorithms on a recognised target: - shepp_logan.rs: standard 10-ellipse Shepp-Logan phantom -> speed map. - reconstruction.rs: Method enum + reconstruct_speed_with; Landweber solver (gradient descent on ‖As−t‖²) alongside backprojection (1 sweep) and SART. - metrics.rs: standard image-quality metrics RMSE, PSNR (dB), SSIM. - sonic_ct_methods bin -> docs/sonic-ct/METHOD-BENCHMARK.md (deterministic). Measured: backprojection < SART < Landweber on every metric for both Shepp-Logan and abdomen (abdomen RMSE 130→99→51 m/s, SSIM 0.22→0.60→0.92) at ~4/28/100 ms. SART stays production default; Landweber is the higher-fidelity option. 2 new tests; 14 integration tests pass; clippy clean. ADR-0025 added. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(metabiohacker): rigid translation registration for real-slice calibration Replace the centroid-only proxy with registerByTranslation — finds the integer offset that maximises predicted/target body-mask overlap Dice, returning the offset, residual misalignment (errorPx), and aligned overlap. Gives the domain-gap honesty gate a real registration estimate (landmark refinement is the next step). +1 test (recovers a known offset; maximises overlap). 24 tests pass. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(sonic_ct): full-waveform inversion (FWI) — forward + adjoint-state gradient The SOTA step beyond straight-ray TOF (ADR-0004 roadmap), as a dependency-free 2-D reference: - fwi.rs: FDTD scalar-wave forward model (∂ₜ²p = κ∇²p + f), CFL-stable, damping sponge; adjoint-state gradient ∂χ/∂κ = Σ_t λ ∇²p; gradient descent with source/receiver-footprint muting, smoothing, and backtracking line search. - Proven by the gold-standard adjoint-vs-finite-difference gradient check (cosine > 0.85) + an inversion that cuts data misfit ≥15% and recovers a centrally-concentrated velocity anomaly. 2 new tests; 23 Rust tests pass; clippy clean. - Honest scope: single-frequency, unregularised — frequency continuation, regularisation, source encoding, and 3-D are the documented next steps; no quantitative clinical recovery claimed. ADR-0026 added. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(sonic-ct): add FWI frequency continuation (multiscale inversion) Add invert_multiscale + Stage to fwi.rs: chains low->high frequency FWI stages with between-stage model smoothing to avoid cycle-skipping. Low frequencies recover the smooth background first, keeping high-frequency stages out of local minima. Proven by a third FWI test: frequency continuation lowers the inclusion-region error below single-scale FWI at matched iteration count (deterministic). Adjoint-vs-FD gradient check and misfit-reduction tests still pass. Updates ADR-0026. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 --------- Co-authored-by: Claude <noreply@anthropic.com>
206 lines
9.5 KiB
JavaScript
206 lines
9.5 KiB
JavaScript
// MetaBioHacker benchmark: baseline vs Darwin-evolved reconstruction harness,
|
||
// over a reproducible synthetic corpus AND a real anatomical CT slice.
|
||
//
|
||
// The frozen Rust engine (sonic_ct_serve) is the physics layer; we only vary the
|
||
// harness config. Writes BENCHMARK.md + benchmark.report.json.
|
||
//
|
||
// Prereqs: cargo build --release --bin sonic_ct_serve
|
||
// node tools/fetchRealSlice.mjs (optional, for the real sample)
|
||
// Run: npm run benchmark
|
||
|
||
import fs from "node:fs";
|
||
import path from "node:path";
|
||
import { spawn } from "node:child_process";
|
||
import { fileURLToPath } from "node:url";
|
||
|
||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||
const SERVE = path.join(__dirname, "..", "..", "crates", "sonic-ct", "target", "release", "sonic_ct_serve");
|
||
const BENCH_DIR = path.join(__dirname, "public", "benchmark");
|
||
const N_SEEDS = Number(process.argv[2] || 40);
|
||
|
||
if (!fs.existsSync(SERVE)) {
|
||
console.error(`missing engine: ${SERVE}\nbuild it: cargo build --release --bin sonic_ct_serve`);
|
||
process.exit(1);
|
||
}
|
||
|
||
function runEngine(reconstruction, sample) {
|
||
return new Promise((resolve, reject) => {
|
||
const t0 = performance.now();
|
||
const child = spawn(SERVE, []);
|
||
let out = "";
|
||
child.stdout.on("data", (c) => (out += c));
|
||
child.on("error", reject);
|
||
child.on("close", () => {
|
||
try {
|
||
const r = JSON.parse(out);
|
||
r.latencyMs = performance.now() - t0;
|
||
resolve(r);
|
||
} catch {
|
||
reject(new Error(`bad engine output: ${out}`));
|
||
}
|
||
});
|
||
child.stdin.write(JSON.stringify({ sample, reconstruction }));
|
||
child.stdin.end();
|
||
});
|
||
}
|
||
|
||
// Harness configs: baseline vs evolved (from optimize.report.json if present).
|
||
const baseline = {
|
||
voxelResolutionMm: 4,
|
||
temporalWindowMs: 800,
|
||
smoothingAlpha: 0.35,
|
||
ghostBodyPriorWeight: 0.4,
|
||
atlasPriorWeight: 0.25,
|
||
organBoundarySharpness: 0.5,
|
||
};
|
||
let evolved = { ...baseline, smoothingAlpha: 0.95, voxelResolutionMm: 3.5, organBoundarySharpness: 0.7 };
|
||
const reportPath = path.join(__dirname, "optimize.report.json");
|
||
if (fs.existsSync(reportPath)) {
|
||
try {
|
||
const rep = JSON.parse(fs.readFileSync(reportPath, "utf8"));
|
||
if (rep?.evolved?.reconstruction) evolved = { ...baseline, ...rep.evolved.reconstruction };
|
||
} catch {}
|
||
}
|
||
|
||
// Dataset: reproducible synthetic seeds + every real CT slice fetched.
|
||
const samples = [];
|
||
for (let seed = 1; seed <= N_SEEDS; seed++) samples.push({ id: `synthetic-${seed}`, seed, kind: "synthetic" });
|
||
const realFiles = fs.existsSync(BENCH_DIR)
|
||
? fs.readdirSync(BENCH_DIR).filter((f) => /^real_.*\.pgm$/.test(f))
|
||
: [];
|
||
for (const f of realFiles) {
|
||
samples.push({ id: `real-${f.replace(/^real_|\.pgm$/g, "")}`, seed: 1, kind: "real", pgm: path.join(BENCH_DIR, f) });
|
||
}
|
||
|
||
const mean = (a) => a.reduce((s, x) => s + x, 0) / Math.max(a.length, 1);
|
||
const std = (a) => {
|
||
if (a.length < 2) return 0;
|
||
const m = mean(a);
|
||
return Math.sqrt(a.map((x) => (x - m) ** 2).reduce((s, x) => s + x, 0) / (a.length - 1));
|
||
};
|
||
const ci95 = (a) => (a.length > 1 ? (1.96 * std(a)) / Math.sqrt(a.length) : 0);
|
||
|
||
async function evalConfig(name, reconstruction) {
|
||
const rows = [];
|
||
for (const s of samples) {
|
||
const recon = s.kind === "real" ? { ...reconstruction, phantomPgm: s.pgm } : reconstruction;
|
||
const r = await runEngine(recon, { id: s.id, seed: s.seed });
|
||
rows.push({ ...s, ...r });
|
||
}
|
||
const agg = (key, kind) => {
|
||
const v = rows.filter((r) => !kind || r.kind === kind).map((r) => r[key]);
|
||
return { mean: mean(v), std: std(v), ci95: ci95(v), n: v.length };
|
||
};
|
||
return { name, rows, summary: {
|
||
shape: agg("shapeConsistency", "synthetic"),
|
||
residual: agg("acousticResidual", "synthetic"),
|
||
confidence: agg("confidence", "synthetic"),
|
||
latency: agg("latencyMs"),
|
||
realShape: agg("shapeConsistency", "real"),
|
||
} };
|
||
}
|
||
|
||
console.log("== MetaBioHacker benchmark ==");
|
||
console.log(`samples: ${samples.length} (${samples.filter((s) => s.kind === "real").length} real)\n`);
|
||
|
||
const base = await evalConfig("baseline", baseline);
|
||
const evo = await evalConfig("evolved", evolved);
|
||
|
||
const pct = (a, b) => (b !== 0 ? ((a - b) / Math.abs(b)) * 100 : 0);
|
||
const dShape = pct(evo.summary.shape.mean, base.summary.shape.mean);
|
||
const dLatency = pct(base.summary.latency.mean, evo.summary.latency.mean);
|
||
const dResidual = pct(base.summary.residual.mean, evo.summary.residual.mean);
|
||
|
||
const f = (x) => x.toFixed(3);
|
||
console.log(`samples: ${samples.length} synthetic seeds=${N_SEEDS}, real=${realFiles.length}`);
|
||
console.log("config shape(Dice, 95% CI) residual latency(ms) real-Dice");
|
||
for (const c of [base, evo]) {
|
||
const s = c.summary;
|
||
console.log(
|
||
`${c.name.padEnd(9)} ${f(s.shape.mean)}±${f(s.shape.ci95)} ${f(s.residual.mean)} ` +
|
||
`${s.latency.mean.toFixed(0).padStart(6)} ${f(s.realShape.mean)}`
|
||
);
|
||
}
|
||
console.log(`\nevolved vs baseline: shape ${dShape >= 0 ? "+" : ""}${dShape.toFixed(1)}% · latency ${dLatency >= 0 ? "+" : ""}${dLatency.toFixed(1)}% faster · residual ${dResidual >= 0 ? "-" : "+"}${Math.abs(dResidual).toFixed(1)}%`);
|
||
|
||
// --- Real-slice region Dice + honesty gate (ADR-0024) -----------------------
|
||
const REGION = ["fluid", "fat", "softTissue (muscle)", "softTissue (organ)", "bone"];
|
||
function realSliceAnalysis(row) {
|
||
const rd = row.regionDice || [0, 0, 0, 0, 0];
|
||
const region = { fluid: rd[0], fat: rd[1], softTissue: Math.min(rd[2], rd[3]), bone: rd[4] };
|
||
const meanRegion = (region.fluid + region.fat + region.softTissue + region.bone) / 4;
|
||
// Conservative domain-gap heuristic: soft tissue + bone failing => high gap.
|
||
const missingAcoustic = 1 - (region.softTissue + region.bone) / 2;
|
||
const domainGap = Math.max(0, Math.min(1, 0.2 + 0.4 * missingAcoustic));
|
||
const registrationErrorPx = 6; // proxy registration (no landmark reg yet)
|
||
let classification = "headline";
|
||
if (registrationErrorPx > 12 || domainGap > 0.6) classification = "exclude";
|
||
else if (row.shapeConsistency < 0.45 || domainGap > 0.3) classification = "researchOnly";
|
||
return { id: row.id, region, meanRegion, domainGap, registrationErrorPx, classification };
|
||
}
|
||
const realAnalyses = evo.rows.filter((r) => r.kind === "real").map(realSliceAnalysis);
|
||
|
||
const report = {
|
||
engine: "sonic_ct_serve (frozen)",
|
||
samples: samples.map((s) => ({ id: s.id, kind: s.kind })),
|
||
synthetic: { baseline: base.summary, evolved: evo.summary, deltas: { shapePct: dShape, latencyPctFaster: dLatency, residualPctLower: dResidual } },
|
||
real: realAnalyses,
|
||
governance: {
|
||
headlineRealSlices: realAnalyses.filter((a) => a.classification === "headline").length,
|
||
note: "Real slices below the honesty gate are excluded from headline metrics.",
|
||
},
|
||
rows: { baseline: base.rows, evolved: evo.rows },
|
||
};
|
||
fs.writeFileSync(path.join(__dirname, "benchmark.report.json"), JSON.stringify(report, null, 2));
|
||
|
||
const realRows = realAnalyses
|
||
.map((a) => `| ${a.id} | ${f(a.region.fluid)} | ${f(a.region.fat)} | ${f(a.region.softTissue)} | ${f(a.region.bone)} | ${f(a.domainGap)} | **${a.classification}** |`)
|
||
.join("\n");
|
||
|
||
const md = `# MetaBioHacker reconstruction benchmark
|
||
|
||
Frozen engine: \`sonic_ct_serve\`. Only the harness config differs between rows.
|
||
Reports are split so reconstruction **speed** is never conflated with real
|
||
anatomical **fidelity**.
|
||
|
||
## 1. Synthetic phantom benchmark
|
||
|
||
Statistics over ${base.summary.shape.n} reproducible synthetic phantoms (mean ± 95% CI).
|
||
|
||
| Config | Dice (95% CI) | Acoustic residual | Latency (ms) |
|
||
|--------|---------------|-------------------|--------------|
|
||
| baseline | ${f(base.summary.shape.mean)} ± ${f(base.summary.shape.ci95)} | ${f(base.summary.residual.mean)} | ${base.summary.latency.mean.toFixed(0)} |
|
||
| evolved | ${f(evo.summary.shape.mean)} ± ${f(evo.summary.shape.ci95)} | ${f(evo.summary.residual.mean)} | ${evo.summary.latency.mean.toFixed(0)} |
|
||
|
||
**Evolved vs baseline:** Dice ${dShape >= 0 ? "+" : ""}${dShape.toFixed(1)}%, **latency ${dLatency.toFixed(1)}% faster**, residual ${dResidual >= 0 ? "−" : "+"}${Math.abs(dResidual).toFixed(1)}%.
|
||
|
||
## 2. Real public slice benchmark (region-level)
|
||
|
||
Real CT slices (Wikimedia Commons, fetched on demand, not committed) are
|
||
calibration targets — **not** ultrasound-CT. Intensity is banded into the five
|
||
acoustic classes as a proxy ground truth. Region-level Dice + a domain-gap score
|
||
gate headline inclusion.
|
||
|
||
| Slice | fluid | fat | soft tissue | bone | domain gap | inclusion |
|
||
|-------|-------|-----|-------------|------|-----------|-----------|
|
||
${realRows || "| (none fetched) | | | | | | |"}
|
||
|
||
Domain gap < 0.30 → headline · 0.30–0.60 → research only · > 0.60 → excluded.
|
||
|
||
## 3. Governance & safety benchmark
|
||
|
||
- Acoustic residual is invariant to multimodal/contradiction layers (physics frozen).
|
||
- Pathology/biopsy/Pap/HPV/cytology force human review.
|
||
- User-facing claims require ruvn evidence grade **A/B** with citations (acoustic USCT grades **C → research-only**).
|
||
- Reconstruction run ledgers verify end-to-end (tamper-evident).
|
||
|
||
## Headline (honest wording)
|
||
|
||
> The Darwin-evolved reconstruction harness achieved about **${dLatency.toFixed(0)}% faster runtime at equal synthetic-phantom Dice**.
|
||
> On real public CT slices, Dice remained **research stage (~${f(evo.summary.realShape.mean)})**, showing the expected domain
|
||
> gap between controlled acoustic phantoms and real anatomical images.
|
||
> No diagnostic claims are emitted; the multimodal layer only adjusts priors, uncertainty, routing, and review state.
|
||
`;
|
||
fs.writeFileSync(path.join(__dirname, "..", "..", "docs", "sonic-ct", "BENCHMARK.md"), md);
|
||
console.log(`\nreal slices: ${realAnalyses.map((a) => `${a.id}=${a.classification}`).join(", ") || "none"}`);
|
||
console.log(`reports -> benchmark.report.json + docs/sonic-ct/BENCHMARK.md`);
|