from dataclasses import replace import pytest from linkerhand_calibration.core.domain.profile import ReferenceWaypoint from linkerhand_calibration.profiles import load_bundled_hand_profile, dump_hand_profile, load_hand_profile from linkerhand_calibration.runtime.execution import SessionExecution from linkerhand_calibration.runtime.session import CalibrationPhase as Phase from linkerhand_calibration.runtime.resume import select_installation_evidence, ResumeVerifier from test_resume_v2 import _fingerprint def test_reference_waypoint_cannot_drive_disabled_channel(): from linkerhand_calibration.core.domain.profile import validate_profile profile = load_bundled_hand_profile("g20_right_19") channel = next(iter(profile.command.disabled_indices)) pose = list(profile.command.baseline_values) pose[channel] -= 1 view = profile.vision.views[0] tag = next(tag for tag in view.tags if not tag.fixed_reference) waypoint = ReferenceWaypoint("show", tuple(pose), {view.name: (tag.tag_id,)}) profile = replace(profile, motion=replace(profile.motion, resume_verification_waypoints=(waypoint,))) with pytest.raises(ValueError, match="disabled channels"): validate_profile(profile) def test_reference_waypoints_share_executor_and_return_before_resume(tmp_path): profile = load_bundled_hand_profile("l6_right_8") # Legacy v2 sessions retain their all-at-start verification waypoint API. profile = replace(profile, artifacts=replace(profile.artifacts, output_schema_version=2)) pose = (230., 255., 255., 255., 255., 255.) waypoint = ReferenceWaypoint("show_tip", pose, {"front": (2,)}) profile = replace(profile, motion=replace(profile.motion, resume_verification_waypoints=(waypoint,))) path = tmp_path/"virtual.yaml" path.write_text(dump_hand_profile(profile)) assert load_hand_profile(path) == profile engine = SessionExecution(profile) engine.session.device_ready() engine.session.start(resume_requested=True) current = profile.command.baseline_values while engine.session.phase == Phase.BASELINE: motion = engine.motion(current); current = motion.target; engine.motion_complete() engine.session.reference_locked() assert engine.session.phase == Phase.REFERENCE_POSES motion = engine.motion(current) assert motion.phase == "reference_pose" and motion.target == pose while engine.session.phase == Phase.REFERENCE_POSES: motion = engine.motion(current); current = motion.target; engine.motion_complete() assert current == profile.command.baseline_values assert engine.session.phase == Phase.RESUME_VERIFY def test_resume_never_compares_mounts_from_different_waypoint_poses(): fingerprint = _fingerprint() pose = fingerprint.moving_tag_poses["finger"] old = replace(fingerprint, moving_tag_poses={"show/finger": pose}) new = replace(fingerprint, moving_tag_poses={"other/finger": pose}) checker = ResumeVerifier(required_moving_poses=("finger",)) assert not checker.compare(*select_installation_evidence(old, new, {"finger"})).reuse assert checker.compare(*select_installation_evidence(old, old, {"finger"})).reuse missing = replace(fingerprint, moving_tag_poses={}) assert not checker.compare(*select_installation_evidence(old, missing, {"finger"})).reuse