Loki Labs ← All papers

The Field Compiler

Replicator software RSW-1 — a native macOS slicer whose output is boundary field states, and whose viewport is the RH-1 build volume with the whole machine running on the GPU: scanning real objects, and growing new ones out of feedstock.

v0.8 · 2026-07-27 · supersedes v0.2 (browser / WebGPU / sphere-first). Part 0 = what changed. Part I = concepts. Part II = the end state (what "done" looks like). Part III = the build specification. Part IV = the test harness — load-bearing, not an appendix. Part V = milestones and gates. Part VI = register.
v0.4 additions (same day, after an open-source survey and a round of benchmarking on the target machine): the three-layer epistemic viewport and the Machine View reconstruction renderer (§16.2–16.3); the T0.5 BEM and T1f CBS solver tiers (§5); AcousTools adopted as the validation twin in place of a hand-rolled one (§8); and learned components ruled on — mostly rejected, with evidence (§17).
v0.5 (operator review, same day): the four-way diversity budget — what can and cannot enlarge what the machine knows, including adaptive selection as policy not source, and detail-adaptive chord budgeting (§16.3); measured/inferred provenance on every chord and reconstruction, enforced in the schema and by gate G17 (§16.3, §19); and §18 rewritten — multi-bounce virtual apertures ranked first because the machine measures its own cavity.
v0.6 (operator ruling, same day): zero moving parts is Plan A. The turntable is removed from the plan entirely rather than demoted; G18 is rewritten around held-out gate/frequency prediction (a wrong Green's function cannot predict a measurement it was not fitted to), and G19 adds a static machined phantom for absolute accuracy (§18).

One-line north star. Drag in an STL, pick a material, press Build — and watch matter leave the cartridge, rise through the bore, and settle into the object inside a 280 × 300 mm cylinder, in real time, on the GPU. Press Scan instead and the same machine runs backwards: an object in the chamber becomes a .pattern file. Every pixel of that is a simulation today and a hardware backend later, with no rewrite in between.

Part 0 — What changed from v0.2, and why

0 · Three reversals

 v0.2 (2026-07-21)v0.3 (this document)why
platform Browser app; React + TS + Tailwind; WebGPU/WGSL; handed to a Lovable builder session Native macOS app. Swift 6 + SwiftUI + Metal, built with SwiftPM. Single window, single process, plus a fieldc CLI that links the same core The matter layer is the product, and it is not a browser workload. Four GPU tiers must share buffers with the renderer with zero readback and no 4 GB / workgroup / storage-buffer ceilings; the particle and occupancy state must live in unified memory beside the field. Native also buys the one thing v0.2 had no answer for — a headless screenshot path (§16)
geometry The ideal KOSMOS sphere (Rc = 200 mm, Goldberg screen at 150 mm). "RH-1 cylindrical geometry is a later config preset, not v0" The RH-1 cylinder is the default preset and the product surface. The sphere survives as sphere-v0, a validation-only preset whose sole job is to keep the analytic Mie gate runnable A slicer's viewport is its build volume; you cannot ship a slicer for a cylinder that shows a sphere. Keeping the sphere as a gate fixture costs one preset and preserves the acceptance discipline — no gate is weakened, one is relocated
scope "v0 is the converter": import → emulated scan → .pattern. Gor'kov particle layer deferred to M6+ The matter layer is in scope from M4. Radiation force, particle transport, melt, solidification, and a growing occupancy volume are first-class Because that is the request, and because the machine's own doctrine demands it: KOSMOS §8 mandates a twin of "acoustic FEM + thermal + particle dynamics" so the machine is "sized, not guessed," and every force, pressure, trap-stiffness and weld-power number in the corpus is deferred to "a number the digital twin pins." This app is where that debt gets paid
Honest inventory before we start. A survey of the repo found that the acoustic side of the twin does not exist yet, in text or in code: there is no acoustic forward model, no Gor'kov evaluator, no phase-retrieval solver, and no force or pressure number anywhere in lpoh/ or papers/ — not one Pa, not one mN. The only propagator ever written down is the discrete Kirchhoff–Helmholtz monopole sum in lpoh/sims/S3_e_screen_renders_bulk.py, explicitly labelled "a stated convention, not a claim." What does exist is ~2,400 lines of real algorithm in the v0.2 web build (resonance-weaver): FDTD in WGSL, matrix pencil, Goldberg tessellation, voxelizer, Mie, STL import. Those are the port source; everything in §§10–13 below is new work. Say so in commit messages; do not let the spec's confidence read as existing capability.

Part I — Concepts

1 · What this software is

A 3D-printer slicer converts geometry into toolpaths because its tool is a point. The Replicator's tool is the entire boundary field, so this compiler converts geometry into time-sequences of boundary drive states — and, in reverse, converts measured boundary responses into stored object patterns. One architectural law governs everything:

The emulator API is the hardware API. All physics targets an abstract gated machine; whether frames are consumed by the GPU wave emulator or by physical electronics is a backend swap. The product is real software from day one: a converter and simulator now, the control stack later, no rewrite.

The unfamiliar part is that a slicer for this machine must simulate its own output to be useful at all. A FDM slicer can emit G-code without modelling plastic, because a nozzle's effect is local and obvious. A boundary field's effect is global and non-obvious — you cannot look at 24 complex drive amplitudes and know what shape they mold. The emulator is not a preview feature bolted onto the compiler; it is the compiler's error function. That is why the four solver tiers of §§10–13 carry as much of this document as the UI does.

2 · The machine model — eight faces, gated

RH-1 is a cylinder because its work happens between two circular boundary plates. The mechanical paper models it as eight active faces of a would-be shell — between the "6" and "12" rungs of the boundary ladder:

surfacencarrierrole
circular caps (top & bottom)2EM microwave toroidal-pulse launch + super-resolution sensing; each holds the Ø80 bore, the bore winding, and the optical sightline — the axis
back-wall phononic panels6acoustic force and momentum: holds, moves, sculpts matter — the only channel with real force-per-watt — the equator
front glass (rotating door)1 the one uncommanded face; passive, but its rotation adds aperture diversity to the scan
base bay1 generation only; no field elements

The mnemonic the hardware spec fixes, and which the UI should teach without a tutorial: sound is the muscle, microwave is the ears and the axial drive, light is the fingertip and the eyes, the bore winding is the experiment.

Above the physical surfaces sits the abstract machine the compiler actually targets. At any frequency f, machine–object interaction is completely described by the scattering matrix S(f): drive vector a in (each component = amplitude and phase at one gate — a chord), response b = S(f)·a out. For the canonical 12-gate abstraction, reciprocity leaves 78 independent complex entries. Everything the machine can learn about an object through its gates is S(f).

Three special drive states give physical intuition and, later, scan strategy: zeros of S — drives the object completely absorbs (coherent perfect absorption; the field "hugs" the object and nothing echoes); eigenvectors of S — patterns scattered back into themselves, changed only in phase (characteristic modes); poles of S — the object's ring-down resonances, its acoustic fingerprint.

The gate count is a preset, not a constant. RH-1's physical channels are 24 acoustic (6 panels × 4 PMN-PT drivers) + 12 modal EM ports per cap (6 cone-modes × I/Q). The abstract 12-gate machine of the boundary ladder is a different 12 from LPOH's 12 icosahedral transducers, which is a different 12 again from the Goldberg screen's 12 Euler-forced pentagons. The app must therefore carry gate count and gate geometry as machine-preset data, never as a hard-coded 12. This has bitten this document family before.

3 · Chords — the format that replaces STL

Causality makes S(f) an analytic function of frequency, hence determined by its discrete resonances. The compressed, physical, machine-native representation of an object is therefore the chord list:

chord[k] = ( complex frequency p_k , port-vector r_k )
#  where the object rings, and the gate pattern that
#  addresses that ringing.  ~100 bytes per chord.

Properties: resolution = number of chords stored (ordered by contribution; progressive streaming — objects sharpen as chords arrive); .pattern (scan output) and .fcode (build input) share this alphabet — the scanner measures chords, the builder plays them; and the format stores what triangles cannot: response = geometry + material + interior in one object. Known caveat, handled: bare eigenfrequency lists have rare "isospectral drum" ambiguities; port-vectors add the spatial information that breaks them.

4 · Call and response

The unifying operational picture: scan is call-and-response; build is call-and-response run until the response matches.

Two consequences the software must reflect. The build verifies itself continuously — listening is mW-class and always on, so every instant of fabrication is also a scan, and the UI should never present "build" and "inspect" as disjoint modes with a wall between them. And feedback beats open-loop fidelity: the machine needs to recognize the target ring, not to possess a perfect forward model. That is the luthier's method (tap-tuning plates to target tones) and industrial resonant-ultrasound QC, made exact.

Throughput = bandwidth, with one hard limit: a resonance of quality factor Q at frequency f takes ~Q/f to ring up or resolve — no electronics outruns the ring. The win is parallelism across the band. Acoustic ~10⁵/s across a 100 kHz band; EM ~10⁹⁺/s across GHz bands. Hence the loop's natural role split: acoustic builds, EM verifies — matter-moving chords are acoustic and slow; the EM octaves listen at ~10⁴× the rate.

5 · Solver tiers, because one solver cannot be both true and fast

This is the single most important architectural decision in the document. The naive design — one FDTD, used for everything — fails on arithmetic. FDTD in this chamber at 40 kHz is ~8 M cells and ~1 µs timesteps; a single 40 ms capture is ~30k steps, tens of seconds of wall clock. A viewport that updates when you drag a slider needs milliseconds. Those are not the same program.

tiermodelcostused for
T0 — propagator Rayleigh–Sommerfeld / angular-spectrum monopole sum over surface elements. A dense linear operator H: drive → complex field ~ms the interactive viewport; the forward model inside the inverse solver; trap placement; everything you touch with a slider
T0.5 — BEM (added v0.4) Boundary-element scattering off the workpiece. For a rigid scatterer in air only the surface is unknown, so the problem is orders smaller than a volume solve ~0.1–2 s The missing middle. T0 ignores scattering; T1 is too slow to iterate. T0.5 is scattering-aware and still interactive-ish — it is what the compile loop should actually run against
T1 — FDTD Staggered-grid linear acoustic FDTD with a sponge layer. Scattering, transients, ring-down, material interiors ~10–60 s/run scan runs, S(f) assembly, and the truth against which T0 and T0.5 are validated (gate G5). Time-domain is mandatory here: the matrix pencil eats ring-down, which a frequency-domain solver cannot produce
T1f — CBS (added v0.4, optional) Convergent Born Series in the frequency domain — matrix-free, FFT-based ~1–4 s Steady state at one frequency does not need 3,500 timesteps. Measured on the target machine: a 200³ complex FFT pair is 34.6 ms, so 30 iterations ≈ 1.0 s — 13–45× faster than T1, converged and exact. Caveat: CBS convergence degrades with impedance contrast, and rigid-in-air (~10³) is the worst case — which is exactly why T0.5 BEM is listed above it
T2 — matter Gor'kov radiation potential + drag + gravity; GPU particle integration ~ms/frame levitation, traps, droplet transport, the build's visible motion
T3 — consolidation Lumped-capacity thermal per particle; melt/wet/latch; occupancy grid; surface extraction ~ms/frame the object appearing; build progress; inspect-vs-target diff

T0 and T1 are the same physics at different fidelity, and they are wired together by an acceptance gate rather than by faith: G5 requires T0's field to match T1's steady state inside the build volume to better than 5% relative L2. When that gate holds, the interactive tier is trustworthy; when it breaks, the UI is lying and the build fails loudly.

Part II — The end state

6 · What "done" looks like

Written as a walkthrough, because that is the specification most likely to be read correctly. Nothing below is aspirational framing; each numbered step maps to a milestone in §20.

  1. Open. A dark instrument-panel window. Centre: the RH-1 machine, drawn honestly — two Ø300 caps 300 mm apart with their 12-arm spiral gratings and Ø80 bores, six hex-screened phononic panels standing at r = 155 across the back, seven dark columns between them, the front glass a faint arc you can rotate open. A translucent cylinder — Ø280 × 300 mm — marks the build volume, ticked and gridded. Nothing else. This is the empty-state screenshot and it should be good enough to put on a slide.
  2. Import. Drop in an STL. It lands centred on the deck, scaled and clamped to the cylinder, with the out-of-bounds indicator a slicer user already understands. Assign a material from the preset list. The left rail behaves like a slicer's object list because it is one.
  3. Compile. Press Compile. The inverse solver (§14) turns the target volume into a schedule of boundary drive states: per-channel, per-band complex amplitudes with a verb (ADD / REMOVE) and RX gates. Progress is shown as the residual of the phase-retrieval loop, not a fake bar. Output is a .fcode file — the artifact this whole program exists to produce.
  4. Watch the field. The Field overlay draws a slice of |p| through the build volume, log-compressed, with the Gor'kov trap set marked. Drag the slice plane; it updates at frame rate because T0 is doing it. This is where a user develops intuition about what a boundary can and cannot mold — the thing no amount of documentation conveys.
  5. Build. Press Build and the transport bar comes alive. Particles leave the cartridge, rise through the lower bore, get caught by traps, migrate to nodes, glow as they pass the heat stage, wet onto their neighbours, and latch. The occupancy volume fills; a marching-cubes surface thickens inside the ghost of the target mesh. Build percentage is real — latched voxels over target voxels — and so is the overspill number beside it. You can scrub back and forth over the whole sequence.
  6. It listens while it builds. The S(f) error curve runs along the bottom the entire time. The build is done when the object rings true, not when the frame counter runs out. That curve is the same metric the verify module reports, which is the same metric the acceptance gate reads — one number, three consumers.
  7. Scan. Switch to Scan with a real object in the emulated chamber. The machine runs its power-up sequence — self-calibration (every element pings every other; the TX→RX identity matrix is measured), coupling-lock, cavity ring-up — with the column light strips reporting each stage, exactly as the hardware will. Then 12 or 24 coded runs, S(f) assembly against the cached empty-chamber reference, matrix-pencil extraction, and a .pattern file. Chords stream in and the reconstruction sharpens as they arrive.
  8. Copy. Scan → pattern → viewport → build. The loop closes inside one application, with no hardware in the room.
  9. Swap the backend. The MachineBackend protocol has two implementations: Emulated (the four tiers) and Serial (frames to an RP2350 over USB). The same .fcode drives both. On the day hardware exists, the app does not change — a picker in the machine panel changes.
  10. Prove it, in one image. fieldc shot --contact-sheet renders every screen of the application, both themes, into a single labelled PNG. That is how a session — human or agent — checks the whole UI in one look. See Part IV; this is not a nice-to-have.

7 · Non-goals for v1

Part III — Build specification

8 · Stack and platform rulings

These were verified on the target machine (Apple M5, 10 GPU cores, macOS 26, Swift 6.2.3, Command Line Tools only — no Xcode installed) before being written down. They are rulings, not preferences.

rulingdecisionverified
platform macOS 14+. Swift 6 + SwiftUI + Metal. Built with SwiftPM (swift build), no .xcodeproj SwiftUI / Metal / MetalKit / ModelIO all import and link under the CommandLineTools SDK. A SwiftUI App compiles with swiftc -parse-as-library
shaders Written as .metal source, shipped as package resources, compiled at runtime via device.makeLibrary(source:options:) Confirmed working with no Xcode present (the offline metal compiler is unavailable; the runtime compiler is part of the OS). Two bonuses fall out: no build-system coupling, and hot-reloadable kernels — edit a .metal file, hit reload, see the field change
testing (corrected v0.6) Not XCTest. A ~60-line harness inside FieldCore/Testing, run via fieldc test XCTest ships with Xcode, which is not installed, so swift test fails with no such module 'XCTest'. Requiring a 10 GB Xcode install to run the suite would contradict the zero-dependency ruling. Verified consequence: the suite runs anywhere Swift does, including bare CI containers. An earlier draft of this spec assumed Tests/FieldCoreTests XCTest targets; that was wrong for this toolchain
dependencies Zero external packages in the shipped app. No ML framework, no numeric library, no 3D engine. SVD via Accelerate (zgesvd) or one-sided Jacobi, FFT hand-rolled, mesh loading via ModelIO. Two sanctioned code liftings, both permissive and both attributed: Inviwo (BSD-2) for the volume-raycast shaders, and Deepwave (MIT) as the reference to port PML + adjoint from Everything needed is in Foundation / simd / Accelerate / Metal / SwiftUI. Zero runtime deps means swift build works offline and the harness has nothing to mock. Writing a raycaster or a PML from scratch when a BSD-2/MIT reference exists is not craftsmanship, it is a schedule risk
the twin (revised v0.4) Do not hand-roll it. Use AcousTools (MIT, pip install acoustools, v1.1.2 2026-06-05, UCL, actively maintained) as the primary reference implementation, and k-wave-python (LGPL-3, native arm64) as the independent second oracle AcousTools is PyTorch-tensor-native and implements exactly this architecture: a free-field piston/Rayleigh propagator, a BEM scattering propagator, analytic Gor'kov gradients, and explicit propagation-matrix caching for static geometry. It is T0, T0.5 and T2 with the inverse problem attached, already published and validated. A twin I write myself is a worse oracle than one built by the group that builds these machines. LGPL note: link k-wave-python, do not transcribe it
MLX? Not in the app. MLX/Python remains the offline validation twin only (§19) The in-app hot loop is a memory-bound stencil, a scatter-gather particle push, and a dense complex matvec — three things hand-written Metal does better than any tensor framework, and which must share buffers with the render pass with no readback. The one place a tensor framework would earn its keep is the inverse solver's autodiff, and that need vanishes because T0 is linear: its adjoint is HH, exact and free (§14)
viewport One MTKView, one renderer. Field, particles, surfaces and machine geometry are drawn from the same buffers the compute passes write. No readback anywhere in the display path This is the reason the whole program is native and single-process
persistence Project files, .pattern and .fcode as JSON headers with binary Float32 payloads in a sidecar or appended blob. Documented, versioned, round-trip tested
the web build resonance-weaver becomes port source, then reference. Its matrixPencil.ts, goldberg.ts, voxelizer.ts, mie.ts, stlImport.ts, fdtd.wgsl.ts port to Swift/Metal nearly line-for-line. After M7 it is archived, not maintained in parallel ~2,400 lines of physics/scan/geom/verify/io already written and partially gated

9 · Package layout and the module map

field-compiler/
  Package.swift
  Sources/
    FieldCore/          # PURE. No AppKit, no SwiftUI, no Metal.
      Geometry/         machinePreset.swift  rh1.swift  sphereV0.swift
                        goldberg.swift  spiralGrating.swift  scene.swift
      Model/            schemas.swift  materials.swift  fcode.swift  pattern.swift
      Solvers/          propagator.swift(protocol)  fdtd.swift(protocol)
                        gorkov.swift  thermal.swift  inverse.swift
                        referenceCPU/   # small, slow, obviously-correct twins
      Scan/             scanRunner.swift  spectra.swift  matrixPencil.swift
                        chords.swift  calibration.swift
      Verify/           mie.swift  sfError.swift  energy.swift  gates.swift
      IO/               stl.swift  project.swift  receipts.swift
    FieldGPU/           # Metal. Implements the Solver protocols.
      device.swift  bufferPool.swift  kernelLibrary.swift
      propagatorGPU.swift  fdtdGPU.swift  particlesGPU.swift  occupancyGPU.swift
      Renderer/  renderer.swift  passes/  offscreen.swift
    FieldUI/            # SwiftUI. Every view is a pure function of a value struct.
      Shell/     appShell.swift  toolbar.swift  transportBar.swift
      Viewport/  viewportView.swift  overlayChips.swift  cameraController.swift
      Panels/    objectList.swift  inspector.swift  chordList.swift
                 gateReport.swift  logDrawer.swift
      Scenes/    sceneRegistry.swift   # THE screenshot registry (§16)
      Theme/     tokens.swift  dark.swift  light.swift
    FieldCompilerApp/   # @main. Target ~200 lines. Wires Core+GPU+UI. No logic.
    fieldc/             # CLI. Same core. sim|scan|compile|build|shot|film|gate|twin-export
  Shaders/              # .metal sources, shipped as resources, compiled at runtime
    propagator.metal  fdtd.metal  particles.metal  occupancy.metal  render.metal
  Tests/
    FieldCoreTests/     # unit + physics gates
    FieldUITests/       # snapshot tests
    __snapshots__/      # golden PNGs, committed
  Scripts/
    twin/               # MLX/Python validation twin (§19)
    contact_sheet.py
  Receipts/             # every gate run writes here; committed

10 · Geometry — the RH-1 preset

Cylindrical frame: z along the axis, origin at the lower plate face, z increasing upward. All mm. These are the canonical numbers from the hardware spec §3/§8 and the mechanical build sheet §10; they are the same numbers the Blender renders use, and the app should agree with those renders pixel-for-pixel in silhouette.

elementgeometry
build volume cylinder, Ø280 × 300 — r ≤ 140, z ∈ [0, 300]. This is the viewport's subject.
caps ×2 Ø300 discs (r ≤ 150) with Ø80 bores (r ≥ 40) at z = 0 and z = 300; ~20 stack thickness; mirror-imaged (opposite handedness). Lower face = base deck; upper face-down in the crown
spiral grating 12 arms at 30° increments; r(φ) = r₀·ecotα·φ; one arm sweeps r = 45 → 145 over 0.75 turn (⇒ cotα ≈ 0.2483, α ≈ 76.0°); slot widens 2.8 → 6.0 outward. Slots are voids in the conductor, not traces — get this right in the render or the caps look wrong
bore winding 44 turns toroidal at the bore rim. Inert in v1 (§7)
panels ×6 42.5 wide × 300 tall × 5 thick, at r = 155, centred in the 15.7° clear gaps of the 30°-pitch column ring. Face: graded hex phononic screen standing 0.9 proud, cells large at the bottom (low f) grading small at the top (high f) — rainbow trapping. 4 PMN-PT drivers behind each ⇒ 24 acoustic channels
columns ×7 40 tangential × 20 radial × 300 tall, at r = 160 (spanning 150–170), 30° spacing across the rear. Light strip on the inner face — this is the power-up progress indicator. All 7 carry RX strips; 3 carry service bundles
glass two 4 mm low-iron half-cylinders: rear Ø344 fixed, front Ø364 rotating outside it, detents at 0° (sealed) and 180° (open). Door state is a model property: open ⇒ drive power gated to mW listening (the Hall interlock), which the UI must enforce, not merely depict
body Ø360 × 560 overall (Ø380 over the front glass); base 180 below the deck, build 300, crown 80. Mass ≈ 14 kg
Two documented conflicts — resolve in code, and record the resolution. (1) Column section: the mechanical paper §4 says 40×40, but §10 and the hardware spec say 40×20 with an explicit CAD-correction note (a square section does not fit the 22 mm annulus between the plate rim at r=150 and the rear glass at r=172). Use 40×20; §4 is stale. (2) Azimuthal coverage: mechanical Fig. 1 says panels command ~240° and the door ~120°, while the hardware spec says the arcade spans the rear 180° (7 columns × 30° = 180°). These cannot both hold for the same parts. Build to the 180° arcade, expose the span as a preset parameter, and file the discrepancy back to the mechanical paper rather than silently picking one.

Other presets. sphere-v0: Rc = 200 mm chamber, Goldberg screen at Rs = 150 mm, 12 gates at icosahedral vertex directions (class-I geodesic, n=4, take the dual; the 12 cells dual to the original icosahedral vertices are the pentagons = the gates). Exists only so gate G4 (analytic Mie) stays runnable — a sphere is where closed-form truth lives. table-1plate: single cap, half-space, Rayleigh–Sommerfeld; the cheapest sanity preset. lpoh-icosa12: 12 transducers on the icosahedral directions (±1,±φ,0 and cyclic, normalized), ~50 mm gap — so the app can also drive the bench hardware that actually exists.

11 · T0 — the propagator

Discretize each active surface into elements of area ≤ (λ/2)². Each element e at xe with outward normal ne, area Ae, and complex drive ue contributes a Rayleigh–Sommerfeld (baffled-piston, far-from-element) term to the complex pressure at field point x:

p(x) = Σ_e  u_e · H_e(x),

H_e(x) = (i ρ₀ c₀ k A_e / 2π) · D_e(θ) · e^{ i k r } / r ,
         r = |x − x_e| ,  cosθ = (x − x_e)·n_e / r ,
         D_e(θ) = directivity;  v1 uses the circular-piston form
                        2 J₁(k a sinθ) / (k a sinθ)  with a = equivalent
                        element radius, falling back to cosθ for a ≪ λ.

Stack the He over field points and you have a dense complex matrix H of shape (Nvoxels × Nchannels), and the forward model is one matvec: p = H u. For RH-1 at 40 kHz with a 2 mm evaluation lattice over the build volume, Nvoxels ≈ 1.4 M and Nchannels = 24 → ~34 M complex MACs per evaluation: sub-millisecond on the M5, and the matrix is small enough (~270 MB at Float32 complex) to precompute and cache per (preset, frequency, lattice). That cache is what makes the viewport interactive and the inverse solver cheap.

Two exactness notes worth writing into the code as comments, because they will otherwise be rediscovered painfully. First, H is linear in u, so the adjoint needed by the inverse solver is literally HH — no autodiff, no framework, no approximation. Second, T0 knows nothing about scattering off the workpiece; it is a free-field propagator. That is exactly why G5 exists (T0 vs T1 in an empty chamber) and exactly why T1 owns the scan path (where the object is the whole point).

Velocity for Gor'kov comes from the same sum, differentiated analytically: v = −(1/iωρ₀)∇p, with ∇He in closed form. Do not finite-difference the pressure field for this — the force is a gradient of a quantity that is already a gradient, and the error compounds visibly as trap jitter.

12 · T1 — acoustic FDTD

Standard staggered-grid (Yee-style) acoustic FDTD, ported from the v0.2 WGSL kernel. Two coupled fields on the voxel grid: pressure p at cell centres, velocity v at face centres. Per-cell material arrays rho[], c2[] from the voxelizer.

v[f] −= dt/(rho_face · dx) · (p[cell+] − p[cell−])       // 3 components
p[c] −= rho[c]·c2[c]·dt/dx · ( Σ_faces v_out )        // divergence

stability : dt = 0.5 · dx / (c_max · √3)                  // CFL with margin
boundary  : cylinder wall + caps rigid (v·n = 0);
            16-cell sponge shell inside every wall,
            p,v *= exp(−σ(d)·dt), σ ramping quadratically in
            depth d — models real chamber loss and guarantees
            ring-down decays (a lossless closed cavity never stops
            ringing, and its S(f) is garbage)
source    : soft source over the active gate's element patch,
            p += A · exp(−((t−t₀)/τ)²) · sin(2π f₀ t)
record    : every step, average p over each gate patch
            → portRecord[gate][step]

Sizing, with the arithmetic shown — because this is where a design either is or is not feasible, and the number should not be a surprise at M3. Domain 340³ mm bounds the panels at r=155 plus a sponge margin. At 40 kHz, λ = 8.575 mm and dx = λ/5 = 1.715 mm → 198³ ≈ 7.8 M cells; p + 3v at Float32 = ~125 MB plus material arrays. dt = 0.5 · 1.715e−3 / (343·√3) = 1.44 µs, i.e. ~17 steps per period. An axial round trip is 0.6 m / 343 = 1.75 ms → ~1,200 steps; a 30k-step capture is ~43 ms simulated, ~25 round trips — enough ring-down for the matrix pencil. At a memory-bound ~1010 cell-updates/s that is ~45 s per run, ~10 min for a 12-run scan. Show the live field while it runs; the wait is the show.

Two sizing traps to design around, not discover. (1) CFL is set by the fastest material in the grid. Put steel (c = 5900) in the chamber and dt drops 17× — a 45-second run becomes 13 minutes. Surface this in the UI as an estimated runtime before the user presses go, and default metals to a sub-domain or to T0. (2) High bands do not fit. At the air band's 200–300 kHz ceiling, dx = 0.343 mm → ~109 cells. Full-domain FDTD is available at 20–80 kHz only; above that the app runs T0, or T1 on a bounded sub-domain around the workpiece with T0 supplying the incident field. Make this a visible, explained constraint rather than a silent quality cliff.

Material presets (ρ kg/m³, c m/s), carried forward from v0.2: air (1.204, 343), PLA (1240, 2220), aluminium (2700, 6320), steel (7850, 5900), glass (2500, 5640), water (998, 1481), rubber (1100, 1600).

13 · T2 and T3 — the matter layer

This is the new physics, the thing the corpus has been deferring to "the digital twin," and the reason the app is worth building rather than reading about.

13.1 Radiation force (Gor'kov)

For a particle of radius a ≪ λ, density ρp, sound speed cp, in a time-harmonic field with local complex amplitudes p and v, the acoustic radiation potential is (Bruus 2012 form of Gor'kov 1962):

U_rad = (4/3)πa³ [ f₁ · (½)κ₀ ⟨p²⟩ − f₂ · (¾)ρ₀ ⟨v²⟩ ]

  κ₀ = 1/(ρ₀c₀²)                  (compressibility of the medium)
  f₁ = 1 − κ_p/κ₀                  (monopole  contrast)
  f₂ = 2(ρ_p − ρ₀) / (2ρ_p + ρ₀)      (dipole    contrast)
  ⟨p²⟩ = ½|p|² ,  ⟨v²⟩ = ½|v|²   (time averages of the complex amplitudes)

  F_rad = −∇U_rad

The acoustic contrast factor Φ = f₁ + (3/2)f₂ decides the physics: Φ > 0 traps at pressure nodes (which is every solid-in-air case we care about), Φ < 0 at antinodes. Compute U on the same lattice T0 evaluates, take −∇U by central differences of the potential (which is smooth), and sample per particle with trilinear interpolation.

Convention trap in the closed form — corrected 2026-07-26, after gate G7 caught it in the implementation. For a 1-D standing wave with p = P₀ sin(kz), the correct force is
F_z = −(4/3) π a³ k E_ac Φ sin(2kz),   Φ = f₁ + (3/2)f₂,   E_ac = P₀²/(4ρ₀c₀²)
An earlier draft quoted the literature's F_z = 4πa³kE_acΦsin(2kz), which is wrong here for two independent reasons that happen to compound: (i) the commonly-tabulated ΦB is the Settnes–Bruus acoustophoretic contrast factor and carries a factor 1/3 (ΦB = Φ/3); and (ii) the sign follows the pressure convention — with a sin() field the pressure node sits at z = 0, so a positive-contrast particle must be pushed toward it, which requires the leading minus. Quoting the literature form against a sin() field silently inverts the trap, turning nodes into antinodes — a bug that yields a plausible-looking levitation sim that is wrong everywhere. Verified by symbolic differentiation of the potential; both normalizations agree once matched. This is exactly the class of error the gate ladder exists to catch, and it was caught on the first run.

Particle equation of motion, integrated with velocity Verlet on the GPU:

m · dv/dt = F_rad  +  m&g  −  6πμa(v_p − v_fluid)  +  F_contact
μ_air = 1.81e−5 Pa·s ;  optional F_stream from acoustic streaming (off by default,
                            behind a flag, because it is not gated)

Trap capture is the condition |Frad| > mg, and the standing-wave case gives the closed form the gate needs: for a 1D standing wave p = P₀sin(kz), Fz = 4πa³kEacΦsin(2kz) with Eac = P₀²/(4ρ₀c₀²). That closed form is gate G7.

13.2 Consolidation (T3)

Per-particle lumped-capacity thermal state, driven by whichever heat stage the preset selects (the doctrine is emphatic that "the sound IS the heat" is superseded — 40 kHz absorption in a sub-mm bead cannot sinter PLA, and the "nanosecond weld" figure is dropped as having no bench basis; printing takes a separate heat source):

m c_p dT/dt = Q_stage(z) − h A (T − T_amb)

states:  FEEDSTOCK → IN_TRANSIT → MOLTEN (T > T_melt)
                   → WETTED (contact with a latched neighbour)
                   → LATCHED (T < T_glass; position frozen into the
                                occupancy grid, particle retired)

Anchors to calibrate against, from the printer-concept doc: a 200 µm PLA bead is ~5 µg and needs ~0.8 mJ to melt (~8 mW over a 100 ms transit); tin, nylon, PETG and soda-lime glass are tabulated alongside; a 200 µm PLA droplet cools below Tg in 1–10 ms in still air. The occupancy grid is a 3D uint8 texture at build resolution; the visible surface is marching cubes over it, re-extracted on change with a dirty-region queue. Build progress = latched-and-inside-target / target; overspill = latched-and-outside-target / target. Both are shown; the second is the honest one.

14 · The inverse solver — target field to drive

Given a target amplitude distribution |p|* over a set of control points (trap positions, or the target's surface shell), find the complex drive u. Three methods, all sharing the cached H, selectable in the inspector and raced against each other in the gate report:

methoditerationcharacter
IBP (iterative back-propagation) u ← HH (target phase applied to current field); normalize trivial, fast, mediocre contrast — the honest baseline every other method must beat
GS-PAT Gerchberg–Saxton on the reduced point-to-point matrix HcHHc (control points only, so the matrices are tiny), then one back-projection the standard for multi-trap holography; milliseconds; the default
Diff-PAT gradient descent (Adam) on L(u) = Σc wc(|Hu|c − |p|*c)² + λ‧‖u‖², with ∇L supplied analytically via HH slower, best fidelity, handles amplitude constraints and per-channel power limits; the one to use when compiling a whole object rather than a handful of traps

Hardware constraints enter as projection steps inside the loop, not as post-hoc rounding: per-channel amplitude ceiling, phase quantization (the bench anchor is ~1° at 40 kHz on an RP2350 at 150 MHz), and the spec's λ/20 per-band phase tolerance. A drive that only works at infinite precision is not a compile result; it is a bug that will reappear on hardware.

The measured calibration matrix multiplies in ahead of H: the power-up self-calibration measures every element's TX→RX transfer and stores it as that machine's identity matrix, and the mechanical paper is blunt that "without this matrix the field compile is blind." The emulator therefore simulates a calibration — with configurable per-element gain and phase error — so that the compile path exercises the same code the hardware will.

15 · Scan pipeline

  1. Empty-chamber reference. One run per preset+band, cached, keyed by config hash. Everything downstream normalizes against it.
  2. Coded runs. v1 ships identity coding (one gate per run). Also implement the Welch–Costas schedule from M5 on — 13 is prime with primitive root 2, so a perfect thumbtack-ambiguity schedule exists for exactly 12 gates: slot k → gate 2ᵏ mod 13 = 2, 4, 8, 3, 6, 12, 11, 9, 5, 10, 7, 1. It is ~20 lines and it is the thing to race in the scan-policy comparison.
  3. S(f) assembly. FFT every port record; column r of S(f) = spectra normalized by the source spectrum from the reference run.
  4. Chord extraction. Matrix pencil: build Hankel matrices H₀, H₁ per record (window L ≈ N/3), stack all gates' Hankels vertically (joint poles — one object, one set of resonances), SVD(H₀) truncated to K, generalized eigenvalues → poles pk, least squares → port-vectors rk, order by contribution weight. SVD by one-sided Jacobi; matrices are at most a few hundred rows.
  5. Emit .pattern, with the calibration reference recorded in the metadata.

16 · The interface

The design brief is a clean slicer, and the discipline that implies is subtractive: a person who has used Bambu Studio or PrusaSlicer should be productive without a manual, and every control that cannot justify its pixels should be in a disclosure triangle or gone. The instrument content — and there is a lot of it — earns its place by being the viewport, not by being more panels.

16.1 Layout

┌─ toolbar ──────────────────────────────────────────────────────────────┐
│  [Scan | Compile | Build | Inspect]   RH-1 v   PLA v      [ Compile ]  │
├───────────┬────────────────────────────────────────┬───────────────────┤
│  objects  │ [field][traps][matter][solid][bnd]     │  inspector        │
│  240pt    │                                        │  300pt            │
│           │                                        │                   │
│  cup.stl  │      T H E   V I E W P O R T           │  machine          │
│   PLA     │                                        │  carrier / band   │
│           │  (cylindrical build volume, the        │  field / verb     │
│           │   machine around it, overlays on)      │  matter           │
│           │                                        │  solver           │
│           │                                        │  quality          │
├───────────┴────────────────────────────────────────┴───────────────────┤
│  > ||  < >   -----o---------   t=12.4 ms   build 34%   S(f) err ___    │
└────────────────────────────────────────────────────────────────────────┘

The transport bar is the slicer's layer slider, re-pointed at time: scrub the .fcode frame timeline, step, play, loop a range. The S(f)-error sparkline lives beside it because §4 says the build's acceptance criterion belongs in the user's peripheral vision, not in a dialog.

16.2 The viewport — three epistemic layers

Machine geometry as described in §10, drawn to be recognizable against the Blender renders: caps as amber-lit bullseyes with the spiral face and lit bore, the six back panels as hex-tiled sheets glowing with their live boundary state, the columns as dark bars with white light strips. Build volume as a translucent ticked cylinder. Front glass rotatable, with the interlock enforced.

Everything else the viewport draws is sorted by epistemic status — not by object type, and not by aesthetics. The machine has no camera. It never sees the inside of its own chamber; it drives a boundary, listens to the echo, and reconstructs. A viewport that quietly draws the mesh we already have in memory is showing the user something the instrument will never possess. Three layers, rendered three ways:

layercontentsrendered asbecause
KNOWN machine chrome, build-volume cylinder, dimension ticks, the imported target mesh, the cartridge crisp CAD — sharp, dimensioned, unambiguous These are files and specifications; we know them exactly. Rendering them holographically would destroy slicer legibility and be dishonest in the opposite direction — pretending not to know something we do
SIMULATED the field, the particles, the latched voxels direct volumetric / instanced draw from the sim buffers We are the simulator. This is ground truth of the model — which is not the same as ground truth
RECONSTRUCTED whatever the boundary measurements actually support holographic reconstruction from the port records (§16.4) This is all the real machine will ever have

Global toggle: Machine View / God View. The KNOWN layer is drawn in both; the other two swap. Machine View is the default in Scan and Inspect — the hardware spec's product staging is scanner-first, so in those modes the reconstruction is the product — and God View is the default in Compile and Build, where the user is authoring rather than measuring. The toggle is always one keystroke away, and the difference between the two views is a first-class metric with its own acceptance gate (G14), not a curiosity.

Overlays are chips along the viewport's top edge, each independently toggleable:

  1. Field — |p| on a draggable slice plane (XY / XZ / YZ), log-compressed, diverging colormap, with a scale bar in Pa. Fed by T0 at frame rate, or by T1's current step during a run.
  2. Traps — Gor'kov minima as markers sized by trap stiffness, optionally an isosurface of U. This is the overlay that makes the inverse solver legible.
  3. Matter — instanced particles coloured by thermal state (feedstock grey → molten orange → latched material colour), with the cartridge and bore feed visible below the deck.
  4. Solid — marching-cubes surface of the occupancy grid, with the target mesh as a ghost. Toggling between "what I asked for" and "what the field actually made" is the app's most important single interaction.
  5. Boundary — per-element drive as coloured quads on the caps and panels (brightness = amplitude, hue = phase), gates outlined and numbered. This is v0.2's screen renderer, mapped onto RH-1's eight faces instead of a Goldberg sphere. During power-up it animates the real sequence: calibrating → locking → ringing-up → ready.
  6. Chords — the chord list as an overlay panel; hovering a chord highlights its port-vector on the boundary and its pole on the spectrum strip.

Camera: orbit / dolly / pan; number keys for front / top / iso / home; perspective–orthographic toggle. Empty state is the machine alone, composed well enough to screenshot.

16.3 Machine View — the reconstruction renderer

The caveat that shapes this entire section, stated before the method. Kirchhoff–Helmholtz determines the field everywhere inside a source-free volume from boundary data. Put an object in the chamber and the volume is no longer source-free — the scatterer is a secondary source — and recovering the object from boundary data is inverse scattering: nonlinear, ill-posed, and the problem full-waveform inversion exists to attack. Consequently a naive boundary backprojection yields a reflectivity image — a 3D B-scan — and not a geometry. The UI must say so, the export must label it, and nobody may quietly threshold a reflectivity field into a mesh and call it a scan.

The reconstruction ladder, cheapest first. Each rung is a separate, selectable operator over the same port records, so their outputs can be compared side by side in the same viewport:

rungmethodcostship
L0 Kirchhoff–Helmholtz / delay-and-sum backprojection. f(x) = Σg ag·eikr/(4πr) over gates g. One Metal kernel, O(Nvox×Ngates) msM7, default
L1 DORT / time-reversal operator. Take the SVD of S(f) directlynever form SHS, which squares the dynamic range. Rank by Gavish–Donoho (2.858·median σ when noise is unknown); each significant right-singular vector backprojects to one scatterer. Free reciprocity QC falls out: ‖K−KT‖/‖K‖ > 0.1 means a calibration fault, not a target. Read the warning below before implementing the imaging half msM7
L2 Regularized linear inversion. min ‖Hm − b‖² + λR(m), with H the T0 operator and R Tikhonov or L1. Reuses the inverse solver's machinery and its free adjoint HH (§14) sM8, optional
L3 FWI-style iterative inversion against T1 by the adjoint-state method — the honest answer to the box above minM10+, scheduled not promised
The Green's-function trap — the single biggest technical risk in this project. DORT is model-free only up to the SVD. The imaging step needs a Green's function g(x) for every voxel, and inside a closed high-Q cylinder that must be the cavity Green's function — chaotically sensitive to geometry and not computable from CAD. Running textbook DORT or MUSIC with a free-space g() will produce a confident, sharp, meaningless image, which is far worse than producing nothing. Two further traps in the same family: a single sphere yields up to four significant singular values (monopole + three dipoles), not one, so "eigenvalue count = target count" is wrong; and every chamber wall generates its own large, stable singular value that must be identified and rejected against the empty-chamber reference. Across DORT, MUSIC, LSM and FWI alike, the binding constraint on real data is never the algorithm and never the compute — it is having a correct Green's function for the medium. Ship L1's SVD and its reciprocity QC at M7 because they are honest and cheap; gate the imaging half behind a measured cavity Green's function or an aberration-estimating method (Aubry-group distortion-matrix / ultrasound matrix imaging is the only family that estimates aberration from data instead of assuming it).

What can and cannot enlarge what the machine knows

Before the renderer, the information budget — because the most attractive wrong idea in this project is that a machine with this much field control can simply compute its way out of a measurement gap. It cannot, and the reason is worth stating precisely rather than as a slogan. Four kinds of diversity are available; only two of them add independent information:

diversityadds information?why
Transmit-pattern — beamforming, coded excitation, holographic drive, any clever u No With N elements every transmit pattern is a linear combination of the N individual element responses. Patterned transmission cannot synthesize a measurement that was never made. It buys SNR and conditioning — real and worth having, but not new k-space
Frequency Yes Different ω probes different k-space. Genuinely new samples — and this machine is broadband by construction (octave addressing; the printed holograms steer by frequency, so every frequency is a different illumination geometry from a static aperture)
Position — real or virtual Yes A new viewpoint is a new row in the measurement operator. Crucially, a reflection off a known wall places a virtual source at the mirror-image position — position diversity with nothing moving (§18)
Optically-placed virtual sources — photoacoustic spot-scanning (§17.6) Yes A pulsed laser absorbed at a surface launches ultrasound from that spot, so the optical channel can place an acoustic source anywhere it can see — including on the workpiece. This is position diversity with no motion and no added transducers, and it is strictly better than rotating the scene. Established art: laser ultrasonics
Adaptive / sequential selection — "smart exploration", AI-guided scanning, next-best-measurement No It allocates a finite measurement budget over the information the aperture already offers. That is a policy, not a source — and it is the right place for intelligence in this system

The fourth row deserves its own paragraph, because it is the one that pays off daily. Resolution in this format is chord count, and chord count should be spatially non-uniform: spend chords where the object rings complex, stop early where it is homogeneous, refine where the residual is high. A large single-material volume and an intricate lattice of the same bounding box do not deserve the same budget, and a scanner that gives them the same budget is either wasting minutes or missing detail. This is already latent in the design — progressive chord streaming ordered by weight (§3), the adaptive scan-policy race at M6, and call-and-response's "until it rings true" stopping criterion (§4) are all the same mechanism seen from three angles. Make it explicit: detail-adaptive chord budgeting is a first-class feature, not an optimization.

And the firewall, in the same breath: adaptive selection chooses among available measurements; it cannot synthesize one. A policy that decides where to look next is doing real work. A policy that reports a region it never successfully measured is doing damage. The two are easy to conflate in code and impossible to distinguish in a rendered image — hence §16.3's provenance rule below.

Provenance — the model may propose, only the aperture asserts

The moment a learned prior or a regularizer fills null space, the output contains plausible data rather than measured data. Two failure modes converge here and produce the identical artifact: a wrong Green's function (§16.3 above) and a confident prior both yield sharp, detailed, meaningless images. Neither announces itself.

For this machine that is not a nitpick, because of a property no ordinary scanner has: the scan output is also the build acceptance criterion (§4). A .pattern is not merely a picture — it is what the builder plays and what the loop listens for. An inferred interior therefore becomes a fabricated-from-a-guess interior, and the error is laundered through a fabrication step that looks like verification.

Ruling. Every chord carries a provenance: measured | inferred tag in .pattern, and so does every reconstruction derived from it. The viewer renders the difference — inferred content is visually distinct at a glance, never merely footnoted. Export, receipts and the gate report all carry the measured/inferred split. The model may propose; only the aperture asserts.

Two consequences that follow immediately and should be built in, not retrofitted. Inferred chords are excluded by default from the build acceptance criterion — you may look at them, you may not fabricate to them, and promoting one to load-bearing is an explicit, logged user action. And the coverage channel below is the rendering half of the same commitment: provenance says where a value came from, coverage says whether the aperture could have seen it at all. Ship both.

The coverage channel — rendering what the machine does not know

This is the single most important rendering decision in the document. The specular gap is a null-space of the measurement operator, not an algorithm failure: a facet is measurable only if some (Tx, Rx, f) triple makes the bistatic bisector parallel to its normal. No regularizer recovers it, and no amount of compute changes that. So the renderer's job is not to hide it — it is to show it.

Carry a tri-state, borrowed from OctoMap's occupancy model, and never collapse it to one scalar:

The rule that makes this work: confirmed-empty and never-observed must never interpolate into one another. They are different facts. A trilinear filter that averages them produces a plausible surface out of pure ignorance — which is the most misleading thing this application could do, and precisely the failure the machine's lack of a camera makes easy.

Compute the confidence field properly rather than by eye. Two methods, in increasing order of honesty: a visibility-cone mask (per voxel, which (Tx,Rx,f) triples could see a facet at each orientation — cheap, geometric, and already enough to answer "why did that face vanish"); and a random-walk confidence map in the Karamalis sense — the probability that a random walk from a voxel reaches a transducer, a derived coverage field obtained as a Laplacian solve rather than a rendering trick. Ship the cone mask at M7; the Laplacian version is a clean upgrade.

The strongest version of the idea, and worth building because it is honest by construction: render level-crossing probability (Pöthkow) — P(the surface passes through this voxel) — instead of an isosurface. Roughly 30 lines of MSL, two fetches per sample, and with it you cannot accidentally draw a crisp lie. Related and equally cheap: display the local point-spread-function width, so a low-resolution region is physically incapable of rendering sharp detail.

Technique — and one thing that does not work

Volumetric ray-march of the complex reconstruction in a Metal pass: amplitude → intensity (log-compressed); confidence → extinction, via a 2D transfer function (value, confidence) → (rgb, extinction) so that low confidence drives extinction toward zero — regions read as visibly hollow, not merely tinted. Optionally animate uncertainty (Lundström's probabilistic animation): uncertain regions boil, certain regions are steady.

Phase-as-hue does not survive alpha compositing. Front-to-back over blending of many hues averages to mush; domain coloring is inherently a 2D technique and does not lift to a volume. This was specified wrongly in an earlier draft. The correct idioms, in order of preference: animate Re{p·e−iωt} so that phase becomes motion (the k-Wave idiom, and the most legible by a wide margin); render isophase surfaces; or display ∇arg(p), which is not cyclic and therefore composites correctly.

Isosurface extraction remains available for export, always labelled with the threshold that produced it and always accompanied by its coverage statistics.

Metal specifics worth fixing now

Two design rules imported from measured sim results

The research lane has run the only holographic-reconstruction experiment this project owns (S3-e, 2026-07-19), and it returned two results that constrain this renderer. Both are carried here as rules rather than as background:

  1. Frames must be read young. A-vs-B render distinguishability decayed from 0.76 correlation at t=25 to 0.92 at t=100 — a holographic frame must be read within roughly one chamber mixing time. Rule: reconstruct from early ring-down, and treat Machine View as a refresh-cycle device, not a static image.
  2. The sparse-screen assumption failed its own gates. S3-e's G1 (hexagon-pixel sufficiency, bar ≥0.9) came in at 0.76–0.78 and G2 (bulk addressability, bar <0.5) at 0.77 — both FAIL as frozen. So "drive the twelve defects, read the hexagons" is not validated at C₈₀ resolution. Rule: the app may not assume a sparse gate set suffices for reconstruction; RH-1's real listening aperture is the seven dense column RX strips plus the two caps, and that is what Machine View must model.

16.4 Theme

Dark instrument panel by default; light theme fully supported and equally screenshot-tested — a light theme that is not in the golden set will rot within a week. Colour tokens centralized in Theme/tokens.swift; no literal colours in views. Field colormaps are perceptually uniform and identical across themes, because a physics colormap that changes with chrome is a lie.

17 · Learned components — what we adopt, reject, and defer

A survey of the mid-2026 open-source landscape was run before committing to this architecture (three parallel research passes, 2026-07-26). The conclusions are unusually clear-cut, so they are recorded as rulings rather than as options.

Rejected, with evidence

Generative video "world models" (Genie lineage and successors) are not a weaker solver — they are a different category of object, and the evidence against them is specifically about our equation. A tokenized world model on the heat equation reaches MSE 4.3×10⁻⁵; on the wave equation the same setup gives L1 0.4676 / MSE 0.3420 — order-unity, because it cannot hold phase. The same work proves constant-coefficient (homogeneous) systems are formally non-observable from tokenized observations: a uniform medium is literally invisible to this model class. DeepMind's own Physics-IQ benchmark scores the best generative video model 24.1/100 with realism and physics uncorrelated (r = −0.46). And a June-2026 result finds autoregressive rollouts on wavefields fail by polarity inversion that magnitude-based spectral losses cannot penalize — phase is the signal, and the loss cannot see it. We already possess the exact operator. Do not build this, and do not accept a proposal to.

End-to-end neural PDE surrogates: also rejected, and this one was settled by measurement on the target machine rather than by reading:

The one structural insight worth keeping

Put the network inside the physics loop, never in place of it.

This recurred independently three times in the survey — the Born-series-structured operator that was the only thing to work on OpenBreastUS, the neural warm-start that preserves solver convergence guarantees (NOWS: an honest 25–90% runtime saving, not 1000×), and the learned Born-series preconditioner. If any learned component is ever added here, it must be of that shape: it accelerates a real solver and cannot change the answer. Everything else is deferred indefinitely.

Adopted now

whatlicensefor
AcousTools (UCL)MIT the validation twin — T0, T0.5 and T2 with analytic Gor'kov gradients, already published and maintained
k-wave-pythonLGPL-3 independent second oracle; native arm64. Link, do not transcribe
Inviwo volume shadersBSD-2 the raycaster (§16.3)
DeepwaveMIT reference for PML + adjoint before writing MSL
trellis-mac (TRELLIS.2)MIT the only learned model adopted at start, and only to generate the test-fixture corpus — verified running on MPS, ~3.3 min/mesh. Pin to --no-texture to stay inside 32 GB and to avoid its CC-BY-NC background-remover step

Deferred, with a reason to revisit

Licensing landmine, likely disqualifying and worth checking before anyone experiments. The Tencent Hunyuan community licence defines Territory as "the worldwide territory, excluding the territory of the European Union, United Kingdom and South Korea," and forbids use of the works' outputs outside it. If this project is operated from the EU, Hunyuan3D-2.1, Hunyuan3D-Omni, every MLX port, and anything derived from them are off the table — including meshes they generate. That removes the single best-designed shape-completion candidate. Also flagged: Stride is AGPL (poison for a shipped app), and several otherwise-attractive repos (SH-SAS, ESM-based-NAH, the SAS reconstruction code) carry no licence file at all, which means all rights reserved, not "public."

17.5 · Three precision levers a free-field model assumes away

Recorded because this program nearly shipped a wrong hardware finding. A first implementation pass measured RH-1's 24 acoustic channels at 10.8× focusing gain against a 512-channel dense array's 18.0×, and was about to escalate "24 channels cannot focus" to the hardware lane. That number came from a free-field, monochromatic, pressure-domain model, which assumes away three of this machine's designed-in precision levers. Any channel-count verdict must be measured with all three present, or it misleads.
leverwhat the naive model assumeswhat the machine does
1. The cavity is the aperture Rayleigh–Sommerfeld in open air; DOF ≈ channel count RH-1 is a closed high-Q cavity with calibrated walls. Time-reversal focusing through the multipath makes the cavity the aperture, and controllable DOF per channel scale with the time–bandwidth product B·τreverb, not with channel count — published down to single-channel focusing in chaotic cavities (Draeger & Fink). This is the same multi-bounce lever ranked first for imaging in §18, applied to transmit by reciprocity, with the same honest cost (it needs the calibrated Green's function) and the same mitigation (the machine measures its own cavity; T1 has walls, T0 does not)
2. The spectrum is the address bus one frequency; a frequency-flat gate→element map The panels' printed holograms steer by frequency — the graded hex screen radiates a different computed pattern per tone. So a chord is 24 DOF per tone with per-tone aperture patterns, not "the same 24 DOF, louder". A frequency-flat map models a plain array, not RH-1. And at the force level the tones compose: for well-separated frequencies the cross terms time-average out, so per-tone Gor'kov force fields add — co-locate the main lobes and the sidelobes land in different places and average down
3. Force, not spot size a pressure sidelobe level stands in for precision The deliverable is force on an object, and precision has three separate axes that "spot size" conflates: (a) steering resolution of the potential minimum — continuous, set by phase resolution and servo SNR, routinely far sub-λ, and closed-loop via the 0.5λ toroidal-pulse servo; (b) trap stiffness (N/m at SI drive — blocked on the physical-amplitude fix); (c) selectivity / parallelism — where spot size and parasitic traps genuinely bite, because sidelobes grab stray powder

Consequences now implemented. G9b stands as informational, but is explicitly scoped to monochromatic free-field T0 and is not the machine's parasitic-trap floor. The real gate is defined at the force level: G9d — parasitic-to-main trap depth ratio under an N-tone chord, per-tone Gor'kov superposition, in the walled model. Frequency-dependent gate→element patterns (the rainbow map) are in the machine model as a stub table, to be replaced by the surface hologram Z(r) once the surface compiler exists (§17). And the 24-vs-512 comparison is rerun broadband, with walls, at equal time–bandwidth before any channel-count finding ships.

The general rule this is an instance of, worth stating once: a null measured on a model that assumes away the mechanism under test indicts the model, not the hardware. The research lane already carries this as an anti-pessimism guardrail; it applies to this app's own outputs too.

17.6 · Cross-carrier couplings in the volume

(Note 2026-08-01: the canonical home of the cross-carrier crossings is now The Two Carriers §6b; this section remains the software-facing copy until the next compiler revision.)

The transduction note maps phonon↔photon crossings at the element level — piezo, PMUTs, sonoluminescence, the polaritonic roadmap row. What that leaves unexploited is the crossing in the build volume itself: the two carriers interacting in flight, in the air and in the melt. Three verbs, each with measured art behind it, and all three are just the holographic-synthesis equation (§17) with one carrier as reference wave and the other as recording medium.

Arithmetic verified independently, 2026-07-27, because the whole section rests on one number. Air, Gladstone–Dale n−1 = 2.9×10⁻⁴, δρ/ρ = p/ρc²:
155 dB -> p = 1,125 Pa   dn = 2.3e-6   1.38 optical waves over 300 mm   theta 1.6e-4 rad
165 dB -> p = 3,557 Pa   dn = 7.3e-6   4.37 optical waves over 300 mm   theta 5.1e-4 rad
175 dB -> p = 11,247 Pa  dn = 2.3e-5  13.8 optical waves over 300 mm   theta 1.6e-3 rad
So Δn ~ 10⁻⁵ and "several optical wavelengths of accumulated phase" are both correct at the kPa class the muscle channel reaches.
verbmechanismwhat it buys this program
1. Sound steers light
(acousto-optic)
Sound is a density wave; density sets refractive index. The acoustic hologram is therefore also a volumetric, reprogrammable optical element at microsecond refresh. Commodity art: AOMs In air, deflection stays ~10⁻⁴ rad — a fine-trim and modulation channel along the axial sightline, not a steering channel. Genuine beam shaping belongs to the melt (see the caveat below)
2. Light reads sound
(schlieren / refracto-vibrometry)
The same Δn lets the optical channel see the acoustic field — full-field, tomographic, live. Measured art: schlieren imaging of ultrasound, laser Doppler vibrometry through air Attacks the Green's-function problem head on. The drive field stops being something inferred from RX ports and becomes something photographed — a physically independent calibration path that does not pass through the microphone chain at all
3. Light writes sound
(photoacoustic)
A pulsed or modulated laser absorbed at a surface launches ultrasound from that spot. Established NDT art: laser ultrasonics A programmable acoustic source aperture on any optically visible surface, including the workpiece — genuinely new rows in the measurement operator, with no motion and no added transducers. (Rev 2026-07-30, ruling R2: spot-scanning is merely the delta basis of this operator, and the worst one — patterned bases carry the multiplex SNR advantage.)

Verb 3 is a fifth row in the diversity table, and it is the one that changes the argument

§16.3 established that only frequency and position diversity add independent information. Photoacoustic excitation supplies position diversity from a channel already in the architecture — and per rev 2026-07-30 (ruling R2) it does so holographically, not by scanning: project a structured light pattern onto the object and the photoacoustic conversion launches a shaped acoustic wavefront whose emitter geometry is the light pattern. The workpiece surface becomes a programmable phased array whose elements are optically defined. Spot-scanning ("walk a laser spot across the object") is the delta-function basis of this operator and the worst basis: patterned (Hadamard-class) bases put the full optical power budget into every measurement (MEASURED art: structured-illumination photoacoustics, single-pixel imaging). This is the no-moving-parts answer to the problem §18's turntable discussion was circling — and it is strictly better than a turntable, because the source aperture is written on the workpiece itself, at optical precision, rather than rotating the whole scene.

It also composes with the call-and-response frame exactly: tap the object at a chosen point with light, listen with the whole screen. That is the luthier's tap-tuning made literal, with the tap placeable to microns.

Software consequences — what changes in this program

Two bounds, and one correction to the source note. (i) All three verbs are parametric couplings — one field modulates the medium the other propagates through. Energy exchange between carriers is negligible outside engineered cavities, and this project has already rejected radiation pressure as a drive for exactly that reason. The unlock is information and addressing, never power or force. Coherent phonon↔photon amplification (Brillouin gain in the melt) is real physics but belongs on the roadmap shelf beside the polaritonic element, not in RH-1's baseline. (ii) The claim that photoelastic coupling makes this "orders stronger" in the melt needs care: at equal pressure a liquid is worse, not better — water gives Δn ~ 5×10⁻⁷ against air's 7×10⁻⁶ at the same 3.5 kPa, because ρc² is ~10³× larger so the same pressure buys far less density change. The real advantage in melt or coupling fluid is that it admits far higher drive pressures and a different acousto-optic figure of merit (M₂ = n⁶p²/ρv³, where the lower sound speed helps), not a larger response per pascal. State it that way or the number will propagate wrong.

17.7 · The optical stem (rev 2026-07-30; rulings R1, R2, R2-b, R13)

The control/muscle principle (R1). Light addresses, measures, and calibrates; sound and induction exert force and heat; electrons only amplify at the boundary edge and carry DC power — never information. Not a preference: §17.6 bound (i) makes every cross-carrier coupling parametric, so light cannot be muscle; it is the machine's independent information plane.

The stem is one bidirectional TX/RX holographic port (R2, R2-b). Baseline addressing element: commodity SLM at the bore; roadmap: the optically-addressed metasurface SLM (Fan et al., Nat. Nanotechnol. 2026 — 756 nm pitch, 2.3×10¹² px·s⁻¹·cm⁻²), making the chain photonic end-to-end. Outbound, the stem speaks the caps' own alphabet at optical frequency: toroidal (flying-doughnut) chords, MEASURED (Zdagkas et al., Nat. Photon. 2022; Vignjevic et al., arXiv:2509.10924 — pulse shaper × polarization converter, no metasurface required), with two gifts: self-healing (imperfect synthesis corrects in flight) and isodiffraction (each frequency keeps its own radius — the frequency→radius map carried by the pulse; the on-axis null shares the bore with transport). Inbound, state tomography of returned pulses reconstructs the density matrix in space⊗polarization⊗spectrum (MEASURED: concurrences 0.80/0.91) — a generalized hologram whose purity deficit reads the object's roughness/depolarization as data. Single-aperture position self-encoding via space-time nonseparability: MEASURED at microwave (Wang et al. 2024, cm-class). OPEN: anapole spectroscopy; real-time (vs projection-scanned) tomography. The acousto-optic vernier stands: 5.1×10⁻⁴ rad at 165 dB ≈ 0.15 mm trim over the axial sightline.

Topological registers (R13). Drive and readback states carry integer skyrmion-number labels on both carriers, robust through the chamber's reverberant chaos — robust-extraction toolkit MEASURED and published (Peters et al., Adv. Photonics 8:023001, 2026; explicitly valid for acoustic fields); programmable-metasurface topological TX MEASURED at microwave (Chen et al., Nat. Electronics 2026).

Full rulings: REPLICATOR_CAP_STACK_RULINGS_2026-07-30.md (R1–R13).

18 · Closing the specular gap — ranked, with no moving parts

The specular gap is a null-space of the measurement operator: a facet is measurable only if some (Tx, Rx, f) triple makes the bistatic bisector parallel to its normal. Per §16.3, only frequency and position diversity enlarge that set. The good news is that this machine has an unusual amount of both, and its best move requires no moving parts at all.

#mitigationneeds motion?status
1 Multi-bounce / half-skip / full-skip imaging. A reflection off a known chamber wall places a virtual source at the mirror-image position — genuine position diversity with a static aperture and a static object. RH-1 is a closed cavity with known walls, so every wall is a mirror and the machine's effective aperture is far larger than its transducer count suggests no deployed industrial NDT practice (Zhang / Wilcox / Drinkwater 2010). Build first. M8
2 Frequency diversity. Broadband by construction, and the printed holograms steer by frequency — so each frequency is a different illumination geometry for free. In a high-Q cavity, reverberation multiplies this further no native to the design. DOF capped at ≈ Q × bandwidth — a real budget, and one the machine is built to maximize. M7
3 Segmented ITO on the front glass. The hardware spec already carries this as a "latent upgrade to segmented addressable electrodes" — it converts the passive front ~120°, the one uncommanded face, into an active surface. This closes the aperture gap at its source rather than working around it no the most on-doctrine answer, and already in the spec. Model it as a preset; report what it would buy
4 The rotating glass door. RH-1 already has a moving element, and the spec already credits it with "an aperture-diversity sweep" yes, existing free aperture diversity from hardware that exists. M8
5 Object rotation (turntable). Not in the plan — see the no-moving-parts ruling below yes, new simulated as a control only; nothing may depend on it

Why multi-bounce ranks first despite needing the Green's function

The obvious objection to ranking wall multipath first is that it is more Green's-function-dependent than direct imaging, not less — you are placing virtual sources that exist only if the cavity's response is known precisely, and §16.3 names a wrong Green's function as the project's biggest technical risk. The objection would be decisive for a machine that had to assume its forward model. This one does not.

The machine measures its own cavity. The empty-chamber reference run, the per-plate TX→RX identity matrix measured at assembly and at every power-up, and the double-precision twin gates are not incidental calibration chores — they are exactly the measurements that turn wall multipath from a liability into aperture.

That is the whole argument, and it is why the ordering inverts relative to a naive reading. A machine that self-calibrates its cavity gets to spend that calibration on virtual apertures. The prerequisite is real — multi-bounce imaging must be gated behind a measured cavity Green's function, never a modelled one — but the prerequisite is already on the roadmap for independent reasons (§6 step 7, and the power-up sequence the UI animates). Rank multi-bounce first because the calibration exists, and gate it on that calibration passing.

No moving parts is Plan A

Design ruling (operator, 2026-07-26). The machine aims at zero moving parts. Rows 1–3 are all static, and together they are the plan. Row 4 uses motion that already exists for another reason and is therefore free. Row 5 is a bench contingency, not a component, and no part of the architecture may come to depend on it.

This ruling has one real consequence and it is worth working through rather than asserting: if there is no turntable, what validates the multi-bounce reconstruction? The argument for the turntable was that a wrong Green's function produces confident, sharp, meaningless images, and only an independent view distinguishes the two. That problem does not go away when the turntable does. It needs a different answer, and there is a better one.

Held-out validation — the no-moving-parts answer

The standard way to validate an inverse problem without ground truth is cross-validation against measurements the reconstruction never saw. Two forms, both free, both static, and both stronger than a turntable because they test the forward model directly rather than by proxy:

Two further static checks that cost nothing: reciprocity (already G15) and inter-rung agreement — L0, L1 and L2 disagreeing beyond their expected characters is a signal that at least one is wrong. And for absolute accuracy rather than self-consistency, the right instrument is not a second view but a known reference artifact: a machined phantom whose geometry is known to metrology tolerance, placed in the chamber. Phantoms are how ultrasound and NDT establish absolute accuracy, they require no motion, and their ground truth is exact rather than merely independent — which makes them strictly better than a turntable for the job the turntable was proposed to do.

So the turntable is not retired to the bench; it is removed from the plan, and G18 is rewritten around held-out prediction. If a bench session later wants a rotating stage as an extra cross-check, nothing forbids it — but no gate, no milestone and no reconstruction path may require it.

The emulator should still model all five rows, because the M6 policy race is how we find out what each is worth. The expectation to test: rows 1–3 close the gap, row 4 adds a little for free, and row 5 — simulated but not built — tells us how much, if anything, we gave up by refusing to move.

Two further design-time rulings, both free and both easier to apply now than later. Choose the array layout by sum-coarray design (dTx = NRx·dRx, with gcd(NTx, NRx) = 1): this puts real nulls in the two-way pattern at zero runtime cost, which no amount of weighting can buy back later. And discard coprime / nested / MRA processing — those are difference-coarray results for incoherent sources, and this machine is coherent reflection-mode, which needs the sum coarray. Getting that distinction wrong is a subtle and expensive error.

Finally, a framing to keep in the code comments, because it prevents a whole class of overclaim: delay-and-sum is the adjoint, not the inverse. Coherence-factor, DMAS and similar tricks suppress how artifacts look without restoring unsampled k-space — ship them as display layers, and never feed their output into anything downstream.

Three back-ends, not two (added 2026-07-26 from holographic_memory_and_compute_plan.html). That plan rules that the build chamber must not double as the machine's computer — a mode count settles it: 18.5 L holds ~10⁶ acoustic modes but ~10¹⁸ optical ones, so "the build chamber is a poor computer because it is a good replicator." Three cavities instead: the build chamber (actuator), an optical compute toroid (processor), and an optical phase-change store (memory).

The consequence for this program is small but load-bearing: "the same synthesis step — record reference against object, modulate the surface — is what programs a holographic aperture, and what writes a page into the memory volume. One toolchain, three back-ends." So the surface-synthesis primitive Z(r) = X₀ + M·Re{Ψ*refΨobj} (§17) must live as a standalone, machine-agnostic function — not buried inside the RH-1 preset, and not specialized to acoustics. It is the shared primitive of all three back-ends. Nothing else in v1 changes; this is a note against designing the generality out before it is needed.

19 · File formats and the backend swap

.fcode   { version, machine, calibrationRef, band,
           frames: [ { t, verb: ADD|REMOVE,
                       drive: [ per-channel { band, re, im } ],
                       rxGates: [...] } ] }

.pattern {
  version,
  meta {
    name, date, source: emulated|hardware, machine, calibrationRef,
    reconstruction: { rung, greensFunction: measured|modelled },
    counts: { measured, inferred }        // the split, visible at the top
  },
  material, band,
  chords: [ {
    p: [re, im], r: [ per-gate complex ], weight,
    provenance: "measured" | "inferred",  // REQUIRED — no default
    inferredBy?: "prior-id/version",      // required iff inferred
    coverage?: float                      // 0..1, aperture support
  } ],
  sBandRef?, meshRef?
}

Three schema rules, all load-bearing (§16.3). provenance has no default — a reader that encounters a chord without it must reject the file rather than assume "measured", because the assumption is the failure. inferredBy is mandatory whenever provenance is inferred, so a fabricated interior can always be traced to the thing that fabricated it. And the measured/inferred counts are duplicated in meta so the split is visible without parsing the chord list — a reviewer, a log line, or a build gate should not have to scan an array to learn that a third of a pattern is a guess.

protocol MachineBackend {
    func describe() -> MachinePreset
    func calibrate() async throws -> CalibrationMatrix
    func play(_ frames: FCodeStream) async throws -> PortRecords
    func listen(_ gates: [GateID], steps: Int) async throws -> PortRecords
}
// EmulatedBackend : the four tiers.
// SerialBackend   : frames over USB to an RP2350. M9.

The protocol is deliberately narrow, and every UI action routes through it. If a feature cannot be expressed as calibrate / play / listen, it is a simulator feature and does not belong above the backend line.

Part IV — Testability

20 · Five laws

The request was for software you can easily test, especially by looking at screenshots. Testability of a GPU application with an animated 3D viewport is not achievable by adding tests afterwards; it is achievable only by constraining the architecture up front. These five constraints are what make the rest of Part IV possible, and none of them may be relaxed for convenience.

lawstatementconsequence
L1 No logic above FieldCore. Every SwiftUI view is a pure function of a plain value struct. Views own no state and compute no physics Any screen can be rendered headlessly from a literal fixture — which is exactly what the screenshot harness does
L2 One core, two front-ends. The app and fieldc link the same FieldCore. Anything the UI can do, the CLI can do, through the same call Every behaviour is reachable from a shell, so every behaviour is scriptable, diffable, and CI-able
L3 Determinism is a flag. --deterministic pins the RNG seed, freezes the animation clock at a stated frame, fixes window metrics, colour scheme, and device-selection order Screenshots stop flapping. Without this, golden-image testing is a source of noise rather than signal, and the team quietly abandons it
L4 Every run writes a receipt. JSON to Receipts/: config hash, git SHA, device name, timings, every gate metric with its threshold and verdict Claims quote receipts. This is the repo's existing discipline ("every claimed number ships with its receipt — script path plus output file") applied to an app
L5 No gate weakening. Thresholds change only in a commit that changes nothing else and states the reason in its message Carried verbatim from v0.2, where it read "the builder must not weaken an acceptance gate to pass it." It was right then

21 · The screenshot harness

Two capture paths, composited into one image, both verified to work on this machine with no Xcode, no window server, and no screen-recording permission:

fieldc shot --scene build-midway --theme dark --size 1440x900 --out shots/
fieldc shot --all --out shots/            # every scene × both themes
fieldc shot --contact-sheet --out sheet.png
fieldc shot --record                      # overwrite goldens; never automatic
fieldc film --script demo/build.json --out frames/   # numbered PNGs of a sequence

The scene registry is the contract. FieldUI/Scenes/sceneRegistry.swift holds an array of (id, description, fixture). A UI state that is not in the registry does not ship — adding a panel means adding a scene, and the pull request that forgets is caught by a test asserting that every top-level view type appears in at least one scene. Minimum registry at v1: empty, imported, compiled, field-slice, traps, build-start, build-midway, build-complete, scan-running, chords, gate-report, machine-lpoh, machine-sphere, error-unsupported-gpu, door-open-interlock.

Golden comparison. Tests/__snapshots__/<scene>.<theme>.png, committed. Comparison is perceptual (per-pixel ΔE with a small tolerance, plus a cap on the fraction of changed pixels) rather than bit-exact, because GPU rasterization is not bit-stable across OS updates. On failure, write <scene>.actual.png and a red-highlighted <scene>.diff.png to .build/snapshot-failures/ and name them in the assertion message.

The contact sheet is the deliverable. fieldc shot --contact-sheet produces one labelled PNG grid of every scene in both themes. It is how a reviewer — person or agent — inspects the entire application in a single look, and it is the artifact to attach to any "here is where the UI stands" report. Regenerate it in CI on every push and keep the current one at docs/contact-sheet.png.

22 · Physics acceptance gates

Numeric, blocking, and each one external to the emulator — analytic formulas, conservation laws, or the independent twin. Agreement with itself proves nothing; that principle is inherited from the sim lane and is non-negotiable here.

idgatethresholdfrom
G1voxelizer: Ø60 mm sphere STL voxel volume within 2% of 4πr³/3M1
G2energy conservation: empty chamber, sponge off, rigid walls total energy drift <1% over 10k stepsM3
G3time of flight: axial pulse round trip within 2% of 2·300 mm/c₀M3
G4the Mie gate (on sphere-v0): 60 mm rigid sphere at centre 5 lowest scattering resonances within 3% of analytic MieM3
G5T0 vs T1: single 40 kHz tone, empty chamber, T0 field vs T1 steady state relative L2 <5% inside the build volumeM3
G6standing wave: opposed-cap drive node spacing = λ/2 ±1%; node count = ⌊2L/λ⌋M2
G7Gor'kov analytic: 1D standing wave force on a small sphere within 2% of F_z = 4πa³kEacΦsin(2kz)M4
G8levitation: 200 µm PLA bead released near a trap settles within λ/20 of the analytic node; stiffness within 5% of analyticM4
G9inverse solver: single focus at 5 random points peak within 0.5 mm of target; sidelobes <−10 dB; GS-PAT and Diff-PAT both beat IBP on contrastM5
G10chords: S(f) rebuilt from top-K relative L2 <10% at K=8, monotone decreasing in KM7
G11formats: .pattern / .fcode export → import bit-exact round tripM7
G12the twin gate: raw port records vs the MLX double-precision twin on identical configs relative difference <10⁻³M8
G13build closure: Ø20 mm sphere, full pipeline latched occupancy ≥95% of target; overspill ≤2%M6
G14
(v0.4)
Machine View vs God View — scan a known synthetic object, compare the thresholded reconstruction against sim ground truth report both raw IoU/Chamfer and the coverage-weighted version restricted to observed regions. The gap between them is the specular-gap cost and is the number this gate exists to publish. No pass/fail threshold on raw IoU — a threshold there would reward hallucinationM7
G15
(v0.4)
Reciprocity QC on every measured or simulated S(f) ‖K − KTF / ‖K‖F < 0.1. Free, runs on every scan, and catches calibration faults that would otherwise be read as targetsM7
G16
(v0.4)
T0.5 vs T1 — BEM scattering off a rigid sphere against the FDTD truth relative L2 <5% in the build volume, matching G5's bar for the free-field tierM3
G17
(v0.5)
Provenance integrity — no inferred content may cross into fabrication unnoticed (§16.3) every chord carries provenance; a file missing it is rejected, not defaulted; every inferred chord carries inferredBy; meta.counts matches the chord list exactly; and a .fcode compiled from a pattern containing inferred chords fails to build unless each was explicitly promoted by a logged user actionM7
G18
(v0.6)
Held-out prediction — the no-moving-parts validation of the cavity Green's function and of multi-bounce (§18) reconstruct from a subset of gates and frequencies, then predict the withheld ones: relative error on held-out measurements <15%, and no worse than 1.5× the in-fit residual. A wrong cavity Green's function cannot predict a measurement it was not fitted to — this is the gate that catches a confident, sharp, meaningless image before it reaches a .pattern. Run it on every reconstruction, not just at M8M8
G19
(v0.6)
Phantom accuracy — absolute, not self-consistent a machined reference artifact of known geometry reconstructs within the coverage-weighted G14 bound. Static, exact ground truth, no motion — this is what replaces the turntable for absolute accuracyM8

G14 deserves a note, because it is the gate that encodes this document's central honesty commitment. It is deliberately not a pass/fail bar on reconstruction accuracy. Setting one would create pressure to fill unmeasured regions with plausible geometry — which is exactly the failure mode §16.3 exists to prevent, and exactly what a learned prior would do if pointed at this metric. The gate's product is a pair of numbers and the distance between them.

The validation twin lives at Scripts/twin/. Revised in v0.4: it is no longer hand-rolled. The primary oracle is AcousTools (MIT) — free-field propagator, BEM scattering, and analytic Gor'kov gradients from the group that builds these machines — with k-wave-python (LGPL-3, native arm64) as an independent second opinion where the two disagree. fieldc twin-export writes the config and raw port records as JSON; make twin runs both comparisons and writes a receipt. Hand-rolled MLX remains available for the pieces neither covers, and one measured fact makes that easier than expected: MPS complex64 and FFT do work on current PyTorch, and MLX's FFT primitive declares gradients — the widely-repeated claim that Apple GPUs cannot do complex FFT is stale. What is still missing is complex linear algebra on MPS; do those on CPU via Accelerate.

Why this is a strict improvement. The point of a twin is to be an independent check. A twin written by the same author, from the same misunderstanding, in the same week, is not independent — it is the same bug twice. A published, maintained, separately-validated implementation is a real oracle, and it also collapses the risk on gates G7 and G8, which were the two most likely to be quietly wrong.

23 · Everything else that must be testable

Part V — Milestones

24 · Ten milestones, each with a blocking gate

#buildblocking gate
M0 SwiftPM package; app launches to an empty dark window; fieldc exists; snapshot harness and contact sheet wired; CI green Harness first, deliberately. fieldc shot --contact-sheet produces a PNG; one golden committed and compared
M1 RH-1 scene graph, viewport, camera, overlay chrome, STL import, GPU voxelizer, object list G1; ≥6 scenes in the sheet; silhouette matches the canonical render dimensions
M2 T0 propagator + H cache; Field overlay live at ≥30 fps while dragging the slice plane G6
M3 T1 FDTD in Metal; sponge; energy readout; runtime estimator; sphere-v0 preset G2, G3, G4, G5, G16 — the hardest cluster in the project; do not proceed past a soft pass
M4 T2 matter layer: Gor'kov, particle integration, Traps and Matter overlays, cartridge and bore feed G7, G8
M5 Inverse solver (IBP / GS-PAT / Diff-PAT); target-from-STL; hardware constraint projections; Compile emits .fcode G9
M6 T3 consolidation: thermal, latch, occupancy, marching cubes, ghost target, transport scrubber, build/overspill metrics G13; fieldc film renders the full build sequence
M7 Scan mode: power-up sequence, calibration, coded runs, S(f), matrix pencil, chord list, .pattern I/O, progressive streaming; Machine View L0+L1, coverage channel, provenance tagging, frequency diversity, detail-adaptive chord budgeting G10, G11, G14, G15, G17
M8 Twin cross-check; receipts; light theme; gate report screen; full scene registry; performance baselines; multi-bounce virtual apertures, door-sweep diversity, and the turntable validation view (§18) G12, G18, G19; every scene green in both themes; contact sheet published
M9 MachineBackend split; SerialBackend to RP2350; lpoh-icosa12 preset driving real bench hardware A recorded .fcode replays identically through Emulated, and produces the frame log Serial would consume, byte-for-byte
M10+ On request from the supervising session: the full five-way specular-gap race (§18), segmented-ITO preset, scan-policy races (identity vs Welch–Costas vs adaptive), EM carrier preset, toroidal-pulse position dictionary, melt-sculpting mode, reclaim loop specified when scheduled

Part VI — Register

25 · What this software claims, and what it does not

The emulator implements validated physics only: linear acoustics on a voxel grid, classical loss, Gor'kov radiation forces over that linear field, lumped-capacity thermal transport, and rigid-body particle motion. It contains no transmutation, no open-sector mechanism, and no free-energy accounting. The bore winding's potential-port role is OPEN in the science paper and is inert geometry here.

Its agreement with itself proves nothing — which is why every milestone carries an external gate: analytic Mie, energy conservation, the closed-form Gor'kov standing-wave force, and the independent double-precision twin. The claims ladder is unchanged from v0.2: kernel matches twin → emulator matches closed-form physics → only then a design tool.

One addition to the register, and it is the reason this app is worth building rather than reading about. The corpus repeatedly defers its hardest numbers — trap stiffness versus payload, the nonlinear-onset drive level, the focused weld-power budget at a node, loop bandwidth versus trap stiffness — to "a number the digital twin pins," and mandates a twin of "acoustic FEM + thermal + particle dynamics" so that the machine is "sized, not guessed." This application is that twin, with a viewport. Every force and pressure it emits is therefore a model number carrying the model's assumptions, not a measurement, until a bench matches it. Label them that way in the UI, in exports, and in receipts. A number that looks measured because it appeared in a nicely-rendered panel is the specific failure this register exists to prevent.

Finally, the compiler and the formats are real from day one. The .pattern emitted by the emulated scanner is the format the hardware scanner will fill; the .fcode compiled here is the frame stream the electronics will consume; and the boundary-first architecture is the control stack the machine will run.