devagent-physical-engine 1.6.0__tar.gz → 1.6.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. {devagent_physical_engine-1.6.0/src/devagent_physical_engine.egg-info → devagent_physical_engine-1.6.2}/PKG-INFO +30 -5
  2. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/README.md +29 -4
  3. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/pyproject.toml +1 -1
  4. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/__init__.py +5 -1
  5. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/joint_state_recorder.py +40 -4
  6. devagent_physical_engine-1.6.2/src/devagent_physical_engine/ros2/moveit_joint_plan_v161_probe.py +154 -0
  7. devagent_physical_engine-1.6.2/src/devagent_physical_engine/ros2/support_contact_runner_v161.py +41 -0
  8. devagent_physical_engine-1.6.2/src/devagent_physical_engine/ros2/support_contact_v161.py +165 -0
  9. devagent_physical_engine-1.6.2/src/devagent_physical_engine/smooth_motion_hotfix_v162.py +39 -0
  10. devagent_physical_engine-1.6.2/src/devagent_physical_engine/support_contact_hotfix_v161.py +12 -0
  11. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2/src/devagent_physical_engine.egg-info}/PKG-INFO +30 -5
  12. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine.egg-info/SOURCES.txt +8 -0
  13. devagent_physical_engine-1.6.2/tests/test_golden_abb_showcase.py +102 -0
  14. devagent_physical_engine-1.6.2/tests/test_smooth_motion_hotfix_v162.py +81 -0
  15. devagent_physical_engine-1.6.2/tests/test_support_contact_hotfix_v161.py +169 -0
  16. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/NOTICE +0 -0
  17. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/setup.cfg +0 -0
  18. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/agent/__init__.py +0 -0
  19. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/agent/compiler.py +0 -0
  20. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/agent/contracts.py +0 -0
  21. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/agent/coordinator.py +0 -0
  22. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/agent/critic.py +0 -0
  23. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/agent/evidence.py +0 -0
  24. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/agent/interpreter.py +0 -0
  25. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/agent/planner.py +0 -0
  26. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/agent/recovery.py +0 -0
  27. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/agent/routing.py +0 -0
  28. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/agent/runtime.py +0 -0
  29. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/agent/semantic.py +0 -0
  30. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/agent/structured.py +0 -0
  31. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ai_cli.py +0 -0
  32. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/cli.py +0 -0
  33. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/commercial.py +0 -0
  34. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/commercial_campaign.py +0 -0
  35. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/commercial_cli.py +0 -0
  36. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/commercial_importer.py +0 -0
  37. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/commercial_intelligence.py +0 -0
  38. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/commercial_readiness.py +0 -0
  39. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/commercial_repository.py +0 -0
  40. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/continuous_clearance.py +0 -0
  41. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/doctor.py +0 -0
  42. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/engineering_agent.py +0 -0
  43. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/engineering_request.py +0 -0
  44. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/evidence_replay.py +0 -0
  45. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/evidence_trust.py +0 -0
  46. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/execution.py +0 -0
  47. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/models.py +0 -0
  48. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/one_command.py +0 -0
  49. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/one_command_runtime.py +0 -0
  50. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/one_command_v15.py +0 -0
  51. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/one_command_v16.py +0 -0
  52. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/operating_envelope.py +0 -0
  53. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/optimization/__init__.py +0 -0
  54. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/optimization/benchmark.py +0 -0
  55. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/optimization/candidates.py +0 -0
  56. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/optimization/contracts.py +0 -0
  57. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/optimization/evaluator.py +0 -0
  58. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/optimization/evidence.py +0 -0
  59. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/optimization/experience.py +0 -0
  60. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/optimization/measured.py +0 -0
  61. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/optimization/optimizer.py +0 -0
  62. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/optimization/orchestrator.py +0 -0
  63. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/physical_campaign.py +0 -0
  64. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/physical_evidence.py +0 -0
  65. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/physical_motion.py +0 -0
  66. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/planning.py +0 -0
  67. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/pose_math.py +0 -0
  68. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/preexecution_contract.py +0 -0
  69. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/production_authority.py +0 -0
  70. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/production_grade.py +0 -0
  71. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/project.py +0 -0
  72. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/provider_adapters/__init__.py +0 -0
  73. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/provider_adapters/anthropic.py +0 -0
  74. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/provider_adapters/common.py +0 -0
  75. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/provider_adapters/factory.py +0 -0
  76. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/provider_adapters/gemini.py +0 -0
  77. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/provider_adapters/openai.py +0 -0
  78. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/provider_criterion.py +0 -0
  79. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/provider_qualification.py +0 -0
  80. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/providers.py +0 -0
  81. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/qualification.py +0 -0
  82. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/qualification_cli.py +0 -0
  83. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/qualification_harness.py +0 -0
  84. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/reference_workcell.py +0 -0
  85. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/report_test_execution.py +0 -0
  86. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/report_test_execution_strict.py +0 -0
  87. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/robot_platform.py +0 -0
  88. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/robots.py +0 -0
  89. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/__init__.py +0 -0
  90. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/acceptance.py +0 -0
  91. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/commands.py +0 -0
  92. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/continuous_clearance_probe.py +0 -0
  93. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/doctor.py +0 -0
  94. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/fk_pose.py +0 -0
  95. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/fk_probe.py +0 -0
  96. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/frame_alignment.py +0 -0
  97. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/gazebo_cli.py +0 -0
  98. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/gazebo_pose.py +0 -0
  99. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/gazebo_world.py +0 -0
  100. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/joint_state_probe.py +0 -0
  101. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/measured_motion.py +0 -0
  102. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/moveit_joint_plan_probe.py +0 -0
  103. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/moveit_scene.py +0 -0
  104. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/moveit_task_planner.py +0 -0
  105. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/preexecution.py +0 -0
  106. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/qualification.py +0 -0
  107. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/qualification_v10.py +0 -0
  108. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/qualification_v11.py +0 -0
  109. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/qualification_v12.py +0 -0
  110. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/report_test_visualization.py +0 -0
  111. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/scene_probe.py +0 -0
  112. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/state_validity_probe.py +0 -0
  113. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/task_adapter.py +0 -0
  114. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/task_visualization.py +0 -0
  115. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/tf_probe.py +0 -0
  116. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/tool_scene.py +0 -0
  117. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/tool_scene_probe.py +0 -0
  118. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/trajectory.py +0 -0
  119. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/trajectory_action_probe.py +0 -0
  120. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/trajectory_tracking.py +0 -0
  121. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/ur5e.py +0 -0
  122. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/ur5e_adapter.py +0 -0
  123. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/ur5e_v10_adapter.py +0 -0
  124. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/workpiece_follow.py +0 -0
  125. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/workpiece_gazebo_follower.py +0 -0
  126. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/workpiece_scene.py +0 -0
  127. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/ros2/workpiece_scene_probe.py +0 -0
  128. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/selective_verification.py +0 -0
  129. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/selective_verification_v16.py +0 -0
  130. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/setup_profile.py +0 -0
  131. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/sim_real_qualification.py +0 -0
  132. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/simulation.py +0 -0
  133. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/simulation_platform.py +0 -0
  134. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/tool_collision.py +0 -0
  135. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/trajectory_qualification.py +0 -0
  136. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/twin.py +0 -0
  137. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/twin_builder.py +0 -0
  138. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/twin_codec.py +0 -0
  139. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/twin_materialization.py +0 -0
  140. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/user_cli.py +0 -0
  141. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/user_cli_v15.py +0 -0
  142. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/user_cli_v16.py +0 -0
  143. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/verification.py +0 -0
  144. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine/workpiece_lifecycle.py +0 -0
  145. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine.egg-info/dependency_links.txt +0 -0
  146. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine.egg-info/entry_points.txt +0 -0
  147. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine.egg-info/requires.txt +0 -0
  148. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/src/devagent_physical_engine.egg-info/top_level.txt +0 -0
  149. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_agent_core.py +0 -0
  150. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_agent_semantic_hardening.py +0 -0
  151. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_ai_cli.py +0 -0
  152. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_ai_cli_v07.py +0 -0
  153. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_commercial_importer_v1.py +0 -0
  154. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_commercial_intelligence_v15.py +0 -0
  155. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_commercial_readiness_v1.py +0 -0
  156. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_commercial_v1.py +0 -0
  157. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_continuous_clearance_v011.py +0 -0
  158. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_core.py +0 -0
  159. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_engineering_request_v07.py +0 -0
  160. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_evidence_replay_v12.py +0 -0
  161. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_evidence_trust_coverage_v12.py +0 -0
  162. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_evidence_trust_transport_v12.py +0 -0
  163. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_evidence_trust_v12.py +0 -0
  164. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_evidence_viewer_palette_v130.py +0 -0
  165. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_gazebo_cli_v0122.py +0 -0
  166. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_interpreter_profiles_v08.py +0 -0
  167. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_joint_state_probe_v0125.py +0 -0
  168. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_live_provider_qualification.py +0 -0
  169. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_measured_motion_v10.py +0 -0
  170. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_moveit_planning_diagnostics_v0125.py +0 -0
  171. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_moveit_scene_v0123.py +0 -0
  172. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_natural_language_agent_v07.py +0 -0
  173. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_one_command_hardening_v13.py +0 -0
  174. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_one_command_pose_hardening_v15.py +0 -0
  175. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_one_command_regression_v141.py +0 -0
  176. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_one_command_v13.py +0 -0
  177. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_openai_strict_schema_v0113.py +0 -0
  178. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_optimization_v05.py +0 -0
  179. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_physical_campaign_v09.py +0 -0
  180. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_physical_evidence_v09.py +0 -0
  181. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_physical_motion_v09.py +0 -0
  182. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_planning_fallback_v012.py +0 -0
  183. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_pose_math_v0125.py +0 -0
  184. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_preexecution_contract_v10.py +0 -0
  185. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_production_authority_v11.py +0 -0
  186. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_production_grade_coverage_v11.py +0 -0
  187. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_production_grade_v11.py +0 -0
  188. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_project_spine_v013.py +0 -0
  189. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_provider_and_qualification.py +0 -0
  190. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_provider_criterion_v15.py +0 -0
  191. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_qualification_cli_lifecycle_v06.py +0 -0
  192. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_qualification_harness_v06.py +0 -0
  193. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_readme_pypi.py +0 -0
  194. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_real_provider_adapters.py +0 -0
  195. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_reference_workcell_ros_frames_v0125.py +0 -0
  196. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_reference_workcell_v012.py +0 -0
  197. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_report_test_contract_coverage_v16.py +0 -0
  198. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_report_test_lineage_v16.py +0 -0
  199. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_report_test_visual_execution_v16.py +0 -0
  200. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_robot_platform_v08.py +0 -0
  201. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_ros2_production_receipts_v011.py +0 -0
  202. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_ros2_simulation.py +0 -0
  203. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_ros_trajectory_v09.py +0 -0
  204. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_selective_verification_v14.py +0 -0
  205. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_setup_profile.py +0 -0
  206. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_sim_real_qualification_v011.py +0 -0
  207. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_simulation_platform_v08.py +0 -0
  208. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_tool_collision_v011.py +0 -0
  209. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_tool_scene_v0124.py +0 -0
  210. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_trajectory_action_probe_v0125.py +0 -0
  211. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_trajectory_qualification_v09.py +0 -0
  212. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_trajectory_tracking_v0125.py +0 -0
  213. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_twin_materialization_v10.py +0 -0
  214. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_twin_v08.py +0 -0
  215. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_ur5e_adapter_scopes_v09.py +0 -0
  216. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_ur5e_v10_adapter_scopes.py +0 -0
  217. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_user_cli_interactive_v131.py +0 -0
  218. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_user_cli_progress_v131.py +0 -0
  219. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_user_cli_report_visual_v16.py +0 -0
  220. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_user_cli_selective_v14.py +0 -0
  221. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_user_cli_v15.py +0 -0
  222. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_user_cli_v15_hotfix_inheritance.py +0 -0
  223. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_v052_stabilization.py +0 -0
  224. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_v08_catalog_mapping_regression.py +0 -0
  225. {devagent_physical_engine-1.6.0 → devagent_physical_engine-1.6.2}/tests/test_workpiece_lifecycle_v011.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devagent-physical-engine
3
- Version: 1.6.0
3
+ Version: 1.6.2
4
4
  Summary: Production-grade verification-first robotics evidence runtime with one-command customer intake, validated requirement mapping, report-test Gazebo visualization, requirement-driven test generation, selective verification, deterministic Twin lineage, measured physical verification, replay inspection, regression, and FAT evidence.
5
5
  Author: Tom Ha
6
6
  License: All Rights Reserved
@@ -82,7 +82,7 @@ DevAgent is designed to answer: **What can be proven about this cell, what faile
82
82
  Python 3.11+ is required.
83
83
 
84
84
  ```bash
85
- python -m pip install --upgrade devagent-physical-engine==1.6.0
85
+ python -m pip install --upgrade devagent-physical-engine==1.6.2
86
86
  ```
87
87
 
88
88
  Verify the installed package:
@@ -94,7 +94,7 @@ python -c "import devagent_physical_engine as d; print(d.__version__)"
94
94
  Expected:
95
95
 
96
96
  ```text
97
- 1.6.0
97
+ 1.6.2
98
98
  ```
99
99
 
100
100
  Run the normal customer workflow:
@@ -207,6 +207,31 @@ devagent-physical ros demo
207
207
 
208
208
  for report evidence.
209
209
 
210
+ ## v1.6.1 support-contact lift hotfix
211
+
212
+ The qualified reference load profile starts with the workpiece physically resting on its source support. During the first attached-object `lift` preflight, v1.6.1 preserves the complete live MoveIt Allowed Collision Matrix and enables exactly one temporary request-local pair:
213
+
214
+ ```text
215
+ attached workpiece ↔ conveyor_a support surface
216
+ ```
217
+
218
+ That allowance is scoped to lift departure only. Transfer/place keep normal collision checking, no global PlanningScene collision policy is disabled, and the live ACM is never replaced by a sparse two-object matrix.
219
+
220
+ ## v1.6.2 smooth visual motion hotfix
221
+
222
+ v1.6.2 makes the packaged UR5e visual task deliberately slower and easier to inspect. The task-specific MoveIt planner defaults are reduced from 25% velocity / 25% acceleration to:
223
+
224
+ ```text
225
+ velocity scale: 12%
226
+ acceleration scale: 8%
227
+ ```
228
+
229
+ This is real trajectory time parameterization through MoveIt and `FollowJointTrajectory`; DevAgent does not fake smoothness with teleports or sleeps. Explicit planner scales remain authoritative. Collision checks, endpoint tolerances, tracking tolerances, Twin lineage, and real-execution authority are unchanged.
230
+
231
+ The joint-state recorder also rejects duplicate/backward ROS source timestamps before trajectory interpolation while recording the number of dropped samples. This removes the false `trajectory_tracking_time_not_increasing` failure caused by duplicate Gazebo/ros2_control JointState stamps without manufacturing synthetic timestamps.
232
+
233
+ Because the visual trajectory now executes more slowly, cycle-time requirements are evaluated against the actual slower simulation execution. DevAgent does not normalize the observed duration back to a faster value or claim performance that was not executed.
234
+
210
235
  ## Exact lineage hardening
211
236
 
212
237
  A case ID such as `case-0001` is local to its verification plan. v1.6 therefore requires the complete lineage:
@@ -502,9 +527,9 @@ devagent-physical-ai optional provider-backed engineering front end
502
527
 
503
528
  # Project status
504
529
 
505
- **v1.6.0 — Production/Stable software workflow**
530
+ **v1.6.2 — Production/Stable software workflow**
506
531
 
507
- v1.6.0 adds exact-Twin report-test visual execution, immutable Requirement→Mapping→Verification Plan→Case lineage validation, qualified Gazebo/MoveIt execution for the packaged UR5e nominal report profile, typed simulation measurement binding, interactive report-case visualization, and fail-closed handling for unsupported or ambiguous execution scopes.
532
+ v1.6.2 slows the packaged UR5e task/report visual motion to conservative 12% velocity / 8% acceleration defaults and hardens JointState acquisition against duplicate/backward ROS timestamps. It retains the v1.6.1 lift support-contact fix, exact-Twin report execution, immutable Requirement→Mapping→Verification Plan→Case lineage, typed simulation measurements, and fail-closed authority boundaries.
508
533
 
509
534
  Production-oriented software capabilities include:
510
535
 
@@ -41,7 +41,7 @@ DevAgent is designed to answer: **What can be proven about this cell, what faile
41
41
  Python 3.11+ is required.
42
42
 
43
43
  ```bash
44
- python -m pip install --upgrade devagent-physical-engine==1.6.0
44
+ python -m pip install --upgrade devagent-physical-engine==1.6.2
45
45
  ```
46
46
 
47
47
  Verify the installed package:
@@ -53,7 +53,7 @@ python -c "import devagent_physical_engine as d; print(d.__version__)"
53
53
  Expected:
54
54
 
55
55
  ```text
56
- 1.6.0
56
+ 1.6.2
57
57
  ```
58
58
 
59
59
  Run the normal customer workflow:
@@ -166,6 +166,31 @@ devagent-physical ros demo
166
166
 
167
167
  for report evidence.
168
168
 
169
+ ## v1.6.1 support-contact lift hotfix
170
+
171
+ The qualified reference load profile starts with the workpiece physically resting on its source support. During the first attached-object `lift` preflight, v1.6.1 preserves the complete live MoveIt Allowed Collision Matrix and enables exactly one temporary request-local pair:
172
+
173
+ ```text
174
+ attached workpiece ↔ conveyor_a support surface
175
+ ```
176
+
177
+ That allowance is scoped to lift departure only. Transfer/place keep normal collision checking, no global PlanningScene collision policy is disabled, and the live ACM is never replaced by a sparse two-object matrix.
178
+
179
+ ## v1.6.2 smooth visual motion hotfix
180
+
181
+ v1.6.2 makes the packaged UR5e visual task deliberately slower and easier to inspect. The task-specific MoveIt planner defaults are reduced from 25% velocity / 25% acceleration to:
182
+
183
+ ```text
184
+ velocity scale: 12%
185
+ acceleration scale: 8%
186
+ ```
187
+
188
+ This is real trajectory time parameterization through MoveIt and `FollowJointTrajectory`; DevAgent does not fake smoothness with teleports or sleeps. Explicit planner scales remain authoritative. Collision checks, endpoint tolerances, tracking tolerances, Twin lineage, and real-execution authority are unchanged.
189
+
190
+ The joint-state recorder also rejects duplicate/backward ROS source timestamps before trajectory interpolation while recording the number of dropped samples. This removes the false `trajectory_tracking_time_not_increasing` failure caused by duplicate Gazebo/ros2_control JointState stamps without manufacturing synthetic timestamps.
191
+
192
+ Because the visual trajectory now executes more slowly, cycle-time requirements are evaluated against the actual slower simulation execution. DevAgent does not normalize the observed duration back to a faster value or claim performance that was not executed.
193
+
169
194
  ## Exact lineage hardening
170
195
 
171
196
  A case ID such as `case-0001` is local to its verification plan. v1.6 therefore requires the complete lineage:
@@ -461,9 +486,9 @@ devagent-physical-ai optional provider-backed engineering front end
461
486
 
462
487
  # Project status
463
488
 
464
- **v1.6.0 — Production/Stable software workflow**
489
+ **v1.6.2 — Production/Stable software workflow**
465
490
 
466
- v1.6.0 adds exact-Twin report-test visual execution, immutable Requirement→Mapping→Verification Plan→Case lineage validation, qualified Gazebo/MoveIt execution for the packaged UR5e nominal report profile, typed simulation measurement binding, interactive report-case visualization, and fail-closed handling for unsupported or ambiguous execution scopes.
491
+ v1.6.2 slows the packaged UR5e task/report visual motion to conservative 12% velocity / 8% acceleration defaults and hardens JointState acquisition against duplicate/backward ROS timestamps. It retains the v1.6.1 lift support-contact fix, exact-Twin report execution, immutable Requirement→Mapping→Verification Plan→Case lineage, typed simulation measurements, and fail-closed authority boundaries.
467
492
 
468
493
  Production-oriented software capabilities include:
469
494
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "devagent-physical-engine"
7
- version = "1.6.0"
7
+ version = "1.6.2"
8
8
  description = "Production-grade verification-first robotics evidence runtime with one-command customer intake, validated requirement mapping, report-test Gazebo visualization, requirement-driven test generation, selective verification, deterministic Twin lineage, measured physical verification, replay inspection, regression, and FAT evidence."
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  requires-python = ">=3.11"
@@ -108,6 +108,8 @@ from .selective_verification import (
108
108
  VerificationTestMappingRecorder,
109
109
  )
110
110
  from .selective_verification_v16 import SelectiveVerificationServiceV16
111
+ from .smooth_motion_hotfix_v162 import install_smooth_motion_hotfix_v162
112
+ from .support_contact_hotfix_v161 import install_support_contact_hotfix_v161
111
113
  from .twin import TwinConfidenceLevel, TwinSpec, TwinValidationReport, TwinValidator
112
114
  from .twin_codec import twin_from_dict, twin_from_revision
113
115
 
@@ -209,6 +211,8 @@ __all__ = [
209
211
  "twin_from_revision",
210
212
  ]
211
213
 
214
+ install_support_contact_hotfix_v161()
215
+ install_smooth_motion_hotfix_v162()
212
216
  install_one_command_runtime()
213
217
 
214
- __version__ = "1.6.0"
218
+ __version__ = "1.6.2"
@@ -14,6 +14,29 @@ def _atomic_json(path: Path, payload: dict[str, object]) -> None:
14
14
  temporary.replace(path)
15
15
 
16
16
 
17
+ def accepted_sample_time_ns(
18
+ *,
19
+ stamped_ns: int,
20
+ fallback_ns: int,
21
+ previous_ns: int | None,
22
+ ) -> int | None:
23
+ """Return one strictly increasing sample timestamp or reject the duplicate.
24
+
25
+ Some ros2_control/Gazebo publishers can emit more than one JointState callback
26
+ with the same ROS header stamp. Tracking interpolation requires a strictly
27
+ increasing time axis, so duplicate/backward source stamps are discarded rather
28
+ than silently perturbing their timestamps. The recorder reports how many samples
29
+ were discarded so the raw acquisition behavior remains auditable.
30
+ """
31
+
32
+ candidate = int(stamped_ns) if int(stamped_ns) > 0 else int(fallback_ns)
33
+ if candidate < 0:
34
+ return None
35
+ if previous_ns is not None and candidate <= int(previous_ns):
36
+ return None
37
+ return candidate
38
+
39
+
17
40
  def main() -> int:
18
41
  parser = argparse.ArgumentParser()
19
42
  parser.add_argument("--output", required=True)
@@ -30,6 +53,7 @@ def main() -> int:
30
53
  samples: list[dict[str, object]] = []
31
54
  overflow = False
32
55
  ready_written = False
56
+ dropped_non_increasing = 0
33
57
 
34
58
  import rclpy
35
59
  from sensor_msgs.msg import JointState
@@ -37,20 +61,29 @@ def main() -> int:
37
61
  rclpy.init()
38
62
  node = rclpy.create_node("devagent_joint_state_recorder")
39
63
  started_ns: int | None = None
64
+ previous_ns: int | None = None
40
65
 
41
66
  def callback(message: JointState) -> None:
42
- nonlocal started_ns, overflow, ready_written
67
+ nonlocal started_ns, previous_ns, overflow, ready_written, dropped_non_increasing
43
68
  stamp = message.header.stamp
44
69
  stamped_ns = int(stamp.sec) * 1_000_000_000 + int(stamp.nanosec)
45
- now_ns = stamped_ns if stamped_ns > 0 else node.get_clock().now().nanoseconds
70
+ selected_ns = accepted_sample_time_ns(
71
+ stamped_ns=stamped_ns,
72
+ fallback_ns=node.get_clock().now().nanoseconds,
73
+ previous_ns=previous_ns,
74
+ )
75
+ if selected_ns is None:
76
+ dropped_non_increasing += 1
77
+ return
78
+ previous_ns = selected_ns
46
79
  if started_ns is None:
47
- started_ns = now_ns
80
+ started_ns = selected_ns
48
81
  if len(samples) >= int(args.max_samples):
49
82
  overflow = True
50
83
  return
51
84
  samples.append(
52
85
  {
53
- "time_s": (now_ns - started_ns) / 1_000_000_000.0,
86
+ "time_s": (selected_ns - started_ns) / 1_000_000_000.0,
54
87
  "names": list(message.name),
55
88
  "positions_rad": list(message.position),
56
89
  }
@@ -62,6 +95,7 @@ def main() -> int:
62
95
  "ready": True,
63
96
  "topic": args.topic,
64
97
  "first_sample_received": True,
98
+ "strictly_increasing_time": True,
65
99
  },
66
100
  )
67
101
  ready_written = True
@@ -77,6 +111,8 @@ def main() -> int:
77
111
  "sample_count": len(samples),
78
112
  "overflow": overflow,
79
113
  "ready_observed": ready_written,
114
+ "strictly_increasing_time": True,
115
+ "dropped_non_increasing_count": dropped_non_increasing,
80
116
  "samples": samples,
81
117
  }
82
118
  _atomic_json(output, payload)
@@ -0,0 +1,154 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ from pathlib import Path
6
+ import sys
7
+ from typing import Any, Mapping
8
+
9
+ # ROS helpers are executed by absolute file path under the distro Python rather than
10
+ # the caller's virtualenv. Add the package src root explicitly so this hotfix can reuse
11
+ # the validated v1.6 probe contract without inheriting virtualenv Python overrides.
12
+ _SRC_ROOT = Path(__file__).resolve().parents[2]
13
+ if str(_SRC_ROOT) not in sys.path:
14
+ sys.path.insert(0, str(_SRC_ROOT))
15
+
16
+ from devagent_physical_engine.ros2 import moveit_joint_plan_probe as base
17
+ from devagent_physical_engine.ros2.support_contact_v161 import (
18
+ SUPPORT_CONTACT_SCOPE,
19
+ SupportContactContractError,
20
+ allow_only_support_pair,
21
+ )
22
+
23
+
24
+ def _support_contract(path: Path) -> tuple[str, str] | None:
25
+ try:
26
+ payload = json.loads(path.read_text(encoding="utf-8"))
27
+ except (OSError, json.JSONDecodeError) as exc:
28
+ raise SupportContactContractError("support_contact_request_invalid") from exc
29
+ if not isinstance(payload, Mapping):
30
+ raise SupportContactContractError("support_contact_request_invalid")
31
+ scene = payload.get("scene_contract")
32
+ if not isinstance(scene, Mapping) or scene.get("allow_support_contact") is not True:
33
+ return None
34
+ if str(scene.get("state") or "") != "attached":
35
+ raise SupportContactContractError("support_contact_requires_attached_scene")
36
+ if str(scene.get("support_contact_scope") or "") != SUPPORT_CONTACT_SCOPE:
37
+ raise SupportContactContractError("support_contact_scope_invalid")
38
+ workpiece = scene.get("workpiece")
39
+ if not isinstance(workpiece, Mapping):
40
+ raise SupportContactContractError("support_contact_workpiece_missing")
41
+ workpiece_id = str(workpiece.get("id") or "").strip()
42
+ support_id = str(scene.get("support_surface_id") or "").strip()
43
+ if not workpiece_id or not support_id or workpiece_id == support_id:
44
+ raise SupportContactContractError("support_contact_pair_invalid")
45
+ return workpiece_id, support_id
46
+
47
+
48
+ def _read_live_acm(*, timeout_s: float) -> dict[str, Any]:
49
+ import rclpy
50
+ from moveit_msgs.msg import PlanningSceneComponents
51
+ from moveit_msgs.srv import GetPlanningScene
52
+
53
+ rclpy.init()
54
+ node = rclpy.create_node("devagent_moveit_support_acm_probe_v161")
55
+ client = node.create_client(GetPlanningScene, "/get_planning_scene")
56
+ try:
57
+ if not client.wait_for_service(timeout_sec=timeout_s):
58
+ raise SupportContactContractError("moveit_planning_scene_service_unavailable")
59
+ request = GetPlanningScene.Request()
60
+ request.components.components = PlanningSceneComponents.ALLOWED_COLLISION_MATRIX
61
+ future = client.call_async(request)
62
+ rclpy.spin_until_future_complete(node, future, timeout_sec=timeout_s)
63
+ if not future.done() or future.result() is None:
64
+ raise SupportContactContractError("moveit_planning_scene_acm_timeout")
65
+ acm = future.result().scene.allowed_collision_matrix
66
+ return {
67
+ "entry_names": [str(value) for value in acm.entry_names],
68
+ "entry_values": [list(item.enabled) for item in acm.entry_values],
69
+ "default_entry_names": [str(value) for value in acm.default_entry_names],
70
+ "default_entry_values": [bool(value) for value in acm.default_entry_values],
71
+ }
72
+ finally:
73
+ node.destroy_client(client)
74
+ node.destroy_node()
75
+ if rclpy.ok():
76
+ rclpy.shutdown()
77
+
78
+
79
+ def _install_full_acm(payload: Mapping[str, Any]):
80
+ original = base._apply_scene_contract
81
+
82
+ def apply(goal, contract):
83
+ original(goal, contract)
84
+ from moveit_msgs.msg import AllowedCollisionEntry
85
+
86
+ acm = goal.planning_options.planning_scene_diff.allowed_collision_matrix
87
+ acm.entry_names = list(payload["entry_names"])
88
+ acm.entry_values = [
89
+ AllowedCollisionEntry(enabled=list(row))
90
+ for row in payload["entry_values"]
91
+ ]
92
+ acm.default_entry_names = list(payload["default_entry_names"])
93
+ acm.default_entry_values = list(payload["default_entry_values"])
94
+
95
+ base._apply_scene_contract = apply
96
+ return original
97
+
98
+
99
+ def plan(path: Path, *, timeout_s: float) -> dict[str, Any]:
100
+ support = _support_contract(path)
101
+ if support is None:
102
+ return base.plan(path, timeout_s=timeout_s)
103
+ workpiece_id, support_id = support
104
+ live = _read_live_acm(timeout_s=timeout_s)
105
+ augmented = allow_only_support_pair(
106
+ live,
107
+ workpiece_id=workpiece_id,
108
+ support_surface_id=support_id,
109
+ )
110
+ original = _install_full_acm(augmented)
111
+ try:
112
+ result = dict(base.plan(path, timeout_s=timeout_s))
113
+ finally:
114
+ base._apply_scene_contract = original
115
+ result.update(
116
+ {
117
+ "support_contact_allowed": True,
118
+ "support_contact_scope": SUPPORT_CONTACT_SCOPE,
119
+ "support_surface_id": support_id,
120
+ "support_workpiece_id": workpiece_id,
121
+ "support_acm_entry_count": len(augmented["entry_names"]),
122
+ }
123
+ )
124
+ if (
125
+ result.get("success") is not True
126
+ and str(result.get("code") or "").startswith("move_group_action_status_")
127
+ ):
128
+ result["underlying_code"] = result.get("code")
129
+ result["code"] = "moveit_support_contact_departure_aborted"
130
+ return result
131
+
132
+
133
+ def main() -> int:
134
+ parser = argparse.ArgumentParser()
135
+ parser.add_argument("--input", required=True)
136
+ parser.add_argument("--timeout", type=float, default=15.0)
137
+ args = parser.parse_args()
138
+ try:
139
+ result = plan(
140
+ Path(args.input).expanduser().resolve(),
141
+ timeout_s=float(args.timeout),
142
+ )
143
+ except Exception as exc:
144
+ result = {
145
+ "success": False,
146
+ "code": f"moveit_support_contact_probe_error:{type(exc).__name__}",
147
+ "detail": str(exc),
148
+ }
149
+ print(json.dumps(result, sort_keys=True))
150
+ return 0 if result.get("success") else 2
151
+
152
+
153
+ if __name__ == "__main__":
154
+ raise SystemExit(main())
@@ -0,0 +1,41 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from typing import Sequence
5
+
6
+ from .commands import CommandResult, SubprocessRosRunner
7
+ from .support_contact_v161 import prepare_lift_support_request
8
+
9
+
10
+ _LEGACY_PROBE = "moveit_joint_plan_probe.py"
11
+ _HOTFIX_PROBE = "moveit_joint_plan_v161_probe.py"
12
+
13
+
14
+ def rewrite_moveit_probe_command(command: Sequence[str]) -> tuple[str, ...]:
15
+ rewritten = [str(value) for value in command]
16
+ if len(rewritten) < 2 or Path(rewritten[1]).name != _LEGACY_PROBE:
17
+ return tuple(rewritten)
18
+ try:
19
+ input_index = rewritten.index("--input") + 1
20
+ request_path = Path(rewritten[input_index]).expanduser().resolve()
21
+ except (ValueError, IndexError):
22
+ return tuple(rewritten)
23
+ if not prepare_lift_support_request(request_path):
24
+ return tuple(rewritten)
25
+ rewritten[1] = str(Path(__file__).with_name(_HOTFIX_PROBE).resolve())
26
+ return tuple(rewritten)
27
+
28
+
29
+ class SupportContactSubprocessRosRunner(SubprocessRosRunner):
30
+ """Report-test ROS runner with a bounded lift support-contact preflight hotfix."""
31
+
32
+ def run(
33
+ self,
34
+ command: Sequence[str],
35
+ *,
36
+ timeout_s: float = 15.0,
37
+ ) -> CommandResult:
38
+ return super().run(
39
+ rewrite_moveit_probe_command(command),
40
+ timeout_s=timeout_s,
41
+ )
@@ -0,0 +1,165 @@
1
+ from __future__ import annotations
2
+
3
+ from copy import deepcopy
4
+ import json
5
+ from pathlib import Path
6
+ from typing import Any, Mapping, Sequence
7
+
8
+ from ..twin_materialization import _backend_id as _materialized_backend_id
9
+
10
+
11
+ QUALIFIED_SOURCE_ENTITY_ID = "conveyor_a"
12
+ SUPPORT_CONTACT_SCOPE = "lift_departure_only"
13
+
14
+
15
+ class SupportContactContractError(ValueError):
16
+ pass
17
+
18
+
19
+ def support_surface_backend_id(
20
+ source_entity_id: str = QUALIFIED_SOURCE_ENTITY_ID,
21
+ ) -> str:
22
+ source = str(source_entity_id).strip()
23
+ if not source:
24
+ raise SupportContactContractError("support_surface_entity_id_missing")
25
+ return _materialized_backend_id(source)
26
+
27
+
28
+ def prepare_lift_support_request(
29
+ path: Path | str,
30
+ *,
31
+ source_entity_id: str = QUALIFIED_SOURCE_ENTITY_ID,
32
+ ) -> bool:
33
+ """Annotate only the qualified lift-departure request with one support pair.
34
+
35
+ The v1.6 report profile preflights every phase before execution. The workpiece is
36
+ resting on the source fixture at the grasp pose, so the first request-local
37
+ attached-object scene must tolerate exactly that workpiece/support contact while
38
+ departing upward. Transfer/place remain untouched and therefore keep normal
39
+ collision checking.
40
+ """
41
+
42
+ target = Path(path).expanduser().resolve()
43
+ if not target.name.endswith("-lift.request.json"):
44
+ return False
45
+ try:
46
+ payload = json.loads(target.read_text(encoding="utf-8"))
47
+ except (OSError, json.JSONDecodeError) as exc:
48
+ raise SupportContactContractError("support_contact_request_invalid") from exc
49
+ if not isinstance(payload, dict):
50
+ raise SupportContactContractError("support_contact_request_invalid")
51
+ raw_scene = payload.get("scene_contract")
52
+ if not isinstance(raw_scene, Mapping) or str(raw_scene.get("state") or "") != "attached":
53
+ return False
54
+ raw_workpiece = raw_scene.get("workpiece")
55
+ if not isinstance(raw_workpiece, Mapping):
56
+ raise SupportContactContractError("support_contact_workpiece_missing")
57
+ workpiece_id = str(raw_workpiece.get("id") or "").strip()
58
+ if not workpiece_id:
59
+ raise SupportContactContractError("support_contact_workpiece_missing")
60
+ support_id = support_surface_backend_id(source_entity_id)
61
+ if support_id == workpiece_id:
62
+ raise SupportContactContractError("support_contact_pair_invalid")
63
+
64
+ scene = dict(raw_scene)
65
+ scene.update(
66
+ {
67
+ "allow_support_contact": True,
68
+ "support_contact_scope": SUPPORT_CONTACT_SCOPE,
69
+ "support_surface_id": support_id,
70
+ }
71
+ )
72
+ payload["scene_contract"] = scene
73
+ temporary = target.with_suffix(target.suffix + ".tmp")
74
+ temporary.write_text(
75
+ json.dumps(payload, sort_keys=True, separators=(",", ":"), allow_nan=False),
76
+ encoding="utf-8",
77
+ )
78
+ temporary.replace(target)
79
+ return True
80
+
81
+
82
+ def _validated_bool_rows(raw: object, *, size: int) -> list[list[bool]]:
83
+ if isinstance(raw, (str, bytes, bytearray)) or not isinstance(raw, Sequence):
84
+ raise SupportContactContractError("allowed_collision_matrix_invalid")
85
+ rows: list[list[bool]] = []
86
+ for item in raw:
87
+ if isinstance(item, (str, bytes, bytearray)) or not isinstance(item, Sequence):
88
+ raise SupportContactContractError("allowed_collision_matrix_invalid")
89
+ row = [bool(value) for value in item]
90
+ if len(row) != size:
91
+ raise SupportContactContractError("allowed_collision_matrix_invalid")
92
+ rows.append(row)
93
+ if len(rows) != size:
94
+ raise SupportContactContractError("allowed_collision_matrix_invalid")
95
+ return rows
96
+
97
+
98
+ def allow_only_support_pair(
99
+ payload: Mapping[str, Any],
100
+ *,
101
+ workpiece_id: str,
102
+ support_surface_id: str,
103
+ ) -> dict[str, Any]:
104
+ """Return a full ACM preserving every existing entry and allowing one pair.
105
+
106
+ MoveIt replaces the ACM when a PlanningScene diff contains entry_names, so a sparse
107
+ two-name matrix would accidentally discard SRDF self-collision allowances. This
108
+ function starts from the full live ACM returned by /get_planning_scene, adds names
109
+ using MoveIt's default-entry semantics, and flips only the symmetric
110
+ workpiece/support pair to True.
111
+ """
112
+
113
+ left = str(workpiece_id).strip()
114
+ right = str(support_surface_id).strip()
115
+ if not left or not right or left == right:
116
+ raise SupportContactContractError("support_contact_pair_invalid")
117
+
118
+ result = deepcopy(dict(payload))
119
+ raw_names = result.get("entry_names", [])
120
+ if isinstance(raw_names, (str, bytes, bytearray)) or not isinstance(raw_names, Sequence):
121
+ raise SupportContactContractError("allowed_collision_matrix_invalid")
122
+ names = [str(value).strip() for value in raw_names]
123
+ if any(not value for value in names) or len(set(names)) != len(names):
124
+ raise SupportContactContractError("allowed_collision_matrix_invalid")
125
+ rows = _validated_bool_rows(result.get("entry_values", []), size=len(names))
126
+
127
+ raw_default_names = result.get("default_entry_names", [])
128
+ raw_default_values = result.get("default_entry_values", [])
129
+ if (
130
+ isinstance(raw_default_names, (str, bytes, bytearray))
131
+ or not isinstance(raw_default_names, Sequence)
132
+ or isinstance(raw_default_values, (str, bytes, bytearray))
133
+ or not isinstance(raw_default_values, Sequence)
134
+ ):
135
+ raise SupportContactContractError("allowed_collision_matrix_invalid")
136
+ default_names = [str(value).strip() for value in raw_default_names]
137
+ default_values = [bool(value) for value in raw_default_values]
138
+ if len(default_names) != len(default_values) or any(not value for value in default_names):
139
+ raise SupportContactContractError("allowed_collision_matrix_invalid")
140
+ default_by_name = dict(zip(default_names, default_values))
141
+
142
+ def add_name(name: str) -> None:
143
+ if name in names:
144
+ return
145
+ if name in default_by_name:
146
+ new_values = [default_by_name[name]] * len(names)
147
+ else:
148
+ new_values = [default_by_name.get(existing, False) for existing in names]
149
+ for row, enabled in zip(rows, (*new_values, False)):
150
+ row.append(bool(enabled))
151
+ names.append(name)
152
+ rows.append([*new_values, False])
153
+
154
+ add_name(left)
155
+ add_name(right)
156
+ left_index = names.index(left)
157
+ right_index = names.index(right)
158
+ rows[left_index][right_index] = True
159
+ rows[right_index][left_index] = True
160
+
161
+ result["entry_names"] = names
162
+ result["entry_values"] = rows
163
+ result["default_entry_names"] = default_names
164
+ result["default_entry_values"] = default_values
165
+ return result
@@ -0,0 +1,39 @@
1
+ from __future__ import annotations
2
+
3
+ from functools import wraps
4
+ from typing import Any
5
+
6
+ from .ros2.moveit_task_planner import MoveItTaskPlanner
7
+
8
+
9
+ VISUAL_MOVEIT_VELOCITY_SCALE = 0.12
10
+ VISUAL_MOVEIT_ACCELERATION_SCALE = 0.08
11
+ _PATCH_MARKER = "_devagent_smooth_motion_v162"
12
+
13
+
14
+ def install_smooth_motion_hotfix_v162() -> None:
15
+ """Install conservative defaults for the task-specific visual MoveIt planner.
16
+
17
+ MoveItTaskPlanner is used only by the packaged task/report visual execution paths.
18
+ Those paths previously inherited 25% velocity and 25% acceleration. On the
19
+ qualified UR5e reference cell that made short pick/lift phases visually abrupt
20
+ and also reduced controller tracking margin on a real Gazebo/ros2_control stack.
21
+
22
+ v1.6.2 lowers only the planner defaults used when the caller did not explicitly
23
+ request a scale. Explicit planner scales remain authoritative. Collision checking,
24
+ endpoint tolerances, tracking tolerances, exact-Twin lineage, and real-execution
25
+ authority are not relaxed.
26
+ """
27
+
28
+ current = MoveItTaskPlanner.__init__
29
+ if getattr(current, _PATCH_MARKER, False):
30
+ return
31
+
32
+ @wraps(current)
33
+ def patched(self: MoveItTaskPlanner, *args: Any, **kwargs: Any) -> None:
34
+ kwargs.setdefault("velocity_scale", VISUAL_MOVEIT_VELOCITY_SCALE)
35
+ kwargs.setdefault("acceleration_scale", VISUAL_MOVEIT_ACCELERATION_SCALE)
36
+ current(self, *args, **kwargs)
37
+
38
+ setattr(patched, _PATCH_MARKER, True)
39
+ MoveItTaskPlanner.__init__ = patched
@@ -0,0 +1,12 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ def install_support_contact_hotfix_v161() -> None:
5
+ """Install the v1.6.1 report-test ROS runner without changing other ROS paths."""
6
+
7
+ from . import report_test_execution
8
+ from .ros2.support_contact_runner_v161 import SupportContactSubprocessRosRunner
9
+
10
+ if report_test_execution.SubprocessRosRunner is SupportContactSubprocessRosRunner:
11
+ return
12
+ report_test_execution.SubprocessRosRunner = SupportContactSubprocessRosRunner