rosotacom-dev 2.5.dev6__tar.gz → 2.5.dev7__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 (339) hide show
  1. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/PKG-INFO +23 -1
  2. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/README.md +22 -0
  3. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/cli.py +211 -30
  4. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom_dev.egg-info/PKG-INFO +23 -1
  5. rosotacom_dev-2.5.dev7/src/rosotacom_dev.egg-info/scm_version.json +8 -0
  6. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_cli.py +128 -1
  7. rosotacom_dev-2.5.dev6/src/rosotacom_dev.egg-info/scm_version.json +0 -8
  8. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.devcontainer/devcontainer.json.template +0 -0
  9. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.devcontainer/re_generate_devcontainer_json.py +0 -0
  10. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.github/CODEOWNERS +0 -0
  11. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.github/ISSUE_TEMPLATE/documentation-audit.md +0 -0
  12. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.github/ISSUE_TEMPLATE/implementation-cleanup.md +0 -0
  13. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.github/ISSUE_TEMPLATE/quality-workflow.md +0 -0
  14. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.github/ISSUE_TEMPLATE/redesign.md +0 -0
  15. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.github/ISSUE_TEMPLATE/release-process.md +0 -0
  16. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.github/ISSUE_TEMPLATE/repository-diagnosis.md +0 -0
  17. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.github/ISSUE_TEMPLATE/test-ci-audit.md +0 -0
  18. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.github/ISSUE_TEMPLATE/work-item.md +0 -0
  19. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  20. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.github/dependabot.yml +0 -0
  21. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.github/workflows/benchmark-calibrate.yml +0 -0
  22. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.github/workflows/benchmark-gate.yml +0 -0
  23. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.github/workflows/dev-release.yml +0 -0
  24. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.github/workflows/image-scan.yml +0 -0
  25. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.github/workflows/nightly-e2e.yml +0 -0
  26. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.github/workflows/pr-lightweight.yml +0 -0
  27. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.github/workflows/pr-merge-gate.yml +0 -0
  28. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.github/workflows/release.yml +0 -0
  29. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/.pre-commit-config.yaml +0 -0
  30. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/AGENTS.md +0 -0
  31. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/CONCURRENCY.md +0 -0
  32. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/CONTRIBUTING.md +0 -0
  33. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/DEVELOPMENT_PRINCIPLES.md +0 -0
  34. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/LICENSE.txt +0 -0
  35. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/MANIFEST.in +0 -0
  36. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/budgets.jsonl +0 -0
  37. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/calibration/README.md +0 -0
  38. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/calibration/capacity-size-tight-cyclone.json +0 -0
  39. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/calibration/probe-loss-gop-tight-cyclone.json +0 -0
  40. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/calibration/probe-loss-nominal-cyclone.json +0 -0
  41. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/calibration/probe-loss-tight-cyclone.json +0 -0
  42. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/calibration/probe-loss-tight-fastdds.json +0 -0
  43. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/calibration/probe-loss-tight-zenoh.json +0 -0
  44. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/codecov.yml +0 -0
  45. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/deployment-configuration.md +0 -0
  46. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/benchmark-ab.md +0 -0
  47. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/benchmark-bag-as-load.md +0 -0
  48. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/ci.md +0 -0
  49. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/ffmpeg-keyframes.md +0 -0
  50. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/findings/README.md +0 -0
  51. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/findings/cyclone-spdp-discovery-bursts.md +0 -0
  52. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/findings/delay-alone-no-loss.md +0 -0
  53. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/findings/head-of-line-irregularity.md +0 -0
  54. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/findings/jitter-loss-bandwidth-latency.md +0 -0
  55. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/findings/lighter-message-loss.md +0 -0
  56. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/findings/zero-loss-boundaries-18kb-20hz.md +0 -0
  57. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/forensics-report.md +0 -0
  58. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/geo-link-map.md +0 -0
  59. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/github-repository-settings.md +0 -0
  60. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/link-trace.md +0 -0
  61. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/owner-runbook.md +0 -0
  62. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/performance-bands.md +0 -0
  63. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/playbooks/README.md +0 -0
  64. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/quality-model.md +0 -0
  65. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/release-notes/TEMPLATE.md +0 -0
  66. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/release-notes/v2.1.md +0 -0
  67. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/release-notes/v2.2.md +0 -0
  68. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/release-notes/v2.3.md +0 -0
  69. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/release-notes/v2.4.md +0 -0
  70. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/release.md +0 -0
  71. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/rfcs/0001-expectation-driven-test-suite.md +0 -0
  72. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/rfcs/0002-expectation-concepts.md +0 -0
  73. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/rfcs/0003-metric-backbone.md +0 -0
  74. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/rfcs/0004-network-profiles.md +0 -0
  75. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/rfcs/0005-benchmark-genres-and-ci.md +0 -0
  76. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/rfcs/0006-dynamic-qos.md +0 -0
  77. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/rfcs/0007-regression-gate.md +0 -0
  78. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/rfcs/README.md +0 -0
  79. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/testing.md +0 -0
  80. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/docs/work-items.md +0 -0
  81. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/install.sh +0 -0
  82. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/justfile +0 -0
  83. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/media/control_center.png +0 -0
  84. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/media/echo_test.png +0 -0
  85. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/media/forensics-report-example.png +0 -0
  86. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/media/host.png +0 -0
  87. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/media/vehicle.png +0 -0
  88. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/pyproject.toml +0 -0
  89. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/requirements.txt +0 -0
  90. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/rosotacom.yaml +0 -0
  91. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/run_session_in_container.py +0 -0
  92. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/session-configuration.md +0 -0
  93. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/setup.cfg +0 -0
  94. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/__init__.py +0 -0
  95. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/__main__.py +0 -0
  96. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/anonymize.py +0 -0
  97. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/bag_ground_truth.py +0 -0
  98. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/benched_set.py +0 -0
  99. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/benchmark.py +0 -0
  100. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/bundle_check.py +0 -0
  101. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/cli_benchmark.py +0 -0
  102. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/deployment.py +0 -0
  103. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/ffmpeg_packet.py +0 -0
  104. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/forensics.py +0 -0
  105. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/geomap.py +0 -0
  106. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/network_profiles.py +0 -0
  107. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/network_shaper.py +0 -0
  108. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/plots.py +0 -0
  109. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/py.typed +0 -0
  110. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/benched-set.yaml +0 -0
  111. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/.gitignore +0 -0
  112. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/README.md +0 -0
  113. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/__init__.py +0 -0
  114. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/bags/8_drop_reference/metadata.yaml +0 -0
  115. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/deployment.example.yaml +0 -0
  116. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/profiles.yaml +0 -0
  117. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/ros2docker.json +0 -0
  118. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/rosotacom.yaml +0 -0
  119. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scenarios/2_native_chatter/scenario-definition.yaml +0 -0
  120. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_a.sh +0 -0
  121. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_b.sh +0 -0
  122. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.ros2docker.json +0 -0
  123. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_communication.sh +0 -0
  124. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_external.py +0 -0
  125. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/wait_for_echo_topic.sh +0 -0
  126. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.ros2docker.json +0 -0
  127. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_communication.sh +0 -0
  128. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_external.py +0 -0
  129. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external.ros2docker.json +0 -0
  130. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external_session.yaml +0 -0
  131. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/foxglove.json +0 -0
  132. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_communication.sh +0 -0
  133. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_external.py +0 -0
  134. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
  135. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/metadata.yaml +0 -0
  136. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/external.ros2docker.json +0 -0
  137. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_communication.sh +0 -0
  138. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_external.py +0 -0
  139. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external.ros2docker.json +0 -0
  140. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external_session.yaml +0 -0
  141. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/foxglove.json +0 -0
  142. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_communication.sh +0 -0
  143. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_external.py +0 -0
  144. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
  145. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/metadata.yaml +0 -0
  146. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/external.ros2docker.json +0 -0
  147. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_communication.sh +0 -0
  148. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_external.py +0 -0
  149. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external.ros2docker.json +0 -0
  150. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external_session.yaml +0 -0
  151. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_communication.sh +0 -0
  152. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_external.py +0 -0
  153. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external.ros2docker.json +0 -0
  154. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external_session.yaml +0 -0
  155. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_communication.sh +0 -0
  156. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_external.py +0 -0
  157. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external.ros2docker.json +0 -0
  158. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external_session.yaml +0 -0
  159. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_communication.sh +0 -0
  160. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_external.py +0 -0
  161. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external.ros2docker.json +0 -0
  162. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external_session.yaml +0 -0
  163. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_communication.sh +0 -0
  164. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_external.py +0 -0
  165. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/10_restamp/session-definition.yaml +0 -0
  166. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/11_trickle/session-definition.yaml +0 -0
  167. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/12_content_integrity/session-definition.yaml +0 -0
  168. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/13_link_latency/session-definition.yaml +0 -0
  169. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/14_remote_assist_anonymized/session-definition.yaml +0 -0
  170. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/15_remote_assist_anonymized_costmap/session-definition.yaml +0 -0
  171. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/16_remote_assist_anonymized_camera/session-definition.yaml +0 -0
  172. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/17_synthetic_camera_quality/session-definition.yaml +0 -0
  173. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/1_heartbeat/session-definition.yaml +0 -0
  174. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/1_heartbeat_status/session-definition.yaml +0 -0
  175. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/2_native_chatter/session-definition.yaml +0 -0
  176. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/3_comp_occ_grid/session-definition.yaml +0 -0
  177. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/4_comp_occ_grid_zen/session-definition.yaml +0 -0
  178. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/5_sized_payload/session-definition.yaml +0 -0
  179. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/6_sized_payload_zen/session-definition.yaml +0 -0
  180. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/7_latched_static/session-definition.yaml +0 -0
  181. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/8_drop/session-definition.yaml +0 -0
  182. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/9_throttle/session-definition.yaml +0 -0
  183. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/bench_1_1_capacity/session-definition.yaml +0 -0
  184. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/bench_1_2_load_sweep/session-definition.yaml +0 -0
  185. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/bench_1_3_ramp/session-definition.yaml +0 -0
  186. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/bench_1_4_recovery/session-definition.yaml +0 -0
  187. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/bench_1_5_camera/session-definition.yaml +0 -0
  188. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ros2docker.json.example +0 -0
  189. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/.vscode/c_cpp_properties.json +0 -0
  190. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/.vscode/settings.json +0 -0
  191. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_easy_mode.xml.template +0 -0
  192. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_initial_peer_list.xml.template +0 -0
  193. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v2.xml.template +0 -0
  194. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v3.xml.template +0 -0
  195. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v4.xml.template +0 -0
  196. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v5.xml.template +0 -0
  197. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py +0 -0
  198. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template +0 -0
  199. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template +0 -0
  200. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/fastdds_unicast.xml.template +0 -0
  201. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/get_ota_xml.py +0 -0
  202. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/utils.py +0 -0
  203. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/zenoh.json5.template +0 -0
  204. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/.gitkeep +0 -0
  205. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_cpp/CMakeLists.txt +0 -0
  206. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_cpp/COLCON_IGNORE +0 -0
  207. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_cpp/LICENSE.txt +0 -0
  208. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_cpp/package.xml +0 -0
  209. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_cpp/src/hz_monitor.cpp +0 -0
  210. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_compressor.cpp +0 -0
  211. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_decompressor.cpp +0 -0
  212. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_msgs/CMakeLists.txt +0 -0
  213. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_msgs/LICENSE.txt +0 -0
  214. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/CompressedData.msg +0 -0
  215. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/EchoHeartbeat.msg +0 -0
  216. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/OtaStamped.msg +0 -0
  217. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/SizedPayload.msg +0 -0
  218. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_msgs/package.xml +0 -0
  219. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/LICENSE.txt +0 -0
  220. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/__init__.py +0 -0
  221. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/base_bridge_relay.py +0 -0
  222. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_in.py +0 -0
  223. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_out.py +0 -0
  224. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/heartbeat_echo.py +0 -0
  225. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/hz_monitor.py +0 -0
  226. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_bandwidth_reducer.py +0 -0
  227. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_pixel_capper.py +0 -0
  228. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/lanelet_saver.py +0 -0
  229. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/latch_relay.py +0 -0
  230. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/costmap_remapper.py +0 -0
  231. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/marker_remapper.py +0 -0
  232. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/speed_test.py +0 -0
  233. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/tf_remapper.py +0 -0
  234. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/traffic_monitor.py +0 -0
  235. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/wifi_network_analysis_1.py +0 -0
  236. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_bytes.py +0 -0
  237. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_trace.py +0 -0
  238. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/local_global_frame_bridge.py +0 -0
  239. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/localization_map_split_reduce_saver.py +0 -0
  240. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/msg_transform.py +0 -0
  241. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pair_management.py +0 -0
  242. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pub_sub_pair.py +0 -0
  243. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/qos.py +0 -0
  244. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_in.py +0 -0
  245. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_out.py +0 -0
  246. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/restamp.py +0 -0
  247. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/sized_publisher.py +0 -0
  248. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency.py +0 -0
  249. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency_core.py +0 -0
  250. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview.py +0 -0
  251. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview_core.py +0 -0
  252. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/tf_map_to_cart_saver.py +0 -0
  253. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_monitor.py +0 -0
  254. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_resolution.py +0 -0
  255. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/trickle.py +0 -0
  256. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_compressor.py +0 -0
  257. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_decompressor.py +0 -0
  258. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_unwrapper.py +0 -0
  259. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_wrapper.py +0 -0
  260. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/package.xml +0 -0
  261. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/resource/com_py +0 -0
  262. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/setup.cfg +0 -0
  263. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/setup.py +0 -0
  264. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/test/test_copyright.py +0 -0
  265. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/test/test_flake8.py +0 -0
  266. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/test/test_pep257.py +0 -0
  267. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/content/base/session_plugin_base.yaml +0 -0
  268. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/content/network/up_connectivity.py +0 -0
  269. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/content/network/wifi_network_analysis_2.py +0 -0
  270. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/creation/anonymize_bag.py +0 -0
  271. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/creation/catmux_log_setup.sh +0 -0
  272. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/creation/create_session_yaml.py +0 -0
  273. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/creation/generate_session_files.py +0 -0
  274. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/creation/run_session.py +0 -0
  275. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/creation/run_session_in_external_terminal.py +0 -0
  276. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/creation/strip_ansi.py +0 -0
  277. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/status_eval.py +0 -0
  278. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/stream_stats.py +0 -0
  279. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/trace_profiles.py +0 -0
  280. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/transit.py +0 -0
  281. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom/video_quality.py +0 -0
  282. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom_dev.egg-info/SOURCES.txt +0 -0
  283. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom_dev.egg-info/dependency_links.txt +0 -0
  284. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom_dev.egg-info/entry_points.txt +0 -0
  285. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom_dev.egg-info/requires.txt +0 -0
  286. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom_dev.egg-info/scm_file_list.json +0 -0
  287. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/src/rosotacom_dev.egg-info/top_level.txt +0 -0
  288. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/stop_session_in_container.py +0 -0
  289. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/terminology.md +0 -0
  290. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/contract/test_benched_set_registry.py +0 -0
  291. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/contract/test_findings.py +0 -0
  292. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/contract/test_markdown_links.py +0 -0
  293. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/contract/test_ota_source_bundle.py +0 -0
  294. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/contract/test_package_metadata.py +0 -0
  295. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/contract/test_packaged_resources.py +0 -0
  296. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/contract/test_profile_covers_generated_commands.py +0 -0
  297. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/contract/test_pytest_policy.py +0 -0
  298. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/contract/test_readme_examples.py +0 -0
  299. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/contract/test_security_maintenance_config.py +0 -0
  300. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/contract/test_workflow_contracts.py +0 -0
  301. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/e2e/conftest.py +0 -0
  302. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/e2e/test_anonymize_e2e.py +0 -0
  303. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/e2e/test_benchmark_ab.py +0 -0
  304. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/e2e/test_benchmark_capacity.py +0 -0
  305. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/e2e/test_benchmark_replay.py +0 -0
  306. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/e2e/test_parallel_smoke.py +0 -0
  307. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/e2e/test_smoke.py +0 -0
  308. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/e2e/test_timeline_stepping.py +0 -0
  309. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/e2e/test_video_quality_e2e.py +0 -0
  310. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/sessions/generate_rmw_matrix.py +0 -0
  311. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-local_zenoh-ros2dds-ota/session-definition.yaml +0 -0
  312. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota/session-definition.yaml +0 -0
  313. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota-tuned/session-definition.yaml +0 -0
  314. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/sessions/rmw_matrix/1_heartbeat_fastdds/session-definition.yaml +0 -0
  315. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/sessions/rmw_matrix/1_heartbeat_zen-endpoints/session-definition.yaml +0 -0
  316. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_anonymize.py +0 -0
  317. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_bag_ground_truth.py +0 -0
  318. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_benched_set.py +0 -0
  319. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_benchmark.py +0 -0
  320. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_bundle_check.py +0 -0
  321. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_cli_benchmark.py +0 -0
  322. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_concurrency.py +0 -0
  323. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_deployment.py +0 -0
  324. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_ffmpeg_packet.py +0 -0
  325. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_forensics.py +0 -0
  326. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_geomap.py +0 -0
  327. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_link_bytes.py +0 -0
  328. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_link_trace.py +0 -0
  329. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_network_profiles.py +0 -0
  330. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_network_shaper.py +0 -0
  331. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_ota_xml.py +0 -0
  332. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_plots.py +0 -0
  333. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_stage_latency.py +0 -0
  334. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_status_eval.py +0 -0
  335. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_status_overview.py +0 -0
  336. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_stream_stats.py +0 -0
  337. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_trace_profiles.py +0 -0
  338. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_transit.py +0 -0
  339. {rosotacom_dev-2.5.dev6 → rosotacom_dev-2.5.dev7}/tests/unit/test_video_quality.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rosotacom-dev
3
- Version: 2.5.dev6
3
+ Version: 2.5.dev7
4
4
  Summary: Host CLI for ROS OTA communication sessions.
5
5
  Author: develNor
6
6
  License-Expression: BSD-3-Clause
@@ -460,6 +460,11 @@ rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
460
460
  --install-mode pin # defaults to your own version
461
461
  rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
462
462
  --install-mode pin --install-pin 2.4
463
+
464
+ # test the machines as they are: no staging, no install, their own checkouts
465
+ rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
466
+ --peer-ssh b=robot-b --install-mode checkout \
467
+ --peer-checkout a=/home/me/fleet_mgmt --peer-checkout b=/home/robot/fleet_mgmt
463
468
  ```
464
469
 
465
470
  `source` is right while iterating on rosotacom itself — the peers run the code
@@ -469,6 +474,23 @@ missing from the wheel, an undeclared dependency) fails in the rehearsal instead
469
474
  of on the target machine. `source` cannot catch that class of defect by
470
475
  construction, because it never builds the artefact that ships.
471
476
 
477
+ `checkout` answers a different question again: not "does this artefact work" but
478
+ "is *this machine* ready". Nothing is staged and nothing is installed — each
479
+ peer runs the rosotacom it already has, from the project checkout it already
480
+ has, so what is under test is the state git and the machine's own install left
481
+ behind, dependency pins included. Ground truth moves into the repository: push,
482
+ pull, run. It is also the only mode in which a project may reference anything
483
+ outside its own directory — staging copies the project directory, so a mount or
484
+ config path leading above it cannot survive the copy and fails on the peer as a
485
+ missing path.
486
+
487
+ Because the same repository sits at a different absolute path on every machine,
488
+ `--peer-checkout` is required for every peer; the path *inside* the repository
489
+ is taken from your own checkout, so the project has to live in one. Preparation
490
+ becomes verification: each peer is asked whether the checkout, the project file
491
+ and `rosotacom` are there, and each version is printed. `--cleanup` does nothing
492
+ in this mode — there is no staging to undo, and the workdir is your repository.
493
+
472
494
  The run manifest records which mode and which version the peers ran, so a result
473
495
  can be attributed to an artefact rather than to a working copy.
474
496
 
@@ -415,6 +415,11 @@ rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
415
415
  --install-mode pin # defaults to your own version
416
416
  rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
417
417
  --install-mode pin --install-pin 2.4
418
+
419
+ # test the machines as they are: no staging, no install, their own checkouts
420
+ rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
421
+ --peer-ssh b=robot-b --install-mode checkout \
422
+ --peer-checkout a=/home/me/fleet_mgmt --peer-checkout b=/home/robot/fleet_mgmt
418
423
  ```
419
424
 
420
425
  `source` is right while iterating on rosotacom itself — the peers run the code
@@ -424,6 +429,23 @@ missing from the wheel, an undeclared dependency) fails in the rehearsal instead
424
429
  of on the target machine. `source` cannot catch that class of defect by
425
430
  construction, because it never builds the artefact that ships.
426
431
 
432
+ `checkout` answers a different question again: not "does this artefact work" but
433
+ "is *this machine* ready". Nothing is staged and nothing is installed — each
434
+ peer runs the rosotacom it already has, from the project checkout it already
435
+ has, so what is under test is the state git and the machine's own install left
436
+ behind, dependency pins included. Ground truth moves into the repository: push,
437
+ pull, run. It is also the only mode in which a project may reference anything
438
+ outside its own directory — staging copies the project directory, so a mount or
439
+ config path leading above it cannot survive the copy and fails on the peer as a
440
+ missing path.
441
+
442
+ Because the same repository sits at a different absolute path on every machine,
443
+ `--peer-checkout` is required for every peer; the path *inside* the repository
444
+ is taken from your own checkout, so the project has to live in one. Preparation
445
+ becomes verification: each peer is asked whether the checkout, the project file
446
+ and `rosotacom` are there, and each version is printed. `--cleanup` does nothing
447
+ in this mode — there is no staging to undo, and the workdir is your repository.
448
+
427
449
  The run manifest records which mode and which version the peers ran, so a result
428
450
  can be attributed to an artefact rather than to a working copy.
429
451
 
@@ -125,9 +125,25 @@ OTA_SUDO_MODES = ("passwordless", "askpass")
125
125
  # that ships, so a packaging defect — a file missing from the wheel, an
126
126
  # undeclared dependency — fails here rather than on a Versuchsträger. `source`
127
127
  # cannot catch that class of bug by construction.
128
- OTA_INSTALL_MODES = ("source", "pin")
128
+ #
129
+ # `checkout` is the third answer, and it inverts the question: nothing is
130
+ # staged and nothing is installed. Each peer runs the rosotacom it already has
131
+ # from the project checkout it already has, so what is under test is the state
132
+ # git put on that machine — including its dependency pins. `pin` still proves
133
+ # the artefact ships correctly; only `checkout` proves *this machine* is ready,
134
+ # which is what a deployment rehearsal actually asks. It is also the only mode
135
+ # in which a project may reference anything outside its own directory: staging
136
+ # copies the project directory, so a path leading above it cannot survive.
137
+ OTA_INSTALL_MODES = ("source", "pin", "checkout")
129
138
  OTA_DEFAULT_SUDO_MODE = "passwordless"
130
139
 
140
+ # `ssh host 'cmd'` runs a non-login shell, so a pipx install in ~/.local/bin is
141
+ # not on PATH and the peer answers `rosotacom: command not found` — which reads
142
+ # as a broken machine rather than a missing PATH entry. The staged modes never
143
+ # meet this because they call an absolute path inside the workdir; checkout mode
144
+ # calls the peer's own command by name, so it has to say where that lives.
145
+ OTA_CHECKOUT_PATH_PREFIX = 'export PATH="$HOME/.local/bin:$PATH"; '
146
+
131
147
  ws_creation_dir = WS_DIR / "session" / "creation"
132
148
  session_gen_path = ws_creation_dir / "generate_session_files.py"
133
149
  spec = importlib.util.spec_from_file_location("session_gen", session_gen_path)
@@ -212,6 +228,12 @@ class OtaSmokePeer:
212
228
  name: str
213
229
  ssh: str | None
214
230
  address: str
231
+ #: Absolute path of this peer's project checkout, in `checkout` install mode
232
+ #: only. Per peer rather than one plan-wide value because the same
233
+ #: repository lives at a different absolute path on every machine — a
234
+ #: control centre runs it under a different account than a laptop does — and
235
+ #: a single workdir would silently be wrong on all but one of them.
236
+ checkout: str | None = None
215
237
 
216
238
 
217
239
  @dataclass(frozen=True)
@@ -1001,6 +1023,10 @@ def _parse_peer_ssh_overrides(overrides: list[str] | None) -> dict[str, str]:
1001
1023
  return parse_assignments(overrides, option="--peer-ssh")
1002
1024
 
1003
1025
 
1026
+ def _parse_peer_checkout_overrides(overrides: list[str] | None) -> dict[str, str]:
1027
+ return parse_assignments(overrides, option="--peer-checkout")
1028
+
1029
+
1004
1030
  def _deployment_config(runtime: RuntimeConfig) -> DeploymentConfig | None:
1005
1031
  return load_deployment(runtime.deployment)
1006
1032
 
@@ -1500,18 +1526,65 @@ def _ota_validate_install_mode(install_mode: str) -> str:
1500
1526
 
1501
1527
  def _ota_rosotacom_path(install_mode: str) -> str:
1502
1528
  """Where the peer's rosotacom executable lands, relative to the workdir."""
1529
+ if install_mode == "checkout":
1530
+ # Not a path: the peer's own installation, whatever put it there. Naming
1531
+ # a path here would re-introduce the thing this mode removes — an
1532
+ # assumption by the orchestrator about the peer's file system.
1533
+ return "rosotacom"
1503
1534
  return "venv/bin/rosotacom" if install_mode == "pin" else "source/.venv/bin/rosotacom"
1504
1535
 
1505
1536
 
1537
+ def _ota_checkout_project_path(project_config: Path) -> tuple[Path, str]:
1538
+ """Split an active `rosotacom.yaml` into (checkout root, path inside it).
1539
+
1540
+ Checkout mode needs one repository-relative project path that is valid on
1541
+ every peer, and the honest source for it is the local checkout: walk up from
1542
+ the config until a `.git` entry appears. That is not a heuristic here — a
1543
+ mode whose ground truth is "what git put on the machine" is entitled to
1544
+ require that the project is in a repository, and requiring it makes the
1545
+ failure legible instead of producing a path that happens to be wrong on the
1546
+ other machine.
1547
+ """
1548
+ config = project_config.resolve()
1549
+ for candidate in config.parents:
1550
+ if (candidate / ".git").exists():
1551
+ return candidate, config.relative_to(candidate).as_posix()
1552
+ raise RuntimeError(
1553
+ f"--install-mode checkout needs the project to live in a git checkout, and {config} is not in one. "
1554
+ "The peers resolve the project by its path inside the repository, so there has to be a repository."
1555
+ )
1556
+
1557
+
1506
1558
  def _ota_plan_from_bindings(
1507
1559
  bindings: dict[str, PeerBinding],
1508
1560
  *,
1509
1561
  workdir: str,
1510
1562
  install_mode: str = "source",
1511
1563
  install_pin: str | None = None,
1564
+ checkouts: Mapping[str, str] | None = None,
1565
+ project: str | None = None,
1512
1566
  ) -> OtaSmokePlan:
1513
- _ota_validate_prepare_workdir(workdir)
1514
1567
  _ota_validate_install_mode(install_mode)
1568
+ if install_mode == "checkout":
1569
+ if not checkouts or not project:
1570
+ raise RuntimeError("--install-mode checkout requires --peer-checkout for every peer.")
1571
+ missing = sorted(set(bindings) - set(checkouts))
1572
+ if missing:
1573
+ raise RuntimeError(
1574
+ "--install-mode checkout needs a checkout for every peer; missing: "
1575
+ + ", ".join(f"--peer-checkout {name}=<path>" for name in missing)
1576
+ )
1577
+ unknown = sorted(set(checkouts) - set(bindings))
1578
+ if unknown:
1579
+ raise RuntimeError(f"--peer-checkout names a peer the session does not have: {', '.join(unknown)}")
1580
+ for name, path in sorted(checkouts.items()):
1581
+ if not path.startswith("/"):
1582
+ raise RuntimeError(f"--peer-checkout {name}={path}: a peer checkout must be an absolute path.")
1583
+ _ota_validate_prepare_workdir(path)
1584
+ else:
1585
+ _ota_validate_prepare_workdir(workdir)
1586
+ if checkouts:
1587
+ raise RuntimeError("--peer-checkout only applies to --install-mode checkout.")
1515
1588
  if install_mode == "pin":
1516
1589
  # Defaulting to the caller's own version makes `--install-mode pin`
1517
1590
  # mean "rehearse what I am running, as it ships" without a second flag.
@@ -1524,13 +1597,19 @@ def _ota_plan_from_bindings(
1524
1597
  elif install_pin is not None:
1525
1598
  raise RuntimeError("--install-pin only applies to --install-mode pin.")
1526
1599
  peers = {
1527
- name: OtaSmokePeer(name=name, ssh=binding.ssh, address=binding.address) for name, binding in bindings.items()
1600
+ name: OtaSmokePeer(
1601
+ name=name,
1602
+ ssh=binding.ssh,
1603
+ address=binding.address,
1604
+ checkout=(checkouts or {}).get(name) if install_mode == "checkout" else None,
1605
+ )
1606
+ for name, binding in bindings.items()
1528
1607
  }
1529
1608
  return OtaSmokePlan(
1530
1609
  state_path=None,
1531
1610
  workdir=workdir,
1532
1611
  rosotacom=_ota_rosotacom_path(install_mode),
1533
- project="project/rosotacom.yaml",
1612
+ project=(project or "") if install_mode == "checkout" else "project/rosotacom.yaml",
1534
1613
  peers=peers,
1535
1614
  install_mode=install_mode,
1536
1615
  install_pin=install_pin,
@@ -1540,13 +1619,16 @@ def _ota_plan_from_bindings(
1540
1619
  def _ota_write_state(instance: SessionInstance, plan: OtaSmokePlan) -> OtaSmokePlan:
1541
1620
  path = instance.host_dir / "ota-deployment.yaml"
1542
1621
  payload = {
1543
- "schema_version": 2,
1622
+ "schema_version": 3,
1544
1623
  "workdir": plan.workdir,
1545
1624
  "rosotacom": plan.rosotacom,
1546
1625
  "project": plan.project,
1547
1626
  "install_mode": plan.install_mode,
1548
1627
  "install_pin": plan.install_pin,
1549
- "peers": {name: {"address": peer.address, "ssh": peer.ssh} for name, peer in sorted(plan.peers.items())},
1628
+ "peers": {
1629
+ name: {"address": peer.address, "ssh": peer.ssh, "checkout": peer.checkout}
1630
+ for name, peer in sorted(plan.peers.items())
1631
+ },
1550
1632
  }
1551
1633
  path.write_text(yaml.safe_dump(payload, sort_keys=False), encoding="utf-8")
1552
1634
  return replace(plan, state_path=path)
@@ -1555,7 +1637,7 @@ def _ota_write_state(instance: SessionInstance, plan: OtaSmokePlan) -> OtaSmokeP
1555
1637
  def _ota_load_state(path_arg: str) -> OtaSmokePlan:
1556
1638
  path = Path(path_arg).expanduser().resolve()
1557
1639
  raw = _load_yaml_file(path)
1558
- if raw.get("schema_version") != 2:
1640
+ if raw.get("schema_version") != 3:
1559
1641
  raise RuntimeError(f"Unsupported OTA deployment state: {path}")
1560
1642
  peers_raw = raw.get("peers")
1561
1643
  if not isinstance(peers_raw, dict) or len(peers_raw) != 2:
@@ -1568,6 +1650,7 @@ def _ota_load_state(path_arg: str) -> OtaSmokePlan:
1568
1650
  name=str(name),
1569
1651
  address=str(peer_raw["address"]),
1570
1652
  ssh=str(peer_raw["ssh"]) if peer_raw.get("ssh") else None,
1653
+ checkout=str(peer_raw["checkout"]) if peer_raw.get("checkout") else None,
1571
1654
  )
1572
1655
  install_pin = raw.get("install_pin")
1573
1656
  return OtaSmokePlan(
@@ -1680,9 +1763,15 @@ def _ota_project_cli_args(plan: OtaSmokePlan) -> list[str]:
1680
1763
  return ["--rosotacom-config", plan.project]
1681
1764
 
1682
1765
 
1683
- def _ota_rosotacom_command(plan: OtaSmokePlan, parts: list[str]) -> str:
1766
+ def _ota_peer_workdir(plan: OtaSmokePlan, peer: OtaSmokePeer) -> str:
1767
+ """The directory a peer's commands run in: its checkout, or the staging dir."""
1768
+ return peer.checkout or plan.workdir
1769
+
1770
+
1771
+ def _ota_rosotacom_command(plan: OtaSmokePlan, parts: list[str], peer: OtaSmokePeer) -> str:
1684
1772
  command = [plan.rosotacom, *parts, *_ota_project_cli_args(plan)]
1685
- return f"cd {shlex.quote(plan.workdir)} && {_ota_quote_cmd(command)}"
1773
+ prefix = OTA_CHECKOUT_PATH_PREFIX if plan.install_mode == "checkout" else ""
1774
+ return f"{prefix}cd {shlex.quote(_ota_peer_workdir(plan, peer))} && {_ota_quote_cmd(command)}"
1686
1775
 
1687
1776
 
1688
1777
  def _ota_source_checkout() -> Path | None:
@@ -2248,11 +2337,27 @@ def _resolve_ota_smoke_context(
2248
2337
  peer_address=getattr(args, "peer_address", None),
2249
2338
  peer_ssh=getattr(args, "peer_ssh", None),
2250
2339
  )
2340
+ install_mode = str(getattr(args, "install_mode", None) or "source")
2341
+ checkouts = _parse_peer_checkout_overrides(getattr(args, "peer_checkout", None))
2342
+ project: str | None = None
2343
+ if install_mode == "checkout":
2344
+ if not runtime.rosotacom_config:
2345
+ raise RuntimeError("--install-mode checkout requires an active rosotacom.yaml project.")
2346
+ local_checkout, project = _ota_checkout_project_path(runtime.rosotacom_config)
2347
+ for name, path in sorted(checkouts.items()):
2348
+ binding = bindings.get(name)
2349
+ if binding is not None and not binding.ssh and Path(path).resolve() != local_checkout:
2350
+ raise RuntimeError(
2351
+ f"--peer-checkout {name}={path} names the peer that runs on this machine, but the active "
2352
+ f"project lives in {local_checkout}. Point it there, or give that peer an SSH target."
2353
+ )
2251
2354
  plan = _ota_plan_from_bindings(
2252
2355
  bindings,
2253
2356
  workdir=str(getattr(args, "workdir", None) or "/tmp/rosotacom_ota"),
2254
- install_mode=str(getattr(args, "install_mode", None) or "source"),
2357
+ install_mode=install_mode,
2255
2358
  install_pin=getattr(args, "install_pin", None),
2359
+ checkouts=checkouts,
2360
+ project=project,
2256
2361
  )
2257
2362
  plan_peers = set(plan.peers)
2258
2363
  target_peers = set(_peer_keys_from_cfg(target.cfg))
@@ -2643,10 +2748,62 @@ def _ota_remote_package_dir(peer: OtaSmokePeer, plan: OtaSmokePlan, *, dry_run:
2643
2748
  return located
2644
2749
 
2645
2750
 
2751
+ def _ota_verify_checkouts(plan: OtaSmokePlan, *, dry_run: bool) -> None:
2752
+ """Checkout mode's replacement for staging: assert, do not install.
2753
+
2754
+ Nothing is copied and nothing is installed, so the only thing that can go
2755
+ wrong is a peer that is not in the state the caller thinks it is in — an
2756
+ unsynced checkout, a rosotacom that never got installed, a project path that
2757
+ exists on the laptop and not on the other machine. Each of those has a
2758
+ distinct one-line failure here, before any container starts, rather than a
2759
+ confusing one an hour later.
2760
+ """
2761
+ for peer in plan.peers.values():
2762
+ checkout = shlex.quote(_ota_peer_workdir(plan, peer))
2763
+ project = shlex.quote(plan.project)
2764
+ _ota_run(
2765
+ peer,
2766
+ f"test -d {checkout}",
2767
+ label=f"{peer.name}: project checkout {_ota_peer_workdir(plan, peer)}",
2768
+ dry_run=dry_run,
2769
+ batch=True,
2770
+ )
2771
+ _ota_run(
2772
+ peer,
2773
+ f"test -f {checkout}/{project}",
2774
+ label=f"{peer.name}: project config {plan.project} inside the checkout",
2775
+ dry_run=dry_run,
2776
+ batch=True,
2777
+ )
2778
+ _ota_run(
2779
+ peer,
2780
+ f"{OTA_CHECKOUT_PATH_PREFIX}command -v rosotacom >/dev/null 2>&1",
2781
+ label=f"{peer.name}: rosotacom installed",
2782
+ dry_run=dry_run,
2783
+ batch=True,
2784
+ )
2785
+ version = _ota_run(
2786
+ peer,
2787
+ f"{OTA_CHECKOUT_PATH_PREFIX}rosotacom --version",
2788
+ label=f"{peer.name}: rosotacom version",
2789
+ dry_run=dry_run,
2790
+ batch=True,
2791
+ check=False,
2792
+ )
2793
+ if not dry_run and version.returncode == 0:
2794
+ # Printed rather than enforced. Peers running different versions is
2795
+ # a real hazard, but it is also a legitimate mid-migration state,
2796
+ # and a check that refuses it would be the wrong place to find out.
2797
+ print(f"+ {peer.name}: rosotacom {version.stdout.strip() or 'unknown'}")
2798
+
2799
+
2646
2800
  def _ota_prepare_hosts(args: argparse.Namespace, runtime: RuntimeConfig, plan: OtaSmokePlan) -> None:
2647
2801
  if not runtime.rosotacom_config:
2648
2802
  raise RuntimeError("ota-smoke requires an active rosotacom.yaml project.")
2649
2803
  dry_run = bool(getattr(args, "dry_run", False))
2804
+ if plan.install_mode == "checkout":
2805
+ _ota_verify_checkouts(plan, dry_run=dry_run)
2806
+ return
2650
2807
  from_pin = plan.install_mode == "pin"
2651
2808
  source_checkout: Path | None = None
2652
2809
  temporary_bundle: Path | None = None
@@ -2924,6 +3081,7 @@ def _ota_start_peers(
2924
3081
  command = _ota_rosotacom_command(
2925
3082
  plan,
2926
3083
  _ota_start_parts(target, peer_name, instance_id, peer_args, mode=mode, link_trace_parts=link_trace_parts),
3084
+ peer,
2927
3085
  )
2928
3086
  _ota_run(peer, command, label=f"{peer_name}: start {target.name}", dry_run=dry_run)
2929
3087
 
@@ -2940,7 +3098,7 @@ def _ota_start_session_publishers(
2940
3098
  peer_args = _ota_peer_address_args(plan)
2941
3099
  for peer_name in sorted(plan.peers):
2942
3100
  peer = plan.peers[peer_name]
2943
- command = _ota_rosotacom_command(plan, _ota_publish_parts(target, peer_name, peer_args))
3101
+ command = _ota_rosotacom_command(plan, _ota_publish_parts(target, peer_name, peer_args), peer)
2944
3102
  result = _ota_run(peer, command, label=f"{peer_name}: start synthetic publishers", dry_run=dry_run, check=False)
2945
3103
  _print_completed_output(result)
2946
3104
  if result.returncode != 0:
@@ -2958,7 +3116,7 @@ def _ota_stop_session_publishers(
2958
3116
  peer_args = _ota_peer_address_args(plan)
2959
3117
  for peer_name in sorted(plan.peers):
2960
3118
  peer = plan.peers[peer_name]
2961
- command = _ota_rosotacom_command(plan, _ota_publish_parts(target, peer_name, peer_args, stop=True))
3119
+ command = _ota_rosotacom_command(plan, _ota_publish_parts(target, peer_name, peer_args, stop=True), peer)
2962
3120
  _ota_run(peer, command, label=f"{peer_name}: stop synthetic publishers", dry_run=dry_run, check=False)
2963
3121
 
2964
3122
 
@@ -2974,7 +3132,7 @@ def _ota_verify_delivery(
2974
3132
  print("OTA smoke: running status/expectation checks on every peer.")
2975
3133
  for peer_name in sorted(plan.peers):
2976
3134
  peer = plan.peers[peer_name]
2977
- command = _ota_rosotacom_command(plan, _ota_test_parts(target, instance_id, profile=profile))
3135
+ command = _ota_rosotacom_command(plan, _ota_test_parts(target, instance_id, profile=profile), peer)
2978
3136
  result = _ota_run(peer, command, label=f"{peer_name}: rosotacom test", dry_run=dry_run, check=False)
2979
3137
  if result.returncode != 0:
2980
3138
  _ota_print_failure_output(f"{peer_name}: rosotacom test", result)
@@ -2997,14 +3155,14 @@ def _ota_verify_isolation(
2997
3155
  peer_args = _ota_peer_address_args(plan)
2998
3156
  errors: list[str] = []
2999
3157
  print(f"OTA smoke: checking isolation from {source_name} to {receiver_name}.")
3000
- publish = _ota_rosotacom_command(plan, _ota_probe_publish_parts(target, source_name, peer_args, stop=False))
3158
+ publish = _ota_rosotacom_command(plan, _ota_probe_publish_parts(target, source_name, peer_args, stop=False), source)
3001
3159
  published = _ota_run(source, publish, label=f"{source_name}: publish isolation probe", dry_run=dry_run, check=False)
3002
3160
  if published.returncode != 0:
3003
3161
  _ota_print_failure_output(f"{source_name}: publish isolation probe", published)
3004
3162
  errors.append(f"{source_name}: isolation probe publisher failed")
3005
3163
  return errors
3006
3164
  _print_completed_output(published)
3007
- check = _ota_rosotacom_command(plan, _ota_probe_check_parts(target, receiver_name, peer_args))
3165
+ check = _ota_rosotacom_command(plan, _ota_probe_check_parts(target, receiver_name, peer_args), receiver)
3008
3166
  checked = _ota_run(
3009
3167
  receiver,
3010
3168
  check,
@@ -3017,7 +3175,7 @@ def _ota_verify_isolation(
3017
3175
  errors.append(f"{receiver_name}: isolation probe crossed OTA boundary")
3018
3176
  else:
3019
3177
  _print_completed_output(checked)
3020
- stop = _ota_rosotacom_command(plan, _ota_probe_publish_parts(target, source_name, peer_args, stop=True))
3178
+ stop = _ota_rosotacom_command(plan, _ota_probe_publish_parts(target, source_name, peer_args, stop=True), source)
3021
3179
  stopped = _ota_run(source, stop, label=f"{source_name}: stop isolation probe", dry_run=dry_run, check=False)
3022
3180
  _print_completed_output(stopped)
3023
3181
  return errors
@@ -3046,7 +3204,7 @@ def _ota_verify_content_integrity(
3046
3204
  for receiver_name, receiver in plan.peers.items():
3047
3205
  for topic, msg_type, field, expected in _content_integrity_specs(cfg, receiver_name):
3048
3206
  parts = _ota_content_check_parts(target, receiver_name, peer_args, topic, msg_type, field, expected)
3049
- cmd = _ota_rosotacom_command(plan, parts)
3207
+ cmd = _ota_rosotacom_command(plan, parts, receiver)
3050
3208
  print(f"OTA smoke: checking content integrity for {receiver_name} {topic}.")
3051
3209
  result = _ota_run(
3052
3210
  receiver, cmd, label=f"{receiver_name}: content integrity {topic}", dry_run=dry_run, check=False
@@ -3067,16 +3225,16 @@ def _ota_collect_logs(
3067
3225
  ) -> None:
3068
3226
  project = shlex.quote(plan.project)
3069
3227
  instance_suffix = shlex.quote(f"*_{instance.instance_id}")
3070
- script = (
3071
- f"cd {shlex.quote(plan.workdir)} && "
3072
- f"project_dir=$(dirname {project}) && "
3073
- f'instance_dir=$(find "$project_dir/session-instances" -mindepth 2 -maxdepth 2 '
3074
- f"-type d -name {instance_suffix} -print -quit 2>/dev/null) && "
3075
- 'if [ -n "$instance_dir" ]; then '
3076
- 'relative=${instance_dir#"$project_dir"/}; '
3077
- 'tar cz -C "$project_dir" "$relative" 2>/dev/null | base64; fi'
3078
- )
3079
3228
  for peer in plan.peers.values():
3229
+ script = (
3230
+ f"cd {shlex.quote(_ota_peer_workdir(plan, peer))} && "
3231
+ f"project_dir=$(dirname {project}) && "
3232
+ f'instance_dir=$(find "$project_dir/session-instances" -mindepth 2 -maxdepth 2 '
3233
+ f"-type d -name {instance_suffix} -print -quit 2>/dev/null) && "
3234
+ 'if [ -n "$instance_dir" ]; then '
3235
+ 'relative=${instance_dir#"$project_dir"/}; '
3236
+ 'tar cz -C "$project_dir" "$relative" 2>/dev/null | base64; fi'
3237
+ )
3080
3238
  result = _ota_run(peer, script, label=f"{peer.name}: collect session-instances", dry_run=dry_run, check=False)
3081
3239
  if dry_run or not result.stdout.strip():
3082
3240
  continue
@@ -3139,7 +3297,7 @@ def _ota_stop_peers(
3139
3297
  peer_args = _ota_peer_address_args(plan)
3140
3298
  for peer_name in sorted(plan.peers):
3141
3299
  peer = plan.peers[peer_name]
3142
- command = _ota_rosotacom_command(plan, _ota_stop_parts(target, peer_name, instance_id, peer_args))
3300
+ command = _ota_rosotacom_command(plan, _ota_stop_parts(target, peer_name, instance_id, peer_args), peer)
3143
3301
  _ota_run(peer, command, label=f"{peer_name}: stop {target.name}", dry_run=dry_run, check=False)
3144
3302
 
3145
3303
 
@@ -3186,7 +3344,9 @@ def _ota_application_run_script(
3186
3344
  ) -> str:
3187
3345
  communication_suffix = _sanitize_docker_name(f"_com_to_{_remote_peer_name(target.cfg, peer_name)}")
3188
3346
  label = f"{peer_name}:{application.name}"
3189
- command = _ota_rosotacom_command(plan, _ota_application_parts(target, peer_name, application, instance_id))
3347
+ command = _ota_rosotacom_command(
3348
+ plan, _ota_application_parts(target, peer_name, application, instance_id), plan.peers[peer_name]
3349
+ )
3190
3350
  return (
3191
3351
  f"{_ota_wait_for_running_container_suffix_script(communication_suffix, f'{peer_name}:communication')}; "
3192
3352
  f"echo '[INFO] starting native application container:' {shlex.quote(label)}; "
@@ -3219,6 +3379,7 @@ def _ota_create_tmux(
3219
3379
  mode="attach",
3220
3380
  link_trace_parts=link_trace_parts,
3221
3381
  ),
3382
+ first_peer,
3222
3383
  )
3223
3384
  first_script = (
3224
3385
  "set -e; "
@@ -3298,6 +3459,7 @@ def _ota_create_tmux(
3298
3459
  mode="attach",
3299
3460
  link_trace_parts=link_trace_parts,
3300
3461
  ),
3462
+ peer,
3301
3463
  )
3302
3464
  script = (
3303
3465
  "set -e; "
@@ -3432,6 +3594,13 @@ def _list_ota_smoke(args: argparse.Namespace) -> int:
3432
3594
 
3433
3595
 
3434
3596
  def _ota_cleanup_hosts(plan: OtaSmokePlan, *, dry_run: bool) -> None:
3597
+ if plan.install_mode == "checkout":
3598
+ # The workdir is the user's repository here. `rm -rf` on it would delete
3599
+ # a checkout with its untracked work — bags, instance artefacts, local
3600
+ # edits — to clean up files this mode never created. There is nothing to
3601
+ # remove: staging is what cleanup undoes, and staging did not happen.
3602
+ print("OTA smoke: nothing to clean up — checkout mode staged nothing.")
3603
+ return
3435
3604
  _ota_validate_prepare_workdir(plan.workdir)
3436
3605
  for peer in plan.peers.values():
3437
3606
  _ota_run(
@@ -3497,7 +3666,7 @@ def _start_interactive_ota_smoke(args: argparse.Namespace) -> int:
3497
3666
  print("Local control tmux prefix: Ctrl-b. Send the peer tmux/catmux prefix with Ctrl-b Ctrl-b.")
3498
3667
  if target.target_type == "scenario":
3499
3668
  for peer_name, peer in plan.peers.items():
3500
- attach = _ota_rosotacom_command(plan, ["scenario", "attach", target.name, "--identity", peer_name])
3669
+ attach = _ota_rosotacom_command(plan, ["scenario", "attach", target.name, "--identity", peer_name], peer)
3501
3670
  attach_cmd = _ota_quote_cmd(_ota_remote_argv(peer, attach, tty=bool(peer.ssh)))
3502
3671
  print(f"Manual remote scenario reattach for {peer_name}: {attach_cmd}")
3503
3672
  if mode == "attach":
@@ -8266,6 +8435,16 @@ def main(argv: list[str] | None = None) -> int:
8266
8435
  _add_peer_arg(ota_smoke_parser)
8267
8436
  _add_peer_address_arg(ota_smoke_parser)
8268
8437
  _add_peer_ssh_arg(ota_smoke_parser)
8438
+ ota_smoke_parser.add_argument(
8439
+ "--peer-checkout",
8440
+ action="append",
8441
+ default=[],
8442
+ metavar="PEER=PATH",
8443
+ help=(
8444
+ "Absolute path of a peer's project checkout, for --install-mode checkout. "
8445
+ "Required for every peer in that mode; the same repository is at a different path on each machine."
8446
+ ),
8447
+ )
8269
8448
  ota_smoke_parser.add_argument("--target-type", choices=["auto", "session", "scenario"], default="auto")
8270
8449
  ota_smoke_parser.add_argument("--interactive", action="store_true", help="Open a local control tmux UI.")
8271
8450
  ota_smoke_parser.add_argument("--stop", action="store_true", help="Stop an OTA smoke run.")
@@ -8289,7 +8468,9 @@ def main(argv: list[str] | None = None) -> int:
8289
8468
  help=(
8290
8469
  "How the peers get rosotacom. 'source' (default) stages and installs what you are running — "
8291
8470
  "right while iterating on rosotacom. 'pin' installs a published release from the index, so the "
8292
- "peers run the artefact that ships — right when rehearsing a deployment."
8471
+ "peers run the artefact that ships — right when rehearsing a deployment. 'checkout' stages and "
8472
+ "installs nothing: each peer uses its own installed rosotacom and its own project checkout "
8473
+ "(see --peer-checkout), so the run tests the machines as git left them."
8293
8474
  ),
8294
8475
  )
8295
8476
  ota_smoke_parser.add_argument(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rosotacom-dev
3
- Version: 2.5.dev6
3
+ Version: 2.5.dev7
4
4
  Summary: Host CLI for ROS OTA communication sessions.
5
5
  Author: develNor
6
6
  License-Expression: BSD-3-Clause
@@ -460,6 +460,11 @@ rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
460
460
  --install-mode pin # defaults to your own version
461
461
  rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
462
462
  --install-mode pin --install-pin 2.4
463
+
464
+ # test the machines as they are: no staging, no install, their own checkouts
465
+ rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
466
+ --peer-ssh b=robot-b --install-mode checkout \
467
+ --peer-checkout a=/home/me/fleet_mgmt --peer-checkout b=/home/robot/fleet_mgmt
463
468
  ```
464
469
 
465
470
  `source` is right while iterating on rosotacom itself — the peers run the code
@@ -469,6 +474,23 @@ missing from the wheel, an undeclared dependency) fails in the rehearsal instead
469
474
  of on the target machine. `source` cannot catch that class of defect by
470
475
  construction, because it never builds the artefact that ships.
471
476
 
477
+ `checkout` answers a different question again: not "does this artefact work" but
478
+ "is *this machine* ready". Nothing is staged and nothing is installed — each
479
+ peer runs the rosotacom it already has, from the project checkout it already
480
+ has, so what is under test is the state git and the machine's own install left
481
+ behind, dependency pins included. Ground truth moves into the repository: push,
482
+ pull, run. It is also the only mode in which a project may reference anything
483
+ outside its own directory — staging copies the project directory, so a mount or
484
+ config path leading above it cannot survive the copy and fails on the peer as a
485
+ missing path.
486
+
487
+ Because the same repository sits at a different absolute path on every machine,
488
+ `--peer-checkout` is required for every peer; the path *inside* the repository
489
+ is taken from your own checkout, so the project has to live in one. Preparation
490
+ becomes verification: each peer is asked whether the checkout, the project file
491
+ and `rosotacom` are there, and each version is printed. `--cleanup` does nothing
492
+ in this mode — there is no staging to undo, and the workdir is your repository.
493
+
472
494
  The run manifest records which mode and which version the peers ran, so a result
473
495
  can be attributed to an artefact rather than to a working copy.
474
496
 
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "2.4",
3
+ "distance": 7,
4
+ "node": "g69ca2b26fe2a31c86e07be8e3aa626ef9a839266",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-08-11"
8
+ }