> **2026-09-30 update:** Newton grasp replays now use explicit shape damping 0.2 at 0.5 ms. The 2 N run completes the grasp; 1 N loses the ball. Other engines and compression controls are unchanged. Historical Newton failures below are diagnostic history, not the currently displayed grasp. See [revision notes](REVISION-2026-09-30.md) and [source hashes/results](revision-summary.json).

Public reproduction note: archive aliases and `SIMCOMPARE_ROOT` are portable placeholders; use your own archive and checkout locations. Private deployment identifiers are omitted.

# Deformable force instrumentation

## Separate diagnostic replay

`deform_feedback_publish.py RESULTS OUTPUT` produces only
`feedback-grasp-{1,2}N.json`; it does not overwrite original replay bundles.
Open `replay/index.html?deform=1&trial=grasp-2N&feedback=1` for the second figure.
PhysX uses feedback-02, Genesis/Newton use feedback-01, and native MuJoCo routes
retain the original grasp-03 references. Each bundle records source paths and
a SHA256 of canonicalized source JSON (not the raw file bytes).

Arrows show net world-frame force on each finger: Newton's **applied** buffer,
Genesis post-step impulse divided by step duration, PhysX reconstructed external
force, or native MuJoCo contacts. They are anchored at pad centres as a display
convention, not a measured point of application. Torque and other-body loads are
not drawn. Arrow scale is 5 cm/N, capped at 15 cm; numbers are not capped.

Forces retain their own sample clock, with the latest preceding recorded body
pose (at most 5 ms older). Sampling forces only on geometry frames would miss
Newton's spikes. The histories and jump-to-peak buttons preserve those spikes.
Histories use log(1 + force magnitude) and separate vertical ranges; compare the
numbers, not plot height. Samples beyond the last displayed valid geometry are
excluded; failed views freeze there. PhysX's initial sensor transient is omitted.
Raw/full-rate sources remain backed up, and this display does not promote the
signals to validated physical loads.

Original outcomes in `deform-grasp-03` are unchanged. Instrumented reruns and
instrument diagnostics use `results/deform-feedback-01`. Instruments distinguish
actual coupling buffers, joint sensors, and inferred contact loads; these must
not be plotted as interchangeable quantities.

## Newton MJWarp + VBD

`deform_grasp_coupled.py` exports `feedback.steps` at every 0.5 ms step.
For each proxy mapping, `applied_to_rigid` is copied before `solver.step`,
`harvested_for_next_step` after it. This is the actual `coupling_forces` buffer
consumed by `SolverCoupledProxy._step_proxy`, not a separate force reconstruction.
The configured solver has one pass, lagged mode and no feedback relaxation.

Dense arrays are indexed with each mapping's `proxy_ids_global`; `source_ids`
and full body labels map the measurements back to the Panda. Native VBD source
defines component order `[Fx,Fy,Fz,Tx,Ty,Tz]` in world coordinates, torque about
proxy-body COM, force in N and torque in N m. These conventions were checked in
Newton1.5.2 `vbd_coupling_kernels.py`, not inferred from the appearance of arrows.

Both 1N and2N instrumented trials saved full-rate buffers. Adjacent harvested /
applied buffers agree exactly (max error0). Peak harvested finger force norms
were2179.35 N and4657.23 N. Restricting to timestamps no later than the last valid
recorded geometry frame gives2179.35 N and4581.03 N. Geometry is checked every
5ms, so this does NOT prove element validity at every intervening step.
The actuator effort limit is not a limit on constraint/contact reaction force.
The failed-stop times differ from the older trials; these are reruns, not added
measurements of the old trajectories. No deterministic-repeat claim is made.

This establishes that large feedback exists in the actual coupling path. It
does not establish that the reaction is physically correct, nor that the
coupler is the original cause. Keep contact arrows withheld pending accounting.

## Genesis FEM / SAP

`deform_grasp_genesis.py` records raw world-frame impulses on rigid bodies,
contact points/body IDs and actuator efforts at every1ms step for both force
conditions. The conversion is `-(t0*gamma_x+t1*gamma_y+n*gamma_z)` in N s.
Source `RigidFEMContactHandler.add_Jt_x` confirms the rigid/FEM sign convention.
These are post-step internal SAP buffers, not yet verified accepted-state loads.

`deform_sap_instrument.py` explicitly recomputes gamma at accepted velocities
for the **compression diagnostic only**, preserving the old buffer separately.
The5-iteration diagnostic still had a maximum momentum residual component of
3.664 N; this timing hypothesis alone did not fix accounting. The50-iteration
control reduced the maximum residual component to0.01784 N (RMS0.00423 N),
versus RMS0.32553 N at5iterations. Insufficient convergence is a substantial
contributor. This does not independently validate each contact magnitude, and
does not justify promoting the old5-iteration readbacks. It is not silently substituted into the
published five-iteration experiment. Native defaults include Rayleigh damping
alpha=.5,beta=.0005; complete force accounting must consider damping too.

## PhysX GPU

The installed6.1 tensor `DeformableBodyView` provides nodal positions/velocities,
elements and transforms but no direct nodal contact-reaction getter. The tested
`RigidContactView` path returned zero for the deformable plate interaction.
This is a limitation of the tested API path, not a claim about every PhysX API.

`grasp_physx.py` now exposes native `get_link_incoming_joint_force` readings;
the soft grasp records all six components for every link at every1ms step.
The frame is the **child joint frame**, in N and N m. This total joint reaction
includes effects of inertia, gravity and actuation. It is NOT labeled as an
isolated soft-ball contact wrench. Existing rigid adapters do not call the new
sensor unless requested, preserving their normal recording path.

`deform_physx.py --loadcell` is a separate one-sided instrument test: the lower
plate stays fixed, the upper plate is a free1kg rigid body with zero gravity,
zero damping and5mm extra initial clearance. A known downward1N force acts
from0.1 to0.8s. Contact load is inferred as `m*(v_after-v_before)/dt-F_applied`.
This is a measured momentum-balance load cell, not a native contact buffer.
Preserve its actual trajectory and do not compare it as the prescribed-motion
compression trial. The early free-motion interval checks the instrument zero.

The load-cell run completed: peak inferred reaction3.016 N; free-motion residual
below1.73e-6 N over0.11–0.15s. Native rigid contact probe remained identically zero.
The plate moves/oscillates freely; its contact load need not equal the1N applied
force instantaneously. Do not call this a quasistatic compression curve.

The no-ball Panda run (`deform_joint_calibration.py`) checks the leaf-finger
identity `F_external = m*delta(v_COM)/dt - m*g - R*F_incoming_joint`.
After the initial sample, the maximum residual component is3.5832e-5 N.
The first sample has a0.1748 N initialization transient and is explicitly flagged.
This supports the sign/frame/units of the reconstruction in free motion, not a
claim of independently validated soft contact under all loads. The subsequent
`deform-feedback-02/physx_gpu-{1,2}N.json` trials preserve the estimate AND all
inputs (velocities, body orientations, masses, joint reactions, actuator efforts).
Only leaf fingers are reconstructed; applying this formula to a link with
unaccounted child-joint forces would be incorrect.

Both reconstructed-force trials completed recording their failed prefixes.
The 1 N rerun stops at 0.066 s with peak inferred finger force below 6.7e-8 N
after the initial sample: that inversion occurs without finger loading.
The 2 N rerun stops at 0.781 s with peak inferred finger force 2.374 N.
These are different reruns from the original blog and from feedback-01, not
extra channels retroactively attached to those original trajectories.

All six feedback-01 grasp recordings are saved (two force limits per route).
Genesis completes both 4.5 s runs; Newton/PhysX preserve their failed prefixes.
Native MuJoCo CPU and native MJWarp already retain per-contact world forces in
the original grasp frames every 5 ms; the new diagnostic recorders operate at
every physics step. These sampling rates must not be conflated for peak comparisons.
Compression raw forces/probes remain in the original forcecheck set, supplemented
by the accepted-velocity / iteration controls and the separate load-cell fixture.
36 Python regression tests pass. All new results are backed up under repository-root
`output/archive-deformable/results/deform-feedback-{01,02}/`, with SHA256 audit files.

## Reproduce and audit

`setup/deform_feedback.py` reruns Newton, PhysX and Genesis at1N/2N using pinned
environments. It skips existing recordings. `setup/deform_feedback.conf`
registers the batch with supervisor. The original reference tape and physical
settings are preserved for those grasp reruns.

```
python deform_genesis.py --output results/deform-feedback-01/genesis-compression.json
python deform_genesis.py --sap-iterations 50 --output results/deform-feedback-01/genesis-compression-50iter.json
python deform_physx.py --loadcell --output results/deform-feedback-01/physx-loadcell.json
python deform_feedback_audit.py results/deform-feedback-01 results/deform-feedback-01/audit.json
```

Use each script's respective isolated environment. Save raw recordings, exact
environment locks, source code, tape hash and audit SHA256s together. Missing
validated contact measurements remain null; joint sensor data is a distinct
schema. The blog replay must not automatically turn these raw signals into
validated contact arrows.
