rosotacom-dev 2.5.dev52__tar.gz → 2.5.dev53__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 (377) hide show
  1. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/PKG-INFO +19 -1
  2. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/README.md +18 -0
  3. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/deployment-configuration.md +23 -0
  4. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/cli.py +93 -2
  5. rosotacom_dev-2.5.dev53/src/rosotacom/network_preflight.py +134 -0
  6. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom_dev.egg-info/PKG-INFO +19 -1
  7. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom_dev.egg-info/SOURCES.txt +2 -0
  8. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom_dev.egg-info/scm_file_list.json +2 -0
  9. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom_dev.egg-info/scm_version.json +2 -2
  10. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_cli.py +19 -2
  11. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_concurrency.py +25 -1
  12. rosotacom_dev-2.5.dev53/tests/unit/test_network_preflight.py +173 -0
  13. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.devcontainer/devcontainer.json.template +0 -0
  14. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.devcontainer/re_generate_devcontainer_json.py +0 -0
  15. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/CODEOWNERS +0 -0
  16. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/ISSUE_TEMPLATE/documentation-audit.md +0 -0
  17. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/ISSUE_TEMPLATE/implementation-cleanup.md +0 -0
  18. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/ISSUE_TEMPLATE/quality-workflow.md +0 -0
  19. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/ISSUE_TEMPLATE/redesign.md +0 -0
  20. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/ISSUE_TEMPLATE/release-process.md +0 -0
  21. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/ISSUE_TEMPLATE/repository-diagnosis.md +0 -0
  22. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/ISSUE_TEMPLATE/test-ci-audit.md +0 -0
  23. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/ISSUE_TEMPLATE/work-item.md +0 -0
  24. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  25. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/actions/setup-just/action.yml +0 -0
  26. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/dependabot.yml +0 -0
  27. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/workflows/benchmark-calibrate.yml +0 -0
  28. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/workflows/benchmark-gate.yml +0 -0
  29. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/workflows/dev-release.yml +0 -0
  30. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/workflows/image-scan.yml +0 -0
  31. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/workflows/nightly-e2e.yml +0 -0
  32. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/workflows/pr-lightweight.yml +0 -0
  33. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/workflows/pr-merge-gate.yml +0 -0
  34. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/workflows/release.yml +0 -0
  35. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.pre-commit-config.yaml +0 -0
  36. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/AGENTS.md +0 -0
  37. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/CONCURRENCY.md +0 -0
  38. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/CONTRIBUTING.md +0 -0
  39. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/DEVELOPMENT_PRINCIPLES.md +0 -0
  40. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/LICENSE.txt +0 -0
  41. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/MANIFEST.in +0 -0
  42. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/budgets.jsonl +0 -0
  43. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/calibration/README.md +0 -0
  44. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/calibration/capacity-size-tight-cyclone.json +0 -0
  45. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/calibration/probe-loss-gop-tight-cyclone.json +0 -0
  46. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/calibration/probe-loss-nominal-cyclone.json +0 -0
  47. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/calibration/probe-loss-tight-cyclone.json +0 -0
  48. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/calibration/probe-loss-tight-fastdds.json +0 -0
  49. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/calibration/probe-loss-tight-zenoh.json +0 -0
  50. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/codecov.yml +0 -0
  51. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/benchmark-ab.md +0 -0
  52. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/benchmark-bag-as-load.md +0 -0
  53. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/ci.md +0 -0
  54. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/ffmpeg-keyframes.md +0 -0
  55. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/README.md +0 -0
  56. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/cyclone-spdp-discovery-bursts.md +0 -0
  57. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/delay-alone-no-loss.md +0 -0
  58. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/fastdds-datagram-cap-drops-large-samples.md +0 -0
  59. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/graph-derived-types-block-a-non-graph-transport.md +0 -0
  60. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/head-of-line-irregularity.md +0 -0
  61. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/jitter-loss-bandwidth-latency.md +0 -0
  62. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/keyframe-loss-kills-the-next-deltas.md +0 -0
  63. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/lighter-message-loss.md +0 -0
  64. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/oversubscription-queues-not-losses.md +0 -0
  65. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/reorder-becomes-reader-loss.md +0 -0
  66. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/repro/decode_chain_repro.py +0 -0
  67. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/repro/reorder_drop_repro.py +0 -0
  68. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/sender-rows-make-a-dead-link-look-loss-free.md +0 -0
  69. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/zero-loss-boundaries-18kb-20hz.md +0 -0
  70. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/forensics-report.md +0 -0
  71. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/geo-link-map.md +0 -0
  72. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/github-repository-settings.md +0 -0
  73. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/link-bandwidth.md +0 -0
  74. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/link-trace.md +0 -0
  75. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/owner-runbook.md +0 -0
  76. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/performance-bands.md +0 -0
  77. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/playbooks/README.md +0 -0
  78. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/quality-model.md +0 -0
  79. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/release-notes/TEMPLATE.md +0 -0
  80. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/release-notes/v2.1.md +0 -0
  81. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/release-notes/v2.2.md +0 -0
  82. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/release-notes/v2.3.md +0 -0
  83. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/release-notes/v2.4.md +0 -0
  84. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/release.md +0 -0
  85. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/rfcs/0001-expectation-driven-test-suite.md +0 -0
  86. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/rfcs/0002-expectation-concepts.md +0 -0
  87. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/rfcs/0003-metric-backbone.md +0 -0
  88. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/rfcs/0004-network-profiles.md +0 -0
  89. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/rfcs/0005-benchmark-genres-and-ci.md +0 -0
  90. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/rfcs/0006-dynamic-qos.md +0 -0
  91. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/rfcs/0007-regression-gate.md +0 -0
  92. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/rfcs/README.md +0 -0
  93. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/testing.md +0 -0
  94. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/work-items.md +0 -0
  95. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/install.sh +0 -0
  96. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/justfile +0 -0
  97. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/media/control_center.png +0 -0
  98. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/media/echo_test.png +0 -0
  99. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/media/forensics-report-example.png +0 -0
  100. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/media/host.png +0 -0
  101. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/media/vehicle.png +0 -0
  102. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/pyproject.toml +0 -0
  103. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/requirements.txt +0 -0
  104. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/rosotacom.yaml +0 -0
  105. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/session-configuration.md +0 -0
  106. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/setup.cfg +0 -0
  107. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/__init__.py +0 -0
  108. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/__main__.py +0 -0
  109. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/anonymize.py +0 -0
  110. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/bag_ground_truth.py +0 -0
  111. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/benched_set.py +0 -0
  112. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/benchmark.py +0 -0
  113. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/benchmark_delta.py +0 -0
  114. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/bundle_check.py +0 -0
  115. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/cli_benchmark.py +0 -0
  116. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/deployment.py +0 -0
  117. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/ffmpeg_packet.py +0 -0
  118. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/forensics.py +0 -0
  119. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/geomap.py +0 -0
  120. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/image_cache.py +0 -0
  121. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/netem_dist.py +0 -0
  122. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/network_profiles.py +0 -0
  123. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/network_shaper.py +0 -0
  124. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/plots.py +0 -0
  125. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/py.typed +0 -0
  126. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/benched-set.yaml +0 -0
  127. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/.gitignore +0 -0
  128. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/README.md +0 -0
  129. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/__init__.py +0 -0
  130. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/bags/8_drop_reference/metadata.yaml +0 -0
  131. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/deployment.example.yaml +0 -0
  132. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/dist/field-20260817.dist +0 -0
  133. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/profiles.yaml +0 -0
  134. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/ros2docker.json +0 -0
  135. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/rosotacom.yaml +0 -0
  136. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scenarios/2_native_chatter/scenario-definition.yaml +0 -0
  137. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_a.sh +0 -0
  138. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_b.sh +0 -0
  139. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.ros2docker.json +0 -0
  140. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_communication.sh +0 -0
  141. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_external.py +0 -0
  142. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/wait_for_echo_topic.sh +0 -0
  143. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.ros2docker.json +0 -0
  144. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_communication.sh +0 -0
  145. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_external.py +0 -0
  146. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external.ros2docker.json +0 -0
  147. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external_session.yaml +0 -0
  148. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/foxglove.json +0 -0
  149. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_communication.sh +0 -0
  150. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_external.py +0 -0
  151. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
  152. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/metadata.yaml +0 -0
  153. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/external.ros2docker.json +0 -0
  154. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_communication.sh +0 -0
  155. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_external.py +0 -0
  156. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external.ros2docker.json +0 -0
  157. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external_session.yaml +0 -0
  158. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/foxglove.json +0 -0
  159. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_communication.sh +0 -0
  160. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_external.py +0 -0
  161. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
  162. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/metadata.yaml +0 -0
  163. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/external.ros2docker.json +0 -0
  164. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_communication.sh +0 -0
  165. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_external.py +0 -0
  166. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external.ros2docker.json +0 -0
  167. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external_session.yaml +0 -0
  168. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_communication.sh +0 -0
  169. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_external.py +0 -0
  170. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external.ros2docker.json +0 -0
  171. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external_session.yaml +0 -0
  172. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_communication.sh +0 -0
  173. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_external.py +0 -0
  174. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external.ros2docker.json +0 -0
  175. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external_session.yaml +0 -0
  176. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_communication.sh +0 -0
  177. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_external.py +0 -0
  178. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external.ros2docker.json +0 -0
  179. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external_session.yaml +0 -0
  180. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_communication.sh +0 -0
  181. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_external.py +0 -0
  182. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/10_restamp/session-definition.yaml +0 -0
  183. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/11_trickle/session-definition.yaml +0 -0
  184. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/12_content_integrity/session-definition.yaml +0 -0
  185. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/13_link_latency/session-definition.yaml +0 -0
  186. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/14_remote_assist_anonymized/session-definition.yaml +0 -0
  187. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/15_remote_assist_anonymized_costmap/session-definition.yaml +0 -0
  188. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/16_remote_assist_anonymized_camera/session-definition.yaml +0 -0
  189. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/17_synthetic_camera_quality/session-definition.yaml +0 -0
  190. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/1_heartbeat/session-definition.yaml +0 -0
  191. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/1_heartbeat_status/session-definition.yaml +0 -0
  192. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/2_native_chatter/session-definition.yaml +0 -0
  193. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/3_comp_occ_grid/session-definition.yaml +0 -0
  194. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/4_comp_occ_grid_zen/session-definition.yaml +0 -0
  195. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/5_sized_payload/session-definition.yaml +0 -0
  196. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/6_sized_payload_zen/session-definition.yaml +0 -0
  197. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/7_latched_static/session-definition.yaml +0 -0
  198. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/8_drop/session-definition.yaml +0 -0
  199. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/9_throttle/session-definition.yaml +0 -0
  200. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/bench_1_1_capacity/session-definition.yaml +0 -0
  201. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/bench_1_2_load_sweep/session-definition.yaml +0 -0
  202. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/bench_1_3_ramp/session-definition.yaml +0 -0
  203. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/bench_1_4_recovery/session-definition.yaml +0 -0
  204. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/bench_1_5_camera/session-definition.yaml +0 -0
  205. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ros2docker.json.example +0 -0
  206. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/.vscode/c_cpp_properties.json +0 -0
  207. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/.vscode/settings.json +0 -0
  208. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_easy_mode.xml.template +0 -0
  209. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_initial_peer_list.xml.template +0 -0
  210. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v2.xml.template +0 -0
  211. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v3.xml.template +0 -0
  212. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v4.xml.template +0 -0
  213. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v5.xml.template +0 -0
  214. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py +0 -0
  215. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/cyclonedds_local_participants.xml.template +0 -0
  216. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template +0 -0
  217. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template +0 -0
  218. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/fastdds_easy_mode.xml.template +0 -0
  219. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/fastdds_tuned.xml.template +0 -0
  220. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/fastdds_unicast.xml.template +0 -0
  221. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/get_ota_xml.py +0 -0
  222. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/utils.py +0 -0
  223. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/zenoh.json5.template +0 -0
  224. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/.gitkeep +0 -0
  225. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_cpp/CMakeLists.txt +0 -0
  226. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_cpp/COLCON_IGNORE +0 -0
  227. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_cpp/LICENSE.txt +0 -0
  228. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_cpp/package.xml +0 -0
  229. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_cpp/src/hz_monitor.cpp +0 -0
  230. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_compressor.cpp +0 -0
  231. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_decompressor.cpp +0 -0
  232. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_msgs/CMakeLists.txt +0 -0
  233. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_msgs/LICENSE.txt +0 -0
  234. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/CompressedData.msg +0 -0
  235. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/EchoHeartbeat.msg +0 -0
  236. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/OtaStamped.msg +0 -0
  237. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/SizedPayload.msg +0 -0
  238. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_msgs/package.xml +0 -0
  239. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/LICENSE.txt +0 -0
  240. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/__init__.py +0 -0
  241. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/base_bridge_relay.py +0 -0
  242. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_in.py +0 -0
  243. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_out.py +0 -0
  244. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/ffmpeg_flags.py +0 -0
  245. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/heartbeat_echo.py +0 -0
  246. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/hz_monitor.py +0 -0
  247. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_bandwidth_reducer.py +0 -0
  248. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_pixel_capper.py +0 -0
  249. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/lanelet_saver.py +0 -0
  250. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/latch_relay.py +0 -0
  251. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/costmap_remapper.py +0 -0
  252. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/marker_remapper.py +0 -0
  253. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/speed_test.py +0 -0
  254. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/tf_remapper.py +0 -0
  255. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/traffic_monitor.py +0 -0
  256. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/wifi_network_analysis_1.py +0 -0
  257. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_bytes.py +0 -0
  258. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_trace.py +0 -0
  259. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/local_global_frame_bridge.py +0 -0
  260. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/localization_map_split_reduce_saver.py +0 -0
  261. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/msg_transform.py +0 -0
  262. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pair_management.py +0 -0
  263. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer.py +0 -0
  264. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer_core.py +0 -0
  265. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pub_sub_pair.py +0 -0
  266. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/qos.py +0 -0
  267. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_in.py +0 -0
  268. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_out.py +0 -0
  269. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/restamp.py +0 -0
  270. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/sized_publisher.py +0 -0
  271. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency.py +0 -0
  272. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency_core.py +0 -0
  273. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview.py +0 -0
  274. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview_core.py +0 -0
  275. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/tf_map_to_cart_saver.py +0 -0
  276. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_monitor.py +0 -0
  277. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_resolution.py +0 -0
  278. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/trickle.py +0 -0
  279. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_compressor.py +0 -0
  280. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_decompressor.py +0 -0
  281. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_unwrapper.py +0 -0
  282. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_wrapper.py +0 -0
  283. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/package.xml +0 -0
  284. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/resource/com_py +0 -0
  285. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/setup.cfg +0 -0
  286. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/setup.py +0 -0
  287. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/test/test_copyright.py +0 -0
  288. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/test/test_flake8.py +0 -0
  289. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/test/test_pep257.py +0 -0
  290. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/content/base/session_plugin_base.yaml +0 -0
  291. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/content/network/up_connectivity.py +0 -0
  292. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/content/network/wifi_network_analysis_2.py +0 -0
  293. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/creation/anonymize_bag.py +0 -0
  294. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/creation/catmux_log_setup.sh +0 -0
  295. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/creation/create_session_yaml.py +0 -0
  296. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/creation/generate_session_files.py +0 -0
  297. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/creation/run_session.py +0 -0
  298. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/creation/run_session_in_external_terminal.py +0 -0
  299. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/creation/strip_ansi.py +0 -0
  300. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/status_eval.py +0 -0
  301. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/stream_stats.py +0 -0
  302. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/trace_profiles.py +0 -0
  303. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/transit.py +0 -0
  304. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/video_quality.py +0 -0
  305. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom_dev.egg-info/dependency_links.txt +0 -0
  306. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom_dev.egg-info/entry_points.txt +0 -0
  307. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom_dev.egg-info/requires.txt +0 -0
  308. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom_dev.egg-info/top_level.txt +0 -0
  309. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/terminology.md +0 -0
  310. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_benched_set_registry.py +0 -0
  311. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_findings.py +0 -0
  312. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_markdown_links.py +0 -0
  313. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_ota_source_bundle.py +0 -0
  314. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_package_metadata.py +0 -0
  315. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_packaged_resources.py +0 -0
  316. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_profile_covers_generated_commands.py +0 -0
  317. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_pytest_policy.py +0 -0
  318. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_readme_examples.py +0 -0
  319. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_security_maintenance_config.py +0 -0
  320. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_session_configuration_doc.py +0 -0
  321. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_session_template_substitution.py +0 -0
  322. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_workflow_contracts.py +0 -0
  323. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/e2e/conftest.py +0 -0
  324. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/e2e/test_anonymize_e2e.py +0 -0
  325. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/e2e/test_benchmark_ab.py +0 -0
  326. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/e2e/test_benchmark_capacity.py +0 -0
  327. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/e2e/test_benchmark_replay.py +0 -0
  328. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/e2e/test_parallel_smoke.py +0 -0
  329. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/e2e/test_smoke.py +0 -0
  330. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/e2e/test_timeline_stepping.py +0 -0
  331. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/e2e/test_video_quality_e2e.py +0 -0
  332. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/sessions/generate_rmw_matrix.py +0 -0
  333. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-local_zenoh-ros2dds-ota/session-definition.yaml +0 -0
  334. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota/session-definition.yaml +0 -0
  335. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota-tuned/session-definition.yaml +0 -0
  336. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/sessions/rmw_matrix/1_heartbeat_fastdds/session-definition.yaml +0 -0
  337. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/sessions/rmw_matrix/1_heartbeat_fastdds-default/session-definition.yaml +0 -0
  338. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/sessions/rmw_matrix/1_heartbeat_zen-endpoints/session-definition.yaml +0 -0
  339. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_anonymize.py +0 -0
  340. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_bag_ground_truth.py +0 -0
  341. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_benched_set.py +0 -0
  342. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_benchmark.py +0 -0
  343. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_benchmark_delta.py +0 -0
  344. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_bundle_check.py +0 -0
  345. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_catmux_pane_logging.py +0 -0
  346. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_cli_benchmark.py +0 -0
  347. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_container_shaping.py +0 -0
  348. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_deployment.py +0 -0
  349. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_ffmpeg_flags.py +0 -0
  350. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_ffmpeg_packet.py +0 -0
  351. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_field_profiles.py +0 -0
  352. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_forensics.py +0 -0
  353. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_geomap.py +0 -0
  354. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_image_cache.py +0 -0
  355. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_link_bytes.py +0 -0
  356. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_link_trace.py +0 -0
  357. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_netem_dist.py +0 -0
  358. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_network_profiles.py +0 -0
  359. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_network_shaper.py +0 -0
  360. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_ota_link_configs.py +0 -0
  361. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_ota_unwrapper.py +0 -0
  362. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_ota_wrapper.py +0 -0
  363. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_ota_xml.py +0 -0
  364. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_playout_pacer.py +0 -0
  365. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_plots.py +0 -0
  366. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_pub_sub_pair_types.py +0 -0
  367. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_qos_fallback_logging.py +0 -0
  368. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_relay_optional_parameters.py +0 -0
  369. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_session_pipeline.py +0 -0
  370. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_stage_latency.py +0 -0
  371. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_status_eval.py +0 -0
  372. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_status_overview.py +0 -0
  373. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_status_overview_observer.py +0 -0
  374. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_stream_stats.py +0 -0
  375. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_trace_profiles.py +0 -0
  376. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_transit.py +0 -0
  377. {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/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.dev52
3
+ Version: 2.5.dev53
4
4
  Summary: Host CLI for ROS OTA communication sessions.
5
5
  Author: develNor
6
6
  License-Expression: BSD-3-Clause
@@ -309,6 +309,24 @@ rosotacom start 1_heartbeat --identity b \
309
309
  --peer-address a=10.0.0.10 --peer-address b=10.0.0.11
310
310
  ```
311
311
 
312
+ Before `start` stops a conflicting container, writes an instance, or builds an
313
+ image, it verifies that the selected identity's address belongs to this host and
314
+ that the route to the other peer selects that address as its source. A missing
315
+ VPN/data-plane interface or a route through the wrong network therefore fails
316
+ without disturbing a working session. Run the same check on its own with
317
+ `preflight`; deployments that require the other host to be online already can
318
+ also make three bounded ICMP probes mandatory:
319
+
320
+ ```bash
321
+ rosotacom preflight 1_heartbeat --identity a \
322
+ --peer-address a=10.0.0.10 --peer-address b=10.0.0.11 \
323
+ --require-peer-reachable
324
+ ```
325
+
326
+ Peer reachability is opt-in because some valid networks block ICMP and peers may
327
+ be started in either order. `rosotacom start` accepts the same
328
+ `--require-peer-reachable` policy when a deployment does require it.
329
+
312
330
  `rosotacom` reads the static session input and creates generated files under `session-instances/<date>/<session>_<timestamp>_<id>/config/`, including per-peer plugin/session specs, topic lists, optional QoS, and optional `domain_bridge.yaml`. Catmux pane output is logged under the same instance in `logs/<peer>/catmux/`.
313
331
 
314
332
  What else a run leaves under `logs/<peer>/`, and which file to open first when a
@@ -264,6 +264,24 @@ rosotacom start 1_heartbeat --identity b \
264
264
  --peer-address a=10.0.0.10 --peer-address b=10.0.0.11
265
265
  ```
266
266
 
267
+ Before `start` stops a conflicting container, writes an instance, or builds an
268
+ image, it verifies that the selected identity's address belongs to this host and
269
+ that the route to the other peer selects that address as its source. A missing
270
+ VPN/data-plane interface or a route through the wrong network therefore fails
271
+ without disturbing a working session. Run the same check on its own with
272
+ `preflight`; deployments that require the other host to be online already can
273
+ also make three bounded ICMP probes mandatory:
274
+
275
+ ```bash
276
+ rosotacom preflight 1_heartbeat --identity a \
277
+ --peer-address a=10.0.0.10 --peer-address b=10.0.0.11 \
278
+ --require-peer-reachable
279
+ ```
280
+
281
+ Peer reachability is opt-in because some valid networks block ICMP and peers may
282
+ be started in either order. `rosotacom start` accepts the same
283
+ `--require-peer-reachable` policy when a deployment does require it.
284
+
267
285
  `rosotacom` reads the static session input and creates generated files under `session-instances/<date>/<session>_<timestamp>_<id>/config/`, including per-peer plugin/session specs, topic lists, optional QoS, and optional `domain_bridge.yaml`. Catmux pane output is logged under the same instance in `logs/<peer>/catmux/`.
268
286
 
269
287
  What else a run leaves under `logs/<peer>/`, and which file to open first when a
@@ -85,6 +85,29 @@ Precedence is explicit:
85
85
  All logical peers must resolve to addresses before a session starts. Session
86
86
  definitions do not accept physical addresses or SSH targets.
87
87
 
88
+ ## Data-plane preflight
89
+
90
+ `rosotacom start` checks the resolved bindings against the host before it stops
91
+ or creates containers:
92
+
93
+ 1. The selected identity's IPv4 address must be assigned locally.
94
+ 2. `ip route get` for the other peer must select that same address as its
95
+ source.
96
+
97
+ This makes an absent VPN/interface, a wrong identity, and a route escaping over
98
+ another network startup errors instead of silent communication failures. Inspect
99
+ the result without starting anything:
100
+
101
+ ```bash
102
+ rosotacom preflight SESSION --identity PEER
103
+ ```
104
+
105
+ Add `--require-peer-reachable` to `preflight` or `start` when this deployment
106
+ also requires three bounded ICMP probes to succeed. Reachability is not the
107
+ global default: ICMP can be intentionally filtered, and valid peers can be
108
+ started in either order. Docker-isolated local smoke networks use their own
109
+ network lifecycle and bypass this host data-plane check.
110
+
88
111
  ## Project selection and completion
89
112
 
90
113
  The nearest `rosotacom.yaml` is discovered upward from the current directory.
@@ -64,6 +64,7 @@ from .image_cache import (
64
64
  image_fingerprint,
65
65
  reference_tag,
66
66
  )
67
+ from .network_preflight import NetworkPreflightResult, run_network_preflight
67
68
 
68
69
  anonymize_lib = importlib.import_module("rosotacom.anonymize")
69
70
 
@@ -1125,7 +1126,7 @@ def _get_local_ipv4s() -> list[str]:
1125
1126
  out = subprocess.check_output(["ip", "-o", "-4", "addr", "show"], text=True)
1126
1127
  except Exception:
1127
1128
  return []
1128
- return _IPV4_RE.findall(out)
1129
+ return re.findall(r"\binet\s+(\d+\.\d+\.\d+\.\d+)/", out)
1129
1130
 
1130
1131
 
1131
1132
  def _default_local_ip() -> str:
@@ -1234,6 +1235,29 @@ def _auto_identity(bindings: dict[str, PeerBinding]) -> str:
1234
1235
  raise RuntimeError(f"Auto identity ambiguous: matched peers={matches} for local IPv4s={sorted(local_ips)}.")
1235
1236
 
1236
1237
 
1238
+ def _network_preflight(
1239
+ bindings: dict[str, PeerBinding],
1240
+ identity: str,
1241
+ *,
1242
+ require_peer_reachable: bool = False,
1243
+ ) -> NetworkPreflightResult:
1244
+ return run_network_preflight(
1245
+ bindings,
1246
+ identity,
1247
+ local_addresses=_get_local_ipv4s(),
1248
+ require_peer_reachable=require_peer_reachable,
1249
+ )
1250
+
1251
+
1252
+ def _print_network_preflight(result: NetworkPreflightResult) -> None:
1253
+ reachability = "peer reachable" if result.peer_reachable else "route verified"
1254
+ print(
1255
+ f"Network preflight OK: {result.identity} ({result.local_address}) -> "
1256
+ f"{result.remote_identity} ({result.remote_address}) via {result.interface} "
1257
+ f"src {result.source_address}; {reachability}."
1258
+ )
1259
+
1260
+
1237
1261
  def _peer_com_name(peers: dict[str, Any], peer_key: str) -> str:
1238
1262
  value = (peers.get(peer_key) or {}).get("com-name")
1239
1263
  if value is None:
@@ -5123,10 +5147,18 @@ def start_session(args: argparse.Namespace) -> str:
5123
5147
  identity = args.identity or _auto_identity(bindings)
5124
5148
  if not args.identity:
5125
5149
  print(f"Auto-selected identity: {identity}")
5150
+ network_isolated = bool(getattr(args, "network_name", None))
5151
+ if not network_isolated:
5152
+ _print_network_preflight(
5153
+ _network_preflight(
5154
+ bindings,
5155
+ identity,
5156
+ require_peer_reachable=getattr(args, "require_peer_reachable", False),
5157
+ )
5158
+ )
5126
5159
  remote_name = _remote_peer_name(cfg, identity)
5127
5160
  instance = _resolve_session_instance(runtime, session, getattr(args, "instance_id", None))
5128
5161
  container_name = _container_name(remote_name, runtime, instance.instance_id)
5129
- network_isolated = bool(getattr(args, "network_name", None))
5130
5162
  if not network_isolated and not getattr(args, "skip_conflict_check", False):
5131
5163
  matching = _matching_com_containers(runtime, remote_name)
5132
5164
  if _fixed_com_container_name(runtime, remote_name) is not None:
@@ -5235,6 +5267,30 @@ def start_session(args: argparse.Namespace) -> str:
5235
5267
  return container_name
5236
5268
 
5237
5269
 
5270
+ def preflight_session(args: argparse.Namespace) -> NetworkPreflightResult:
5271
+ runtime = _load_runtime_config(args)
5272
+ session = _resolve_session(args.session_dir, runtime)
5273
+ cfg = _effective_session_config(session.host_dir, runtime)
5274
+ bindings = _resolve_bindings(
5275
+ cfg,
5276
+ runtime,
5277
+ peer=getattr(args, "peer", None),
5278
+ peer_address=getattr(args, "peer_address", None),
5279
+ )
5280
+ if not args.identity and not getattr(args, "auto_identity", True):
5281
+ raise RuntimeError("Missing --identity. Provide --identity <peer> or allow auto identity.")
5282
+ identity = args.identity or _auto_identity(bindings)
5283
+ if not args.identity:
5284
+ print(f"Auto-selected identity: {identity}")
5285
+ result = _network_preflight(
5286
+ bindings,
5287
+ identity,
5288
+ require_peer_reachable=getattr(args, "require_peer_reachable", False),
5289
+ )
5290
+ _print_network_preflight(result)
5291
+ return result
5292
+
5293
+
5238
5294
  def stop_session(args: argparse.Namespace) -> None:
5239
5295
  runtime = _load_runtime_config(args)
5240
5296
  session = _resolve_session(args.session_dir, runtime)
@@ -8668,6 +8724,11 @@ def _add_start_args(parser: argparse.ArgumentParser) -> None:
8668
8724
  parser.add_argument("--rewrite-formatting", action="store_true")
8669
8725
  _add_peer_arg(parser)
8670
8726
  _add_peer_address_arg(parser)
8727
+ parser.add_argument(
8728
+ "--require-peer-reachable",
8729
+ action="store_true",
8730
+ help="Require three bounded ICMP probes to the peer to succeed before starting.",
8731
+ )
8671
8732
  parser.add_argument("--instance-id", help="Join or create a named runtime session instance.")
8672
8733
  parser.add_argument(
8673
8734
  "--skip-conflict-check",
@@ -8681,6 +8742,22 @@ def _add_start_args(parser: argparse.ArgumentParser) -> None:
8681
8742
  parser.set_defaults(force=True, auto_identity=True)
8682
8743
 
8683
8744
 
8745
+ def _add_preflight_args(parser: argparse.ArgumentParser) -> None:
8746
+ _add_common_config_args(parser)
8747
+ _add_session_arg(parser, "session_dir_positional", nargs="?")
8748
+ _add_session_arg(parser, "-s", "--session-dir", dest="session_dir")
8749
+ _add_identity_arg(parser)
8750
+ parser.add_argument("--no-auto-identity", dest="auto_identity", action="store_false")
8751
+ _add_peer_arg(parser)
8752
+ _add_peer_address_arg(parser)
8753
+ parser.add_argument(
8754
+ "--require-peer-reachable",
8755
+ action="store_true",
8756
+ help="Require three bounded ICMP probes to the peer to succeed.",
8757
+ )
8758
+ parser.set_defaults(auto_identity=True)
8759
+
8760
+
8684
8761
  def _normalize_session_arg(args: argparse.Namespace) -> None:
8685
8762
  positional = getattr(args, "session_dir_positional", None)
8686
8763
  explicit = getattr(args, "session_dir", None)
@@ -8697,6 +8774,12 @@ def start_command(args: argparse.Namespace) -> int:
8697
8774
  return 0
8698
8775
 
8699
8776
 
8777
+ def preflight_command(args: argparse.Namespace) -> int:
8778
+ _normalize_session_arg(args)
8779
+ preflight_session(args)
8780
+ return 0
8781
+
8782
+
8700
8783
  def stop_command(args: argparse.Namespace) -> int:
8701
8784
  _normalize_session_arg(args)
8702
8785
  stop_session(args)
@@ -9052,6 +9135,7 @@ def videoquality_command(args: argparse.Namespace) -> int:
9052
9135
  # turn into `rosotacom start foo` — so a contract test keeps the two in sync.
9053
9136
  TOP_LEVEL_COMMANDS = {
9054
9137
  "start",
9138
+ "preflight",
9055
9139
  "stop",
9056
9140
  "doctor",
9057
9141
  "ps",
@@ -9127,6 +9211,13 @@ def main(argv: list[str] | None = None) -> int:
9127
9211
  _add_start_args(start_parser)
9128
9212
  start_parser.set_defaults(func=start_command)
9129
9213
 
9214
+ preflight_parser = subparsers.add_parser(
9215
+ "preflight",
9216
+ help="Validate the resolved local address, peer route, and optional peer reachability.",
9217
+ )
9218
+ _add_preflight_args(preflight_parser)
9219
+ preflight_parser.set_defaults(func=preflight_command)
9220
+
9130
9221
  stop_parser = subparsers.add_parser("stop", help="Stop rosotacom containers for a session.")
9131
9222
  _add_common_config_args(stop_parser)
9132
9223
  _add_session_arg(stop_parser, "session_dir_positional", nargs="?")
@@ -0,0 +1,134 @@
1
+ """Host data-plane validation for resolved communication peers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import ipaddress
6
+ import re
7
+ import subprocess
8
+ from collections.abc import Iterable
9
+ from dataclasses import dataclass
10
+
11
+ from .deployment import PeerBinding
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class NetworkPreflightResult:
16
+ identity: str
17
+ local_address: str
18
+ remote_identity: str
19
+ remote_address: str
20
+ interface: str
21
+ source_address: str
22
+ peer_reachable: bool | None
23
+
24
+
25
+ def _binding_ipv4(binding: PeerBinding, *, role: str) -> str:
26
+ try:
27
+ return str(ipaddress.IPv4Address(binding.address))
28
+ except ipaddress.AddressValueError as exc:
29
+ raise RuntimeError(
30
+ f"Network preflight failed: {role} peer {binding.peer!r} has non-IPv4 address "
31
+ f"{binding.address!r}. Communication peer addresses must be concrete IPv4 addresses."
32
+ ) from exc
33
+
34
+
35
+ def run_network_preflight(
36
+ bindings: dict[str, PeerBinding],
37
+ identity: str,
38
+ *,
39
+ local_addresses: Iterable[str],
40
+ require_peer_reachable: bool = False,
41
+ ) -> NetworkPreflightResult:
42
+ """Validate the selected local binding and kernel path to its peer."""
43
+ if identity not in bindings:
44
+ raise RuntimeError(f"Network preflight failed: identity {identity!r} is not one of peers={sorted(bindings)}.")
45
+ if len(bindings) != 2:
46
+ raise RuntimeError(f"Network preflight failed: expected exactly 2 peers, got peers={sorted(bindings)}.")
47
+
48
+ local = bindings[identity]
49
+ remote_identity = next(peer for peer in bindings if peer != identity)
50
+ remote = bindings[remote_identity]
51
+ local_address = _binding_ipv4(local, role="local")
52
+ remote_address = _binding_ipv4(remote, role="remote")
53
+
54
+ known_local_addresses = sorted(set(local_addresses))
55
+ if not known_local_addresses:
56
+ raise RuntimeError(
57
+ "Network preflight failed: could not determine any local IPv4 addresses. "
58
+ "Verify that the `ip` command is installed and the required data-plane interface is up."
59
+ )
60
+ if local_address not in known_local_addresses:
61
+ raise RuntimeError(
62
+ f"Network preflight failed for identity {identity!r}: configured local address {local_address} "
63
+ f"is not assigned to this host (local IPv4s: {known_local_addresses}). "
64
+ "Verify --identity and the peer bindings; if the address belongs to a VPN or other data-plane "
65
+ "interface, bring that interface up before starting communication."
66
+ )
67
+
68
+ try:
69
+ route = subprocess.run(
70
+ ["ip", "-4", "route", "get", remote_address],
71
+ text=True,
72
+ capture_output=True,
73
+ check=False,
74
+ )
75
+ except FileNotFoundError as exc:
76
+ raise RuntimeError("Network preflight failed: required command `ip` was not found.") from exc
77
+ route_output = (route.stdout or "").strip()
78
+ if route.returncode != 0 or not route_output:
79
+ detail = (route.stderr or route.stdout or "no route returned").strip()
80
+ raise RuntimeError(
81
+ f"Network preflight failed: no usable IPv4 route from {identity!r} ({local_address}) "
82
+ f"to {remote_identity!r} ({remote_address}): {detail}"
83
+ )
84
+ route_line = route_output.splitlines()[0]
85
+ source_match = re.search(r"\bsrc\s+(\d+\.\d+\.\d+\.\d+)\b", route_line)
86
+ interface_match = re.search(r"\bdev\s+(\S+)", route_line)
87
+ if source_match is None or interface_match is None:
88
+ raise RuntimeError(
89
+ f"Network preflight failed: could not determine source address and interface from route: {route_line}"
90
+ )
91
+ source_address = source_match.group(1)
92
+ interface = interface_match.group(1)
93
+ if source_address != local_address:
94
+ raise RuntimeError(
95
+ f"Network preflight failed: route to {remote_identity!r} ({remote_address}) uses source "
96
+ f"{source_address} on {interface}, but identity {identity!r} is bound to {local_address}. "
97
+ "Fix the route or peer binding before starting communication."
98
+ )
99
+
100
+ peer_reachable: bool | None = None
101
+ if require_peer_reachable:
102
+ try:
103
+ ping = subprocess.run(
104
+ ["ping", "-4", "-n", "-c", "3", "-W", "2", "-I", local_address, remote_address],
105
+ text=True,
106
+ capture_output=True,
107
+ check=False,
108
+ timeout=10,
109
+ )
110
+ except FileNotFoundError as exc:
111
+ raise RuntimeError(
112
+ "Network preflight failed: strict peer reachability was requested, but `ping` was not found."
113
+ ) from exc
114
+ except subprocess.TimeoutExpired as exc:
115
+ raise RuntimeError(
116
+ f"Network preflight failed: ICMP check from {local_address} to {remote_address} exceeded 10 seconds."
117
+ ) from exc
118
+ if ping.returncode != 0:
119
+ raise RuntimeError(
120
+ f"Network preflight failed: peer {remote_identity!r} ({remote_address}) did not answer "
121
+ f"3 ICMP echo requests sent from {local_address} via {interface}. This start requires an "
122
+ "already-reachable peer; verify the data plane, VPN, and firewall."
123
+ )
124
+ peer_reachable = True
125
+
126
+ return NetworkPreflightResult(
127
+ identity=identity,
128
+ local_address=local_address,
129
+ remote_identity=remote_identity,
130
+ remote_address=remote_address,
131
+ interface=interface,
132
+ source_address=source_address,
133
+ peer_reachable=peer_reachable,
134
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rosotacom-dev
3
- Version: 2.5.dev52
3
+ Version: 2.5.dev53
4
4
  Summary: Host CLI for ROS OTA communication sessions.
5
5
  Author: develNor
6
6
  License-Expression: BSD-3-Clause
@@ -309,6 +309,24 @@ rosotacom start 1_heartbeat --identity b \
309
309
  --peer-address a=10.0.0.10 --peer-address b=10.0.0.11
310
310
  ```
311
311
 
312
+ Before `start` stops a conflicting container, writes an instance, or builds an
313
+ image, it verifies that the selected identity's address belongs to this host and
314
+ that the route to the other peer selects that address as its source. A missing
315
+ VPN/data-plane interface or a route through the wrong network therefore fails
316
+ without disturbing a working session. Run the same check on its own with
317
+ `preflight`; deployments that require the other host to be online already can
318
+ also make three bounded ICMP probes mandatory:
319
+
320
+ ```bash
321
+ rosotacom preflight 1_heartbeat --identity a \
322
+ --peer-address a=10.0.0.10 --peer-address b=10.0.0.11 \
323
+ --require-peer-reachable
324
+ ```
325
+
326
+ Peer reachability is opt-in because some valid networks block ICMP and peers may
327
+ be started in either order. `rosotacom start` accepts the same
328
+ `--require-peer-reachable` policy when a deployment does require it.
329
+
312
330
  `rosotacom` reads the static session input and creates generated files under `session-instances/<date>/<session>_<timestamp>_<id>/config/`, including per-peer plugin/session specs, topic lists, optional QoS, and optional `domain_bridge.yaml`. Catmux pane output is logged under the same instance in `logs/<peer>/catmux/`.
313
331
 
314
332
  What else a run leaves under `logs/<peer>/`, and which file to open first when a
@@ -110,6 +110,7 @@ src/rosotacom/forensics.py
110
110
  src/rosotacom/geomap.py
111
111
  src/rosotacom/image_cache.py
112
112
  src/rosotacom/netem_dist.py
113
+ src/rosotacom/network_preflight.py
113
114
  src/rosotacom/network_profiles.py
114
115
  src/rosotacom/network_shaper.py
115
116
  src/rosotacom/plots.py
@@ -351,6 +352,7 @@ tests/unit/test_image_cache.py
351
352
  tests/unit/test_link_bytes.py
352
353
  tests/unit/test_link_trace.py
353
354
  tests/unit/test_netem_dist.py
355
+ tests/unit/test_network_preflight.py
354
356
  tests/unit/test_network_profiles.py
355
357
  tests/unit/test_network_shaper.py
356
358
  tests/unit/test_ota_link_configs.py
@@ -112,6 +112,7 @@
112
112
  "src/rosotacom/geomap.py",
113
113
  "src/rosotacom/image_cache.py",
114
114
  "src/rosotacom/netem_dist.py",
115
+ "src/rosotacom/network_preflight.py",
115
116
  "src/rosotacom/network_profiles.py",
116
117
  "src/rosotacom/network_shaper.py",
117
118
  "src/rosotacom/plots.py",
@@ -346,6 +347,7 @@
346
347
  "tests/unit/test_link_bytes.py",
347
348
  "tests/unit/test_link_trace.py",
348
349
  "tests/unit/test_netem_dist.py",
350
+ "tests/unit/test_network_preflight.py",
349
351
  "tests/unit/test_network_profiles.py",
350
352
  "tests/unit/test_network_shaper.py",
351
353
  "tests/unit/test_ota_link_configs.py",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "tag": "2.4",
3
- "distance": 52,
4
- "node": "g4de846c45fab03bb2bd5b58ccc14d6df1633e735",
3
+ "distance": 53,
4
+ "node": "g05d5905a4728651003afe5bc2feb657a96a1d395",
5
5
  "dirty": false,
6
6
  "branch": "HEAD",
7
7
  "node_date": "2026-08-19"
@@ -1743,12 +1743,13 @@ def test_positional_session_defaults_to_start(monkeypatch: pytest.MonkeyPatch) -
1743
1743
 
1744
1744
  monkeypatch.setattr(rosotacom, "start_session", fake_start_session)
1745
1745
 
1746
- result = rosotacom.main(["1_heartbeat", "--identity", "a"])
1746
+ result = rosotacom.main(["1_heartbeat", "--identity", "a", "--require-peer-reachable"])
1747
1747
 
1748
1748
  assert result == 0
1749
1749
  assert calls
1750
1750
  assert calls[0].session_dir == "1_heartbeat"
1751
1751
  assert calls[0].identity == "a"
1752
+ assert calls[0].require_peer_reachable is True
1752
1753
 
1753
1754
 
1754
1755
  def test_probe_verbs_dispatch_not_wrapped_in_start(monkeypatch: pytest.MonkeyPatch) -> None:
@@ -2017,7 +2018,7 @@ def test_path_yaml_and_network_helpers(tmp_path: Path, monkeypatch: pytest.Monke
2017
2018
 
2018
2019
  def fake_check_output(command: list[str], *, text: bool) -> str:
2019
2020
  if command[:4] == ["ip", "-o", "-4", "addr"]:
2020
- return "1: lo inet 127.0.0.1/8\n2: eth0 inet 10.0.0.5/24\n"
2021
+ return "1: lo inet 127.0.0.1/8\n2: eth0 inet 10.0.0.5/24 brd 10.0.0.255 scope global eth0\n"
2021
2022
  return "1.1.1.1 via 10.0.0.1 dev eth0 src 10.0.0.5 uid 1000"
2022
2023
 
2023
2024
  monkeypatch.setattr(rosotacom.subprocess, "check_output", fake_check_output)
@@ -2287,6 +2288,14 @@ def test_start_session_detached_dispatches_ros2docker(monkeypatch: pytest.Monkey
2287
2288
  monkeypatch.setattr(rosotacom, "_load_runtime_config", lambda args: runtime)
2288
2289
  monkeypatch.setattr(rosotacom, "_resolve_session", lambda session_dir, runtime: session)
2289
2290
  monkeypatch.setattr(rosotacom, "_effective_session_config", lambda *args, **kwargs: cfg)
2291
+ monkeypatch.setattr(
2292
+ rosotacom,
2293
+ "_network_preflight",
2294
+ lambda *args, **kwargs: rosotacom.NetworkPreflightResult(
2295
+ "a", "127.0.0.1", "b", "127.0.0.2", "lo", "127.0.0.1", None
2296
+ ),
2297
+ )
2298
+ monkeypatch.setattr(rosotacom, "_print_network_preflight", lambda result: None)
2290
2299
  monkeypatch.setattr(rosotacom, "_scoped_image_name", lambda runtime: "image:id")
2291
2300
  monkeypatch.setattr(
2292
2301
  rosotacom,
@@ -2334,6 +2343,14 @@ def test_start_session_attach_dispatches_command_run(monkeypatch: pytest.MonkeyP
2334
2343
  monkeypatch.setattr(rosotacom, "_resolve_session", lambda session_dir, runtime: session)
2335
2344
  monkeypatch.setattr(rosotacom, "_effective_session_config", lambda *args, **kwargs: cfg)
2336
2345
  monkeypatch.setattr(rosotacom, "_auto_identity", lambda *args: "a")
2346
+ monkeypatch.setattr(
2347
+ rosotacom,
2348
+ "_network_preflight",
2349
+ lambda *args, **kwargs: rosotacom.NetworkPreflightResult(
2350
+ "a", "127.0.0.1", "b", "127.0.0.2", "lo", "127.0.0.1", None
2351
+ ),
2352
+ )
2353
+ monkeypatch.setattr(rosotacom, "_print_network_preflight", lambda result: None)
2337
2354
  monkeypatch.setattr(rosotacom, "_scoped_image_name", lambda runtime: "image:id")
2338
2355
  monkeypatch.setattr(rosotacom, "_base_extra_run_args", lambda runtime, session, cfg, instance, **kwargs: [])
2339
2356
  monkeypatch.setattr(rosotacom, "_resolve_mode", lambda mode: "attach")
@@ -190,6 +190,14 @@ def _patch_start_session_collaborators(
190
190
  monkeypatch.setattr(rosotacom, "_load_runtime_config", lambda args: runtime)
191
191
  monkeypatch.setattr(rosotacom, "_resolve_session", lambda session_dir, runtime: session)
192
192
  monkeypatch.setattr(rosotacom, "_effective_session_config", lambda *args, **kwargs: cfg)
193
+ monkeypatch.setattr(
194
+ rosotacom,
195
+ "_network_preflight",
196
+ lambda *args, **kwargs: rosotacom.NetworkPreflightResult(
197
+ "a", "127.0.0.1", "b", "127.0.0.2", "lo", "127.0.0.1", None
198
+ ),
199
+ )
200
+ monkeypatch.setattr(rosotacom, "_print_network_preflight", lambda result: None)
193
201
  monkeypatch.setattr(rosotacom, "_scoped_image_name", lambda runtime: "image:id")
194
202
  monkeypatch.setattr(rosotacom, "_base_extra_run_args", lambda runtime, session, cfg, instance, **kwargs: [])
195
203
  monkeypatch.setattr(rosotacom, "_resolve_mode", lambda mode: "detached")
@@ -236,16 +244,31 @@ def test_start_session_force_replaces_conflicting_identity_container(
236
244
  cfg = {"peers": {"a": {}, "b": {"com-name": "remote"}}}
237
245
  calls: list[tuple[str, dict[str, object]]] = []
238
246
  stopped: list[str] = []
247
+ events: list[str] = []
239
248
  _patch_start_session_collaborators(monkeypatch, runtime, session, cfg, calls)
249
+ monkeypatch.setattr(
250
+ rosotacom,
251
+ "_network_preflight",
252
+ lambda *args, **kwargs: (
253
+ events.append("preflight")
254
+ or rosotacom.NetworkPreflightResult("a", "127.0.0.1", "b", "127.0.0.2", "lo", "127.0.0.1", None)
255
+ ),
256
+ )
240
257
  monkeypatch.setattr(
241
258
  rosotacom,
242
259
  "_list_docker_containers",
243
260
  lambda all_states=False: [("rosotacom_id_other_com_to_remote", ["bridge"])],
244
261
  )
262
+
263
+ def record_stop(name: str, runtime: rosotacom.RuntimeConfig, **kwargs: object) -> bool:
264
+ events.append("stop")
265
+ stopped.append(name)
266
+ return True
267
+
245
268
  monkeypatch.setattr(
246
269
  rosotacom,
247
270
  "_stop_container_name",
248
- lambda name, runtime, **kwargs: stopped.append(name) or True,
271
+ record_stop,
249
272
  )
250
273
 
251
274
  container = rosotacom.start_session(_start_session_args(force=True))
@@ -254,6 +277,7 @@ def test_start_session_force_replaces_conflicting_identity_container(
254
277
  # The conflicting other-instance container is stopped first; force also
255
278
  # keeps its pre-existing own-name replace for --instance-id rejoins.
256
279
  assert stopped == ["rosotacom_id_other_com_to_remote", "rosotacom_id_unit_com_to_remote"]
280
+ assert events == ["preflight", "stop", "stop"]
257
281
  assert [name for name, _ in calls] == ["build", "run", "exec"]
258
282
 
259
283