rosotacom-dev 2.5.dev65__tar.gz → 2.5.dev66__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 (391) hide show
  1. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/PKG-INFO +1 -1
  2. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/README.md +1 -0
  3. rosotacom_dev-2.5.dev66/docs/findings/one-domain-two-cyclone-configs-stop-interoperating.md +94 -0
  4. rosotacom_dev-2.5.dev66/src/rosotacom/resources/ws/ota_configs/cyclonedds_scoped.xml.template +87 -0
  5. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/get_ota_xml.py +75 -30
  6. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/content/base/session_plugin_base.yaml +4 -4
  7. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom_dev.egg-info/PKG-INFO +1 -1
  8. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom_dev.egg-info/SOURCES.txt +2 -0
  9. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom_dev.egg-info/scm_file_list.json +2 -0
  10. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom_dev.egg-info/scm_version.json +2 -2
  11. rosotacom_dev-2.5.dev66/tests/unit/test_ota_xml.py +134 -0
  12. rosotacom_dev-2.5.dev65/tests/unit/test_ota_xml.py +0 -70
  13. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.devcontainer/devcontainer.json.template +0 -0
  14. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.devcontainer/re_generate_devcontainer_json.py +0 -0
  15. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/CODEOWNERS +0 -0
  16. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/ISSUE_TEMPLATE/documentation-audit.md +0 -0
  17. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/ISSUE_TEMPLATE/implementation-cleanup.md +0 -0
  18. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/ISSUE_TEMPLATE/quality-workflow.md +0 -0
  19. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/ISSUE_TEMPLATE/redesign.md +0 -0
  20. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/ISSUE_TEMPLATE/release-process.md +0 -0
  21. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/ISSUE_TEMPLATE/repository-diagnosis.md +0 -0
  22. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/ISSUE_TEMPLATE/test-ci-audit.md +0 -0
  23. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/ISSUE_TEMPLATE/work-item.md +0 -0
  24. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  25. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/actions/setup-just/action.yml +0 -0
  26. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/dependabot.yml +0 -0
  27. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/workflows/benchmark-calibrate.yml +0 -0
  28. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/workflows/benchmark-gate.yml +0 -0
  29. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/workflows/dev-release.yml +0 -0
  30. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/workflows/image-scan.yml +0 -0
  31. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/workflows/nightly-e2e.yml +0 -0
  32. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/workflows/pr-lightweight.yml +0 -0
  33. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/workflows/pr-merge-gate.yml +0 -0
  34. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/workflows/release.yml +0 -0
  35. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.pre-commit-config.yaml +0 -0
  36. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/AGENTS.md +0 -0
  37. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/CONCURRENCY.md +0 -0
  38. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/CONTRIBUTING.md +0 -0
  39. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/DEVELOPMENT_PRINCIPLES.md +0 -0
  40. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/LICENSE.txt +0 -0
  41. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/MANIFEST.in +0 -0
  42. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/README.md +0 -0
  43. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/budgets.jsonl +0 -0
  44. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/calibration/README.md +0 -0
  45. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/calibration/capacity-size-tight-cyclone.json +0 -0
  46. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/calibration/probe-loss-gop-tight-cyclone.json +0 -0
  47. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/calibration/probe-loss-nominal-cyclone.json +0 -0
  48. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/calibration/probe-loss-tight-cyclone.json +0 -0
  49. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/calibration/probe-loss-tight-fastdds.json +0 -0
  50. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/calibration/probe-loss-tight-zenoh.json +0 -0
  51. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/codecov.yml +0 -0
  52. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/deployment-configuration.md +0 -0
  53. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/benchmark-ab.md +0 -0
  54. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/benchmark-bag-as-load.md +0 -0
  55. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/ci.md +0 -0
  56. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/ffmpeg-keyframes.md +0 -0
  57. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/a-transport-element-doubles-every-fastdds-sample.md +0 -0
  58. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/cyclone-fragment-equal-to-max-drops-fragmented-samples.md +0 -0
  59. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/cyclone-spdp-discovery-bursts.md +0 -0
  60. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/delay-alone-no-loss.md +0 -0
  61. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/fastdds-datagram-cap-drops-large-samples.md +0 -0
  62. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/graph-derived-types-block-a-non-graph-transport.md +0 -0
  63. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/head-of-line-irregularity.md +0 -0
  64. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/jitter-loss-bandwidth-latency.md +0 -0
  65. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/keyframe-loss-kills-the-next-deltas.md +0 -0
  66. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/lifespan-is-enforced-by-one-reader-and-not-the-other.md +0 -0
  67. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/lighter-message-loss.md +0 -0
  68. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/oversubscription-queues-not-losses.md +0 -0
  69. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/reorder-becomes-reader-loss.md +0 -0
  70. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/repro/decode_chain_repro.py +0 -0
  71. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/repro/reorder_drop_repro.py +0 -0
  72. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/sender-rows-make-a-dead-link-look-loss-free.md +0 -0
  73. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/zero-loss-boundaries-18kb-20hz.md +0 -0
  74. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/forensics-report.md +0 -0
  75. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/geo-link-map.md +0 -0
  76. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/github-repository-settings.md +0 -0
  77. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/link-bandwidth.md +0 -0
  78. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/link-trace.md +0 -0
  79. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/owner-runbook.md +0 -0
  80. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/performance-bands.md +0 -0
  81. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/playbooks/README.md +0 -0
  82. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/quality-model.md +0 -0
  83. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/release-notes/TEMPLATE.md +0 -0
  84. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/release-notes/v2.1.md +0 -0
  85. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/release-notes/v2.2.md +0 -0
  86. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/release-notes/v2.3.md +0 -0
  87. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/release-notes/v2.4.md +0 -0
  88. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/release.md +0 -0
  89. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/rfcs/0001-expectation-driven-test-suite.md +0 -0
  90. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/rfcs/0002-expectation-concepts.md +0 -0
  91. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/rfcs/0003-metric-backbone.md +0 -0
  92. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/rfcs/0004-network-profiles.md +0 -0
  93. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/rfcs/0005-benchmark-genres-and-ci.md +0 -0
  94. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/rfcs/0006-dynamic-qos.md +0 -0
  95. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/rfcs/0007-regression-gate.md +0 -0
  96. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/rfcs/README.md +0 -0
  97. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/testing.md +0 -0
  98. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/work-items.md +0 -0
  99. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/install.sh +0 -0
  100. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/justfile +0 -0
  101. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/media/control_center.png +0 -0
  102. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/media/echo_test.png +0 -0
  103. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/media/forensics-report-example.png +0 -0
  104. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/media/host.png +0 -0
  105. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/media/vehicle.png +0 -0
  106. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/pyproject.toml +0 -0
  107. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/requirements.txt +0 -0
  108. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/rosotacom.yaml +0 -0
  109. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/session-configuration.md +0 -0
  110. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/setup.cfg +0 -0
  111. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/__init__.py +0 -0
  112. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/__main__.py +0 -0
  113. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/anonymize.py +0 -0
  114. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/bag_ground_truth.py +0 -0
  115. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/benched_set.py +0 -0
  116. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/benchmark.py +0 -0
  117. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/benchmark_delta.py +0 -0
  118. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/bundle_check.py +0 -0
  119. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/cli.py +0 -0
  120. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/cli_benchmark.py +0 -0
  121. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/deployment.py +0 -0
  122. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/ffmpeg_packet.py +0 -0
  123. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/forensics.py +0 -0
  124. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/geomap.py +0 -0
  125. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/image_cache.py +0 -0
  126. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/netem_dist.py +0 -0
  127. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/network_preflight.py +0 -0
  128. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/network_profiles.py +0 -0
  129. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/network_shaper.py +0 -0
  130. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/plots.py +0 -0
  131. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/py.typed +0 -0
  132. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/benched-set.yaml +0 -0
  133. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/.gitignore +0 -0
  134. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/README.md +0 -0
  135. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/__init__.py +0 -0
  136. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/bags/8_drop_reference/metadata.yaml +0 -0
  137. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/deployment.example.yaml +0 -0
  138. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/dist/field-20260817.dist +0 -0
  139. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/profiles.yaml +0 -0
  140. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/ros2docker.json +0 -0
  141. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/ros2docker.lyrical.json +0 -0
  142. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/rosotacom.yaml +0 -0
  143. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scenarios/2_native_chatter/scenario-definition.yaml +0 -0
  144. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_a.sh +0 -0
  145. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_b.sh +0 -0
  146. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.lyrical.ros2docker.json +0 -0
  147. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.ros2docker.json +0 -0
  148. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_communication.sh +0 -0
  149. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_external.py +0 -0
  150. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/wait_for_echo_topic.sh +0 -0
  151. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.lyrical.ros2docker.json +0 -0
  152. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.ros2docker.json +0 -0
  153. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_communication.sh +0 -0
  154. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_external.py +0 -0
  155. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external.ros2docker.json +0 -0
  156. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external_session.yaml +0 -0
  157. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/foxglove.json +0 -0
  158. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_communication.sh +0 -0
  159. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_external.py +0 -0
  160. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
  161. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/metadata.yaml +0 -0
  162. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/external.ros2docker.json +0 -0
  163. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_communication.sh +0 -0
  164. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_external.py +0 -0
  165. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external.ros2docker.json +0 -0
  166. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external_session.yaml +0 -0
  167. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/foxglove.json +0 -0
  168. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_communication.sh +0 -0
  169. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_external.py +0 -0
  170. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
  171. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/metadata.yaml +0 -0
  172. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/external.ros2docker.json +0 -0
  173. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_communication.sh +0 -0
  174. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_external.py +0 -0
  175. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external.ros2docker.json +0 -0
  176. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external_session.yaml +0 -0
  177. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_communication.sh +0 -0
  178. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_external.py +0 -0
  179. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external.ros2docker.json +0 -0
  180. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external_session.yaml +0 -0
  181. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_communication.sh +0 -0
  182. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_external.py +0 -0
  183. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external.ros2docker.json +0 -0
  184. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external_session.yaml +0 -0
  185. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_communication.sh +0 -0
  186. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_external.py +0 -0
  187. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external.ros2docker.json +0 -0
  188. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external_session.yaml +0 -0
  189. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_communication.sh +0 -0
  190. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_external.py +0 -0
  191. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/10_restamp/session-definition.yaml +0 -0
  192. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/11_trickle/session-definition.yaml +0 -0
  193. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/12_content_integrity/session-definition.yaml +0 -0
  194. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/13_link_latency/session-definition.yaml +0 -0
  195. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/14_remote_assist_anonymized/session-definition.yaml +0 -0
  196. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/15_remote_assist_anonymized_costmap/session-definition.yaml +0 -0
  197. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/16_remote_assist_anonymized_camera/session-definition.yaml +0 -0
  198. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/17_synthetic_camera_quality/session-definition.yaml +0 -0
  199. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/1_heartbeat/session-definition.yaml +0 -0
  200. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/1_heartbeat_status/session-definition.yaml +0 -0
  201. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/2_native_chatter/session-definition.yaml +0 -0
  202. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/3_comp_occ_grid/session-definition.yaml +0 -0
  203. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/4_comp_occ_grid_zen/session-definition.yaml +0 -0
  204. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/5_sized_payload/session-definition.yaml +0 -0
  205. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/6_sized_payload_zen/session-definition.yaml +0 -0
  206. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/7_latched_static/session-definition.yaml +0 -0
  207. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/8_drop/session-definition.yaml +0 -0
  208. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/9_throttle/session-definition.yaml +0 -0
  209. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/bench_1_1_capacity/session-definition.yaml +0 -0
  210. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/bench_1_2_load_sweep/session-definition.yaml +0 -0
  211. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/bench_1_3_ramp/session-definition.yaml +0 -0
  212. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/bench_1_4_recovery/session-definition.yaml +0 -0
  213. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/bench_1_5_camera/session-definition.yaml +0 -0
  214. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ros2docker.json.example +0 -0
  215. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ros2docker.lyrical.json.example +0 -0
  216. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/.vscode/c_cpp_properties.json +0 -0
  217. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/.vscode/settings.json +0 -0
  218. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_easy_mode.xml.template +0 -0
  219. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_initial_peer_list.xml.template +0 -0
  220. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v2.xml.template +0 -0
  221. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v3.xml.template +0 -0
  222. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v4.xml.template +0 -0
  223. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v5.xml.template +0 -0
  224. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py +0 -0
  225. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/cyclonedds_local_participants.xml.template +0 -0
  226. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template +0 -0
  227. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template +0 -0
  228. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/fastdds_easy_mode.xml.template +0 -0
  229. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/fastdds_local.xml.template +0 -0
  230. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/fastdds_tuned.xml.template +0 -0
  231. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/fastdds_unicast.xml.template +0 -0
  232. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/utils.py +0 -0
  233. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/zenoh.json5.template +0 -0
  234. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/.gitkeep +0 -0
  235. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_cpp/CMakeLists.txt +0 -0
  236. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_cpp/COLCON_IGNORE +0 -0
  237. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_cpp/LICENSE.txt +0 -0
  238. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_cpp/package.xml +0 -0
  239. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_cpp/src/hz_monitor.cpp +0 -0
  240. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_compressor.cpp +0 -0
  241. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_decompressor.cpp +0 -0
  242. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_msgs/CMakeLists.txt +0 -0
  243. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_msgs/LICENSE.txt +0 -0
  244. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/CompressedData.msg +0 -0
  245. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/EchoHeartbeat.msg +0 -0
  246. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/OtaStamped.msg +0 -0
  247. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/SizedPayload.msg +0 -0
  248. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_msgs/package.xml +0 -0
  249. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/LICENSE.txt +0 -0
  250. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/__init__.py +0 -0
  251. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/base_bridge_relay.py +0 -0
  252. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_in.py +0 -0
  253. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_out.py +0 -0
  254. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/ffmpeg_flags.py +0 -0
  255. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/heartbeat_echo.py +0 -0
  256. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/hz_monitor.py +0 -0
  257. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_bandwidth_reducer.py +0 -0
  258. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_pixel_capper.py +0 -0
  259. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/lanelet_saver.py +0 -0
  260. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/latch_relay.py +0 -0
  261. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/costmap_remapper.py +0 -0
  262. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/marker_remapper.py +0 -0
  263. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/speed_test.py +0 -0
  264. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/tf_remapper.py +0 -0
  265. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/traffic_monitor.py +0 -0
  266. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/wifi_network_analysis_1.py +0 -0
  267. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_bytes.py +0 -0
  268. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_trace.py +0 -0
  269. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/local_global_frame_bridge.py +0 -0
  270. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/localization_map_split_reduce_saver.py +0 -0
  271. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/msg_transform.py +0 -0
  272. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pair_management.py +0 -0
  273. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer.py +0 -0
  274. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer_core.py +0 -0
  275. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pub_sub_pair.py +0 -0
  276. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/qos.py +0 -0
  277. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_in.py +0 -0
  278. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_out.py +0 -0
  279. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/restamp.py +0 -0
  280. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/sized_publisher.py +0 -0
  281. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency.py +0 -0
  282. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency_core.py +0 -0
  283. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview.py +0 -0
  284. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview_core.py +0 -0
  285. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/tf_map_to_cart_saver.py +0 -0
  286. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_monitor.py +0 -0
  287. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_resolution.py +0 -0
  288. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/trickle.py +0 -0
  289. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_compressor.py +0 -0
  290. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_decompressor.py +0 -0
  291. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_unwrapper.py +0 -0
  292. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_wrapper.py +0 -0
  293. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/package.xml +0 -0
  294. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/resource/com_py +0 -0
  295. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/setup.cfg +0 -0
  296. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/setup.py +0 -0
  297. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/test/test_copyright.py +0 -0
  298. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/test/test_flake8.py +0 -0
  299. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/test/test_pep257.py +0 -0
  300. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/content/network/up_connectivity.py +0 -0
  301. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/content/network/wifi_network_analysis_2.py +0 -0
  302. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/creation/anonymize_bag.py +0 -0
  303. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/creation/catmux_log_setup.sh +0 -0
  304. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/creation/create_session_yaml.py +0 -0
  305. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/creation/generate_session_files.py +0 -0
  306. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/creation/run_session.py +0 -0
  307. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/creation/run_session_in_external_terminal.py +0 -0
  308. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/creation/strip_ansi.py +0 -0
  309. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/status_eval.py +0 -0
  310. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/stream_stats.py +0 -0
  311. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/trace_profiles.py +0 -0
  312. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/transit.py +0 -0
  313. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/video_quality.py +0 -0
  314. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom_dev.egg-info/dependency_links.txt +0 -0
  315. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom_dev.egg-info/entry_points.txt +0 -0
  316. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom_dev.egg-info/requires.txt +0 -0
  317. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom_dev.egg-info/top_level.txt +0 -0
  318. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/terminology.md +0 -0
  319. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_benched_set_registry.py +0 -0
  320. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_findings.py +0 -0
  321. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_generated_topics_have_a_producer.py +0 -0
  322. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_lyrical_runtime_compat.py +0 -0
  323. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_markdown_links.py +0 -0
  324. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_ota_source_bundle.py +0 -0
  325. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_package_metadata.py +0 -0
  326. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_packaged_resources.py +0 -0
  327. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_profile_covers_generated_commands.py +0 -0
  328. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_pytest_policy.py +0 -0
  329. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_readme_examples.py +0 -0
  330. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_security_maintenance_config.py +0 -0
  331. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_session_configuration_doc.py +0 -0
  332. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_session_template_substitution.py +0 -0
  333. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_workflow_contracts.py +0 -0
  334. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/e2e/conftest.py +0 -0
  335. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/e2e/test_anonymize_e2e.py +0 -0
  336. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/e2e/test_benchmark_ab.py +0 -0
  337. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/e2e/test_benchmark_capacity.py +0 -0
  338. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/e2e/test_benchmark_replay.py +0 -0
  339. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/e2e/test_parallel_smoke.py +0 -0
  340. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/e2e/test_smoke.py +0 -0
  341. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/e2e/test_timeline_stepping.py +0 -0
  342. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/e2e/test_video_quality_e2e.py +0 -0
  343. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/sessions/generate_rmw_matrix.py +0 -0
  344. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-local_zenoh-ros2dds-ota/session-definition.yaml +0 -0
  345. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota/session-definition.yaml +0 -0
  346. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota-tuned/session-definition.yaml +0 -0
  347. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/sessions/rmw_matrix/1_heartbeat_fastdds/session-definition.yaml +0 -0
  348. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/sessions/rmw_matrix/1_heartbeat_fastdds-default/session-definition.yaml +0 -0
  349. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/sessions/rmw_matrix/1_heartbeat_zen-endpoints/session-definition.yaml +0 -0
  350. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_anonymize.py +0 -0
  351. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_bag_ground_truth.py +0 -0
  352. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_benched_set.py +0 -0
  353. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_benchmark.py +0 -0
  354. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_benchmark_delta.py +0 -0
  355. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_bundle_check.py +0 -0
  356. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_catmux_pane_logging.py +0 -0
  357. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_cli.py +0 -0
  358. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_cli_benchmark.py +0 -0
  359. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_concurrency.py +0 -0
  360. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_container_shaping.py +0 -0
  361. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_deployment.py +0 -0
  362. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_ffmpeg_flags.py +0 -0
  363. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_ffmpeg_packet.py +0 -0
  364. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_field_profiles.py +0 -0
  365. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_forensics.py +0 -0
  366. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_geomap.py +0 -0
  367. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_image_cache.py +0 -0
  368. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_link_bytes.py +0 -0
  369. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_link_trace.py +0 -0
  370. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_netem_dist.py +0 -0
  371. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_network_preflight.py +0 -0
  372. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_network_profiles.py +0 -0
  373. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_network_shaper.py +0 -0
  374. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_ota_link_configs.py +0 -0
  375. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_ota_unwrapper.py +0 -0
  376. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_ota_wrapper.py +0 -0
  377. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_playout_pacer.py +0 -0
  378. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_plots.py +0 -0
  379. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_pub_sub_pair_types.py +0 -0
  380. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_qos_fallback_logging.py +0 -0
  381. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_relay_optional_parameters.py +0 -0
  382. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_ros_node_entity_ownership.py +0 -0
  383. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_session_pipeline.py +0 -0
  384. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_stage_latency.py +0 -0
  385. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_status_eval.py +0 -0
  386. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_status_overview.py +0 -0
  387. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_status_overview_observer.py +0 -0
  388. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_stream_stats.py +0 -0
  389. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_trace_profiles.py +0 -0
  390. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_transit.py +0 -0
  391. {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/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.dev65
3
+ Version: 2.5.dev66
4
4
  Summary: Host CLI for ROS OTA communication sessions.
5
5
  Author: develNor
6
6
  License-Expression: BSD-3-Clause
@@ -32,6 +32,7 @@ living verification hook.
32
32
  - [A bridge that learns types from the graph cannot use a transport that does not carry the graph](graph-derived-types-block-a-non-graph-transport.md) - over `zenoh_ros2dds` the payload topic never arrived in either run: the bridge routes a topic once a local reader exists and the reader waited for the bridge, leaving only `Pending=1` in a log.
33
33
  - [A Fast DDS datagram cap stops every message larger than it](fastdds-datagram-cap-drops-large-samples.md) - copying CycloneDDS's 1200 B fragment size into the Fast DDS OTA profile makes every sample above the cap never arrive, at 1200 B and at 8192 B, sync and async — while the 84 B heartbeat keeps flowing at 10 Hz.
34
34
  - [A fragment sized exactly like the datagram cap stops every fragmented sample](cyclone-fragment-equal-to-max-drops-fragmented-samples.md) - CycloneDDS 11.0.1 delivers nothing above one fragment when `FragmentSize` equals `MaxMessageSize`, where 0.10.5 delivers everything on the identical profile; a 40 B string still crosses, and discovery, endpoint announcement and proxy-writer matching all succeed while no sample arrives.
35
+ - [Two CycloneDDS configurations on one domain stop interoperating](one-domain-two-cyclone-configs-stop-interoperating.md) - on 11.0.1 a publisher and a subscriber on the same host and domain deliver nothing when one carries the local profile and the other the OTA profile, where 0.10.5 delivers in all four combinations; discovery, endpoint announcement and matching all succeed while no sample moves.
35
36
  - [A lost keyframe silences exactly the next gop_size−2 deltas](keyframe-loss-kills-the-next-deltas.md) - libavcodec emits nothing for them, the last delta decodes with artifacts, the next keyframe restores clean decode; a lost delta never blocks decode — so the display hole is gop_size × frame period, deterministically.
36
37
  - [Any transport element in a Fast DDS profile doubles every sample on the wire](a-transport-element-doubles-every-fastdds-sample.md) - 366 datagrams for 180 samples against 183 without it; `<builtinTransports>DEFAULT` is a no-op selection and doubles too, so the trigger is the element's presence — removing it takes the shipped OTA profile from 2.10x the payload to 1.04x at identical delivery.
37
38
  - [Lifespan is enforced by one DDS reader and not the other](lifespan-is-enforced-by-one-reader-and-not-the-other.md) - under the same 20% oversubscription both stacks queue alike (472 and 433 delivered at ~1.1-1.2 s); with `lifespan: 0.7` CycloneDDS is unchanged and delivers 9.1% inside the bound, while Fast DDS drops to 4 delivered and never exceeds 570 ms — the policy decides shown-vs-suppressed, not how long the wait is.
@@ -0,0 +1,94 @@
1
+ # Two CycloneDDS Configurations on One Domain Stop Interoperating
2
+
3
+ ## Claim
4
+
5
+ On CycloneDDS 11.0.1 two participants on the **same host and the same domain**
6
+ exchange no data when they are given different configurations. On 0.10.5 they
7
+ do. Discovery is unaffected in the failing combination — the topic appears in
8
+ `ros2 topic list`, both sides announce their endpoints, the reader builds its
9
+ proxy writers — and no sample is delivered.
10
+
11
+ This is what a session relies on without saying so. A peer renders two whole
12
+ configurations, a local one and an OTA one, and exports `CYCLONEDDS_URI` twice,
13
+ so the second replaces the first: processes started after it view the *local*
14
+ domain through the *OTA* profile while the relay and the application containers
15
+ view it through the local one. Under 0.10.5 that mixture worked. Under 11.0.1
16
+ the bridge subscribes on the local domain, receives nothing, forwards nothing
17
+ into the OTA domain, and the far peer receives nothing — with every stage
18
+ reporting itself healthy.
19
+
20
+ ## Setup
21
+
22
+ - Host pair / topology: for the effect itself, one host is enough — two
23
+ containers from the same communication image, `--network host`, one ROS
24
+ domain, one publisher and one subscriber. The session it was found in runs
25
+ across two hosts joined by a point-to-point VPN.
26
+ - Session: none for the isolated measurement; a `std_msgs/msg/String` at 2 Hz
27
+ and `ros2 topic echo … --once`. The two configurations are the ones a session
28
+ renders: `cyclonedds_local_participants.xml` and `cyclonedds_tuned.xml`.
29
+ - rosotacom SHA: measured on the packaged 2.5.dev61 images; re-runs record
30
+ theirs.
31
+ - Profile: none — no impairment; the effect needs none.
32
+ - Seed policy: deterministic (no netem, no random load), `n=1` per cell; the
33
+ effect is present/absent, not a distribution.
34
+ - Stacks: `ros-kilted-cyclonedds` 0.10.5-2noble against
35
+ `ros-lyrical-cyclonedds` 11.0.1-4resolute.
36
+
37
+ ## Evidence
38
+
39
+ | publisher / subscriber | 0.10.5 | 11.0.1 |
40
+ |---|---|---|
41
+ | local / local | 12 B | 12 B |
42
+ | local / **ota** | 12 B | **0** |
43
+ | **ota** / local | 12 B | **0** |
44
+ | ota / ota | 12 B | 12 B |
45
+
46
+ Inside a failing session, one topic the relay publishes on the local domain:
47
+
48
+ ```
49
+ /com/out/<peer>/can/twist/max10hz/ota_stamped, domain 47
50
+ subscriber with local_dds.xml : 512 B received
51
+ subscriber with ota_dds.xml : 0 B
52
+ domain 47 seen through local_dds.xml : 103 topics
53
+ domain 47 seen through ota_dds.xml : 29 topics
54
+ ```
55
+
56
+ Ruled out on the way to it, each measured with the real images on the same
57
+ hosts: cross-host delivery, same-host delivery under one profile,
58
+ `com_msgs/msg/OtaStamped`, the container's IPC namespace, `domain_bridge`
59
+ itself (minimal config, the session's full 27-topic config, with and without the
60
+ OTA profile, with and without `ROS_DOMAIN_ID` set), participant count (0, 6 and
61
+ 12 extra participants), and adding the local profile's
62
+ `ParticipantIndex`/`MaxAutoParticipantIndex` to the OTA profile.
63
+
64
+ Verification: automated:
65
+ `pytest tests/unit/test_ota_xml.py::test_shipped_scoped_template_carries_both_domains_and_only_ota_restrictions`
66
+ holds the shape of the configuration that avoids the mixture — OTA restrictions
67
+ scoped to the OTA domain, the local domain left with default discovery. Manual,
68
+ for the effect itself: two containers on one host and one domain, one publisher
69
+ and one subscriber, each given one of the two rendered profiles, all four
70
+ combinations.
71
+
72
+ ## Status
73
+
74
+ confirmed, 2026-08-20.
75
+
76
+ Addressed by `cyclonedds_scoped.xml.template`, which carries both domains in one
77
+ file with each section scoped by `Domain Id`, so one configuration can be shared
78
+ by every process on the host. It is an additional template: the two-file
79
+ arrangement is unchanged, and a session that does not name the new one behaves
80
+ exactly as before.
81
+
82
+ ## Publication notes
83
+
84
+ The reportable part is not "a DDS version changed". It is that a configuration
85
+ which was *never* uniform became load-bearing without anybody choosing it: the
86
+ mixture had been there all along and was harmless, so nothing recorded it as a
87
+ property of the deployment. A measurement stack should state, beside the
88
+ middleware version, whether every process on a domain was configured
89
+ identically — because on one side of that version boundary the answer does not
90
+ matter and on the other it decides whether any data moves.
91
+
92
+ Second, it is another instance of the same trap as the datagram cap: a link that
93
+ passes discovery, endpoint matching and a heartbeat check while carrying
94
+ nothing. Neither check tests what the payload uses.
@@ -0,0 +1,87 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ One CycloneDDS configuration for both of a peer's domains, each section scoped
4
+ to the domain it belongs to.
5
+
6
+ Set it as `shared.rmw.ota.cyclone.config` and leave the local one unset: this
7
+ file already carries the local domain's section, so nothing has to overwrite
8
+ anything.
9
+
10
+ Why it exists. The two-file arrangement renders a local profile and an OTA
11
+ profile and exports CYCLONEDDS_URI twice, so the second replaces the first and
12
+ every process started after it views the *local* domain through the *OTA*
13
+ profile. On CycloneDDS 0.10.5 that was survivable: participants configured
14
+ differently on one host and one domain still exchanged data. On 11.0.1 they do
15
+ not — they discover each other, announce their endpoints, match, and deliver
16
+ nothing. Measured on one host, one domain, a publisher and a subscriber:
17
+
18
+ publisher / subscriber 0.10.5 11.0.1
19
+ local / local 12 B 12 B
20
+ local / ota 12 B 0
21
+ ota / local 12 B 0
22
+ ota / ota 12 B 12 B
23
+
24
+ A session whose relay publishes under one profile and whose bridge subscribes
25
+ under the other therefore hands nothing from the local domain into the OTA
26
+ domain, and the link carries nothing while every stage looks healthy
27
+ (docs/findings/one-domain-two-cyclone-configs-stop-interoperating.md).
28
+
29
+ Scoping fixes the cause rather than the symptom: the OTA settings apply to the
30
+ OTA domain, the local domain keeps default discovery with room for many
31
+ participants, and one file can be shared by every process on the host.
32
+
33
+ The two-file arrangement stays exactly as it was — this is an additional
34
+ template, not a replacement, and a session that does not name it is unchanged.
35
+ -->
36
+ <CycloneDDS xmlns="https://cdds.io/config">
37
+ <!--
38
+ The OTA domain: interface-pinned, unicast-only, with the datagram caps the
39
+ provisioned link is sized for. Identical to cyclonedds_tuned.xml except that
40
+ it says which domain it is for.
41
+ -->
42
+ <Domain Id="#ota_domain">
43
+ <General>
44
+ <AllowMulticast>false</AllowMulticast>
45
+ <Interfaces>
46
+ <NetworkInterface address="#host_ip"/>
47
+ </Interfaces>
48
+ <MulticastRecvNetworkInterfaceAddresses>none</MulticastRecvNetworkInterfaceAddresses>
49
+ <!-- Strictly below MaxMessageSize; see cyclonedds_tuned.xml for what
50
+ making them equal cost. -->
51
+ <FragmentSize>1024B</FragmentSize>
52
+ <MaxMessageSize>1200B</MaxMessageSize>
53
+ <MaxRexmitMessageSize>1200B</MaxRexmitMessageSize>
54
+ </General>
55
+
56
+ <Discovery>
57
+ <Peers>
58
+ <!--peer-block--><Peer Address="#peer"/><!--/peer-block-->
59
+ </Peers>
60
+ <EnableTopicDiscoveryEndpoints>false</EnableTopicDiscoveryEndpoints>
61
+ <LeaseDuration>60s</LeaseDuration>
62
+ <SPDPInterval>#spdp_interval</SPDPInterval>
63
+ </Discovery>
64
+
65
+ <Internal>
66
+ <SquashParticipants>true</SquashParticipants>
67
+ </Internal>
68
+
69
+ <Tracing>
70
+ <Verbosity>config</Verbosity>
71
+ <OutputFile>/tmp/cyclonedds.log</OutputFile>
72
+ </Tracing>
73
+ </Domain>
74
+
75
+ <!--
76
+ The local domain: default discovery, more participants. It pins no interface,
77
+ disables no multicast and sets no peer list, because intra-host discovery has
78
+ to keep working — the same reasoning as cyclonedds_local_participants.xml,
79
+ including why 119 and not higher.
80
+ -->
81
+ <Domain Id="#local_domain">
82
+ <Discovery>
83
+ <ParticipantIndex>auto</ParticipantIndex>
84
+ <MaxAutoParticipantIndex>119</MaxAutoParticipantIndex>
85
+ </Discovery>
86
+ </Domain>
87
+ </CycloneDDS>
@@ -15,8 +15,20 @@ import re
15
15
  import sys
16
16
  import tempfile
17
17
 
18
-
19
- KNOWN_PLACEHOLDERS = {"#host_ip", "#peer", "#easy_mode_ip", "#spdp_interval"}
18
+ KNOWN_PLACEHOLDERS = {
19
+ "#host_ip",
20
+ "#peer",
21
+ "#easy_mode_ip",
22
+ "#spdp_interval",
23
+ #: A template that scopes its settings to one ROS domain resolves these.
24
+ #: Cyclone applies a <Domain> section to the domain its Id names, so a
25
+ #: single configuration can hold the OTA settings for the OTA domain and
26
+ #: leave the local domain alone — which is what lets every process on a
27
+ #: host share one configuration instead of half of them carrying the OTA
28
+ #: profile and half the local one.
29
+ "#local_domain",
30
+ "#ota_domain",
31
+ }
20
32
  PLACEHOLDER_PATTERN = re.compile(r"#[A-Za-z_][A-Za-z0-9_]*")
21
33
  DEFAULT_SPDP_INTERVAL = "30s"
22
34
 
@@ -48,6 +60,19 @@ def _resolved_address(value: str, label: str) -> str:
48
60
  return address
49
61
 
50
62
 
63
+ def _resolved_domain(value: str, label: str) -> str:
64
+ """A ROS domain id, validated rather than pasted into the XML.
65
+
66
+ An unusable Id is worse than a missing one: Cyclone keeps a <Domain>
67
+ section it cannot match to any domain, so the settings vanish without a
68
+ word and the link comes up on defaults.
69
+ """
70
+ domain = str(value).strip()
71
+ if not domain.isdigit() or not 0 <= int(domain) <= 232:
72
+ raise ValueError(f"{label} must be a ROS domain id between 0 and 232, got {value!r}.")
73
+ return str(int(domain))
74
+
75
+
51
76
  def _resolved_spdp_interval(value: str) -> str:
52
77
  interval = value.strip().lower()
53
78
  if not interval:
@@ -99,9 +124,7 @@ def _expand_peer_block(content: str, peer_ips: list) -> str:
99
124
 
100
125
  has_markers = PEER_BLOCK_OPEN in content
101
126
  if has_markers and (PEER_BLOCK_CLOSE not in content):
102
- raise RuntimeError(
103
- f"Template has '{PEER_BLOCK_OPEN}' without matching '{PEER_BLOCK_CLOSE}'."
104
- )
127
+ raise RuntimeError(f"Template has '{PEER_BLOCK_OPEN}' without matching '{PEER_BLOCK_CLOSE}'.")
105
128
 
106
129
  if len(peer_ips) == 1 and not has_markers:
107
130
  return content.replace("#peer", peer_ips[0])
@@ -116,9 +139,7 @@ def _expand_peer_block(content: str, peer_ips: list) -> str:
116
139
 
117
140
  matches = list(PEER_BLOCK_PATTERN.finditer(content))
118
141
  if len(matches) != 1:
119
- raise RuntimeError(
120
- f"Template must contain exactly one peer-block region; found {len(matches)}."
121
- )
142
+ raise RuntimeError(f"Template must contain exactly one peer-block region; found {len(matches)}.")
122
143
  m = matches[0]
123
144
  block = m.group(1)
124
145
  if "#peer" not in block:
@@ -128,11 +149,11 @@ def _expand_peer_block(content: str, peer_ips: list) -> str:
128
149
 
129
150
  # Preserve the indentation of the marker line so duplicated blocks align.
130
151
  line_start = content.rfind("\n", 0, m.start()) + 1
131
- indent = content[line_start:m.start()]
152
+ indent = content[line_start : m.start()]
132
153
  sep = ("\n" + indent) if not indent.strip() else ""
133
154
 
134
155
  rendered = sep.join(block.replace("#peer", ip) for ip in peer_ips)
135
- return content[:m.start()] + rendered + content[m.end():]
156
+ return content[: m.start()] + rendered + content[m.end() :]
136
157
 
137
158
 
138
159
  def main(
@@ -141,12 +162,14 @@ def main(
141
162
  peer: str = None,
142
163
  easy_mode_ip: str = None,
143
164
  spdp_interval: str = DEFAULT_SPDP_INTERVAL,
165
+ local_domain: str = None,
166
+ ota_domain: str = None,
144
167
  ) -> str:
145
168
  path = _template_path(config)
146
169
  if not os.path.exists(path):
147
170
  raise FileNotFoundError(f"Template not found: {path}")
148
171
 
149
- with open(path, "r", encoding="utf-8") as f:
172
+ with open(path, encoding="utf-8") as f:
150
173
  content = f.read()
151
174
 
152
175
  found = set(PLACEHOLDER_PATTERN.findall(content))
@@ -159,9 +182,7 @@ def main(
159
182
 
160
183
  if "#host_ip" in found:
161
184
  if not host_ip:
162
- raise RuntimeError(
163
- f"Template '{os.path.basename(path)}' uses #host_ip but --host-ip was not provided."
164
- )
185
+ raise RuntimeError(f"Template '{os.path.basename(path)}' uses #host_ip but --host-ip was not provided.")
165
186
  content = content.replace("#host_ip", _resolved_address(host_ip, "Host IP"))
166
187
 
167
188
  if "#easy_mode_ip" in found:
@@ -169,45 +190,60 @@ def main(
169
190
  raise RuntimeError(
170
191
  f"Template '{os.path.basename(path)}' uses #easy_mode_ip but --easy-mode-ip was not provided."
171
192
  )
172
- content = content.replace(
173
- "#easy_mode_ip", _resolved_address(easy_mode_ip, "Easy Mode IP")
174
- )
193
+ content = content.replace("#easy_mode_ip", _resolved_address(easy_mode_ip, "Easy Mode IP"))
175
194
 
176
195
  if "#spdp_interval" in found:
177
196
  content = content.replace("#spdp_interval", _resolved_spdp_interval(spdp_interval))
178
197
 
198
+ for placeholder, value, option in (
199
+ ("#local_domain", local_domain, "--local-domain"),
200
+ ("#ota_domain", ota_domain, "--ota-domain"),
201
+ ):
202
+ if placeholder in found:
203
+ if value is None or not str(value).strip():
204
+ raise RuntimeError(
205
+ f"Template '{os.path.basename(path)}' uses {placeholder} but {option} was not provided."
206
+ )
207
+ content = content.replace(placeholder, _resolved_domain(value, placeholder))
208
+
179
209
  if "#peer" in found:
180
210
  if not peer:
181
- raise RuntimeError(
182
- f"Template '{os.path.basename(path)}' uses #peer but --peer was not provided."
183
- )
211
+ raise RuntimeError(f"Template '{os.path.basename(path)}' uses #peer but --peer was not provided.")
184
212
  content = _expand_peer_block(content, _resolve_peer_ips(peer))
185
213
 
186
214
  return content
187
215
 
188
216
 
189
217
  if __name__ == "__main__":
190
- parser = argparse.ArgumentParser(
191
- description="Resolve placeholders in an OTA DDS XML template."
192
- )
218
+ parser = argparse.ArgumentParser(description="Resolve placeholders in an OTA DDS XML template.")
193
219
  parser.add_argument(
194
- "-c", "--config", required=True,
220
+ "-c",
221
+ "--config",
222
+ required=True,
195
223
  help="Template name (e.g. fastdds_v1.xml, cyclonedds.xml, fastdds_easy_mode.xml).",
196
224
  )
197
225
  parser.add_argument(
198
- "-i", "--host-ip", dest="host_ip",
226
+ "-i",
227
+ "--host-ip",
228
+ dest="host_ip",
199
229
  help="Resolved local host address (#host_ip).",
200
230
  )
201
231
  parser.add_argument(
202
- "-p", "--peer", dest="peer",
232
+ "-p",
233
+ "--peer",
234
+ dest="peer",
203
235
  help="Resolved peer address, or comma-separated addresses (#peer).",
204
236
  )
205
237
  parser.add_argument(
206
- "-e", "--easy-mode-ip", dest="easy_mode_ip",
238
+ "-e",
239
+ "--easy-mode-ip",
240
+ dest="easy_mode_ip",
207
241
  help="Resolved Fast DDS Easy Mode address (#easy_mode_ip).",
208
242
  )
209
243
  parser.add_argument(
210
- "-o", "--output", dest="output",
244
+ "-o",
245
+ "--output",
246
+ dest="output",
211
247
  help=(
212
248
  "Write the rendered XML to this path, atomically. Prefer this over a shell "
213
249
  "redirect: `> file` truncates the target before this script runs, so a "
@@ -216,6 +252,16 @@ if __name__ == "__main__":
216
252
  "comes up carrying nothing."
217
253
  ),
218
254
  )
255
+ parser.add_argument(
256
+ "--local-domain",
257
+ dest="local_domain",
258
+ help="Local ROS domain id, for a template that scopes a section to it (#local_domain).",
259
+ )
260
+ parser.add_argument(
261
+ "--ota-domain",
262
+ dest="ota_domain",
263
+ help="OTA ROS domain id, for a template that scopes a section to it (#ota_domain).",
264
+ )
219
265
  parser.add_argument(
220
266
  "--spdp-interval",
221
267
  dest="spdp_interval",
@@ -224,8 +270,7 @@ if __name__ == "__main__":
224
270
  )
225
271
  args = parser.parse_args()
226
272
  output = args.output
227
- rendered = main(**{k: v for k, v in vars(args).items()
228
- if v is not None and k != "output"})
273
+ rendered = main(**{k: v for k, v in vars(args).items() if v is not None and k != "output"})
229
274
  if not output:
230
275
  print(rendered)
231
276
  raise SystemExit(0)
@@ -292,7 +292,7 @@ common:
292
292
  before_commands:
293
293
  - if [ '${local_domain_id}' != "None" ] && [ -n '${local_domain_id}' ]; then export ROS_DOMAIN_ID='${local_domain_id}'; fi
294
294
  - if [ '${rmw_local}' != "None" ]; then case ${rmw_local} in cyclone) export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp;; fastdds) export RMW_IMPLEMENTATION=rmw_fastrtps_cpp; export FASTDDS_BUILTIN_TRANSPORTS=${FASTDDS_BUILTIN_TRANSPORTS:-UDPv4};; zenoh) export RMW_IMPLEMENTATION=rmw_zenoh_cpp;; *) export RMW_IMPLEMENTATION='${rmw_local}';; esac; fi
295
- - if [ '${local_config_template}' != "None" ] && [ -n '${local_config_template}' ]; then local_args=(--config "${local_config_template}" --host-ip "${ip_local}" --peer "${ip_remote}"); [ '${local_easy_mode_ip}' != "None" ] && [ -n '${local_easy_mode_ip}' ] && local_args+=(--easy-mode-ip "${local_easy_mode_ip}"); [ '${local_spdp_interval}' != "None" ] && [ -n '${local_spdp_interval}' ] && local_args+=(--spdp-interval "${local_spdp_interval}"); python3 /ws/ota_configs/get_ota_xml.py "${local_args[@]}" --output "${local_config_file}" || { echo "FATAL - could not render the local DDS profile ${local_config_template}; refusing to start on defaults." >&2; exit 1; }; case ${rmw_local} in cyclone) export CYCLONEDDS_URI="file://${local_config_file}";; fastdds) export FASTDDS_DEFAULT_PROFILES_FILE="${local_config_file}"; export RMW_FASTRTPS_USE_QOS_FROM_XML=1;; esac; fi
295
+ - if [ '${local_config_template}' != "None" ] && [ -n '${local_config_template}' ]; then local_args=(--config "${local_config_template}" --host-ip "${ip_local}" --peer "${ip_remote}"); [ '${local_domain_id}' != "None" ] && [ -n '${local_domain_id}' ] && local_args+=(--local-domain "${local_domain_id}"); [ '${ota_domain_id}' != "None" ] && [ -n '${ota_domain_id}' ] && local_args+=(--ota-domain "${ota_domain_id}"); [ '${local_easy_mode_ip}' != "None" ] && [ -n '${local_easy_mode_ip}' ] && local_args+=(--easy-mode-ip "${local_easy_mode_ip}"); [ '${local_spdp_interval}' != "None" ] && [ -n '${local_spdp_interval}' ] && local_args+=(--spdp-interval "${local_spdp_interval}"); python3 /ws/ota_configs/get_ota_xml.py "${local_args[@]}" --output "${local_config_file}" || { echo "FATAL - could not render the local DDS profile ${local_config_template}; refusing to start on defaults." >&2; exit 1; }; case ${rmw_local} in cyclone) export CYCLONEDDS_URI="file://${local_config_file}";; fastdds) export FASTDDS_DEFAULT_PROFILES_FILE="${local_config_file}"; export RMW_FASTRTPS_USE_QOS_FROM_XML=1;; esac; fi
296
296
  - if [ '${before_command}' != "None" ]; then ${before_command}; fi
297
297
 
298
298
  windows:
@@ -338,7 +338,7 @@ windows:
338
338
  if: use_domain_bridge
339
339
  splits:
340
340
  - commands:
341
- - if [ '${ota_config_template}' != "None" ] && [ -n '${ota_config_template}' ]; then ota_args=(--config "${ota_config_template}" --host-ip "${ip_local}" --peer "${ip_remote}"); [ '${ota_easy_mode_ip}' != "None" ] && [ -n '${ota_easy_mode_ip}' ] && ota_args+=(--easy-mode-ip "${ota_easy_mode_ip}"); [ '${ota_spdp_interval}' != "None" ] && [ -n '${ota_spdp_interval}' ] && ota_args+=(--spdp-interval "${ota_spdp_interval}"); python3 /ws/ota_configs/get_ota_xml.py "${ota_args[@]}" --output "${ota_config_file}" || { echo "FATAL - could not render the OTA DDS profile ${ota_config_template}; refusing to start on defaults." >&2; exit 1; }; case ${rmw_ota} in cyclone) export CYCLONEDDS_URI="file://${ota_config_file}";; fastdds) export FASTDDS_DEFAULT_PROFILES_FILE="${ota_config_file}"; export RMW_FASTRTPS_USE_QOS_FROM_XML=1;; esac; fi
341
+ - if [ '${ota_config_template}' != "None" ] && [ -n '${ota_config_template}' ]; then ota_args=(--config "${ota_config_template}" --host-ip "${ip_local}" --peer "${ip_remote}"); [ '${local_domain_id}' != "None" ] && [ -n '${local_domain_id}' ] && ota_args+=(--local-domain "${local_domain_id}"); [ '${ota_domain_id}' != "None" ] && [ -n '${ota_domain_id}' ] && ota_args+=(--ota-domain "${ota_domain_id}"); [ '${ota_easy_mode_ip}' != "None" ] && [ -n '${ota_easy_mode_ip}' ] && ota_args+=(--easy-mode-ip "${ota_easy_mode_ip}"); [ '${ota_spdp_interval}' != "None" ] && [ -n '${ota_spdp_interval}' ] && ota_args+=(--spdp-interval "${ota_spdp_interval}"); python3 /ws/ota_configs/get_ota_xml.py "${ota_args[@]}" --output "${ota_config_file}" || { echo "FATAL - could not render the OTA DDS profile ${ota_config_template}; refusing to start on defaults." >&2; exit 1; }; case ${rmw_ota} in cyclone) export CYCLONEDDS_URI="file://${ota_config_file}";; fastdds) export FASTDDS_DEFAULT_PROFILES_FILE="${ota_config_file}"; export RMW_FASTRTPS_USE_QOS_FROM_XML=1;; esac; fi
342
342
  - ros2 run domain_bridge domain_bridge --wait-for-publisher false ${domain_bridge_config_file}
343
343
  - name: IN
344
344
  if: in
@@ -346,7 +346,7 @@ windows:
346
346
  - commands:
347
347
  - if [ '${ota_domain_id}' != "None" ] && [ -n '${ota_domain_id}' ]; then export ROS_DOMAIN_ID='${ota_domain_id}'; fi
348
348
  - case ${rmw_ota} in cyclone) export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp;; fastdds) export RMW_IMPLEMENTATION=rmw_fastrtps_cpp; export FASTDDS_BUILTIN_TRANSPORTS=${FASTDDS_BUILTIN_TRANSPORTS:-UDPv4};; zenoh) export RMW_IMPLEMENTATION=rmw_zenoh_cpp;; esac
349
- - if [ '${ota_config_template}' != "None" ] && [ -n '${ota_config_template}' ]; then ota_args=(--config "${ota_config_template}" --host-ip "${ip_local}" --peer "${ip_remote}"); [ '${ota_easy_mode_ip}' != "None" ] && [ -n '${ota_easy_mode_ip}' ] && ota_args+=(--easy-mode-ip "${ota_easy_mode_ip}"); [ '${ota_spdp_interval}' != "None" ] && [ -n '${ota_spdp_interval}' ] && ota_args+=(--spdp-interval "${ota_spdp_interval}"); python3 /ws/ota_configs/get_ota_xml.py "${ota_args[@]}" --output "${ota_config_file}" || { echo "FATAL - could not render the OTA DDS profile ${ota_config_template}; refusing to start on defaults." >&2; exit 1; }; case ${rmw_ota} in cyclone) export CYCLONEDDS_URI="file://${ota_config_file}";; fastdds) export FASTDDS_DEFAULT_PROFILES_FILE="${ota_config_file}"; export RMW_FASTRTPS_USE_QOS_FROM_XML=1;; esac; fi
349
+ - if [ '${ota_config_template}' != "None" ] && [ -n '${ota_config_template}' ]; then ota_args=(--config "${ota_config_template}" --host-ip "${ip_local}" --peer "${ip_remote}"); [ '${local_domain_id}' != "None" ] && [ -n '${local_domain_id}' ] && ota_args+=(--local-domain "${local_domain_id}"); [ '${ota_domain_id}' != "None" ] && [ -n '${ota_domain_id}' ] && ota_args+=(--ota-domain "${ota_domain_id}"); [ '${ota_easy_mode_ip}' != "None" ] && [ -n '${ota_easy_mode_ip}' ] && ota_args+=(--easy-mode-ip "${ota_easy_mode_ip}"); [ '${ota_spdp_interval}' != "None" ] && [ -n '${ota_spdp_interval}' ] && ota_args+=(--spdp-interval "${ota_spdp_interval}"); python3 /ws/ota_configs/get_ota_xml.py "${ota_args[@]}" --output "${ota_config_file}" || { echo "FATAL - could not render the OTA DDS profile ${ota_config_template}; refusing to start on defaults." >&2; exit 1; }; case ${rmw_ota} in cyclone) export CYCLONEDDS_URI="file://${ota_config_file}";; fastdds) export FASTDDS_DEFAULT_PROFILES_FILE="${ota_config_file}"; export RMW_FASTRTPS_USE_QOS_FROM_XML=1;; esac; fi
350
350
  # For zenoh_ros2dds the OTA domain is loopback-only (zenoh is the inter-host
351
351
  # transport), so confine discovery to localhost instead of statically peering
352
352
  # the remote host — otherwise the OTA-domain DDS double-delivers alongside zenoh.
@@ -373,7 +373,7 @@ windows:
373
373
  - commands:
374
374
  - if [ '${ota_domain_id}' != "None" ] && [ -n '${ota_domain_id}' ]; then export ROS_DOMAIN_ID='${ota_domain_id}'; fi
375
375
  - case ${rmw_ota} in cyclone) export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp;; fastdds) export RMW_IMPLEMENTATION=rmw_fastrtps_cpp; export FASTDDS_BUILTIN_TRANSPORTS=${FASTDDS_BUILTIN_TRANSPORTS:-UDPv4};; zenoh) export RMW_IMPLEMENTATION=rmw_zenoh_cpp;; esac
376
- - if [ '${ota_config_template}' != "None" ] && [ -n '${ota_config_template}' ]; then ota_args=(--config "${ota_config_template}" --host-ip "${ip_local}" --peer "${ip_remote}"); [ '${ota_easy_mode_ip}' != "None" ] && [ -n '${ota_easy_mode_ip}' ] && ota_args+=(--easy-mode-ip "${ota_easy_mode_ip}"); [ '${ota_spdp_interval}' != "None" ] && [ -n '${ota_spdp_interval}' ] && ota_args+=(--spdp-interval "${ota_spdp_interval}"); python3 /ws/ota_configs/get_ota_xml.py "${ota_args[@]}" --output "${ota_config_file}" || { echo "FATAL - could not render the OTA DDS profile ${ota_config_template}; refusing to start on defaults." >&2; exit 1; }; case ${rmw_ota} in cyclone) export CYCLONEDDS_URI="file://${ota_config_file}";; fastdds) export FASTDDS_DEFAULT_PROFILES_FILE="${ota_config_file}"; export RMW_FASTRTPS_USE_QOS_FROM_XML=1;; esac; fi
376
+ - if [ '${ota_config_template}' != "None" ] && [ -n '${ota_config_template}' ]; then ota_args=(--config "${ota_config_template}" --host-ip "${ip_local}" --peer "${ip_remote}"); [ '${local_domain_id}' != "None" ] && [ -n '${local_domain_id}' ] && ota_args+=(--local-domain "${local_domain_id}"); [ '${ota_domain_id}' != "None" ] && [ -n '${ota_domain_id}' ] && ota_args+=(--ota-domain "${ota_domain_id}"); [ '${ota_easy_mode_ip}' != "None" ] && [ -n '${ota_easy_mode_ip}' ] && ota_args+=(--easy-mode-ip "${ota_easy_mode_ip}"); [ '${ota_spdp_interval}' != "None" ] && [ -n '${ota_spdp_interval}' ] && ota_args+=(--spdp-interval "${ota_spdp_interval}"); python3 /ws/ota_configs/get_ota_xml.py "${ota_args[@]}" --output "${ota_config_file}" || { echo "FATAL - could not render the OTA DDS profile ${ota_config_template}; refusing to start on defaults." >&2; exit 1; }; case ${rmw_ota} in cyclone) export CYCLONEDDS_URI="file://${ota_config_file}";; fastdds) export FASTDDS_DEFAULT_PROFILES_FILE="${ota_config_file}"; export RMW_FASTRTPS_USE_QOS_FROM_XML=1;; esac; fi
377
377
  # For zenoh_ros2dds the OTA domain is loopback-only (zenoh is the inter-host
378
378
  # transport), so confine discovery to localhost instead of statically peering
379
379
  # the remote host — otherwise the OTA-domain DDS double-delivers alongside zenoh.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rosotacom-dev
3
- Version: 2.5.dev65
3
+ Version: 2.5.dev66
4
4
  Summary: Host CLI for ROS OTA communication sessions.
5
5
  Author: develNor
6
6
  License-Expression: BSD-3-Clause
@@ -72,6 +72,7 @@ docs/findings/jitter-loss-bandwidth-latency.md
72
72
  docs/findings/keyframe-loss-kills-the-next-deltas.md
73
73
  docs/findings/lifespan-is-enforced-by-one-reader-and-not-the-other.md
74
74
  docs/findings/lighter-message-loss.md
75
+ docs/findings/one-domain-two-cyclone-configs-stop-interoperating.md
75
76
  docs/findings/oversubscription-queues-not-losses.md
76
77
  docs/findings/reorder-becomes-reader-loss.md
77
78
  docs/findings/sender-rows-make-a-dead-link-look-loss-free.md
@@ -212,6 +213,7 @@ src/rosotacom/resources/ws/.vscode/settings.json
212
213
  src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py
213
214
  src/rosotacom/resources/ws/ota_configs/cyclonedds_local_participants.xml.template
214
215
  src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template
216
+ src/rosotacom/resources/ws/ota_configs/cyclonedds_scoped.xml.template
215
217
  src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template
216
218
  src/rosotacom/resources/ws/ota_configs/fastdds_easy_mode.xml.template
217
219
  src/rosotacom/resources/ws/ota_configs/fastdds_local.xml.template
@@ -57,6 +57,7 @@
57
57
  "docs/findings/keyframe-loss-kills-the-next-deltas.md",
58
58
  "docs/findings/lifespan-is-enforced-by-one-reader-and-not-the-other.md",
59
59
  "docs/findings/lighter-message-loss.md",
60
+ "docs/findings/one-domain-two-cyclone-configs-stop-interoperating.md",
60
61
  "docs/findings/oversubscription-queues-not-losses.md",
61
62
  "docs/findings/reorder-becomes-reader-loss.md",
62
63
  "docs/findings/repro/decode_chain_repro.py",
@@ -215,6 +216,7 @@
215
216
  "src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py",
216
217
  "src/rosotacom/resources/ws/ota_configs/cyclonedds_local_participants.xml.template",
217
218
  "src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template",
219
+ "src/rosotacom/resources/ws/ota_configs/cyclonedds_scoped.xml.template",
218
220
  "src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template",
219
221
  "src/rosotacom/resources/ws/ota_configs/fastdds_easy_mode.xml.template",
220
222
  "src/rosotacom/resources/ws/ota_configs/fastdds_local.xml.template",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "tag": "2.4",
3
- "distance": 65,
4
- "node": "g10a4e383f32456a7740c259e780111c21ea071de",
3
+ "distance": 66,
4
+ "node": "g77d4b7e2148ba0d437581a7481f1a96b67a3a6a9",
5
5
  "dirty": false,
6
6
  "branch": "HEAD",
7
7
  "node_date": "2026-08-20"
@@ -0,0 +1,134 @@
1
+ from __future__ import annotations
2
+
3
+ import importlib.util
4
+ from pathlib import Path
5
+ from types import ModuleType
6
+
7
+ import pytest
8
+
9
+
10
+ def _module() -> ModuleType:
11
+ path = (
12
+ Path(__file__).resolve().parents[2]
13
+ / "src"
14
+ / "rosotacom"
15
+ / "resources"
16
+ / "ws"
17
+ / "ota_configs"
18
+ / "get_ota_xml.py"
19
+ )
20
+ spec = importlib.util.spec_from_file_location("test_get_ota_xml", path)
21
+ assert spec is not None and spec.loader is not None
22
+ module = importlib.util.module_from_spec(spec)
23
+ spec.loader.exec_module(module)
24
+ return module
25
+
26
+
27
+ def test_ota_xml_uses_resolved_literal_addresses(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
28
+ module = _module()
29
+ template = tmp_path / "test.xml.template"
30
+ template.write_text("<host>#host_ip</host><peer>#peer</peer><easy>#easy_mode_ip</easy>\n", encoding="utf-8")
31
+ monkeypatch.setattr(module, "_template_path", lambda _name: str(template))
32
+
33
+ rendered = module.main(
34
+ config="test.xml",
35
+ host_ip="10.0.0.10",
36
+ peer="10.0.0.11",
37
+ easy_mode_ip="10.0.0.10",
38
+ )
39
+
40
+ assert rendered == "<host>10.0.0.10</host><peer>10.0.0.11</peer><easy>10.0.0.10</easy>\n"
41
+
42
+
43
+ def test_ota_xml_renders_default_and_overridden_spdp_interval(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
44
+ module = _module()
45
+ template = tmp_path / "test.xml.template"
46
+ template.write_text("<SPDPInterval>#spdp_interval</SPDPInterval>\n", encoding="utf-8")
47
+ monkeypatch.setattr(module, "_template_path", lambda _name: str(template))
48
+
49
+ assert module.main(config="test.xml") == "<SPDPInterval>30s</SPDPInterval>\n"
50
+ assert module.main(config="test.xml", spdp_interval="150s") == "<SPDPInterval>150s</SPDPInterval>\n"
51
+
52
+
53
+ def test_ota_xml_rejects_empty_resolved_address(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
54
+ module = _module()
55
+ template = tmp_path / "test.xml.template"
56
+ template.write_text("<host>#host_ip</host>\n", encoding="utf-8")
57
+ monkeypatch.setattr(module, "_template_path", lambda _name: str(template))
58
+
59
+ with pytest.raises(ValueError, match="non-empty resolved address"):
60
+ module.main(config="test.xml", host_ip=" ")
61
+
62
+
63
+ def test_ota_xml_rejects_invalid_spdp_interval(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
64
+ module = _module()
65
+ template = tmp_path / "test.xml.template"
66
+ template.write_text("<SPDPInterval>#spdp_interval</SPDPInterval>\n", encoding="utf-8")
67
+ monkeypatch.setattr(module, "_template_path", lambda _name: str(template))
68
+
69
+ with pytest.raises(ValueError, match="seconds or milliseconds"):
70
+ module.main(config="test.xml", spdp_interval="2min")
71
+
72
+
73
+ def test_ota_xml_scopes_sections_to_their_domains(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
74
+ module = _module()
75
+ template = tmp_path / "test.xml.template"
76
+ template.write_text('<Domain Id="#ota_domain"/><Domain Id="#local_domain"/>\n', encoding="utf-8")
77
+ monkeypatch.setattr(module, "_template_path", lambda _name: str(template))
78
+
79
+ rendered = module.main(config="test.xml", local_domain="47", ota_domain="48")
80
+
81
+ assert rendered == '<Domain Id="48"/><Domain Id="47"/>\n'
82
+
83
+
84
+ def test_ota_xml_refuses_a_domain_it_cannot_use(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
85
+ """A section Cyclone matches to no domain is silently ignored, so refuse first."""
86
+ module = _module()
87
+ template = tmp_path / "test.xml.template"
88
+ template.write_text('<Domain Id="#ota_domain"/>\n', encoding="utf-8")
89
+ monkeypatch.setattr(module, "_template_path", lambda _name: str(template))
90
+
91
+ for bad in ("233", "-1", "any", "", "4 7"):
92
+ with pytest.raises((ValueError, RuntimeError)):
93
+ module.main(config="test.xml", ota_domain=bad)
94
+
95
+
96
+ def test_ota_xml_names_the_option_a_scoped_template_needs(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
97
+ module = _module()
98
+ template = tmp_path / "test.xml.template"
99
+ template.write_text('<Domain Id="#local_domain"/>\n', encoding="utf-8")
100
+ monkeypatch.setattr(module, "_template_path", lambda _name: str(template))
101
+
102
+ with pytest.raises(RuntimeError) as excinfo:
103
+ module.main(config="test.xml")
104
+
105
+ assert "--local-domain" in str(excinfo.value)
106
+
107
+
108
+ def test_shipped_scoped_template_carries_both_domains_and_only_ota_restrictions() -> None:
109
+ """The point of the file: OTA settings on the OTA domain, local domain left alone.
110
+
111
+ A section that pinned an interface or disabled multicast on the *local*
112
+ domain would recreate the failure it exists to avoid.
113
+ """
114
+ module = _module()
115
+ rendered = module.main(
116
+ config="cyclonedds_scoped.xml",
117
+ host_ip="10.0.0.10",
118
+ peer="10.0.0.11",
119
+ local_domain="47",
120
+ ota_domain="48",
121
+ )
122
+
123
+ assert '<Domain Id="48">' in rendered
124
+ assert '<Domain Id="47">' in rendered
125
+
126
+ ota_section = rendered.split('<Domain Id="48">', 1)[1].split("</Domain>", 1)[0]
127
+ local_section = rendered.split('<Domain Id="47">', 1)[1].split("</Domain>", 1)[0]
128
+
129
+ assert "<AllowMulticast>false</AllowMulticast>" in ota_section
130
+ assert "10.0.0.10" in ota_section and "10.0.0.11" in ota_section
131
+
132
+ for restriction in ("AllowMulticast", "NetworkInterface", "Peer ", "MaxMessageSize"):
133
+ assert restriction not in local_section, restriction
134
+ assert "MaxAutoParticipantIndex" in local_section