Version or commit
Current main (3dbf43b)
Problem & Invariant Violation
The documented contract in src/hflow/checks.py:1344-1349 specifies:
"{topic}/final_pose_unsettled_ratio is emitted only when {topic}/mean_velocity is above zero. For a fully motionless episode the ratio is undefined (zero denominator), so only {topic}/final_pose_speed appears. Curation queries joining on final_pose_unsettled_ratio will silently exclude motionless episodes; use final_pose_speed when you need all episodes regardless of mean motion."
This promises that final_pose_speed is always emitted for all episodes. Furthermore, HFlow's motion metrics strictly weight steps by duration (mean_velocity, idle_fraction, _duration_weighted_median) so irregular sampling does not skew results.
However, in checks.py:1424-1433:
final_window_mask evaluates (profile.stamps_ns[-1] - profile.stamps_ns[:-1]) / 1e9 <= final_pose_window_s. Because profile.stamps_ns[:-1] is the START of each step, any stream whose sample period exceeds final_pose_window_s (e.g. 1 Hz or 2 Hz streams with the default 0.5s window) has zero steps satisfying the mask. Both final_pose_speed and final_pose_unsettled_ratio are silently omitted despite the robot moving actively. Curation queries joining on final_pose_speed drop these episodes completely.
- When steps do match,
final_speed is calculated using unweighted np.mean(profile.speeds[final_window_mask]). Irregular sampling in the final window distorts final_speed by orders of magnitude and produces severe false positives in final_pose_unsettled_ratio.
Minimal Reproduction
import asyncio
from pathlib import Path
import tempfile
import hflow
from hflow.testing import synthesize_episode, SyntheticEpisodeSpec
with tempfile.TemporaryDirectory() as tmp_dir:
mcap_path = Path(tmp_dir) / "test.mcap"
synthesize_episode(
mcap_path,
SyntheticEpisodeSpec(
duration_s=5.0,
cameras=(),
joint_hz=1.0,
joint_jump_at_s=None,
),
)
with hflow.Episode(mcap_path) as ep:
result = asyncio.run(hflow.checks.trajectory_metrics(ep))
assert "/joint_states/final_pose_speed" in result.measurements, (
"CRITICAL BUG: final_pose_speed was silently omitted!"
)
Version or commit
Current
main(3dbf43b)Problem & Invariant Violation
The documented contract in
src/hflow/checks.py:1344-1349specifies:This promises that
final_pose_speedis always emitted for all episodes. Furthermore, HFlow's motion metrics strictly weight steps by duration (mean_velocity,idle_fraction,_duration_weighted_median) so irregular sampling does not skew results.However, in
checks.py:1424-1433:final_window_maskevaluates(profile.stamps_ns[-1] - profile.stamps_ns[:-1]) / 1e9 <= final_pose_window_s. Becauseprofile.stamps_ns[:-1]is the START of each step, any stream whose sample period exceedsfinal_pose_window_s(e.g. 1 Hz or 2 Hz streams with the default 0.5s window) has zero steps satisfying the mask. Bothfinal_pose_speedandfinal_pose_unsettled_ratioare silently omitted despite the robot moving actively. Curation queries joining onfinal_pose_speeddrop these episodes completely.final_speedis calculated using unweightednp.mean(profile.speeds[final_window_mask]). Irregular sampling in the final window distortsfinal_speedby orders of magnitude and produces severe false positives infinal_pose_unsettled_ratio.Minimal Reproduction