mirror of
https://github.com/ruvnet/RuVector.git
synced 2026-07-19 06:03:45 +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>
338 lines
15 KiB
JavaScript
338 lines
15 KiB
JavaScript
// MetaBioHacker harness optimizer — Darwin Mode for acoustic reconstruction.
|
|
//
|
|
// Principle (Meta Harness / @metaharness/darwin): "freeze the model, evolve the
|
|
// harness." The FROZEN MODEL is the Rust acoustic engine (sonic_ct → WASM); we
|
|
// never change the physics. We evolve the RECONSTRUCTION HARNESS: what is
|
|
// reconstructed, how it is routed (cheap → frontier), and how it is scored.
|
|
//
|
|
// Darwin's `evolve()` is its code-surface evolver (it mutates harness *source
|
|
// files* against a task sandbox, for LLM agent harnesses). For our numeric
|
|
// genome we keep the same invariant — genome -> run frozen engine -> scored
|
|
// candidate -> Pareto frontier — using Darwin's `mapLimit` (bounded-concurrency
|
|
// evaluation) and `paretoFront` (multi-objective selection) primitives.
|
|
//
|
|
// Run: npm run optimize
|
|
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { mapLimit, paretoFront } from "@metaharness/darwin";
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
|
// ---- frozen model: load the WASM acoustic engine once ----------------------
|
|
const bytes = fs.readFileSync(path.join(__dirname, "public", "sonic_ct.wasm"));
|
|
const { instance } = await WebAssembly.instantiate(bytes, {});
|
|
const e = instance.exports;
|
|
|
|
// Simulated economics of the model-routing tier (compute arbitrage).
|
|
const FRONTIER_COST_USD = 0.003;
|
|
const FRONTIER_LATENCY_MS = 400;
|
|
const CHEAP_COST_USD = 0.0002;
|
|
|
|
// OpenRouter LLM frontier-mutator config (the "write layer" that proposes
|
|
// harness policy mutations). Bounded so cost stays trivial; falls back to the
|
|
// deterministic random mutator when the key is absent or a call fails.
|
|
const OPENROUTER_KEY = process.env.OPENROUTER_API_KEY || "";
|
|
const CHEAP_MODEL = "openai/gpt-4o-mini";
|
|
const FRONTIER_MODEL = "openai/gpt-4o";
|
|
const LLM_BUDGET = 10; // hard cap on total LLM calls per run
|
|
let llmCalls = 0;
|
|
|
|
async function llmProposeMutation(parent, evalResult, useFrontier) {
|
|
if (!OPENROUTER_KEY || llmCalls >= LLM_BUDGET) return null;
|
|
const model = useFrontier ? FRONTIER_MODEL : CHEAP_MODEL;
|
|
const sys =
|
|
"You evolve the reconstruction HARNESS of an ultrasound-CT engine. The physics engine is FROZEN — never change it. " +
|
|
"Propose ONE mutation to the reconstruction genome to improve temporal stability and shape score while keeping latency, cost, " +
|
|
"acoustic residual, and frontier model-calls low. Reply with ONLY a JSON object for the `reconstruction` field: " +
|
|
'{"voxelResolutionMm":number 3-7.5,"temporalWindowMs":number 20-120,"smoothing":"none|light|medium",' +
|
|
'"organPrior":"none|atlas|ghostBody","confidenceThreshold":number 0.2-0.85,"elements":int 48-280,"fan":int 24-200}.';
|
|
const user = JSON.stringify({ current: parent.reconstruction, lastScores: evalResult });
|
|
try {
|
|
llmCalls++;
|
|
const resp = await fetch("https://openrouter.ai/api/v1/chat/completions", {
|
|
method: "POST",
|
|
headers: { Authorization: `Bearer ${OPENROUTER_KEY}`, "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
model,
|
|
messages: [{ role: "system", content: sys }, { role: "user", content: user }],
|
|
max_tokens: 220,
|
|
temperature: 0.7,
|
|
response_format: { type: "json_object" },
|
|
}),
|
|
});
|
|
if (!resp.ok) return null;
|
|
const data = await resp.json();
|
|
const txt = data?.choices?.[0]?.message?.content;
|
|
if (!txt) return null;
|
|
const r = JSON.parse(txt);
|
|
// Validate + clamp the proposed genome before it can be evaluated.
|
|
const child = structuredClone(parent);
|
|
const c = child.reconstruction;
|
|
if (Number.isFinite(r.voxelResolutionMm)) c.voxelResolutionMm = clampF(r.voxelResolutionMm, 3.0, 7.5);
|
|
if (Number.isFinite(r.temporalWindowMs)) c.temporalWindowMs = clampF(r.temporalWindowMs, 20, 120);
|
|
if (SMOOTHINGS.includes(r.smoothing)) c.smoothing = r.smoothing;
|
|
if (PRIORS.includes(r.organPrior)) c.organPrior = r.organPrior;
|
|
if (Number.isFinite(r.confidenceThreshold)) c.confidenceThreshold = clampF(r.confidenceThreshold, 0.2, 0.85);
|
|
if (Number.isFinite(r.elements)) c.elements = clamp(Math.round(r.elements), 48, 280);
|
|
if (Number.isFinite(r.fan)) c.fan = clamp(Math.round(r.fan), 24, 200);
|
|
child._origin = useFrontier ? "llm-frontier" : "llm-cheap";
|
|
return child;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Reconstruction genome (the evolved harness). The acoustic engine stays frozen.
|
|
// ---------------------------------------------------------------------------
|
|
const FOV_MM = 240;
|
|
|
|
function baselineGenome() {
|
|
return {
|
|
acousticEngine: { frozen: true, binary: "sonic_ct.wasm" },
|
|
reconstruction: {
|
|
voxelResolutionMm: 4.3, // -> grid n ~ 56
|
|
temporalWindowMs: 70, // -> nz ~ 18
|
|
smoothing: "light", // -> SART iters
|
|
organPrior: "atlas",
|
|
confidenceThreshold: 0.55,
|
|
elements: 180,
|
|
fan: 90,
|
|
},
|
|
modelRouting: {
|
|
firstPass: "local",
|
|
escalation: "frontier",
|
|
frontierOnlyWhen: { lowConfidence: true, inconsistentFrames: true, userRequestedExplanation: false },
|
|
},
|
|
scoring: {
|
|
weightShapeConsistency: 1.0,
|
|
weightAcousticResidual: 1.0,
|
|
weightLatency: 0.5,
|
|
weightCost: 0.5,
|
|
weightSafety: 1.0,
|
|
},
|
|
};
|
|
}
|
|
|
|
const SMOOTHING_ITERS = { none: 3, light: 6, medium: 10 };
|
|
const PRIOR_BONUS = { none: 0.0, atlas: 0.02, ghostBody: 0.035 };
|
|
|
|
// Decode genome -> frozen-engine parameters.
|
|
function decode(g) {
|
|
const r = g.reconstruction;
|
|
const n = clamp(Math.round(FOV_MM / r.voxelResolutionMm), 32, 96);
|
|
const nz = clamp(Math.round(((r.temporalWindowMs - 20) / 100) * 20 + 8), 6, 28);
|
|
const iters = SMOOTHING_ITERS[r.smoothing] ?? 6;
|
|
return { n, nz, iters, elements: clamp(Math.round(r.elements), 48, 280), fan: clamp(Math.round(r.fan), 24, 200) };
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Evaluate a genome against the frozen engine -> EvalResult.
|
|
// ---------------------------------------------------------------------------
|
|
function evaluate(g, { seeds }) {
|
|
const p = decode(g);
|
|
const r = g.reconstruction;
|
|
let shapeSum = 0, residualSum = 0, stabilitySum = 0, frontierCalls = 0, wall = 0;
|
|
const flags = [0, 0, 0, 0];
|
|
|
|
for (const seed of seeds) {
|
|
const t0 = performance.now();
|
|
e.sct_vol_begin(p.nz, p.n, p.elements, Math.min(p.fan, p.elements - 1), p.iters, seed);
|
|
while (e.sct_vol_step() < p.nz) {}
|
|
wall += performance.now() - t0;
|
|
|
|
const meanDice = e.sct_vol_mean_dice();
|
|
const sliceDice = new Float32Array(e.memory.buffer, e.sct_vol_slice_dice_ptr(), p.nz).slice();
|
|
const sliceMae = new Float32Array(e.memory.buffer, e.sct_vol_slice_mae_ptr(), p.nz).slice();
|
|
|
|
// Shape score gets a small, bounded organ-prior bonus (priors guide
|
|
// labelling without touching the physics).
|
|
shapeSum += Math.min(1, meanDice + (PRIOR_BONUS[r.organPrior] ?? 0));
|
|
|
|
// Acoustic residual: mean speed MAE normalised by the speed window.
|
|
residualSum += mean(sliceMae) / 1700;
|
|
|
|
// Temporal stability: 1 - normalised stddev of per-slice Dice.
|
|
stabilitySum += clamp(1 - std(sliceDice) / 0.25, 0, 1);
|
|
|
|
// Cheap->frontier routing: the local Rust reconstruction always runs; the
|
|
// frontier model only fires on low-confidence slices (per the routing
|
|
// policy) and never overrides physics — it proposes a policy mutation.
|
|
if (g.modelRouting.frontierOnlyWhen.lowConfidence) {
|
|
frontierCalls += sliceDice.filter((d) => d < r.confidenceThreshold).length;
|
|
}
|
|
for (let i = 0; i < 4; i++) flags[i] = Math.max(flags[i], e.sct_quality_flag(i));
|
|
}
|
|
const k = seeds.length;
|
|
const frontier = Math.round(frontierCalls / k);
|
|
// Safety: penalised by high-severity quality flags (bone shadow, sparse
|
|
// coverage, boundary uncertainty); research-only invariant is structural.
|
|
const sevPenalty = flags.reduce((a, s) => a + s, 0) / (4 * 2);
|
|
return {
|
|
shapeScore: shapeSum / k,
|
|
acousticResidual: residualSum / k,
|
|
temporalStability: stabilitySum / k,
|
|
latencyMs: wall / k + frontier * FRONTIER_LATENCY_MS,
|
|
costUsd: frontier * FRONTIER_COST_USD + (p.nz * CHEAP_COST_USD),
|
|
safetyScore: clamp(1 - sevPenalty, 0, 1),
|
|
frontierCalls: frontier,
|
|
};
|
|
}
|
|
|
|
// Multi-objective vector for paretoFront (it maximises every component, so
|
|
// minimised objectives are negated).
|
|
function objectives(s) {
|
|
return [s.shapeScore, s.temporalStability, s.safetyScore, -s.acousticResidual, -s.latencyMs, -s.costUsd];
|
|
}
|
|
|
|
// Scalar fitness for ranking within a generation (weighted; selection itself
|
|
// uses the Pareto frontier).
|
|
function scalar(s, w) {
|
|
return (
|
|
w.weightShapeConsistency * s.shapeScore +
|
|
w.weightSafety * s.safetyScore +
|
|
0.5 * s.temporalStability -
|
|
w.weightAcousticResidual * s.acousticResidual -
|
|
w.weightLatency * (s.latencyMs / 5000) -
|
|
w.weightCost * (s.costUsd / 0.1)
|
|
);
|
|
}
|
|
|
|
// ---- genome mutation -------------------------------------------------------
|
|
const SMOOTHINGS = ["none", "light", "medium"];
|
|
const PRIORS = ["none", "atlas", "ghostBody"];
|
|
const clampF = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
|
|
function clamp(v, lo, hi) { return Math.max(lo, Math.min(hi, v)); }
|
|
const jitter = (a) => a + (Math.random() * 2 - 1);
|
|
const pick = (arr) => arr[Math.floor(Math.random() * arr.length)];
|
|
|
|
function mutate(g) {
|
|
const n = structuredClone(g);
|
|
const r = n.reconstruction;
|
|
r.voxelResolutionMm = clampF(jitter(r.voxelResolutionMm), 3.0, 7.5);
|
|
r.temporalWindowMs = clampF(r.temporalWindowMs + (Math.random() * 30 - 15), 20, 120);
|
|
if (Math.random() < 0.4) r.smoothing = pick(SMOOTHINGS);
|
|
if (Math.random() < 0.3) r.organPrior = pick(PRIORS);
|
|
r.confidenceThreshold = clampF(r.confidenceThreshold + (Math.random() * 0.2 - 0.1), 0.2, 0.85);
|
|
r.elements = clamp(Math.round(r.elements + (Math.random() * 60 - 30)), 48, 280);
|
|
r.fan = clamp(Math.round(r.fan + (Math.random() * 40 - 20)), 24, 200);
|
|
return n;
|
|
}
|
|
|
|
// ---- helpers ---------------------------------------------------------------
|
|
const mean = (a) => (a.length ? a.reduce((x, y) => x + y, 0) / a.length : 0);
|
|
const std = (a) => {
|
|
const m = mean(a);
|
|
return Math.sqrt(mean(a.map((x) => (x - m) ** 2)));
|
|
};
|
|
|
|
// ---- Darwin Mode evolution -------------------------------------------------
|
|
const POP = 10, GENERATIONS = 6, ELITE = 4;
|
|
const CHEAP = { seeds: [1] };
|
|
const FRONTIER = { seeds: [1, 2, 3] };
|
|
|
|
const baseline = baselineGenome();
|
|
let population = [baseline, ...Array.from({ length: POP - 1 }, () => mutate(baseline))];
|
|
let best = null;
|
|
const archive = []; // every frontier-scored variant (Darwin keeps an archive)
|
|
const history = [];
|
|
|
|
console.log("== MetaBioHacker · Darwin harness optimizer ==");
|
|
console.log("frozen model: sonic_ct WASM | evolving reconstruction + routing + scoring genome\n");
|
|
|
|
for (let gen = 0; gen < GENERATIONS; gen++) {
|
|
// Tier 1 — cheap filter (bounded concurrency via Darwin mapLimit).
|
|
const cheap = await mapLimit(population, 1, async (g) => ({ g, s: evaluate(g, CHEAP) }));
|
|
cheap.sort((a, b) => scalar(b.s, b.g.scoring) - scalar(a.s, a.g.scoring));
|
|
|
|
// Tier 2 — frontier re-evaluation of survivors.
|
|
const scored = await mapLimit(cheap.slice(0, ELITE), 1, async ({ g }) => ({ g, s: evaluate(g, FRONTIER) }));
|
|
|
|
archive.push(...scored);
|
|
// Darwin Pareto frontier across accuracy / latency / cost / safety.
|
|
const front = paretoFront(scored, ({ s }) => objectives(s));
|
|
const winner = scored.reduce((a, b) => (scalar(b.s, b.g.scoring) > scalar(a.s, a.g.scoring) ? b : a));
|
|
if (!best || scalar(winner.s, winner.g.scoring) > scalar(best.s, best.g.scoring)) best = winner;
|
|
|
|
history.push({ gen, winner: summarize(winner), frontSize: front.length });
|
|
console.log(
|
|
`gen ${gen}: shape ${winner.s.shapeScore.toFixed(3)} stab ${winner.s.temporalStability.toFixed(3)} ` +
|
|
`lat ${winner.s.latencyMs.toFixed(0)}ms $${winner.s.costUsd.toFixed(4)} frontier ${winner.s.frontierCalls} · pareto ${front.length}`
|
|
);
|
|
|
|
const elites = scored.map((x) => x.g);
|
|
const next = [...elites];
|
|
|
|
// Cheap -> frontier routing: the LLM "write layer" proposes harness mutations
|
|
// for the best elite. The frontier model fires only when low-confidence slices
|
|
// were detected (frontierCalls > 0); otherwise the cheaper model is used.
|
|
const top = scored[0];
|
|
const lowConfidence = top.s.frontierCalls > 0;
|
|
const useFrontier = top.g.modelRouting.escalation === "frontier" && lowConfidence;
|
|
for (let k = 0; k < 2 && next.length < POP; k++) {
|
|
const child = await llmProposeMutation(top.g, top.s, useFrontier && k === 0);
|
|
if (child) next.push(child);
|
|
}
|
|
while (next.length < POP) next.push(mutate(pick(elites)));
|
|
population = next;
|
|
}
|
|
|
|
// ---- acceptance test (searched over the whole archive) ---------------------
|
|
const base = evaluate(baseline, FRONTIER);
|
|
const gate = (s) => {
|
|
const stabilityGain = (s.temporalStability - base.temporalStability) / Math.max(base.temporalStability, 1e-6);
|
|
const latencyGain = (base.latencyMs - s.latencyMs) / Math.max(base.latencyMs, 1e-6);
|
|
const noRegress =
|
|
s.acousticResidual <= base.acousticResidual + 1e-6 &&
|
|
s.safetyScore >= base.safetyScore - 1e-6 &&
|
|
s.frontierCalls <= base.frontierCalls;
|
|
return { stabilityGain, latencyGain, noRegress, passed: noRegress && (stabilityGain >= 0.1 || latencyGain >= 0.2) };
|
|
};
|
|
|
|
// A Pareto-superior, gate-passing variant is the acceptance target. Among
|
|
// passers prefer the largest combined stability+latency improvement.
|
|
const passers = archive
|
|
.map((x) => ({ x, g: gate(x.s) }))
|
|
.filter((e) => e.g.passed)
|
|
.sort((a, b2) => b2.g.stabilityGain + b2.g.latencyGain - (a.g.stabilityGain + a.g.latencyGain));
|
|
|
|
const accepted = passers[0]?.x ?? best;
|
|
const acc = gate(accepted.s);
|
|
const passed = !!passers.length;
|
|
best = accepted;
|
|
|
|
console.log("\n-- acceptance test (over archive) --");
|
|
console.log(`candidates evaluated: ${archive.length} | gate-passing: ${passers.length}`);
|
|
console.log(`accepted: stability gain ${(acc.stabilityGain * 100).toFixed(1)}% | latency gain ${(acc.latencyGain * 100).toFixed(1)}% | no-regress ${acc.noRegress}`);
|
|
console.log(passed ? "PASS — Pareto-superior harness found (freeze model, evolve harness)" : "no gate-passing variant this run");
|
|
const stabilityGain = acc.stabilityGain;
|
|
const latencyGain = acc.latencyGain;
|
|
const noRegress = acc.noRegress;
|
|
|
|
console.log(`LLM frontier-mutator calls: ${llmCalls}${OPENROUTER_KEY ? "" : " (no OPENROUTER_API_KEY — random mutator only)"}`);
|
|
|
|
const report = {
|
|
tool: "metaharness/darwin",
|
|
philosophy: "freeze the model, evolve the harness",
|
|
frozenModel: "sonic_ct WASM acoustic engine",
|
|
primitivesUsed: ["mapLimit", "paretoFront"],
|
|
writeLayer: { provider: "openrouter", cheapModel: CHEAP_MODEL, frontierModel: FRONTIER_MODEL, llmCalls, budget: LLM_BUDGET },
|
|
baseline: { genome: baseline, eval: base },
|
|
evolved: summarize(best),
|
|
acceptance: { stabilityGain, latencyGain, noRegress, passed },
|
|
history,
|
|
};
|
|
fs.writeFileSync(path.join(__dirname, "optimize.report.json"), JSON.stringify(report, null, 2));
|
|
console.log(`\nreport -> ${path.join(__dirname, "optimize.report.json")}`);
|
|
|
|
function summarize(x) {
|
|
return {
|
|
origin: x.g._origin || "seed/random",
|
|
reconstruction: x.g.reconstruction,
|
|
routing: x.g.modelRouting,
|
|
eval: x.s,
|
|
engineParams: decode(x.g),
|
|
};
|
|
}
|