# Research VIV driver — coupling contract (not production) `run.py` couples a 1-DOF undamped spring–mass (`viv.py`) to the production moving-circle API. Everything specific to fluid–structure coupling lives here, not in `src/`. - Per step: known (y_n, v_n) and the last completed force F_last → exact harmonic candidate (y_{n+1}, v_{n+1}) → `set_body(offset=(0, y_{n+1}), vy=y_{n+1} − y_n)` (interval wall velocity, lattice dt = 1) → `run(1)` → commit y, v and F_last only after the step succeeded. One step of explicit force lag (weak coupling); no sub-iteration. - Structural RHS = CME + Wen (y), read from `moving_diagnostics()` by the names in `MovingTables.DIAG`; raw CME, the `obs` force and node terms are logged as diagnostics. This is a stage choice, not a validated force law. - Production guarantees used: fail-closed target commit (synchronized step, `no_donor == 0`), input rejection before mutation, a failed device step marks the Simulation failed. - Not provided, by design: device-resident structure state or batched (multi-step) coupling, strong/sub-iterated coupling (would need state rollback), more than one DOF. These are future work and would be a separate execution path, not an abstraction over this driver. - Recorded result and limits: `docs/validation/moving_bodies_stage1.md`; predeclaration: `docs/validation/viv_re150_predeclare.md`.