Orbit-grid reconstruction
Concept
Several measurement paths do not read the orbit path from the log — they rebuild it, by re-running the static orbit geometry on a grid of
Nsteps and then interpolating the logged progress marker onto it. The grid’s size is the whole ballgame: size it right and the reconstruction is exact; size it from the wrong quantity and every downstream time reads low, silently.
What this spans
Any measurement that reconstructs a run-time object from a log’s length rather than from the run’s configuration. Orbit-synced termination decoupled those two, so the shortcut that was exact for years is now a defect.
Constituent pages
- orbit — the orbit path geometry itself (
s_end,spacing), the thing being reconstructed
Mechanism (where it lives in code)
-
validation/run_mission.py:169—run_statics(d, robot, suppress, n_steps, freeze_floor=None)rebuilds the static orbit geometry on ann_stepsgrid and returnsdt,s_end,spacing. -
When a log carries no legacy scalars, the mission cap defaults to
n_steps * dt, and the grid is sizedN = cap/dt. -
validation/investigate_mismatched_duration.py:44—decompose()now sizes the grid from the config, not the log:n_grid = max(len(prog), int(round(float(tcfg.duration) / float(tcfg.dt)))) -
validation/investigate_mismatched_duration.py:49— a permanent assert catches any future mis-scaling:assert prog.max() <= n_path + 2, "progress exceeds the rebuilt orbit grid -- statics mismatch"
Note n_path (s_end / spacing, line 48) is a different quantity from n_grid — the assert checks the progress marker against the rebuilt path length, not against the grid it was built on.
Evidence
Before orbit-sync, len(prog) and cap/dt were the same number: a fixed-duration run logged exactly as many samples as its cap allowed (CHAIN_13: 1800 s / 0.03 s = 60,000 steps = 60,000 samples). Since the B1↔B2 merge, missions end at orbit completion, so the log is shorter than the cap. The rebuilt grid then came out under-sized, its spacing too coarse, and find_t_complete crossed the mis-scaled threshold early — rung 3 printed t_c = 427 s on a mission that demonstrably ran 702.6 s.
Fixed-duration logs are unaffected: their len(prog) dominates the max().
The falsifier is what caught it
Nothing in the numbers looked wrong — 427 s is a perfectly plausible mission time. It was caught only because the lab report had pre-registered a stop rule:
t_c < T_kinis definitionally impossible (a mission cannot complete the orbit faster than the orbit’s own kinematic duration,T_kin= 689.69 s). The pre-registered falsifier fired before any conclusion shipped. This is the stop-rule discipline paying rent, not a lucky catch.
Footguns
Any grid rebuilt from a log's LENGTH is now suspect
Event-based termination decoupled log length from configured duration. Every
run_statics(..., len(...))call site must be re-checked before its output is trusted on a post-orbit-sync log. Size the grid from the config (simulation.time.duration / dt), never fromlen(prog)alone.
The failure is silent and one-directional
An under-sized grid has too-coarse spacing, so the progress marker crosses the completion threshold early. The error always reads as a mission that finished sooner than it did — a direction that flatters the result, which is exactly the direction least likely to prompt a second look.
Equations & references
Mission-clock accounting and the kinematic orbit duration T_kin: see the error-floor investigation’s mismatched-duration lab report. Source note: notes/orbit_grid_measurement_footgun.md.