rosotacom-dev 2.5.dev15__tar.gz → 2.5.dev17__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 (342) hide show
  1. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/PKG-INFO +21 -1
  2. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/README.md +20 -0
  3. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/rfcs/0002-expectation-concepts.md +18 -0
  4. rosotacom_dev-2.5.dev17/src/rosotacom/benchmark_delta.py +279 -0
  5. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/cli_benchmark.py +62 -0
  6. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview.py +12 -0
  7. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview_core.py +11 -0
  8. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom_dev.egg-info/PKG-INFO +21 -1
  9. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom_dev.egg-info/SOURCES.txt +2 -0
  10. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom_dev.egg-info/scm_file_list.json +2 -0
  11. rosotacom_dev-2.5.dev17/src/rosotacom_dev.egg-info/scm_version.json +8 -0
  12. rosotacom_dev-2.5.dev17/tests/unit/test_benchmark_delta.py +172 -0
  13. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_status_overview.py +48 -0
  14. rosotacom_dev-2.5.dev15/src/rosotacom_dev.egg-info/scm_version.json +0 -8
  15. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.devcontainer/devcontainer.json.template +0 -0
  16. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.devcontainer/re_generate_devcontainer_json.py +0 -0
  17. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.github/CODEOWNERS +0 -0
  18. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.github/ISSUE_TEMPLATE/documentation-audit.md +0 -0
  19. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.github/ISSUE_TEMPLATE/implementation-cleanup.md +0 -0
  20. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.github/ISSUE_TEMPLATE/quality-workflow.md +0 -0
  21. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.github/ISSUE_TEMPLATE/redesign.md +0 -0
  22. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.github/ISSUE_TEMPLATE/release-process.md +0 -0
  23. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.github/ISSUE_TEMPLATE/repository-diagnosis.md +0 -0
  24. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.github/ISSUE_TEMPLATE/test-ci-audit.md +0 -0
  25. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.github/ISSUE_TEMPLATE/work-item.md +0 -0
  26. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  27. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.github/dependabot.yml +0 -0
  28. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.github/workflows/benchmark-calibrate.yml +0 -0
  29. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.github/workflows/benchmark-gate.yml +0 -0
  30. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.github/workflows/dev-release.yml +0 -0
  31. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.github/workflows/image-scan.yml +0 -0
  32. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.github/workflows/nightly-e2e.yml +0 -0
  33. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.github/workflows/pr-lightweight.yml +0 -0
  34. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.github/workflows/pr-merge-gate.yml +0 -0
  35. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.github/workflows/release.yml +0 -0
  36. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/.pre-commit-config.yaml +0 -0
  37. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/AGENTS.md +0 -0
  38. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/CONCURRENCY.md +0 -0
  39. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/CONTRIBUTING.md +0 -0
  40. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/DEVELOPMENT_PRINCIPLES.md +0 -0
  41. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/LICENSE.txt +0 -0
  42. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/MANIFEST.in +0 -0
  43. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/budgets.jsonl +0 -0
  44. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/calibration/README.md +0 -0
  45. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/calibration/capacity-size-tight-cyclone.json +0 -0
  46. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/calibration/probe-loss-gop-tight-cyclone.json +0 -0
  47. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/calibration/probe-loss-nominal-cyclone.json +0 -0
  48. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/calibration/probe-loss-tight-cyclone.json +0 -0
  49. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/calibration/probe-loss-tight-fastdds.json +0 -0
  50. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/calibration/probe-loss-tight-zenoh.json +0 -0
  51. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/codecov.yml +0 -0
  52. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/deployment-configuration.md +0 -0
  53. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/benchmark-ab.md +0 -0
  54. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/benchmark-bag-as-load.md +0 -0
  55. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/ci.md +0 -0
  56. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/ffmpeg-keyframes.md +0 -0
  57. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/findings/README.md +0 -0
  58. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/findings/cyclone-spdp-discovery-bursts.md +0 -0
  59. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/findings/delay-alone-no-loss.md +0 -0
  60. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/findings/head-of-line-irregularity.md +0 -0
  61. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/findings/jitter-loss-bandwidth-latency.md +0 -0
  62. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/findings/lighter-message-loss.md +0 -0
  63. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/findings/zero-loss-boundaries-18kb-20hz.md +0 -0
  64. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/forensics-report.md +0 -0
  65. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/geo-link-map.md +0 -0
  66. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/github-repository-settings.md +0 -0
  67. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/link-trace.md +0 -0
  68. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/owner-runbook.md +0 -0
  69. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/performance-bands.md +0 -0
  70. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/playbooks/README.md +0 -0
  71. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/quality-model.md +0 -0
  72. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/release-notes/TEMPLATE.md +0 -0
  73. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/release-notes/v2.1.md +0 -0
  74. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/release-notes/v2.2.md +0 -0
  75. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/release-notes/v2.3.md +0 -0
  76. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/release-notes/v2.4.md +0 -0
  77. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/release.md +0 -0
  78. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/rfcs/0001-expectation-driven-test-suite.md +0 -0
  79. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/rfcs/0003-metric-backbone.md +0 -0
  80. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/rfcs/0004-network-profiles.md +0 -0
  81. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/rfcs/0005-benchmark-genres-and-ci.md +0 -0
  82. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/rfcs/0006-dynamic-qos.md +0 -0
  83. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/rfcs/0007-regression-gate.md +0 -0
  84. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/rfcs/README.md +0 -0
  85. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/testing.md +0 -0
  86. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/docs/work-items.md +0 -0
  87. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/install.sh +0 -0
  88. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/justfile +0 -0
  89. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/media/control_center.png +0 -0
  90. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/media/echo_test.png +0 -0
  91. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/media/forensics-report-example.png +0 -0
  92. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/media/host.png +0 -0
  93. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/media/vehicle.png +0 -0
  94. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/pyproject.toml +0 -0
  95. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/requirements.txt +0 -0
  96. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/rosotacom.yaml +0 -0
  97. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/run_session_in_container.py +0 -0
  98. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/session-configuration.md +0 -0
  99. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/setup.cfg +0 -0
  100. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/__init__.py +0 -0
  101. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/__main__.py +0 -0
  102. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/anonymize.py +0 -0
  103. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/bag_ground_truth.py +0 -0
  104. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/benched_set.py +0 -0
  105. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/benchmark.py +0 -0
  106. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/bundle_check.py +0 -0
  107. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/cli.py +0 -0
  108. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/deployment.py +0 -0
  109. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/ffmpeg_packet.py +0 -0
  110. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/forensics.py +0 -0
  111. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/geomap.py +0 -0
  112. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/network_profiles.py +0 -0
  113. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/network_shaper.py +0 -0
  114. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/plots.py +0 -0
  115. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/py.typed +0 -0
  116. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/benched-set.yaml +0 -0
  117. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/.gitignore +0 -0
  118. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/README.md +0 -0
  119. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/__init__.py +0 -0
  120. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/bags/8_drop_reference/metadata.yaml +0 -0
  121. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/deployment.example.yaml +0 -0
  122. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/profiles.yaml +0 -0
  123. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/ros2docker.json +0 -0
  124. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/rosotacom.yaml +0 -0
  125. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scenarios/2_native_chatter/scenario-definition.yaml +0 -0
  126. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_a.sh +0 -0
  127. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_b.sh +0 -0
  128. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.ros2docker.json +0 -0
  129. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_communication.sh +0 -0
  130. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_external.py +0 -0
  131. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/wait_for_echo_topic.sh +0 -0
  132. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.ros2docker.json +0 -0
  133. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_communication.sh +0 -0
  134. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_external.py +0 -0
  135. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external.ros2docker.json +0 -0
  136. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external_session.yaml +0 -0
  137. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/foxglove.json +0 -0
  138. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_communication.sh +0 -0
  139. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_external.py +0 -0
  140. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
  141. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/metadata.yaml +0 -0
  142. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/external.ros2docker.json +0 -0
  143. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_communication.sh +0 -0
  144. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_external.py +0 -0
  145. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external.ros2docker.json +0 -0
  146. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external_session.yaml +0 -0
  147. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/foxglove.json +0 -0
  148. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_communication.sh +0 -0
  149. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_external.py +0 -0
  150. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
  151. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/metadata.yaml +0 -0
  152. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/external.ros2docker.json +0 -0
  153. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_communication.sh +0 -0
  154. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_external.py +0 -0
  155. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external.ros2docker.json +0 -0
  156. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external_session.yaml +0 -0
  157. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_communication.sh +0 -0
  158. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_external.py +0 -0
  159. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external.ros2docker.json +0 -0
  160. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external_session.yaml +0 -0
  161. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_communication.sh +0 -0
  162. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_external.py +0 -0
  163. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external.ros2docker.json +0 -0
  164. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external_session.yaml +0 -0
  165. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_communication.sh +0 -0
  166. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_external.py +0 -0
  167. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external.ros2docker.json +0 -0
  168. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external_session.yaml +0 -0
  169. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_communication.sh +0 -0
  170. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_external.py +0 -0
  171. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/10_restamp/session-definition.yaml +0 -0
  172. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/11_trickle/session-definition.yaml +0 -0
  173. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/12_content_integrity/session-definition.yaml +0 -0
  174. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/13_link_latency/session-definition.yaml +0 -0
  175. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/14_remote_assist_anonymized/session-definition.yaml +0 -0
  176. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/15_remote_assist_anonymized_costmap/session-definition.yaml +0 -0
  177. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/16_remote_assist_anonymized_camera/session-definition.yaml +0 -0
  178. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/17_synthetic_camera_quality/session-definition.yaml +0 -0
  179. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/1_heartbeat/session-definition.yaml +0 -0
  180. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/1_heartbeat_status/session-definition.yaml +0 -0
  181. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/2_native_chatter/session-definition.yaml +0 -0
  182. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/3_comp_occ_grid/session-definition.yaml +0 -0
  183. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/4_comp_occ_grid_zen/session-definition.yaml +0 -0
  184. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/5_sized_payload/session-definition.yaml +0 -0
  185. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/6_sized_payload_zen/session-definition.yaml +0 -0
  186. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/7_latched_static/session-definition.yaml +0 -0
  187. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/8_drop/session-definition.yaml +0 -0
  188. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/9_throttle/session-definition.yaml +0 -0
  189. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/bench_1_1_capacity/session-definition.yaml +0 -0
  190. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/bench_1_2_load_sweep/session-definition.yaml +0 -0
  191. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/bench_1_3_ramp/session-definition.yaml +0 -0
  192. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/bench_1_4_recovery/session-definition.yaml +0 -0
  193. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/examples/sessions/bench_1_5_camera/session-definition.yaml +0 -0
  194. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ros2docker.json.example +0 -0
  195. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/.vscode/c_cpp_properties.json +0 -0
  196. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/.vscode/settings.json +0 -0
  197. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_easy_mode.xml.template +0 -0
  198. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_initial_peer_list.xml.template +0 -0
  199. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v2.xml.template +0 -0
  200. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v3.xml.template +0 -0
  201. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v4.xml.template +0 -0
  202. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v5.xml.template +0 -0
  203. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py +0 -0
  204. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template +0 -0
  205. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template +0 -0
  206. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ota_configs/fastdds_unicast.xml.template +0 -0
  207. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ota_configs/get_ota_xml.py +0 -0
  208. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ota_configs/utils.py +0 -0
  209. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ota_configs/zenoh.json5.template +0 -0
  210. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/.gitkeep +0 -0
  211. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_cpp/CMakeLists.txt +0 -0
  212. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_cpp/COLCON_IGNORE +0 -0
  213. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_cpp/LICENSE.txt +0 -0
  214. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_cpp/package.xml +0 -0
  215. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_cpp/src/hz_monitor.cpp +0 -0
  216. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_compressor.cpp +0 -0
  217. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_decompressor.cpp +0 -0
  218. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_msgs/CMakeLists.txt +0 -0
  219. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_msgs/LICENSE.txt +0 -0
  220. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/CompressedData.msg +0 -0
  221. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/EchoHeartbeat.msg +0 -0
  222. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/OtaStamped.msg +0 -0
  223. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/SizedPayload.msg +0 -0
  224. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_msgs/package.xml +0 -0
  225. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/LICENSE.txt +0 -0
  226. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/__init__.py +0 -0
  227. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/base_bridge_relay.py +0 -0
  228. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_in.py +0 -0
  229. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_out.py +0 -0
  230. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/heartbeat_echo.py +0 -0
  231. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/hz_monitor.py +0 -0
  232. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_bandwidth_reducer.py +0 -0
  233. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_pixel_capper.py +0 -0
  234. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/lanelet_saver.py +0 -0
  235. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/latch_relay.py +0 -0
  236. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/costmap_remapper.py +0 -0
  237. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/marker_remapper.py +0 -0
  238. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/speed_test.py +0 -0
  239. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/tf_remapper.py +0 -0
  240. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/traffic_monitor.py +0 -0
  241. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/wifi_network_analysis_1.py +0 -0
  242. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_bytes.py +0 -0
  243. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_trace.py +0 -0
  244. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/local_global_frame_bridge.py +0 -0
  245. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/localization_map_split_reduce_saver.py +0 -0
  246. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/msg_transform.py +0 -0
  247. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pair_management.py +0 -0
  248. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pub_sub_pair.py +0 -0
  249. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/qos.py +0 -0
  250. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_in.py +0 -0
  251. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_out.py +0 -0
  252. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/restamp.py +0 -0
  253. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/sized_publisher.py +0 -0
  254. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency.py +0 -0
  255. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency_core.py +0 -0
  256. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/tf_map_to_cart_saver.py +0 -0
  257. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_monitor.py +0 -0
  258. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_resolution.py +0 -0
  259. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/trickle.py +0 -0
  260. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_compressor.py +0 -0
  261. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_decompressor.py +0 -0
  262. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_unwrapper.py +0 -0
  263. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_wrapper.py +0 -0
  264. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/package.xml +0 -0
  265. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/resource/com_py +0 -0
  266. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/setup.cfg +0 -0
  267. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/setup.py +0 -0
  268. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/test/test_copyright.py +0 -0
  269. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/test/test_flake8.py +0 -0
  270. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/ros2src/com_py/test/test_pep257.py +0 -0
  271. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/session/content/base/session_plugin_base.yaml +0 -0
  272. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/session/content/network/up_connectivity.py +0 -0
  273. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/session/content/network/wifi_network_analysis_2.py +0 -0
  274. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/session/creation/anonymize_bag.py +0 -0
  275. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/session/creation/catmux_log_setup.sh +0 -0
  276. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/session/creation/create_session_yaml.py +0 -0
  277. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/session/creation/generate_session_files.py +0 -0
  278. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/session/creation/run_session.py +0 -0
  279. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/session/creation/run_session_in_external_terminal.py +0 -0
  280. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/resources/ws/session/creation/strip_ansi.py +0 -0
  281. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/status_eval.py +0 -0
  282. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/stream_stats.py +0 -0
  283. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/trace_profiles.py +0 -0
  284. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/transit.py +0 -0
  285. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom/video_quality.py +0 -0
  286. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom_dev.egg-info/dependency_links.txt +0 -0
  287. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom_dev.egg-info/entry_points.txt +0 -0
  288. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom_dev.egg-info/requires.txt +0 -0
  289. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/src/rosotacom_dev.egg-info/top_level.txt +0 -0
  290. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/stop_session_in_container.py +0 -0
  291. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/terminology.md +0 -0
  292. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/contract/test_benched_set_registry.py +0 -0
  293. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/contract/test_findings.py +0 -0
  294. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/contract/test_markdown_links.py +0 -0
  295. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/contract/test_ota_source_bundle.py +0 -0
  296. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/contract/test_package_metadata.py +0 -0
  297. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/contract/test_packaged_resources.py +0 -0
  298. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/contract/test_profile_covers_generated_commands.py +0 -0
  299. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/contract/test_pytest_policy.py +0 -0
  300. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/contract/test_readme_examples.py +0 -0
  301. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/contract/test_security_maintenance_config.py +0 -0
  302. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/contract/test_session_configuration_doc.py +0 -0
  303. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/contract/test_workflow_contracts.py +0 -0
  304. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/e2e/conftest.py +0 -0
  305. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/e2e/test_anonymize_e2e.py +0 -0
  306. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/e2e/test_benchmark_ab.py +0 -0
  307. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/e2e/test_benchmark_capacity.py +0 -0
  308. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/e2e/test_benchmark_replay.py +0 -0
  309. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/e2e/test_parallel_smoke.py +0 -0
  310. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/e2e/test_smoke.py +0 -0
  311. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/e2e/test_timeline_stepping.py +0 -0
  312. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/e2e/test_video_quality_e2e.py +0 -0
  313. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/sessions/generate_rmw_matrix.py +0 -0
  314. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-local_zenoh-ros2dds-ota/session-definition.yaml +0 -0
  315. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota/session-definition.yaml +0 -0
  316. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota-tuned/session-definition.yaml +0 -0
  317. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/sessions/rmw_matrix/1_heartbeat_fastdds/session-definition.yaml +0 -0
  318. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/sessions/rmw_matrix/1_heartbeat_zen-endpoints/session-definition.yaml +0 -0
  319. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_anonymize.py +0 -0
  320. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_bag_ground_truth.py +0 -0
  321. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_benched_set.py +0 -0
  322. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_benchmark.py +0 -0
  323. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_bundle_check.py +0 -0
  324. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_cli.py +0 -0
  325. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_cli_benchmark.py +0 -0
  326. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_concurrency.py +0 -0
  327. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_deployment.py +0 -0
  328. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_ffmpeg_packet.py +0 -0
  329. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_forensics.py +0 -0
  330. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_geomap.py +0 -0
  331. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_link_bytes.py +0 -0
  332. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_link_trace.py +0 -0
  333. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_network_profiles.py +0 -0
  334. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_network_shaper.py +0 -0
  335. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_ota_xml.py +0 -0
  336. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_plots.py +0 -0
  337. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_stage_latency.py +0 -0
  338. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_status_eval.py +0 -0
  339. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_stream_stats.py +0 -0
  340. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_trace_profiles.py +0 -0
  341. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/tests/unit/test_transit.py +0 -0
  342. {rosotacom_dev-2.5.dev15 → rosotacom_dev-2.5.dev17}/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.dev15
3
+ Version: 2.5.dev17
4
4
  Summary: Host CLI for ROS OTA communication sessions.
5
5
  Author: develNor
6
6
  License-Expression: BSD-3-Clause
@@ -778,6 +778,26 @@ performance bands in `budgets.jsonl` via `rosotacom benchmark compare`, and
778
778
  bands move only through `rosotacom benchmark ratchet` — see
779
779
  [docs/performance-bands.md](docs/performance-bands.md) for the band schema,
780
780
  verdicts, and the ratchet workflow (RFC 0007).
781
+
782
+ Two result sets taken in **different environments** — emulated versus a real
783
+ link, or shaped versus unshaped — are compared with `rosotacom benchmark delta`:
784
+
785
+ ```bash
786
+ rosotacom benchmark delta emulated/ ota/ \
787
+ --label-reference emulated --label-measured ota \
788
+ --out delta.json --markdown delta.md
789
+ ```
790
+
791
+ It pairs runs on genre, profile, RMW and session name, so a row that ran in one
792
+ environment and not the other is reported as unmatched rather than silently
793
+ dropped — "it got faster" and "it did not run" must not look the same. Every
794
+ report is labelled `monitor_only` and carries each side's command and profile
795
+ file, so a table pasted into a paper or an issue can be traced back without the
796
+ directory it came from.
797
+
798
+ It exits 0 whatever the numbers say, and non-zero only when the two sets share
799
+ no rows at all — a delta is an observation to explain, and an exit code would
800
+ turn "explain this" into "re-run until it is quiet".
781
801
  For live benchmark probes, `--duration` is the shaped publish window; after that
782
802
  rosotacom stops synthetic publishers and waits `--drain-s` seconds before
783
803
  tearing down shaping, so delayed in-flight messages are not miscounted as loss.
@@ -733,6 +733,26 @@ performance bands in `budgets.jsonl` via `rosotacom benchmark compare`, and
733
733
  bands move only through `rosotacom benchmark ratchet` — see
734
734
  [docs/performance-bands.md](docs/performance-bands.md) for the band schema,
735
735
  verdicts, and the ratchet workflow (RFC 0007).
736
+
737
+ Two result sets taken in **different environments** — emulated versus a real
738
+ link, or shaped versus unshaped — are compared with `rosotacom benchmark delta`:
739
+
740
+ ```bash
741
+ rosotacom benchmark delta emulated/ ota/ \
742
+ --label-reference emulated --label-measured ota \
743
+ --out delta.json --markdown delta.md
744
+ ```
745
+
746
+ It pairs runs on genre, profile, RMW and session name, so a row that ran in one
747
+ environment and not the other is reported as unmatched rather than silently
748
+ dropped — "it got faster" and "it did not run" must not look the same. Every
749
+ report is labelled `monitor_only` and carries each side's command and profile
750
+ file, so a table pasted into a paper or an issue can be traced back without the
751
+ directory it came from.
752
+
753
+ It exits 0 whatever the numbers say, and non-zero only when the two sets share
754
+ no rows at all — a delta is an observation to explain, and an exit code would
755
+ turn "explain this" into "re-run until it is quiet".
736
756
  For live benchmark probes, `--duration` is the shaped publish window; after that
737
757
  rosotacom stops synthetic publishers and waits `--drain-s` seconds before
738
758
  tearing down shaping, so delayed in-flight messages are not miscounted as loss.
@@ -290,6 +290,24 @@ once `optional` are all fixed:
290
290
  end-to-end by remote_assist (`/tf` local→global, `/move_base_free/goal`
291
291
  global→local, both delivered to `native_in`); ffmpeg video is n/a -- there is no
292
292
  video/ffmpeg feature anywhere in the codebase, so there is nothing to test.
293
+ - [x] The third latched "not delivering" state is named (issue #231, Option A).
294
+ A latched topic that has a publisher but holds no value now reads distinctly
295
+ ("has a publisher but holds no retained latched value") from "no publisher"
296
+ and "stopped", so a broken/empty latch is no longer indistinguishable from a
297
+ silent producer (`classify_stage` carries a `latched` flag; `_stage_diagnosis`
298
+ names it). The transient_local read Option A asks for was **not** forced per
299
+ declared role: a first attempt did (`collect_latched_stage_topics` ->
300
+ forced QoS) and broke `e2e-remote-assist`, because a latched topic's *native
301
+ source* stage is published VOLATILE (the ROS 1 bridge offers no durability)
302
+ and a TRANSIENT_LOCAL reader is incompatible with a VOLATILE writer -- it
303
+ received nothing and reported a false STALLED. The correct, per-stage form
304
+ is the existing publisher-matched `_observation_qos`, which already requests
305
+ transient_local on the delivered stages that offer it (com_in/app_in); that
306
+ matched subscription is observable on the graph (it raises the subscriber
307
+ count). Validation:
308
+ `tests/unit/test_status_overview.py::test_observation_qos_does_not_force_transient_local_for_latched_roles`,
309
+ `::test_stage_diagnosis_names_the_three_latched_states`,
310
+ `::test_classify_stage_marks_latched_role`.
293
311
 
294
312
  ### Replay-only (ground-truth) assertions — from "Live vs replay" above
295
313
 
@@ -0,0 +1,279 @@
1
+ """Compare two benchmark result sets taken in different environments.
2
+
3
+ The local emulated lanes encode most of the performance truth cheaply and
4
+ deterministically. What they cannot show is **which effects exist only on the
5
+ real link** — cellular variability, VPN/MTU quirks, radio behaviour, real
6
+ cross-traffic — and which are emulation artifacts. Real links stay monitor-only
7
+ by the determinism rule, so the missing piece was never another measurement: it
8
+ was the *comparison* between two sets of the same rows.
9
+
10
+ This is that comparison. It reads two directories (or lists) of `result.json`
11
+ runs, pairs them by what makes a row a row, and reports per-row, per-metric
12
+ deltas as JSON plus a short Markdown summary.
13
+
14
+ Three properties are deliberate, because it is easy to produce numbers that lie:
15
+
16
+ * **Pairing is explicit and refuses to guess.** Rows are matched on genre,
17
+ profile, RMW and session name. A row present on one side only is reported as
18
+ unmatched rather than silently dropped, because "it got faster" and "it did
19
+ not run" must not look the same.
20
+ * **Every report says it is correlational.** The two sets differ in the
21
+ environment *and* in everything the environment drags along; a delta is an
22
+ observation, never a verdict. `monitor_only: true` is in the JSON and the
23
+ first line of the Markdown.
24
+ * **It is self-describing.** Each side carries its rosotacom SHA, profile file,
25
+ and the command that produced it, so a report pasted into a paper or an issue
26
+ can be traced back without the directory it came from.
27
+ """
28
+
29
+ from __future__ import annotations
30
+
31
+ import json
32
+ from dataclasses import dataclass, field
33
+ from pathlib import Path
34
+ from typing import Any
35
+
36
+ SCHEMA_VERSION = 1
37
+
38
+ #: Numeric leaves under `result` that are worth comparing across environments.
39
+ #: A deny-list rather than an allow-list would drag in ids and counts whose
40
+ #: "delta" means nothing.
41
+ INTERESTING_SUFFIXES = (
42
+ "capacity",
43
+ "latency_ms",
44
+ "latency_p95_ms",
45
+ "loss_pct",
46
+ "rate_hz",
47
+ "mean_payload_bytes",
48
+ "offered_bandwidth_bps",
49
+ "jitter_ms",
50
+ "throughput_bps",
51
+ "delivered",
52
+ "received",
53
+ "published",
54
+ )
55
+
56
+
57
+ @dataclass(frozen=True)
58
+ class RowKey:
59
+ """What makes two runs the same row in different environments."""
60
+
61
+ genre: str
62
+ profile: str
63
+ rmw: str
64
+ session: str
65
+
66
+ def label(self) -> str:
67
+ return f"{self.genre}/{self.profile}/{self.rmw}/{self.session}"
68
+
69
+
70
+ @dataclass
71
+ class Run:
72
+ key: RowKey
73
+ metrics: dict[str, float]
74
+ provenance: dict[str, Any] = field(default_factory=dict)
75
+ path: str = ""
76
+
77
+
78
+ def _flatten_numbers(value: Any, prefix: str = "") -> dict[str, float]:
79
+ out: dict[str, float] = {}
80
+ if isinstance(value, dict):
81
+ for key, child in value.items():
82
+ out.update(_flatten_numbers(child, f"{prefix}.{key}" if prefix else str(key)))
83
+ elif isinstance(value, bool):
84
+ # Explicitly before the numeric branch: bool is an int in Python, and a
85
+ # "delta" between True and False is a category error dressed as -1.
86
+ return {}
87
+ elif isinstance(value, (int, float)):
88
+ return {prefix: float(value)}
89
+ return out
90
+
91
+
92
+ def interesting_metrics(result: Any) -> dict[str, float]:
93
+ numbers = _flatten_numbers(result)
94
+ return {
95
+ name: value
96
+ for name, value in numbers.items()
97
+ if any(name == suffix or name.endswith("." + suffix) for suffix in INTERESTING_SUFFIXES)
98
+ }
99
+
100
+
101
+ def load_run(path: Path) -> Run | None:
102
+ """Read one `result.json`. Returns None when it is not one."""
103
+ try:
104
+ data = json.loads(path.read_text(encoding="utf-8"))
105
+ except (OSError, json.JSONDecodeError):
106
+ return None
107
+ if not isinstance(data, dict) or "genre" not in data:
108
+ return None
109
+
110
+ context = data.get("context") or {}
111
+ session = context.get("session") or {}
112
+ profile = context.get("profile") or {}
113
+ rmw = context.get("rmw") or {}
114
+
115
+ key = RowKey(
116
+ genre=str(data.get("genre") or ""),
117
+ profile=str(profile.get("name") or (data.get("configuration") or {}).get("profile") or ""),
118
+ rmw=str(rmw.get("requested") or session.get("rmw") or ""),
119
+ session=str(session.get("name") or ""),
120
+ )
121
+ return Run(
122
+ key=key,
123
+ metrics=interesting_metrics(data.get("result")),
124
+ provenance={
125
+ "created_at": data.get("created_at"),
126
+ "command": context.get("command"),
127
+ "profiles_file": (context.get("paths") or {}).get("profiles_file"),
128
+ "rosotacom_sha": (context.get("versions") or {}).get("rosotacom_sha"),
129
+ "verdict": (data.get("verdict") or {}).get("status"),
130
+ },
131
+ path=str(path),
132
+ )
133
+
134
+
135
+ def collect(paths: list[Path]) -> dict[RowKey, Run]:
136
+ """Every `result.json` under the given files or directories, by row."""
137
+ found: dict[RowKey, Run] = {}
138
+ for path in paths:
139
+ candidates = [path] if path.is_file() else sorted(path.rglob("result.json"))
140
+ for candidate in candidates:
141
+ run = load_run(candidate)
142
+ if run is None:
143
+ continue
144
+ # Last one wins, and it is the newest by directory ordering — a
145
+ # re-run of a row supersedes it rather than doubling it.
146
+ found[run.key] = run
147
+ return found
148
+
149
+
150
+ def compare(
151
+ reference: dict[RowKey, Run],
152
+ measured: dict[RowKey, Run],
153
+ *,
154
+ label_reference: str,
155
+ label_measured: str,
156
+ ) -> dict[str, Any]:
157
+ rows: list[dict[str, Any]] = []
158
+ for key in sorted(set(reference) & set(measured), key=lambda k: k.label()):
159
+ a, b = reference[key], measured[key]
160
+ metrics = []
161
+ for name in sorted(set(a.metrics) | set(b.metrics)):
162
+ left = a.metrics.get(name)
163
+ right = b.metrics.get(name)
164
+ if left is None or right is None:
165
+ metrics.append(
166
+ {
167
+ "metric": name,
168
+ label_reference: left,
169
+ label_measured: right,
170
+ "delta": None,
171
+ "relative": None,
172
+ "note": "present on one side only",
173
+ }
174
+ )
175
+ continue
176
+ delta = right - left
177
+ metrics.append(
178
+ {
179
+ "metric": name,
180
+ label_reference: left,
181
+ label_measured: right,
182
+ "delta": delta,
183
+ "relative": (delta / left) if left else None,
184
+ }
185
+ )
186
+ rows.append(
187
+ {
188
+ "row": key.label(),
189
+ "genre": key.genre,
190
+ "profile": key.profile,
191
+ "rmw": key.rmw,
192
+ "session": key.session,
193
+ "metrics": metrics,
194
+ "provenance": {label_reference: a.provenance, label_measured: b.provenance},
195
+ }
196
+ )
197
+
198
+ return {
199
+ "schema_version": SCHEMA_VERSION,
200
+ # First key, and repeated in the Markdown: a delta between two
201
+ # environments is correlational. The two sets differ in the environment
202
+ # and in everything it drags along.
203
+ "monitor_only": True,
204
+ "labels": {"reference": label_reference, "measured": label_measured},
205
+ "rows": rows,
206
+ "unmatched": {
207
+ label_reference: sorted(k.label() for k in set(reference) - set(measured)),
208
+ label_measured: sorted(k.label() for k in set(measured) - set(reference)),
209
+ },
210
+ "counts": {
211
+ "matched": len(rows),
212
+ f"only_{label_reference}": len(set(reference) - set(measured)),
213
+ f"only_{label_measured}": len(set(measured) - set(reference)),
214
+ },
215
+ }
216
+
217
+
218
+ def render_markdown(report: dict[str, Any]) -> str:
219
+ ref = report["labels"]["reference"]
220
+ mea = report["labels"]["measured"]
221
+ lines = [
222
+ f"# Benchmark delta: {ref} vs {mea}",
223
+ "",
224
+ "**Monitor-only and correlational.** The two sets differ in the environment "
225
+ "and in everything the environment drags along; a delta here is an "
226
+ "observation to explain, never a verdict and never a gate.",
227
+ "",
228
+ f"{report['counts']['matched']} row(s) matched, "
229
+ f"{report['counts'][f'only_{ref}']} only in {ref}, "
230
+ f"{report['counts'][f'only_{mea}']} only in {mea}.",
231
+ "",
232
+ ]
233
+
234
+ for row in report["rows"]:
235
+ lines.append(f"## `{row['row']}`")
236
+ lines.append("")
237
+ lines.append(f"| metric | {ref} | {mea} | Δ | Δ% |")
238
+ lines.append("|---|---:|---:|---:|---:|")
239
+ for metric in row["metrics"]:
240
+ left = metric[ref]
241
+ right = metric[mea]
242
+ delta = metric["delta"]
243
+ relative = metric["relative"]
244
+ lines.append(
245
+ f"| `{metric['metric']}` | {_fmt(left)} | {_fmt(right)} | {_fmt(delta, sign=True)} | {_pct(relative)} |"
246
+ )
247
+ lines.append("")
248
+ for side in (ref, mea):
249
+ provenance = row["provenance"][side]
250
+ command = provenance.get("command") or "-"
251
+ lines.append(f"- {side}: `{command}`")
252
+ lines.append("")
253
+
254
+ for side in (ref, mea):
255
+ missing = report["unmatched"][side]
256
+ if missing:
257
+ lines.append(f"## Only in {side}")
258
+ lines.append("")
259
+ lines.extend(f"- `{name}`" for name in missing)
260
+ lines.append("")
261
+ lines.append(
262
+ "A row on one side only is not a delta. It ran in one environment "
263
+ "and not the other, and treating that as an improvement is the "
264
+ "commonest way this kind of report lies."
265
+ )
266
+ lines.append("")
267
+
268
+ return "\n".join(lines)
269
+
270
+
271
+ def _fmt(value: float | None, *, sign: bool = False) -> str:
272
+ if value is None:
273
+ return "—"
274
+ formatted = f"{value:+.4g}" if sign else f"{value:.4g}"
275
+ return formatted
276
+
277
+
278
+ def _pct(value: float | None) -> str:
279
+ return "—" if value is None else f"{value * 100:+.1f}%"
@@ -4843,6 +4843,56 @@ def _parse_values(raw: str) -> list[float]:
4843
4843
  # --------------------------------------------------------------------------- #
4844
4844
 
4845
4845
 
4846
+ def benchmark_delta(args: argparse.Namespace) -> int:
4847
+ """`rosotacom benchmark delta` — the cross-environment comparison.
4848
+
4849
+ Exits 0 whenever the comparison itself succeeded, including when rows are
4850
+ unmatched or every metric moved. This is monitor-only by construction
4851
+ (`benchmark_delta.compare` puts `monitor_only: true` first in the report):
4852
+ the number is the deliverable, and an exit code would turn "explain this"
4853
+ into "re-run until it is quiet".
4854
+
4855
+ It exits non-zero for the one thing that is a failure — no rows in common,
4856
+ which means the two sides were not the same rows and the report would be
4857
+ an empty table with a confident heading.
4858
+ """
4859
+ from . import benchmark_delta as delta_module
4860
+
4861
+ reference = delta_module.collect([Path(args.reference)])
4862
+ measured = delta_module.collect([Path(args.measured)])
4863
+ report = delta_module.compare(
4864
+ reference,
4865
+ measured,
4866
+ label_reference=args.label_reference,
4867
+ label_measured=args.label_measured,
4868
+ )
4869
+
4870
+ if args.out:
4871
+ Path(args.out).write_text(json.dumps(report, indent=2) + "\n", encoding="utf-8")
4872
+ markdown = delta_module.render_markdown(report)
4873
+ if args.markdown:
4874
+ Path(args.markdown).write_text(markdown, encoding="utf-8")
4875
+ else:
4876
+ print(markdown)
4877
+
4878
+ counts = report["counts"]
4879
+ print(
4880
+ f"BENCHMARK DELTA: {counts['matched']} row(s) matched, "
4881
+ f"{counts[f'only_{args.label_reference}']} only in {args.label_reference}, "
4882
+ f"{counts[f'only_{args.label_measured}']} only in {args.label_measured} "
4883
+ "(monitor-only)"
4884
+ )
4885
+ if not report["rows"]:
4886
+ print(
4887
+ "rosotacom: error: the two sets share no rows, so there is nothing to "
4888
+ "compare. Check that both sides ran the same registry rows under the "
4889
+ "same profile and RMW.",
4890
+ file=sys.stderr,
4891
+ )
4892
+ return 1
4893
+ return 0
4894
+
4895
+
4846
4896
  def _add_benchmark_common_args(parser: argparse.ArgumentParser, *, ota_benchmark: bool = False) -> None:
4847
4897
  from .cli import (
4848
4898
  OTA_DEFAULT_SUDO_MODE,
@@ -8068,6 +8118,18 @@ def _register_benchmark_band_parsers(benchmark_subparsers: Any) -> None:
8068
8118
  )
8069
8119
  compare_parser.set_defaults(func=benchmark_compare)
8070
8120
 
8121
+ delta_parser = benchmark_subparsers.add_parser(
8122
+ "delta",
8123
+ help="Compare two result.json sets taken in different environments (monitor-only).",
8124
+ )
8125
+ delta_parser.add_argument("reference", help="Directory or result.json for the reference environment.")
8126
+ delta_parser.add_argument("measured", help="Directory or result.json for the measured environment.")
8127
+ delta_parser.add_argument("--label-reference", default="emulated", help="Name for the reference side.")
8128
+ delta_parser.add_argument("--label-measured", default="ota", help="Name for the measured side.")
8129
+ delta_parser.add_argument("--out", default=None, help="Write the JSON report here.")
8130
+ delta_parser.add_argument("--markdown", default=None, help="Write the Markdown summary here.")
8131
+ delta_parser.set_defaults(func=benchmark_delta)
8132
+
8071
8133
  ratchet_parser = benchmark_subparsers.add_parser(
8072
8134
  "ratchet",
8073
8135
  help="Rewrite committed bands from result.json run(s) — bands are never hand-edited.",
@@ -161,6 +161,18 @@ class StageObserver(Node):
161
161
  value. Adopting the publisher's offered durability/reliability (request ==
162
162
  offered) is always compatible and replays the durable history. Falls back
163
163
  to best-effort/volatile when no publisher QoS is available.
164
+
165
+ Adopting the *publisher's* offered durability (rather than forcing
166
+ TRANSIENT_LOCAL for every stage of a declared latched topic) is
167
+ deliberate: a latched topic's own source stage -- the vehicle's native
168
+ publish -- is VOLATILE (the ROS 1 bridge offers no durability), and a
169
+ TRANSIENT_LOCAL reader is incompatible with a VOLATILE writer and would
170
+ receive nothing, turning a healthy native stage into a false STALLED.
171
+ Only the delivered stages (com_in/app_in) offer TRANSIENT_LOCAL, and the
172
+ per-publisher match already requests it there -- which is the
173
+ "subscribe transient_local on latched roles" of issue #231, made
174
+ per-stage-correct. The matched subscription is observable on the graph
175
+ (it raises the topic's subscriber count).
164
176
  """
165
177
  durability = DurabilityPolicy.VOLATILE
166
178
  reliability = ReliabilityPolicy.BEST_EFFORT
@@ -497,6 +497,7 @@ class StatusAggregator:
497
497
  "quality_reason": None,
498
498
  "observation": "graph" if obs is not None and obs.graph_only else "payload",
499
499
  "inferred_from": None,
500
+ "latched": str((expect or {}).get("mode", "")).strip().lower() == "latched",
500
501
  }
501
502
  if obs is None:
502
503
  return result
@@ -744,6 +745,16 @@ class StatusAggregator:
744
745
  f"{topic} has a publisher; payload is intentionally not "
745
746
  "subscribed and adjacent local flow is not observed"
746
747
  )
748
+ if stage_result.get("latched"):
749
+ # The third state issue #231 names: distinct from "no publisher"
750
+ # (ABSENT) and "stopped" (STALE). The observation subscribes
751
+ # transient_local for latched roles, so a value published before
752
+ # it matched would have been replayed; holding none means nothing
753
+ # was ever latched (empty/broken latch), not a late-joining reader.
754
+ return (
755
+ f"{topic} has a publisher but holds no retained latched "
756
+ "value (nothing was latched, or the latch was lost)"
757
+ )
747
758
  return f"{topic} has a publisher but no messages observed yet"
748
759
  if st == STALE:
749
760
  return f"{topic} stopped receiving messages"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rosotacom-dev
3
- Version: 2.5.dev15
3
+ Version: 2.5.dev17
4
4
  Summary: Host CLI for ROS OTA communication sessions.
5
5
  Author: develNor
6
6
  License-Expression: BSD-3-Clause
@@ -778,6 +778,26 @@ performance bands in `budgets.jsonl` via `rosotacom benchmark compare`, and
778
778
  bands move only through `rosotacom benchmark ratchet` — see
779
779
  [docs/performance-bands.md](docs/performance-bands.md) for the band schema,
780
780
  verdicts, and the ratchet workflow (RFC 0007).
781
+
782
+ Two result sets taken in **different environments** — emulated versus a real
783
+ link, or shaped versus unshaped — are compared with `rosotacom benchmark delta`:
784
+
785
+ ```bash
786
+ rosotacom benchmark delta emulated/ ota/ \
787
+ --label-reference emulated --label-measured ota \
788
+ --out delta.json --markdown delta.md
789
+ ```
790
+
791
+ It pairs runs on genre, profile, RMW and session name, so a row that ran in one
792
+ environment and not the other is reported as unmatched rather than silently
793
+ dropped — "it got faster" and "it did not run" must not look the same. Every
794
+ report is labelled `monitor_only` and carries each side's command and profile
795
+ file, so a table pasted into a paper or an issue can be traced back without the
796
+ directory it came from.
797
+
798
+ It exits 0 whatever the numbers say, and non-zero only when the two sets share
799
+ no rows at all — a delta is an observation to explain, and an exit code would
800
+ turn "explain this" into "re-run until it is quiet".
781
801
  For live benchmark probes, `--duration` is the shaped publish window; after that
782
802
  rosotacom stops synthetic publishers and waits `--drain-s` seconds before
783
803
  tearing down shaping, so delayed in-flight messages are not miscounted as loss.
@@ -92,6 +92,7 @@ src/rosotacom/anonymize.py
92
92
  src/rosotacom/bag_ground_truth.py
93
93
  src/rosotacom/benched_set.py
94
94
  src/rosotacom/benchmark.py
95
+ src/rosotacom/benchmark_delta.py
95
96
  src/rosotacom/bundle_check.py
96
97
  src/rosotacom/cli.py
97
98
  src/rosotacom/cli_benchmark.py
@@ -314,6 +315,7 @@ tests/unit/test_anonymize.py
314
315
  tests/unit/test_bag_ground_truth.py
315
316
  tests/unit/test_benched_set.py
316
317
  tests/unit/test_benchmark.py
318
+ tests/unit/test_benchmark_delta.py
317
319
  tests/unit/test_bundle_check.py
318
320
  tests/unit/test_cli.py
319
321
  tests/unit/test_cli_benchmark.py
@@ -93,6 +93,7 @@
93
93
  "src/rosotacom/bag_ground_truth.py",
94
94
  "src/rosotacom/benched_set.py",
95
95
  "src/rosotacom/benchmark.py",
96
+ "src/rosotacom/benchmark_delta.py",
96
97
  "src/rosotacom/bundle_check.py",
97
98
  "src/rosotacom/cli.py",
98
99
  "src/rosotacom/cli_benchmark.py",
@@ -309,6 +310,7 @@
309
310
  "tests/unit/test_bag_ground_truth.py",
310
311
  "tests/unit/test_benched_set.py",
311
312
  "tests/unit/test_benchmark.py",
313
+ "tests/unit/test_benchmark_delta.py",
312
314
  "tests/unit/test_bundle_check.py",
313
315
  "tests/unit/test_cli.py",
314
316
  "tests/unit/test_cli_benchmark.py",
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "2.4",
3
+ "distance": 17,
4
+ "node": "g1e061c3143329436d338320f8f58fd3d26affbed",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-08-12"
8
+ }