devagent-physical-engine 0.12.0__tar.gz → 0.12.1__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 (149) hide show
  1. {devagent_physical_engine-0.12.0/src/devagent_physical_engine.egg-info → devagent_physical_engine-0.12.1}/PKG-INFO +5 -3
  2. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/README.md +4 -2
  3. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/pyproject.toml +1 -1
  4. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/__init__.py +1 -1
  5. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/trajectory.py +40 -15
  6. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1/src/devagent_physical_engine.egg-info}/PKG-INFO +5 -3
  7. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_ros_trajectory_v09.py +60 -3
  8. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/NOTICE +0 -0
  9. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/setup.cfg +0 -0
  10. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/agent/__init__.py +0 -0
  11. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/agent/compiler.py +0 -0
  12. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/agent/contracts.py +0 -0
  13. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/agent/coordinator.py +0 -0
  14. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/agent/critic.py +0 -0
  15. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/agent/evidence.py +0 -0
  16. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/agent/interpreter.py +0 -0
  17. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/agent/planner.py +0 -0
  18. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/agent/recovery.py +0 -0
  19. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/agent/routing.py +0 -0
  20. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/agent/runtime.py +0 -0
  21. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/agent/semantic.py +0 -0
  22. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/agent/structured.py +0 -0
  23. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ai_cli.py +0 -0
  24. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/cli.py +0 -0
  25. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/continuous_clearance.py +0 -0
  26. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/doctor.py +0 -0
  27. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/engineering_agent.py +0 -0
  28. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/engineering_request.py +0 -0
  29. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/execution.py +0 -0
  30. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/models.py +0 -0
  31. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/operating_envelope.py +0 -0
  32. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/optimization/__init__.py +0 -0
  33. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/optimization/benchmark.py +0 -0
  34. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/optimization/candidates.py +0 -0
  35. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/optimization/contracts.py +0 -0
  36. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/optimization/evaluator.py +0 -0
  37. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/optimization/evidence.py +0 -0
  38. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/optimization/experience.py +0 -0
  39. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/optimization/measured.py +0 -0
  40. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/optimization/optimizer.py +0 -0
  41. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/optimization/orchestrator.py +0 -0
  42. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/physical_campaign.py +0 -0
  43. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/physical_evidence.py +0 -0
  44. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/physical_motion.py +0 -0
  45. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/planning.py +0 -0
  46. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/preexecution_contract.py +0 -0
  47. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/provider_adapters/__init__.py +0 -0
  48. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/provider_adapters/anthropic.py +0 -0
  49. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/provider_adapters/common.py +0 -0
  50. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/provider_adapters/factory.py +0 -0
  51. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/provider_adapters/gemini.py +0 -0
  52. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/provider_adapters/openai.py +0 -0
  53. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/provider_qualification.py +0 -0
  54. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/providers.py +0 -0
  55. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/qualification.py +0 -0
  56. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/qualification_cli.py +0 -0
  57. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/qualification_harness.py +0 -0
  58. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/reference_workcell.py +0 -0
  59. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/robot_platform.py +0 -0
  60. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/robots.py +0 -0
  61. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/__init__.py +0 -0
  62. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/acceptance.py +0 -0
  63. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/commands.py +0 -0
  64. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/continuous_clearance_probe.py +0 -0
  65. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/doctor.py +0 -0
  66. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/fk_pose.py +0 -0
  67. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/fk_probe.py +0 -0
  68. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/frame_alignment.py +0 -0
  69. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/gazebo_pose.py +0 -0
  70. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/gazebo_world.py +0 -0
  71. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/joint_state_recorder.py +0 -0
  72. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/measured_motion.py +0 -0
  73. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/moveit_joint_plan_probe.py +0 -0
  74. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/moveit_scene.py +0 -0
  75. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/moveit_task_planner.py +0 -0
  76. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/preexecution.py +0 -0
  77. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/qualification.py +0 -0
  78. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/qualification_v10.py +0 -0
  79. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/qualification_v11.py +0 -0
  80. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/qualification_v12.py +0 -0
  81. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/scene_probe.py +0 -0
  82. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/state_validity_probe.py +0 -0
  83. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/task_adapter.py +0 -0
  84. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/task_visualization.py +0 -0
  85. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/tf_probe.py +0 -0
  86. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/tool_scene.py +0 -0
  87. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/tool_scene_probe.py +0 -0
  88. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/ur5e.py +0 -0
  89. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/ur5e_adapter.py +0 -0
  90. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/ur5e_v10_adapter.py +0 -0
  91. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/workpiece_follow.py +0 -0
  92. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/workpiece_gazebo_follower.py +0 -0
  93. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/workpiece_scene.py +0 -0
  94. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/ros2/workpiece_scene_probe.py +0 -0
  95. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/setup_profile.py +0 -0
  96. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/sim_real_qualification.py +0 -0
  97. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/simulation.py +0 -0
  98. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/simulation_platform.py +0 -0
  99. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/tool_collision.py +0 -0
  100. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/trajectory_qualification.py +0 -0
  101. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/twin.py +0 -0
  102. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/twin_builder.py +0 -0
  103. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/twin_materialization.py +0 -0
  104. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/verification.py +0 -0
  105. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine/workpiece_lifecycle.py +0 -0
  106. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine.egg-info/SOURCES.txt +0 -0
  107. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine.egg-info/dependency_links.txt +0 -0
  108. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine.egg-info/entry_points.txt +0 -0
  109. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine.egg-info/requires.txt +0 -0
  110. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/src/devagent_physical_engine.egg-info/top_level.txt +0 -0
  111. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_agent_core.py +0 -0
  112. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_agent_semantic_hardening.py +0 -0
  113. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_ai_cli.py +0 -0
  114. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_ai_cli_v07.py +0 -0
  115. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_continuous_clearance_v011.py +0 -0
  116. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_core.py +0 -0
  117. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_engineering_request_v07.py +0 -0
  118. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_interpreter_profiles_v08.py +0 -0
  119. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_live_provider_qualification.py +0 -0
  120. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_measured_motion_v10.py +0 -0
  121. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_natural_language_agent_v07.py +0 -0
  122. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_openai_strict_schema_v0113.py +0 -0
  123. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_optimization_v05.py +0 -0
  124. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_physical_campaign_v09.py +0 -0
  125. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_physical_evidence_v09.py +0 -0
  126. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_physical_motion_v09.py +0 -0
  127. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_planning_fallback_v012.py +0 -0
  128. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_preexecution_contract_v10.py +0 -0
  129. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_provider_and_qualification.py +0 -0
  130. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_qualification_cli_lifecycle_v06.py +0 -0
  131. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_qualification_harness_v06.py +0 -0
  132. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_readme_pypi.py +0 -0
  133. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_real_provider_adapters.py +0 -0
  134. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_reference_workcell_v012.py +0 -0
  135. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_robot_platform_v08.py +0 -0
  136. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_ros2_production_receipts_v011.py +0 -0
  137. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_ros2_simulation.py +0 -0
  138. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_setup_profile.py +0 -0
  139. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_sim_real_qualification_v011.py +0 -0
  140. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_simulation_platform_v08.py +0 -0
  141. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_tool_collision_v011.py +0 -0
  142. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_trajectory_qualification_v09.py +0 -0
  143. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_twin_materialization_v10.py +0 -0
  144. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_twin_v08.py +0 -0
  145. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_ur5e_adapter_scopes_v09.py +0 -0
  146. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_ur5e_v10_adapter_scopes.py +0 -0
  147. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_v052_stabilization.py +0 -0
  148. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/tests/test_v08_catalog_mapping_regression.py +0 -0
  149. {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.1}/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: 0.12.0
3
+ Version: 0.12.1
4
4
  Summary: Verification-first agentic engineering, simulation, and evidence runtime for robotics and industrial automation.
5
5
  Author: Tom Ha
6
6
  License: All Rights Reserved
@@ -189,6 +189,8 @@ measured motion/evidence report
189
189
 
190
190
  On a successful run, Gazebo / MoveIt remains open by default so the engineer can inspect the final workcell. Add `--close-after` to close it after success.
191
191
 
192
+ v0.12.1 hardens the initial ROS joint-state snapshot by parsing `ros2 topic echo --once` output as a YAML document stream. This accepts the normal ROS 2 trailing `---` message separator instead of incorrectly classifying an otherwise valid `/joint_states` sample as `joint_state_snapshot_invalid`.
193
+
192
194
  The packaged reference workcell is **not customer-site geometry**. Arbitrary plant layouts require an imported or user-declared physical Twin with trusted poses, collision geometry, tool/TCP information, and workpiece properties. DevAgent does not invent those site facts from a natural-language prompt.
193
195
 
194
196
  The v0.12 implementation remains evidence-gated: source/CI success does not prove the ROS target campaign has passed on a particular workstation. Use the executable qualification below before treating the task-specific path as qualified on that target.
@@ -416,9 +418,9 @@ Detailed engineering documentation lives in the repository:
416
418
 
417
419
  ## Project status
418
420
 
419
- **v0.12.0 — Beta software / evidence-gated task-specific physical simulation.**
421
+ **v0.12.1 — Beta software / evidence-gated task-specific physical simulation.**
420
422
 
421
- The software and release pipeline are production-oriented, but physical readiness is scope-specific and evidence-driven. The new UR5e task-specific reference-workcell path must pass the executable v0.12 ROS/Gazebo/MoveIt campaign on the target workstation before that scope is considered simulation-qualified there. Real robot execution remains locked. Functional-safety certification and site qualification are not claimed.
423
+ The software and release pipeline are production-oriented, but physical readiness is scope-specific and evidence-driven. The UR5e task-specific reference-workcell path must pass the executable v0.12 ROS/Gazebo/MoveIt campaign on the target workstation before that scope is considered simulation-qualified there. Real robot execution remains locked. Functional-safety certification and site qualification are not claimed.
422
424
 
423
425
  ## Ownership
424
426
 
@@ -148,6 +148,8 @@ measured motion/evidence report
148
148
 
149
149
  On a successful run, Gazebo / MoveIt remains open by default so the engineer can inspect the final workcell. Add `--close-after` to close it after success.
150
150
 
151
+ v0.12.1 hardens the initial ROS joint-state snapshot by parsing `ros2 topic echo --once` output as a YAML document stream. This accepts the normal ROS 2 trailing `---` message separator instead of incorrectly classifying an otherwise valid `/joint_states` sample as `joint_state_snapshot_invalid`.
152
+
151
153
  The packaged reference workcell is **not customer-site geometry**. Arbitrary plant layouts require an imported or user-declared physical Twin with trusted poses, collision geometry, tool/TCP information, and workpiece properties. DevAgent does not invent those site facts from a natural-language prompt.
152
154
 
153
155
  The v0.12 implementation remains evidence-gated: source/CI success does not prove the ROS target campaign has passed on a particular workstation. Use the executable qualification below before treating the task-specific path as qualified on that target.
@@ -375,9 +377,9 @@ Detailed engineering documentation lives in the repository:
375
377
 
376
378
  ## Project status
377
379
 
378
- **v0.12.0 — Beta software / evidence-gated task-specific physical simulation.**
380
+ **v0.12.1 — Beta software / evidence-gated task-specific physical simulation.**
379
381
 
380
- The software and release pipeline are production-oriented, but physical readiness is scope-specific and evidence-driven. The new UR5e task-specific reference-workcell path must pass the executable v0.12 ROS/Gazebo/MoveIt campaign on the target workstation before that scope is considered simulation-qualified there. Real robot execution remains locked. Functional-safety certification and site qualification are not claimed.
382
+ The software and release pipeline are production-oriented, but physical readiness is scope-specific and evidence-driven. The UR5e task-specific reference-workcell path must pass the executable v0.12 ROS/Gazebo/MoveIt campaign on the target workstation before that scope is considered simulation-qualified there. Real robot execution remains locked. Functional-safety certification and site qualification are not claimed.
381
383
 
382
384
  ## Ownership
383
385
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "devagent-physical-engine"
7
- version = "0.12.0"
7
+ version = "0.12.1"
8
8
  description = "Verification-first agentic engineering, simulation, and evidence runtime for robotics and industrial automation."
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  requires-python = ">=3.11"
@@ -41,4 +41,4 @@ __all__ = [
41
41
  "TwinValidator",
42
42
  ]
43
43
 
44
- __version__ = "0.12.0"
44
+ __version__ = "0.12.1"
@@ -39,6 +39,43 @@ class JointStateSnapshot:
39
39
  return tuple(values[name] for name in joint_names)
40
40
 
41
41
 
42
+ def _parse_joint_state_echo(stdout: str) -> JointStateSnapshot:
43
+ """Parse ``ros2 topic echo --once`` output as a YAML document stream.
44
+
45
+ ROS 2 topic echo normally terminates a message with ``---``. PyYAML's
46
+ ``safe_load`` rejects that otherwise-valid output because the separator starts a
47
+ second (empty) YAML document. Treat the CLI output as the stream it actually is,
48
+ ignore empty separator documents, and accept exactly one joint-state mapping.
49
+ """
50
+
51
+ try:
52
+ import yaml
53
+
54
+ documents = tuple(
55
+ document for document in yaml.safe_load_all(stdout) if document is not None
56
+ )
57
+ except Exception as exc:
58
+ raise RosTrajectoryError("joint_state_yaml_invalid") from exc
59
+
60
+ payloads = tuple(document for document in documents if isinstance(document, Mapping))
61
+ if len(payloads) != 1:
62
+ raise RosTrajectoryError("joint_state_document_count_invalid")
63
+
64
+ payload = payloads[0]
65
+ names_raw = payload.get("name")
66
+ positions_raw = payload.get("position")
67
+ if not isinstance(names_raw, list) or not isinstance(positions_raw, list):
68
+ raise RosTrajectoryError("joint_state_fields_invalid")
69
+
70
+ try:
71
+ return JointStateSnapshot(
72
+ tuple(str(item) for item in names_raw),
73
+ tuple(float(item) for item in positions_raw),
74
+ )
75
+ except (TypeError, ValueError) as exc:
76
+ raise RosTrajectoryError("joint_state_values_invalid") from exc
77
+
78
+
42
79
  def read_joint_state(
43
80
  runner: RosCommandRunner,
44
81
  *,
@@ -55,21 +92,9 @@ def read_joint_state(
55
92
  + (result.stderr.strip()[-300:] or "ros2_topic_echo_failed")
56
93
  )
57
94
  try:
58
- import yaml
59
-
60
- payload = yaml.safe_load(result.stdout)
61
- if not isinstance(payload, Mapping):
62
- raise TypeError("joint state payload is not a mapping")
63
- names_raw = payload.get("name")
64
- positions_raw = payload.get("position")
65
- if not isinstance(names_raw, list) or not isinstance(positions_raw, list):
66
- raise TypeError("name/position fields are not arrays")
67
- return JointStateSnapshot(
68
- tuple(str(item) for item in names_raw),
69
- tuple(float(item) for item in positions_raw),
70
- )
71
- except Exception as exc:
72
- raise RosTrajectoryError("joint_state_snapshot_invalid") from exc
95
+ return _parse_joint_state_echo(result.stdout)
96
+ except RosTrajectoryError as exc:
97
+ raise RosTrajectoryError(f"joint_state_snapshot_invalid:{exc}") from exc
73
98
 
74
99
 
75
100
  def _duration_payload(seconds: float) -> dict[str, int]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devagent-physical-engine
3
- Version: 0.12.0
3
+ Version: 0.12.1
4
4
  Summary: Verification-first agentic engineering, simulation, and evidence runtime for robotics and industrial automation.
5
5
  Author: Tom Ha
6
6
  License: All Rights Reserved
@@ -189,6 +189,8 @@ measured motion/evidence report
189
189
 
190
190
  On a successful run, Gazebo / MoveIt remains open by default so the engineer can inspect the final workcell. Add `--close-after` to close it after success.
191
191
 
192
+ v0.12.1 hardens the initial ROS joint-state snapshot by parsing `ros2 topic echo --once` output as a YAML document stream. This accepts the normal ROS 2 trailing `---` message separator instead of incorrectly classifying an otherwise valid `/joint_states` sample as `joint_state_snapshot_invalid`.
193
+
192
194
  The packaged reference workcell is **not customer-site geometry**. Arbitrary plant layouts require an imported or user-declared physical Twin with trusted poses, collision geometry, tool/TCP information, and workpiece properties. DevAgent does not invent those site facts from a natural-language prompt.
193
195
 
194
196
  The v0.12 implementation remains evidence-gated: source/CI success does not prove the ROS target campaign has passed on a particular workstation. Use the executable qualification below before treating the task-specific path as qualified on that target.
@@ -416,9 +418,9 @@ Detailed engineering documentation lives in the repository:
416
418
 
417
419
  ## Project status
418
420
 
419
- **v0.12.0 — Beta software / evidence-gated task-specific physical simulation.**
421
+ **v0.12.1 — Beta software / evidence-gated task-specific physical simulation.**
420
422
 
421
- The software and release pipeline are production-oriented, but physical readiness is scope-specific and evidence-driven. The new UR5e task-specific reference-workcell path must pass the executable v0.12 ROS/Gazebo/MoveIt campaign on the target workstation before that scope is considered simulation-qualified there. Real robot execution remains locked. Functional-safety certification and site qualification are not claimed.
423
+ The software and release pipeline are production-oriented, but physical readiness is scope-specific and evidence-driven. The UR5e task-specific reference-workcell path must pass the executable v0.12 ROS/Gazebo/MoveIt campaign on the target workstation before that scope is considered simulation-qualified there. Real robot execution remains locked. Functional-safety certification and site qualification are not claimed.
422
424
 
423
425
  ## Ownership
424
426
 
@@ -4,7 +4,11 @@ import unittest
4
4
 
5
5
  from devagent_physical_engine.physical_motion import JointTrajectoryPoint, PhysicalMotionPlan
6
6
  from devagent_physical_engine.ros2.commands import CommandResult
7
- from devagent_physical_engine.ros2.trajectory import RosTrajectoryError, execute_joint_trajectory
7
+ from devagent_physical_engine.ros2.trajectory import (
8
+ RosTrajectoryError,
9
+ execute_joint_trajectory,
10
+ read_joint_state,
11
+ )
8
12
 
9
13
 
10
14
  class FakeRunner:
@@ -29,11 +33,64 @@ def motion():
29
33
  )
30
34
 
31
35
 
32
- def result(stdout, *, code=0):
33
- return CommandResult(("ros2",), code, stdout, "", 1.0)
36
+ def result(stdout, *, code=0, stderr=""):
37
+ return CommandResult(("ros2",), code, stdout, stderr, 1.0)
34
38
 
35
39
 
36
40
  class RosTrajectoryV09Tests(unittest.TestCase):
41
+ def test_joint_state_echo_accepts_ros2_trailing_document_separator(self):
42
+ stdout = """header:
43
+ stamp:
44
+ sec: 10
45
+ nanosec: 20
46
+ frame_id: ''
47
+ name:
48
+ - shoulder_pan_joint
49
+ - shoulder_lift_joint
50
+ position:
51
+ - 0.125
52
+ - -1.25
53
+ velocity: []
54
+ effort: []
55
+ ---
56
+ """
57
+ runner = FakeRunner(result(stdout))
58
+
59
+ snapshot = read_joint_state(runner)
60
+
61
+ self.assertEqual(
62
+ snapshot.names,
63
+ ("shoulder_pan_joint", "shoulder_lift_joint"),
64
+ )
65
+ self.assertEqual(snapshot.positions_rad, (0.125, -1.25))
66
+ self.assertEqual(
67
+ runner.commands[0][0],
68
+ ("ros2", "topic", "echo", "/joint_states", "--once"),
69
+ )
70
+
71
+ def test_joint_state_echo_rejects_multiple_nonempty_documents(self):
72
+ stdout = """name: [j1]
73
+ position: [0.0]
74
+ ---
75
+ name: [j1]
76
+ position: [0.1]
77
+ ---
78
+ """
79
+ runner = FakeRunner(result(stdout))
80
+ with self.assertRaisesRegex(
81
+ RosTrajectoryError,
82
+ "joint_state_snapshot_invalid:joint_state_document_count_invalid",
83
+ ):
84
+ read_joint_state(runner)
85
+
86
+ def test_joint_state_echo_preserves_command_failure_detail(self):
87
+ runner = FakeRunner(result("", code=1, stderr="topic unavailable"))
88
+ with self.assertRaisesRegex(
89
+ RosTrajectoryError,
90
+ "joint_state_snapshot_failed:topic unavailable",
91
+ ):
92
+ read_joint_state(runner)
93
+
37
94
  def test_succeeded_action_is_accepted(self):
38
95
  runner = FakeRunner(result("Goal accepted\nResult: error_code=0\nGoal finished with status: SUCCEEDED"))
39
96
  completed = execute_joint_trajectory(runner, motion())