LIDO Stage 2, proposal P01, planning only

Tet-mesh energy, surface encoder and two contact paths for LIDO

plan, nothing implemented Source: worktree learned-instrinic-solver, HEAD 2c7c474cc, 2026-10-10 Written 2026-10-10 by the Fable agent; decisions of the review session folded in 2026-10-11

This page shows the mechanisms the plan turns on. Teal marks the tet mesh and the new energy. Orange marks contact planes and constraints. Green is the certified anchor state, purple the trial state. Formulas are in LIDO's normalised units: cell size 1, time step 1, the scene's reference shear modulus 1.

1. What changes and what stays

Today the energy is the trilinear hex energy of the voxel body. P01 keeps the cell grid, the corner degrees of freedom, the network and the fusion, and swaps the energy for the energy of a tet mesh whose vertices ride on the corners. The hex energy stays behind a switch.

Tet mesh, rest vertices, tets, surface triangles Embedding grid corners x, cell modes m, flags Network + fusion unchanged overlap, embed x_v = J x features fused step d Tet energy E_tet(J x) + damping + inertia J x J^T g Hex energy, today kept behind a switch x
Figure 1. One query with the tet energy. Only the energy box changes. The corner gradient the network and the fusion read comes from the tet energy through the transpose of the embedding map J.

2. Energy transfer: tets ride on corners

Each tet vertex sits at fixed trilinear coordinates inside one cell. Its position is a convex combination of that cell's eight corners. The tet deformation gradient uses these embedded positions. The gradient goes back to the corners by the same weights.

x_1 x_2 x_3 x_4 x_v N_1 N_2 N_3 N_4 x_v = sum_k N_k(xi_v) x_k, g_k += N_k g_v m_v m_v m_v cell c1 cell c2 each vertex gets rho V_t / 4 per tet, then passes it to its cell's 8 corners by J^T sum of corner masses = rho sum_t V_t, exactly
Figure 2. Left: the embedding of one vertex. Right: linear-FEM mass lumping, decided 2026-10-10: tet masses to the vertices, then to the corners through the embedding transpose. The library rule of corner coverage, every corner weighted by at least one vertex, guarantees that every corner has mass and a term in the objective.
F_t      = Ds_t(x_v) Dm_t^-1,             x_v = J x,   Dm_t from the rest vertices
E_el     = sum_t mu_scale_o V_t psi(F_t; lam_o)         psi as physics.stable_neo_hookean, same inversion rule
E_damp   = sum_t mu_scale_o V_t 0.5 eta_o |F_t^T F_t - C_prev_t|^2    C_prev_t at step start, [T,3,3]
g_corner = J^T g_vertex                                 mode gradient paths unchanged (step.py:214, fusion.py:672)
m_corner = J^T m_vertex,  m_vertex = sum over incident tets of rho V_t / 4     every corner weighted (coverage rule)
floor    = volume sum_t V_t h^3, samples = surface vertices
occupancy: the cells that contain a tet vertex; the body is scaled to a drawn cell count

Invariants to test

Zero energy and gradient at rest. Exact equality with the hex energy for any affine deformation of a five-tet lattice body, because the tet volumes of a cell sum to one. Translation invariance. Float64 finite differences. Warp against torch at the existing tolerances. Stress against Newton's formula.

Decision 1, energy transfer: Option A, accepted 2026-10-10

Per-tet F from embedded vertices, the proposal. Option B, the hex F at tet quadrature points, stays the fallback. Verified against the Newton kernels: on lattice tets the forces equal VBD's exactly, damping included, when the inversion stiffening factor is 0 and the masses are tet-lumped. Recorded as ADR 0003.

3. Surface encoder: the rest surface as a per-cell input

Today a cell knows its rest surface through six exposed-face bits. With a tet mesh the surface is a set of triangles that cross the cell. The tokens are built once per mesh. The encoder is small and trained with the network.

rest surface in the cell n centroid, n, area centroid, n, area centroid, n, area tokens: built once, offline attention within the cell runs every update while training mean + max pool 16 + count zero-init node features 142 + 17
Figure 3. The surface encoder, built like the contact encoder, accepted 2026-10-10 as option (a): one token per triangle, at most 16 per cell, the cell's material volume fraction as an extra channel. Tokens are in lattice coordinates, which are rotation invariant like the rest edge offsets. Off by default, so every checkpoint loads; warm starts pad the node encoder with zero columns.

Proof-of-concept restriction: cells that join two sheets

one sheet, one component: accepted two sheets, two components: flagged check per cell: tets overlapping the cell, adjacency by shared faces, components
Figure 4. A cell that holds two disconnected pieces of material would couple them through its eight corners. The proof of concept rejects any mesh with such a cell. Lattice-derived meshes never trigger it. Duplicating cells per component is the long-term fix and out of scope.

4. Contact path A: decoupled DAT planes

Pairs are detected once per step at the step start by Newton's trimesh detector over one model that holds every body's tet surface: vertex-triangle and edge-edge pairs, self-contact on behind a switch, the plane and static quads analytic against surface vertices. The reach is one scalar per step, the radius plus the margin plus twice a budget that exceeds the largest inertial corner displacement. Each pair gets one division plane, placed at a certified, penetration-free anchor. The energy of every vertex is a cubic of its penetration over the plane offset by the radius r, plus gap-rate damping and IPC friction against the plane with the held cubic load, decision F1. The plane is fixed during a query, so the two sides do not exchange momentum within a query. Sliding the plane between truncation rounds is the only exchange.

plane (p, n), margin band plane + r side A, embedded vertices side B, same plane with -n n s_v d = r - s_v > 0: energy on penetration d / r E / (ke r^2) d = r same force at d = r 0 for d < 0 today: ke/2 relu(d)^2 P01: ke/(3r) relu(d)^3
Figure 5. Left: the plane energy. Side B uses the same plane with the opposite normal. Right: the cubic law is softer than the quadratic below depth r, has zero stiffness at first touch, and grows faster beyond r. Its tangent stiffness 2 ke d / r replaces ke in the centroid step.
x_start Y queries 1..K, loss at the trial T final rounds commit margin plane plane slides, room for the side that still moves trial crosses truncate toward Y every N queries: truncate, rebuild planes truncate, slide, refresh normals every M x = anchor v = (anchor - x_start)/dt trial x, may cross anchor, never crosses plane, fixed within a query
Figure 6. The schedule of the pseudo-code mapped onto LIDO's step: detection and planes at the step start, truncation toward the inertial target, K queries on the trial, truncation and plane rebuild after every query (N = 1), three final rounds (T = 3) with plane sliding and a normal refresh every round (M = 1), commit of the anchor. The loss is evaluated at the trial with the planes as step constants, decision L1; the committed anchor is the next step's start, and the trial-to-anchor gap is logged as the truncation fraction.
n side A, rates a_i = max(0, n.r_i) side B, rates a_j = max(0, -n.r_j) b_lo = max_A h_i + m b_hi = min_B h_j - m b: equal fraction tau on both sides b_ij = (a_j (h_i + m) + a_i (h_j - m)) / (a_i + a_j)
Figure 7. Plane sliding. The pseudo-code's formula matches the maximin placement of the reference kernels line by line. A side that does not approach gets no room reserved. The margin m is a small, strictly positive float32 band, not a cushion; the cushion is the radius r alone. The margin shrinks to half the gap for thin pairs.

Truncation on corners, not on vertices

LIDO's degrees of freedom are the corners. The embedding weights are fixed material coordinates, so a vertex path is linear when its eight corners share one factor; with different factors the vertex follows a convex combination and can swerve. The rule agreed on 2026-10-10: truncate at the vertex first, dividing its clearance by the harmful part of its corner motion, then apply that factor to the harmful corners only. It is exact on lattice tets and conservative mid-cell.

plane x_1x_2x_v trial: the interpolated vertex crosses 0.4 * 60 + 0.6 * 220 = 156 > c_v plane both harmful corners scaled by t_v: the vertex lands on the margin 0.4 * 52 + 0.6 * 190 = 135 = c_v t_v = c_v / (0.4 * 60 + 0.6 * 220) = 0.87
Figure 8. Here x_v = 0.4 x_1 + 0.6 x_2 and both corners move toward the plane. The vertex factor t_v divides the clearance by the harmful part of the corner motion, not by the net motion, so helpful and harmful corners cannot cancel. Each harmful corner takes the minimum t_v over the vertices it supports; later cuts only help. The motion budget is a displacement clamp per corner from the step start, not a path length, to avoid the lock-in seen in the reference code.
for vertex v and plane (p, n):   c_v = n . (x_v(anchor) - p) - m >= 0       clearance at the certified anchor
    harmful corners k of v:      a_k = n . dx_k < 0                        sign per side
    t_v = min(1, gamma c_v / sum over harmful k of N_k |a_k|)                harmful part, not the net n . dx_v
    for each harmful k:          t_k = min(t_k, t_v)                        atomic minimum; helpful corners untouched
anchor_k = anchor_k + t_k dx_k,  then clamp |anchor_k - x_start_k| <= B     displacement clamp per corner
B = 1.25 x largest inertial corner displacement;  reach R = r + m + 2 B    one scalar per step for the detector

5. Contact path B: coupled smooth-extrema constraint

One constraint per pair couples both sides, so the forces are exactly equal and opposite. Two corrections to the text: the radius enters with a minus sign, and the energy must be unilateral.

As writtenC = softmin_b - softmax_a + r
C stays non-negative while the sides overlap by up to r.
CorrectedC = softmin_b - softmax_a - r
Separation by r means C at least zero, as in the ALM contact design note.
As writtenE = C^3
Negative and unbounded below for C below zero; pulls the sides together for C above zero.
CorrectedE = ke/(3r) relu(-C)^3
Zero when separated, cubic penalty on the overlap, same unit scale as the plane law.
n a_i, side A U >= max_i n.a_i b_j, side B L <= min_j n.b_j L - U C = L - U - r >= 0: separated by r forces by softmax weights: sum on A = -(sum on B), exactly C E contact at C = 0 corrected: ke/(3r) relu(-C)^3 as written: C^3
Figure 9. Soft bounds are conservative by at most log(m)/beta per side, m the vertex count of the primitive; beta about 10 over r keeps that slack below a tenth of r. The normal is re-picked only at certified anchors. Because the offset of the plane drops out of L minus U, the constraint slides for free.
U = (1/beta) log sum_i exp(+beta n . a_i)          soft-max of side A
L = -(1/beta) log sum_j exp(-beta n . b_j)         soft-min of side B
C = L - U - r,     E = ke / (3 r) relu(-C)^3
dC/da_i = -w_i n,  dC/db_j = +v_j n   (softmax and softmin weights)   ->  equal and opposite
world edges: two directed cell-graph edges per pair in per-cell slots reserved at the detector's row
             capacities, marked valid per step; features: zeros plus a flag for the rest offset, the usual
             current geometry, the partner's mass-ratio and kappa channels; edge width 27, zero-column pad

Decision of 2026-10-11: the coupled path builds the same division planes from the same pairs and runs the same final truncation, so the two paths differ only in the energy. The coupled energy without truncation stays as an ablation arm.

No path promises penetration freedom. The DAT certificate needs complete detection within the reach, strict separation at the step start, linear committed motion and convex primitives. With truncation on both paths the committed state is certified on both, under those assumptions only. The plan measures each assumption: coverage flag, plane-crossing share, true surface penetration on the tet surface.

6. Decisions taken in the review session

Recorded in the worktree glossary and ADR 0003 on 2026-10-10 and 2026-10-11.

  1. Goal. Fidelity on lattice tets against Newton VBD is the first gate; capability on real assets is the second.
  2. Energy transfer. Option A: one deformation gradient per tet from embedded vertices, gradient to corners through the embedding transpose. Option B is the fallback. ADR 0003.
  3. Mass. Linear-FEM lumping to the tet vertices, carried to corners by the embedding transpose; the library enforces corner coverage.
  4. Mesh source. Lattice tets for gates A and B; TetWild assets, QEM-decimated and re-meshed with fTetWild at about one cell edge length, for gates C and D; the fTetWild wrapper is the one new dependency; the library ships as a versioned archive; splits by mesh id.
  5. Surface encoder. One token per triangle, at most 16 per cell, volume fraction as a channel; encoder on against off is the ablation.
  6. Loss location. L1: the potential at the trial with the planes as step constants; the anchor is committed; the truncation fraction is logged.
  7. Tangential forces. F1: gap-rate damping and IPC friction against the plane with the held cubic load; F0 is an ablation.
  8. Schedule. Planes rebuilt after every query, three final rounds, normals refreshed every round; the margin is a small float32 band and the radius r is the whole cushion.
  9. Coupled path. Same planes and truncation as the decoupled path; energy only as an ablation.
  10. World edges. Per-cell slots reserved at the detector's row capacities, marked valid per step; edge width 27 with a zero-column pad.
  11. Detection. Newton's trimesh detector over one model with every body's tet surface; analytic plane and quads against vertices; one scalar reach per step from the largest inertial displacement; self-contact on behind a switch.
  12. Body from a mesh. Scaled to a drawn cell count; occupancy is the cells that contain a vertex; filters for components, closed surface, dihedral angle, joined sheets and coverage.

Defects in the proposal text, corrected

Still open

7. Phases, each behind a switch with the v8 default

PhaseContentCode locationsTests
P0Mesh library and embedding: tets, trilinear weights, vertex-lumped corner masses, occupancy from vertex cells, corner coverage, surface tokens, joined-sheet check. Kinds: five-tet lattice; TetWild assets decimated and re-meshed at about one cell edge length.new tetmesh.py; BodySpec gains mesh beside shape; realise; five-tet tables in pinning_gallery.py:91test_tetmesh.py: weights sum to one, mass totals, sheet check
P1Tet elastic and damping energy with gradient to corners; floor from tet volume; fused inference launch.new tet_energy_kernel.py; dispatch at physics.py:122; energy_kernel.py:252test_tet_energy.py: affine equality, finite differences, Warp against torch, Newton stress
P2Surface encoder, tokens in lattice coordinates, zero-init output, concat or add rule.network.py beside ContactEncoder; adapter at network.py:410test_surface_encoder.py: zero-init identity, loading of old checkpoints
P3Tet-surface detection: Newton's trimesh detector over one model with all bodies' surfaces, vertex-triangle and edge-edge pairs, scalar reach per step, self-contact behind a switch; analytic plane and quads against vertices.contact.py:162, contact.py:271; Newton TriMeshCollisionDetectortest_tet_collision.py: brute force pairs, capacity layout
P4Division planes and corner truncation with the harmful-corner rule, ported from the sibling worktree kernels; F1 damping and friction against the plane; schedule N = 1, T = 3, M = 1 in Step; loss at the trial.new dat_planes.py; step.py:382, step.py:478; source particle_dat_kernels.py of alm-dat-solvertest_dat_planes.py: no committed vertex crosses, resting truncation fraction near zero
P5Coupled constraint with the corrected sign and unilateral cubic, anchor-picked normals, the same planes and truncation, world edges in per-cell slots at the detector's capacities.contact.py, features.py, network.py, grid.pytest_coupled_contact.py: third law to 1e-10, conservative bound

8. Arms, references and gates

ArmEnergySurface encoderCollision surfaceContact methodWorld edges
basehexoffvoxelpairsno
T0tet, latticeoffvoxelpairsno
T1tet, libraryoffvoxelpairsno
T2tet, libraryonvoxelpairsno
C1tetbest of T1, T2tetpairsno
D1tetsametetDAT planesno
K1tetsametetcoupledno
K2tetsametetcoupledyes

Ablation arms added in the review session, each one switch away from its parent: L3 loss with a trial-to-anchor penalty; F0 normal cubic only; N = K planes rebuilt only after the queries; T in 2 and 4; slide-only final rounds; K-A coupled energy without truncation; world-edge capacities 4 and 8; hand-pooled surface features instead of attention; self-contact off; a resolution split in tets per cell.

Gate A: kernels all invariants, Warp = torch stop: any invariant fails Gate B: T0 vs base beam vs VBD, inversion factor 0 stop: worse on all three then try option B Gate C: T1, T2 no divergence, within MDD of T0 encoder kept only on a gain Gate D: D1, K1, K2 0 crossings, third law, pen <= r world edges kept only on a gain
Figure 10. Stop and go. Gate B compares against Newton VBD on the same lattice tets with the inversion stiffening factor at 0 and tet-lumped masses, the two conditions under which the forces coincide exactly. MDD is the benchmark's minimum detectable difference from the stratified cluster bootstrap.

First step. P0 for lattice tets, P1 and its tests, then T0 against base on 4 GPUs each, scored by the beam harness against VBD on the same mesh and by the benchmark with a tet-aware reference. Estimate: one week of implementation, one day of training. Everything stays read-only until you approve and assign a worktree.