rosotacom-dev 2.5.dev67__tar.gz → 2.5.dev69__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 (394) hide show
  1. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/PKG-INFO +3 -2
  2. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/README.md +2 -1
  3. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/ota-pcap.md +19 -3
  4. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/ota_pcap.py +66 -8
  5. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview.py +32 -1
  6. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom_dev.egg-info/PKG-INFO +3 -2
  7. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom_dev.egg-info/SOURCES.txt +1 -0
  8. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom_dev.egg-info/scm_file_list.json +1 -0
  9. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom_dev.egg-info/scm_version.json +2 -2
  10. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/terminology.md +54 -0
  11. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_ota_pcap.py +49 -0
  12. rosotacom_dev-2.5.dev69/tests/unit/test_terminology_stage_ownership.py +103 -0
  13. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.devcontainer/devcontainer.json.template +0 -0
  14. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.devcontainer/re_generate_devcontainer_json.py +0 -0
  15. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/CODEOWNERS +0 -0
  16. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/ISSUE_TEMPLATE/documentation-audit.md +0 -0
  17. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/ISSUE_TEMPLATE/implementation-cleanup.md +0 -0
  18. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/ISSUE_TEMPLATE/quality-workflow.md +0 -0
  19. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/ISSUE_TEMPLATE/redesign.md +0 -0
  20. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/ISSUE_TEMPLATE/release-process.md +0 -0
  21. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/ISSUE_TEMPLATE/repository-diagnosis.md +0 -0
  22. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/ISSUE_TEMPLATE/test-ci-audit.md +0 -0
  23. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/ISSUE_TEMPLATE/work-item.md +0 -0
  24. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  25. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/actions/setup-just/action.yml +0 -0
  26. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/dependabot.yml +0 -0
  27. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/workflows/benchmark-calibrate.yml +0 -0
  28. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/workflows/benchmark-gate.yml +0 -0
  29. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/workflows/dev-release.yml +0 -0
  30. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/workflows/image-scan.yml +0 -0
  31. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/workflows/nightly-e2e.yml +0 -0
  32. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/workflows/pr-lightweight.yml +0 -0
  33. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/workflows/pr-merge-gate.yml +0 -0
  34. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.github/workflows/release.yml +0 -0
  35. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/.pre-commit-config.yaml +0 -0
  36. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/AGENTS.md +0 -0
  37. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/CONCURRENCY.md +0 -0
  38. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/CONTRIBUTING.md +0 -0
  39. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/DEVELOPMENT_PRINCIPLES.md +0 -0
  40. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/LICENSE.txt +0 -0
  41. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/MANIFEST.in +0 -0
  42. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/budgets.jsonl +0 -0
  43. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/calibration/README.md +0 -0
  44. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/calibration/capacity-size-tight-cyclone.json +0 -0
  45. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/calibration/probe-loss-gop-tight-cyclone.json +0 -0
  46. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/calibration/probe-loss-nominal-cyclone.json +0 -0
  47. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/calibration/probe-loss-tight-cyclone.json +0 -0
  48. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/calibration/probe-loss-tight-fastdds.json +0 -0
  49. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/calibration/probe-loss-tight-zenoh.json +0 -0
  50. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/codecov.yml +0 -0
  51. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/deployment-configuration.md +0 -0
  52. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/benchmark-ab.md +0 -0
  53. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/benchmark-bag-as-load.md +0 -0
  54. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/ci.md +0 -0
  55. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/ffmpeg-keyframes.md +0 -0
  56. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/findings/README.md +0 -0
  57. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/findings/a-transport-element-doubles-every-fastdds-sample.md +0 -0
  58. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/findings/cyclone-fragment-equal-to-max-drops-fragmented-samples.md +0 -0
  59. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/findings/cyclone-spdp-discovery-bursts.md +0 -0
  60. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/findings/delay-alone-no-loss.md +0 -0
  61. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/findings/fastdds-datagram-cap-drops-large-samples.md +0 -0
  62. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/findings/graph-derived-types-block-a-non-graph-transport.md +0 -0
  63. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/findings/head-of-line-irregularity.md +0 -0
  64. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/findings/jitter-loss-bandwidth-latency.md +0 -0
  65. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/findings/keyframe-loss-kills-the-next-deltas.md +0 -0
  66. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/findings/lifespan-is-enforced-by-one-reader-and-not-the-other.md +0 -0
  67. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/findings/lighter-message-loss.md +0 -0
  68. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/findings/one-domain-two-cyclone-configs-stop-interoperating.md +0 -0
  69. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/findings/oversubscription-queues-not-losses.md +0 -0
  70. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/findings/reorder-becomes-reader-loss.md +0 -0
  71. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/findings/repro/decode_chain_repro.py +0 -0
  72. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/findings/repro/reorder_drop_repro.py +0 -0
  73. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/findings/sender-rows-make-a-dead-link-look-loss-free.md +0 -0
  74. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/findings/zero-loss-boundaries-18kb-20hz.md +0 -0
  75. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/forensics-report.md +0 -0
  76. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/geo-link-map.md +0 -0
  77. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/github-repository-settings.md +0 -0
  78. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/link-bandwidth.md +0 -0
  79. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/link-trace.md +0 -0
  80. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/owner-runbook.md +0 -0
  81. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/performance-bands.md +0 -0
  82. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/playbooks/README.md +0 -0
  83. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/quality-model.md +0 -0
  84. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/release-notes/TEMPLATE.md +0 -0
  85. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/release-notes/v2.1.md +0 -0
  86. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/release-notes/v2.2.md +0 -0
  87. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/release-notes/v2.3.md +0 -0
  88. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/release-notes/v2.4.md +0 -0
  89. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/release.md +0 -0
  90. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/rfcs/0001-expectation-driven-test-suite.md +0 -0
  91. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/rfcs/0002-expectation-concepts.md +0 -0
  92. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/rfcs/0003-metric-backbone.md +0 -0
  93. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/rfcs/0004-network-profiles.md +0 -0
  94. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/rfcs/0005-benchmark-genres-and-ci.md +0 -0
  95. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/rfcs/0006-dynamic-qos.md +0 -0
  96. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/rfcs/0007-regression-gate.md +0 -0
  97. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/rfcs/README.md +0 -0
  98. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/testing.md +0 -0
  99. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/docs/work-items.md +0 -0
  100. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/install.sh +0 -0
  101. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/justfile +0 -0
  102. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/media/control_center.png +0 -0
  103. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/media/echo_test.png +0 -0
  104. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/media/forensics-report-example.png +0 -0
  105. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/media/host.png +0 -0
  106. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/media/vehicle.png +0 -0
  107. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/pyproject.toml +0 -0
  108. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/requirements.txt +0 -0
  109. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/rosotacom.yaml +0 -0
  110. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/session-configuration.md +0 -0
  111. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/setup.cfg +0 -0
  112. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/__init__.py +0 -0
  113. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/__main__.py +0 -0
  114. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/anonymize.py +0 -0
  115. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/bag_ground_truth.py +0 -0
  116. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/benched_set.py +0 -0
  117. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/benchmark.py +0 -0
  118. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/benchmark_delta.py +0 -0
  119. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/bundle_check.py +0 -0
  120. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/cli.py +0 -0
  121. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/cli_benchmark.py +0 -0
  122. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/deployment.py +0 -0
  123. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/ffmpeg_packet.py +0 -0
  124. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/forensics.py +0 -0
  125. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/geomap.py +0 -0
  126. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/image_cache.py +0 -0
  127. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/netem_dist.py +0 -0
  128. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/network_preflight.py +0 -0
  129. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/network_profiles.py +0 -0
  130. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/network_shaper.py +0 -0
  131. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/plots.py +0 -0
  132. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/py.typed +0 -0
  133. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/benched-set.yaml +0 -0
  134. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/.gitignore +0 -0
  135. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/README.md +0 -0
  136. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/__init__.py +0 -0
  137. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/bags/8_drop_reference/metadata.yaml +0 -0
  138. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/deployment.example.yaml +0 -0
  139. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/dist/field-20260817.dist +0 -0
  140. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/profiles.yaml +0 -0
  141. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/ros2docker.json +0 -0
  142. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/ros2docker.lyrical.json +0 -0
  143. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/rosotacom.yaml +0 -0
  144. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scenarios/2_native_chatter/scenario-definition.yaml +0 -0
  145. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_a.sh +0 -0
  146. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_b.sh +0 -0
  147. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.lyrical.ros2docker.json +0 -0
  148. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.ros2docker.json +0 -0
  149. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_communication.sh +0 -0
  150. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_external.py +0 -0
  151. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/wait_for_echo_topic.sh +0 -0
  152. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.lyrical.ros2docker.json +0 -0
  153. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.ros2docker.json +0 -0
  154. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_communication.sh +0 -0
  155. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_external.py +0 -0
  156. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external.ros2docker.json +0 -0
  157. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external_session.yaml +0 -0
  158. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/foxglove.json +0 -0
  159. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_communication.sh +0 -0
  160. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_external.py +0 -0
  161. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
  162. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/metadata.yaml +0 -0
  163. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/external.ros2docker.json +0 -0
  164. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_communication.sh +0 -0
  165. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_external.py +0 -0
  166. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external.ros2docker.json +0 -0
  167. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external_session.yaml +0 -0
  168. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/foxglove.json +0 -0
  169. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_communication.sh +0 -0
  170. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_external.py +0 -0
  171. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
  172. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/metadata.yaml +0 -0
  173. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/external.ros2docker.json +0 -0
  174. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_communication.sh +0 -0
  175. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_external.py +0 -0
  176. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external.ros2docker.json +0 -0
  177. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external_session.yaml +0 -0
  178. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_communication.sh +0 -0
  179. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_external.py +0 -0
  180. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external.ros2docker.json +0 -0
  181. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external_session.yaml +0 -0
  182. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_communication.sh +0 -0
  183. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_external.py +0 -0
  184. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external.ros2docker.json +0 -0
  185. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external_session.yaml +0 -0
  186. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_communication.sh +0 -0
  187. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_external.py +0 -0
  188. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external.ros2docker.json +0 -0
  189. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external_session.yaml +0 -0
  190. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_communication.sh +0 -0
  191. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_external.py +0 -0
  192. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/10_restamp/session-definition.yaml +0 -0
  193. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/11_trickle/session-definition.yaml +0 -0
  194. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/12_content_integrity/session-definition.yaml +0 -0
  195. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/13_link_latency/session-definition.yaml +0 -0
  196. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/14_remote_assist_anonymized/session-definition.yaml +0 -0
  197. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/15_remote_assist_anonymized_costmap/session-definition.yaml +0 -0
  198. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/16_remote_assist_anonymized_camera/session-definition.yaml +0 -0
  199. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/17_synthetic_camera_quality/session-definition.yaml +0 -0
  200. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/1_heartbeat/session-definition.yaml +0 -0
  201. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/1_heartbeat_status/session-definition.yaml +0 -0
  202. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/2_native_chatter/session-definition.yaml +0 -0
  203. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/3_comp_occ_grid/session-definition.yaml +0 -0
  204. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/4_comp_occ_grid_zen/session-definition.yaml +0 -0
  205. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/5_sized_payload/session-definition.yaml +0 -0
  206. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/6_sized_payload_zen/session-definition.yaml +0 -0
  207. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/7_latched_static/session-definition.yaml +0 -0
  208. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/8_drop/session-definition.yaml +0 -0
  209. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/9_throttle/session-definition.yaml +0 -0
  210. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/bench_1_1_capacity/session-definition.yaml +0 -0
  211. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/bench_1_2_load_sweep/session-definition.yaml +0 -0
  212. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/bench_1_3_ramp/session-definition.yaml +0 -0
  213. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/bench_1_4_recovery/session-definition.yaml +0 -0
  214. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/examples/sessions/bench_1_5_camera/session-definition.yaml +0 -0
  215. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ros2docker.json.example +0 -0
  216. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ros2docker.lyrical.json.example +0 -0
  217. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/.vscode/c_cpp_properties.json +0 -0
  218. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/.vscode/settings.json +0 -0
  219. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_easy_mode.xml.template +0 -0
  220. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_initial_peer_list.xml.template +0 -0
  221. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v2.xml.template +0 -0
  222. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v3.xml.template +0 -0
  223. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v4.xml.template +0 -0
  224. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v5.xml.template +0 -0
  225. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py +0 -0
  226. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ota_configs/cyclonedds_local_participants.xml.template +0 -0
  227. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template +0 -0
  228. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ota_configs/cyclonedds_scoped.xml.template +0 -0
  229. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template +0 -0
  230. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ota_configs/fastdds_easy_mode.xml.template +0 -0
  231. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ota_configs/fastdds_local.xml.template +0 -0
  232. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ota_configs/fastdds_tuned.xml.template +0 -0
  233. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ota_configs/fastdds_unicast.xml.template +0 -0
  234. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ota_configs/get_ota_xml.py +0 -0
  235. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ota_configs/utils.py +0 -0
  236. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ota_configs/zenoh.json5.template +0 -0
  237. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/.gitkeep +0 -0
  238. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_cpp/CMakeLists.txt +0 -0
  239. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_cpp/COLCON_IGNORE +0 -0
  240. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_cpp/LICENSE.txt +0 -0
  241. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_cpp/package.xml +0 -0
  242. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_cpp/src/hz_monitor.cpp +0 -0
  243. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_compressor.cpp +0 -0
  244. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_decompressor.cpp +0 -0
  245. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_msgs/CMakeLists.txt +0 -0
  246. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_msgs/LICENSE.txt +0 -0
  247. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/CompressedData.msg +0 -0
  248. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/EchoHeartbeat.msg +0 -0
  249. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/OtaStamped.msg +0 -0
  250. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/SizedPayload.msg +0 -0
  251. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_msgs/package.xml +0 -0
  252. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/LICENSE.txt +0 -0
  253. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/__init__.py +0 -0
  254. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/base_bridge_relay.py +0 -0
  255. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_in.py +0 -0
  256. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_out.py +0 -0
  257. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/ffmpeg_flags.py +0 -0
  258. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/heartbeat_echo.py +0 -0
  259. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/hz_monitor.py +0 -0
  260. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_bandwidth_reducer.py +0 -0
  261. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_pixel_capper.py +0 -0
  262. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/lanelet_saver.py +0 -0
  263. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/latch_relay.py +0 -0
  264. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/costmap_remapper.py +0 -0
  265. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/marker_remapper.py +0 -0
  266. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/speed_test.py +0 -0
  267. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/tf_remapper.py +0 -0
  268. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/traffic_monitor.py +0 -0
  269. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/wifi_network_analysis_1.py +0 -0
  270. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_bytes.py +0 -0
  271. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_trace.py +0 -0
  272. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/local_global_frame_bridge.py +0 -0
  273. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/localization_map_split_reduce_saver.py +0 -0
  274. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/msg_transform.py +0 -0
  275. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pair_management.py +0 -0
  276. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer.py +0 -0
  277. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer_core.py +0 -0
  278. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pub_sub_pair.py +0 -0
  279. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/qos.py +0 -0
  280. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_in.py +0 -0
  281. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_out.py +0 -0
  282. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/restamp.py +0 -0
  283. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/sized_publisher.py +0 -0
  284. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency.py +0 -0
  285. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency_core.py +0 -0
  286. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview_core.py +0 -0
  287. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/tf_map_to_cart_saver.py +0 -0
  288. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_monitor.py +0 -0
  289. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_resolution.py +0 -0
  290. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/trickle.py +0 -0
  291. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_compressor.py +0 -0
  292. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_decompressor.py +0 -0
  293. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_unwrapper.py +0 -0
  294. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_wrapper.py +0 -0
  295. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/package.xml +0 -0
  296. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/resource/com_py +0 -0
  297. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/setup.cfg +0 -0
  298. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/setup.py +0 -0
  299. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/test/test_copyright.py +0 -0
  300. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/test/test_flake8.py +0 -0
  301. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/ros2src/com_py/test/test_pep257.py +0 -0
  302. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/session/content/base/session_plugin_base.yaml +0 -0
  303. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/session/content/network/up_connectivity.py +0 -0
  304. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/session/content/network/wifi_network_analysis_2.py +0 -0
  305. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/session/creation/anonymize_bag.py +0 -0
  306. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/session/creation/catmux_log_setup.sh +0 -0
  307. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/session/creation/create_session_yaml.py +0 -0
  308. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/session/creation/generate_session_files.py +0 -0
  309. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/session/creation/run_session.py +0 -0
  310. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/session/creation/run_session_in_external_terminal.py +0 -0
  311. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/resources/ws/session/creation/strip_ansi.py +0 -0
  312. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/status_eval.py +0 -0
  313. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/stream_stats.py +0 -0
  314. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/trace_profiles.py +0 -0
  315. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/transit.py +0 -0
  316. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom/video_quality.py +0 -0
  317. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom_dev.egg-info/dependency_links.txt +0 -0
  318. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom_dev.egg-info/entry_points.txt +0 -0
  319. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom_dev.egg-info/requires.txt +0 -0
  320. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/src/rosotacom_dev.egg-info/top_level.txt +0 -0
  321. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/contract/test_benched_set_registry.py +0 -0
  322. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/contract/test_findings.py +0 -0
  323. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/contract/test_generated_topics_have_a_producer.py +0 -0
  324. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/contract/test_lyrical_runtime_compat.py +0 -0
  325. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/contract/test_markdown_links.py +0 -0
  326. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/contract/test_ota_source_bundle.py +0 -0
  327. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/contract/test_package_metadata.py +0 -0
  328. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/contract/test_packaged_resources.py +0 -0
  329. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/contract/test_profile_covers_generated_commands.py +0 -0
  330. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/contract/test_pytest_policy.py +0 -0
  331. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/contract/test_readme_examples.py +0 -0
  332. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/contract/test_security_maintenance_config.py +0 -0
  333. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/contract/test_session_configuration_doc.py +0 -0
  334. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/contract/test_session_template_substitution.py +0 -0
  335. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/contract/test_workflow_contracts.py +0 -0
  336. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/e2e/conftest.py +0 -0
  337. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/e2e/test_anonymize_e2e.py +0 -0
  338. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/e2e/test_benchmark_ab.py +0 -0
  339. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/e2e/test_benchmark_capacity.py +0 -0
  340. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/e2e/test_benchmark_replay.py +0 -0
  341. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/e2e/test_parallel_smoke.py +0 -0
  342. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/e2e/test_smoke.py +0 -0
  343. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/e2e/test_timeline_stepping.py +0 -0
  344. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/e2e/test_video_quality_e2e.py +0 -0
  345. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/sessions/generate_rmw_matrix.py +0 -0
  346. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-local_zenoh-ros2dds-ota/session-definition.yaml +0 -0
  347. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota/session-definition.yaml +0 -0
  348. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota-tuned/session-definition.yaml +0 -0
  349. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/sessions/rmw_matrix/1_heartbeat_fastdds/session-definition.yaml +0 -0
  350. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/sessions/rmw_matrix/1_heartbeat_fastdds-default/session-definition.yaml +0 -0
  351. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/sessions/rmw_matrix/1_heartbeat_zen-endpoints/session-definition.yaml +0 -0
  352. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_anonymize.py +0 -0
  353. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_bag_ground_truth.py +0 -0
  354. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_benched_set.py +0 -0
  355. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_benchmark.py +0 -0
  356. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_benchmark_delta.py +0 -0
  357. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_bundle_check.py +0 -0
  358. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_catmux_pane_logging.py +0 -0
  359. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_cli.py +0 -0
  360. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_cli_benchmark.py +0 -0
  361. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_concurrency.py +0 -0
  362. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_container_shaping.py +0 -0
  363. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_deployment.py +0 -0
  364. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_ffmpeg_flags.py +0 -0
  365. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_ffmpeg_packet.py +0 -0
  366. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_field_profiles.py +0 -0
  367. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_forensics.py +0 -0
  368. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_geomap.py +0 -0
  369. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_image_cache.py +0 -0
  370. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_link_bytes.py +0 -0
  371. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_link_trace.py +0 -0
  372. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_netem_dist.py +0 -0
  373. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_network_preflight.py +0 -0
  374. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_network_profiles.py +0 -0
  375. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_network_shaper.py +0 -0
  376. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_ota_link_configs.py +0 -0
  377. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_ota_unwrapper.py +0 -0
  378. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_ota_wrapper.py +0 -0
  379. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_ota_xml.py +0 -0
  380. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_playout_pacer.py +0 -0
  381. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_plots.py +0 -0
  382. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_pub_sub_pair_types.py +0 -0
  383. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_qos_fallback_logging.py +0 -0
  384. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_relay_optional_parameters.py +0 -0
  385. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_ros_node_entity_ownership.py +0 -0
  386. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_session_pipeline.py +0 -0
  387. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_stage_latency.py +0 -0
  388. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_status_eval.py +0 -0
  389. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_status_overview.py +0 -0
  390. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_status_overview_observer.py +0 -0
  391. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_stream_stats.py +0 -0
  392. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_trace_profiles.py +0 -0
  393. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/tests/unit/test_transit.py +0 -0
  394. {rosotacom_dev-2.5.dev67 → rosotacom_dev-2.5.dev69}/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.dev67
3
+ Version: 2.5.dev69
4
4
  Summary: Host CLI for ROS OTA communication sessions.
5
5
  Author: develNor
6
6
  License-Expression: BSD-3-Clause
@@ -689,7 +689,8 @@ is which fragment was lost, whether a retransmit followed, or how one sample's
689
689
  sub-messages were spaced, enable the [header-only OTA capture](docs/ota-pcap.md)
690
690
  next to them — `shared.ota_pcap.enabled`, off by default, roughly 1 % of payload
691
691
  volume, and every packet labelled uplink or downlink. It needs no capability,
692
- no image change and no extra container.
692
+ no image change and no extra container — only the passwordless sudo the
693
+ container already has, and only until its socket is open.
693
694
 
694
695
  Convert a recorded link trace into a profiles-file entry when you want to replay
695
696
  the same drive conditions in a repeatable benchmark:
@@ -644,7 +644,8 @@ is which fragment was lost, whether a retransmit followed, or how one sample's
644
644
  sub-messages were spaced, enable the [header-only OTA capture](docs/ota-pcap.md)
645
645
  next to them — `shared.ota_pcap.enabled`, off by default, roughly 1 % of payload
646
646
  volume, and every packet labelled uplink or downlink. It needs no capability,
647
- no image change and no extra container.
647
+ no image change and no extra container — only the passwordless sudo the
648
+ container already has, and only until its socket is open.
648
649
 
649
650
  Convert a recorded link trace into a profiles-file entry when you want to replay
650
651
  the same drive conditions in a repeatable benchmark:
@@ -110,9 +110,25 @@ runs on. `shared.ota_pcap.enabled` therefore requires
110
110
 
111
111
  ## Privilege, containers, and what the option costs
112
112
 
113
- Nothing is added. The communication container already runs as root with
114
- `CAP_NET_RAW` in docker's default set, so the capture needs no `--cap-add`, no
115
- image change, no rebuild and no extra container in `docker ps`.
113
+ No image change, no rebuild, no added capability and no extra container in
114
+ `docker ps`. What it does need is `sudo`, and only until the socket is open.
115
+
116
+ ros2docker's entrypoint runs this container's processes as `containeruser`,
117
+ whose `CapEff` is `0000000000000000`. A non-root process cannot open an
118
+ `AF_PACKET` socket however the container was started, so `--cap-add NET_RAW`
119
+ would buy nothing. `containeruser` does have passwordless sudo here — the NET
120
+ pane's `sudo iftop` already depends on it — so the capture is launched through
121
+ it, and `--drop-to` hands the process back to `containeruser` the moment the
122
+ socket exists. The pcap therefore belongs to the same user as
123
+ `link_trace.jsonl` beside it, rather than to root.
124
+
125
+ Two earlier attempts at this assumed root from a `docker run` that bypassed the
126
+ entrypoint, and were wrong in the same way both times. If you change this,
127
+ check the **running** container:
128
+
129
+ ```bash
130
+ docker exec <com-container> bash -lc 'id; grep CapEff /proc/self/status'
131
+ ```
116
132
 
117
133
  `CAP_NET_ADMIN` is *not* taken and is not needed: it buys promiscuous mode,
118
134
  which this capture deliberately does not use. Everything of interest is
@@ -35,9 +35,22 @@ to a 6 Mbit/s link and survived a field session (#267). A capture that has to
35
35
  re-derive link knowledge is in the wrong place; this one asks the same
36
36
  resolution the status snapshot's own link block uses.
37
37
 
38
- It also needs no privilege here. This container already runs as root with
39
- `CAP_NET_RAW` in the default docker set, so the option adds no capability, no
40
- image change and no container.
38
+ WHAT IT NEEDS, MEASURED RATHER THAN ASSUMED
39
+ -------------------------------------------
40
+ `sudo`, and only until the socket is open. ros2docker's entrypoint runs this
41
+ container's processes as `containeruser`, whose `CapEff` is
42
+ 0000000000000000 — a non-root process cannot open an `AF_PACKET` socket
43
+ however the container was started, so `--cap-add` buys nothing. `containeruser`
44
+ does have passwordless sudo here, which the NET pane's `sudo iftop` already
45
+ relies on, so the capture is launched through it and `--drop-to` hands the
46
+ process back to `containeruser` the moment the socket exists. The pcap in
47
+ `logs/<peer>/status/` therefore belongs to the same user as `link_trace.jsonl`
48
+ beside it.
49
+
50
+ That is the whole cost: no image change, no rebuild, no added capability and no
51
+ extra container. Two earlier attempts at this assumed root from a `docker run`
52
+ that bypassed the entrypoint, and both were wrong in the same way — check the
53
+ *running* container, not the image.
41
54
 
42
55
  THE FILE
43
56
  --------
@@ -72,6 +85,7 @@ from __future__ import annotations
72
85
 
73
86
  import argparse
74
87
  import json
88
+ import os
75
89
  import signal
76
90
  import socket
77
91
  import struct
@@ -240,6 +254,40 @@ def open_socket(iface: str) -> socket.socket:
240
254
  return sock
241
255
 
242
256
 
257
+ def drop_privileges(spec: str | None) -> str | None:
258
+ """Hand the process back to the user that started it.
259
+
260
+ The capture is launched through `sudo` — see the module header — because a
261
+ non-root process cannot open an `AF_PACKET` socket. Nothing after that call
262
+ needs root, and the artifacts in `logs/<peer>/status/` belong to
263
+ `containeruser` like `link_trace.jsonl` beside them: a root-owned file in
264
+ that directory is a `sudo rm` waiting to happen months later, and
265
+ `gather_drive.py` would copy it without noticing.
266
+
267
+ `spec` is "uid:gid". An argument rather than an environment variable
268
+ because sudo does not pass the environment through. Returns what it did, or
269
+ None when there was nothing to do.
270
+ """
271
+ if not spec:
272
+ return None
273
+ try:
274
+ uid_text, _, gid_text = spec.partition(":")
275
+ uid, gid = int(uid_text), int(gid_text or uid_text)
276
+ except ValueError:
277
+ log(f"WARN --drop-to {spec!r} is not uid:gid — staying as I am")
278
+ return None
279
+ if os.geteuid() != 0:
280
+ return None
281
+ try:
282
+ os.setgroups([])
283
+ os.setgid(gid)
284
+ os.setuid(uid)
285
+ except OSError as error:
286
+ log(f"WARN could not drop to {uid}:{gid} ({error}) — the file will be root's")
287
+ return None
288
+ return f"{uid}:{gid}"
289
+
290
+
243
291
  def kernel_timestamp(ancdata) -> tuple[int, int] | None:
244
292
  """(seconds, microseconds) out of SCM_TIMESTAMPNS, if the kernel sent it."""
245
293
  for level, kind, data in ancdata:
@@ -264,7 +312,9 @@ class Capture:
264
312
  """One pcap file, and the counts needed to trust it."""
265
313
 
266
314
  def __init__(self, iface: str, out: Path, *, snaplen: int = DEFAULT_SNAPLEN,
267
- peer: str | None = None, max_bytes: int = DEFAULT_MAX_MB * 1000 * 1000):
315
+ peer: str | None = None, max_bytes: int = DEFAULT_MAX_MB * 1000 * 1000,
316
+ drop_to: str | None = None):
317
+ self.drop_to = drop_to
268
318
  self.iface = iface
269
319
  self.out = out
270
320
  self.snaplen = snaplen
@@ -300,6 +350,10 @@ class Capture:
300
350
 
301
351
  def run(self, stop: list) -> None:
302
352
  sock = open_socket(self.iface)
353
+ # Root was needed for that one call and for nothing after it.
354
+ dropped = drop_privileges(self.drop_to)
355
+ if dropped:
356
+ log(f"privileges dropped to {dropped}; the socket stays open")
303
357
  packet_statistics(sock) # zero the counters; the run owns them from here
304
358
  ancillary = socket.CMSG_SPACE(16)
305
359
  self.out.parent.mkdir(parents=True, exist_ok=True)
@@ -365,10 +419,13 @@ def main(argv: list[str] | None = None) -> int:
365
419
  parser.add_argument("--peer", help="keep only packets to or from this address")
366
420
  parser.add_argument("--max-mb", type=int, default=DEFAULT_MAX_MB,
367
421
  help=f"stop after this many MB (default {DEFAULT_MAX_MB})")
422
+ parser.add_argument("--drop-to", metavar="UID:GID",
423
+ help="give root back once the socket is open, so the pcap "
424
+ "belongs to the user that started the session")
368
425
  args = parser.parse_args(argv)
369
426
 
370
427
  capture = Capture(args.iface, args.out, snaplen=args.snaplen, peer=args.peer,
371
- max_bytes=args.max_mb * 1000 * 1000)
428
+ max_bytes=args.max_mb * 1000 * 1000, drop_to=args.drop_to)
372
429
 
373
430
  stop: list = []
374
431
  for name in (signal.SIGINT, signal.SIGTERM):
@@ -379,9 +436,10 @@ def main(argv: list[str] | None = None) -> int:
379
436
  try:
380
437
  capture.run(stop)
381
438
  except PermissionError:
382
- log("FAIL no permission to open a packet socket. Inside the recorder "
383
- "container this should not happen CAP_NET_RAW is in docker's "
384
- "default set. Outside it, run as root.")
439
+ log("FAIL no permission to open a packet socket. This is meant to run "
440
+ "through `sudo` from inside the communication container, where "
441
+ "containeruser has passwordless sudo; a non-root process cannot "
442
+ "open AF_PACKET whatever capabilities the container was given.")
385
443
  return 3
386
444
  except OSError as error:
387
445
  log(f"FAIL {error}")
@@ -564,6 +564,9 @@ class StatusOverview(Node):
564
564
  "--out", path,
565
565
  "--snaplen", str(int(self.get_parameter("ota_pcap_snaplen").value)),
566
566
  "--max-mb", str(int(self.get_parameter("ota_pcap_max_mb").value)),
567
+ # Root opens the socket; this hands it straight back, so the pcap
568
+ # belongs to the same user as link_trace.jsonl beside it.
569
+ "--drop-to", f"{os.getuid()}:{os.getgid()}",
567
570
  ]
568
571
  # Narrowed to the remote peer by default. On a VPN tunnel the whole
569
572
  # device is the link and the filter changes nothing; on a LAN port it
@@ -573,6 +576,16 @@ class StatusOverview(Node):
573
576
  if bool(self.get_parameter("ota_pcap_peer_filter").value) and peer_ip:
574
577
  argv += ["--peer", peer_ip]
575
578
 
579
+ # An `AF_PACKET` socket needs root, and this node is `containeruser`:
580
+ # its `CapEff` is zero, so no `--cap-add` on the container would help.
581
+ # `containeruser` has passwordless sudo here — the NET pane's
582
+ # `sudo iftop` already depends on it — so the capture goes through it
583
+ # and gives root back as soon as the socket exists. Where there is no
584
+ # sudo (this module run somewhere else, or already as root) the plain
585
+ # command is tried instead rather than refused.
586
+ if os.geteuid() != 0 and self._sudo_available():
587
+ argv = ["sudo", "-n", *argv]
588
+
576
589
  try:
577
590
  self._pcap = subprocess.Popen(argv, start_new_session=True)
578
591
  except OSError as exc: # noqa: BLE001 - a sidecar may not stop a session
@@ -588,6 +601,16 @@ class StatusOverview(Node):
588
601
  bool(self.get_parameter("ota_pcap_peer_filter").value) else "")
589
602
  )
590
603
 
604
+ @staticmethod
605
+ def _sudo_available() -> bool:
606
+ """Can this process become root without being asked for a password?"""
607
+ try:
608
+ return subprocess.run(
609
+ ["sudo", "-n", "true"], capture_output=True, timeout=5.0
610
+ ).returncode == 0
611
+ except (OSError, subprocess.SubprocessError):
612
+ return False
613
+
591
614
  def _stop_ota_pcap(self) -> None:
592
615
  """SIGINT and wait, so the sidecar JSON and the drop counts are written.
593
616
 
@@ -599,7 +622,15 @@ class StatusOverview(Node):
599
622
  if child is None or child.poll() is not None:
600
623
  return
601
624
  try:
602
- child.send_signal(signal.SIGINT)
625
+ # Through sudo the child is root, so an ordinary kill would be
626
+ # refused; `sudo -n kill` is how a non-root parent signals it.
627
+ # SIGINT and not SIGTERM, because SIGINT is what makes the capture
628
+ # write ota.json on the way out.
629
+ if os.geteuid() != 0:
630
+ subprocess.run(["sudo", "-n", "kill", "-INT", str(child.pid)],
631
+ capture_output=True, timeout=5.0)
632
+ else:
633
+ child.send_signal(signal.SIGINT)
603
634
  child.wait(timeout=20.0)
604
635
  except subprocess.TimeoutExpired:
605
636
  child.kill()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rosotacom-dev
3
- Version: 2.5.dev67
3
+ Version: 2.5.dev69
4
4
  Summary: Host CLI for ROS OTA communication sessions.
5
5
  Author: develNor
6
6
  License-Expression: BSD-3-Clause
@@ -689,7 +689,8 @@ is which fragment was lost, whether a retransmit followed, or how one sample's
689
689
  sub-messages were spaced, enable the [header-only OTA capture](docs/ota-pcap.md)
690
690
  next to them — `shared.ota_pcap.enabled`, off by default, roughly 1 % of payload
691
691
  volume, and every packet labelled uplink or downlink. It needs no capability,
692
- no image change and no extra container.
692
+ no image change and no extra container — only the passwordless sudo the
693
+ container already has, and only until its socket is open.
693
694
 
694
695
  Convert a recorded link trace into a profiles-file entry when you want to replay
695
696
  the same drive conditions in a repeatable benchmark:
@@ -386,6 +386,7 @@ tests/unit/test_status_eval.py
386
386
  tests/unit/test_status_overview.py
387
387
  tests/unit/test_status_overview_observer.py
388
388
  tests/unit/test_stream_stats.py
389
+ tests/unit/test_terminology_stage_ownership.py
389
390
  tests/unit/test_trace_profiles.py
390
391
  tests/unit/test_transit.py
391
392
  tests/unit/test_video_quality.py
@@ -381,6 +381,7 @@
381
381
  "tests/unit/test_status_overview.py",
382
382
  "tests/unit/test_status_overview_observer.py",
383
383
  "tests/unit/test_stream_stats.py",
384
+ "tests/unit/test_terminology_stage_ownership.py",
384
385
  "tests/unit/test_trace_profiles.py",
385
386
  "tests/unit/test_transit.py",
386
387
  "tests/unit/test_video_quality.py"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "tag": "2.4",
3
- "distance": 67,
4
- "node": "g66ad66a5a0a3d15dec65006745d88e43757f6c72",
3
+ "distance": 69,
4
+ "node": "g429a2536fa56d96c76f3c306809f3dc6864f051e",
5
5
  "dirty": false,
6
6
  "branch": "HEAD",
7
7
  "node_date": "2026-08-21"
@@ -305,6 +305,9 @@ Notes:
305
305
  - Preprocessing/postprocessing are just processing stages applied at different points:
306
306
  - outbound: native → processed (optional)
307
307
  - inbound: processed → native (optional)
308
+ - Being postprocessing does **not** by itself make a transformation a processing
309
+ stage of this project. Which transformations belong here is decided by
310
+ §9.1, not by where or when they run.
308
311
 
309
312
  ---
310
313
 
@@ -323,6 +326,57 @@ Example: `/com/out/A/to_B/sensors/camera/image_raw/restamped/max20hz/bz2`
323
326
 
324
327
  ## 9. Module responsibilities
325
328
 
329
+ ### 9.1 Stage ownership (which transformations belong to this project)
330
+
331
+ A **processing stage** (§7) belongs to this project when it either
332
+
333
+ 1. **undoes a stage this project applied** — decompression undoes compression,
334
+ the OTA unwrapper undoes the OTA wrapper, `global_to_local` undoes
335
+ `local_to_global`, `trickle` undoes `latch`; or
336
+ 2. **compensates for the medium** — the playout pacer against the arrival
337
+ jitter a link introduces.
338
+
339
+ Everything else that happens to a stream after the inbound native topic
340
+ belongs to whoever consumes it, and is that consumer's code in that
341
+ consumer's repository. The inbound native topic (§3) is where this project's
342
+ canonical lifecycle ends, and stage ownership ends with it.
343
+
344
+ **Two criteria that do not decide it**, because both are true of stages on
345
+ either side:
346
+
347
+ - *Where it runs.* Decompression, the unwrapper, `trickle` and the pacer all
348
+ run at the receiving peer. So does an application transform that has nothing
349
+ to do with the link.
350
+ - *That it is postprocessing.* §3 names inbound postprocessing as part of the
351
+ lifecycle, so the word describes a position, not an owner.
352
+
353
+ `trickle` is the stage that makes the boundary feel ambiguous, and rule 1
354
+ resolves it. It can be read as a fix for a consumer that expects a periodic
355
+ stream — but the question is not what it is good for, it is why the value was
356
+ latched in the first place: repeating a state at a fixed rate over a metered
357
+ link is waste, so latching is a link decision and `trickle` is its inverse.
358
+ Without the link there would be nothing to un-latch.
359
+
360
+ **The quick test is a counterfactual.** Change the *link* — other radio, other
361
+ route, other codec — and ask whether the stage has to change; then change the
362
+ *consumer* — other display, other viewer, an automated pipeline instead of a
363
+ person — and ask the same. A stage that survives every link change and breaks
364
+ on a consumer change is the consumer's.
365
+
366
+ **The falsifiable test, for cases the counterfactual leaves open.** A stage
367
+ here becomes part of the session contract, so it must carry an `expect:` the
368
+ harness can assert. If no `hz`, `loss_pct`, `latency_ms` or
369
+ `completeness.vs_bag_ratio` on that stage would mean anything, the contract
370
+ cannot check it — and a stage the contract cannot check does not belong in the
371
+ contract.
372
+
373
+ This is about **stages, not about code**. A generic operation — resampling an
374
+ image, filtering a point cloud — may live here as a reusable node the day a
375
+ second session needs it. What must not move here is the decision that a
376
+ particular consumer wants a particular result.
377
+
378
+ ---
379
+
326
380
  ### App Relay
327
381
  The **App Relay** (application relay) maps between application topics and com topics.
328
382
 
@@ -306,3 +306,52 @@ def test_the_node_is_handed_the_remote_peers_address_to_narrow_the_capture() ->
306
306
  other conversation the machine is having."""
307
307
  text = PLUGIN_BASE.read_text(encoding="utf-8")
308
308
  assert "-p ota_pcap_peer_ip:=${ip_remote}" in text
309
+
310
+
311
+ # ---------------------------------------------------------------------------
312
+ # root for one system call
313
+ # ---------------------------------------------------------------------------
314
+
315
+
316
+ def test_the_capture_gives_root_back_as_soon_as_the_socket_exists(monkeypatch) -> None:
317
+ """Launched through sudo, dropped straight after — so the pcap belongs to
318
+ the same user as `link_trace.jsonl` beside it, not to root."""
319
+ calls = {}
320
+ monkeypatch.setattr(ota_pcap.os, "geteuid", lambda: 0)
321
+ monkeypatch.setattr(ota_pcap.os, "setgroups", lambda g: calls.setdefault("groups", g))
322
+ monkeypatch.setattr(ota_pcap.os, "setgid", lambda gid: calls.setdefault("gid", gid))
323
+ monkeypatch.setattr(ota_pcap.os, "setuid", lambda uid: calls.setdefault("uid", uid))
324
+
325
+ assert ota_pcap.drop_privileges("1000:1001") == "1000:1001"
326
+ assert calls == {"groups": [], "gid": 1001, "uid": 1000}
327
+
328
+
329
+ def test_a_capture_that_is_not_root_leaves_the_ids_alone(monkeypatch) -> None:
330
+ monkeypatch.setattr(ota_pcap.os, "geteuid", lambda: 1000)
331
+ monkeypatch.setattr(ota_pcap.os, "setuid", lambda uid: pytest.fail("must not be called"))
332
+ assert ota_pcap.drop_privileges("1000:1000") is None
333
+
334
+
335
+ @pytest.mark.parametrize("spec", [None, "", "root", "1000:nobody"])
336
+ def test_a_spec_that_is_not_uid_gid_never_changes_the_process(spec, monkeypatch) -> None:
337
+ monkeypatch.setattr(ota_pcap.os, "geteuid", lambda: 0)
338
+ monkeypatch.setattr(ota_pcap.os, "setuid", lambda uid: pytest.fail("must not be called"))
339
+ assert ota_pcap.drop_privileges(spec) is None
340
+
341
+
342
+ def test_the_node_launches_it_through_sudo_and_hands_root_straight_back() -> None:
343
+ """The node runs as `containeruser`, whose CapEff is zero, so no `--cap-add`
344
+ on the container would let it open an AF_PACKET socket. Asserted over the
345
+ source because the node needs rclpy, which the host suite does not have."""
346
+ source = (WS_PY / "com_py" / "status_overview.py").read_text(encoding="utf-8")
347
+ assert 'argv = ["sudo", "-n", *argv]' in source
348
+ assert '"--drop-to", f"{os.getuid()}:{os.getgid()}"' in source
349
+ # And the stop goes the same way: the child is root, so an ordinary kill
350
+ # would be refused — and it must be SIGINT, which is what writes ota.json.
351
+ assert '"sudo", "-n", "kill", "-INT"' in source
352
+
353
+
354
+ def test_the_capture_is_a_process_not_a_thread_in_the_status_node() -> None:
355
+ """A capture that misbehaves must not reach the snapshot an operator watches."""
356
+ source = (WS_PY / "com_py" / "status_overview.py").read_text(encoding="utf-8")
357
+ assert "subprocess.Popen(argv, start_new_session=True)" in source
@@ -0,0 +1,103 @@
1
+ """The stage-ownership rule in `terminology.md` §9.1, against the code.
2
+
3
+ The rule is normative — it decides what may be added to this project — and it
4
+ argues from concrete pairs: decompression undoes compression, the unwrapper
5
+ undoes the wrapper, `global_to_local` undoes `local_to_global`, `trickle`
6
+ undoes `latch`, and the playout pacer compensates for the medium. A rule that
7
+ reasons from examples is only as good as the examples, and a renamed node
8
+ leaves it quietly arguing from things that are not there any more.
9
+
10
+ This is a documentation test, not a behaviour test: there is no behaviour to
11
+ run. What it pins is that every node the rule names still exists, that the two
12
+ tests it offers still name assertions the session schema accepts, and that the
13
+ section it belongs to is still where §7 sends the reader.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import re
19
+ from pathlib import Path
20
+
21
+ REPO_ROOT = Path(__file__).resolve().parents[2]
22
+ TERMINOLOGY = REPO_ROOT / "terminology.md"
23
+ COM_PY = REPO_ROOT / "src" / "rosotacom" / "resources" / "ws" / "ros2src" / "com_py" / "com_py"
24
+ STATUS_EVAL = REPO_ROOT / "src" / "rosotacom" / "status_eval.py"
25
+ GENERATOR_PY = (
26
+ REPO_ROOT / "src" / "rosotacom" / "resources" / "ws" / "session" / "creation" / "generate_session_files.py"
27
+ )
28
+
29
+ #: The nodes §9.1 argues from, as module names in `com_py`.
30
+ CITED_NODES = (
31
+ "universal_compressor",
32
+ "universal_decompressor",
33
+ "universal_ota_wrapper",
34
+ "universal_ota_unwrapper",
35
+ "local_global_frame_bridge",
36
+ "trickle",
37
+ "playout_pacer",
38
+ )
39
+
40
+ #: The processing keys §9.1's inverse pairs are stated in. A session has to
41
+ #: still be able to declare each of them, or the pair argues from nothing.
42
+ CITED_STAGE_KEYS = ("latch", "local_to_global", "global_to_local")
43
+
44
+ #: The assertion keys §9.1 offers as its falsifiable test. They are only a
45
+ #: test if a session may actually declare them, so each is checked against the
46
+ #: evaluator that reads them. `vs_bag_ratio` sits under `completeness` and is
47
+ #: named that way in the text for the same reason.
48
+ CITED_EXPECTATIONS = ("hz", "loss_pct", "latency_ms", "completeness.vs_bag_ratio")
49
+
50
+
51
+ #: `## 9.` and `### App Relay` are both headings, so a section has to run to
52
+ #: the next heading of its own level or higher, not to the next heading.
53
+ def section(title: str) -> str:
54
+ """The text of one `terminology.md` section, up to the next peer heading."""
55
+ text = TERMINOLOGY.read_text(encoding="utf-8")
56
+ match = re.search(
57
+ rf"^(#+) {re.escape(title)}\s*$",
58
+ text,
59
+ re.MULTILINE,
60
+ )
61
+ assert match is not None, f"terminology.md has no section '{title}'"
62
+ depth = len(match.group(1))
63
+ rest = text[match.end() :]
64
+ end = re.search(rf"^#{{1,{depth}}} ", rest, re.MULTILINE)
65
+ return rest[: end.start()] if end else rest
66
+
67
+
68
+ def test_the_rule_is_where_the_stage_definition_sends_the_reader():
69
+ # §7 defers the ownership question rather than answering it twice.
70
+ assert "§9.1" in section("7. Processing and transformations")
71
+ assert section("9.1 Stage ownership (which transformations belong to this project)")
72
+
73
+
74
+ def test_every_node_the_rule_argues_from_still_exists():
75
+ missing = [name for name in CITED_NODES if not (COM_PY / f"{name}.py").is_file()]
76
+
77
+ assert not missing, f"terminology.md §9.1 cites nodes that are gone: {missing}"
78
+
79
+
80
+ def test_the_stage_keywords_the_rule_argues_from_are_still_session_vocabulary():
81
+ # The rule reasons from inverse pairs, so it breaks quietly when a session
82
+ # key is renamed: the prose keeps arguing from a `latch` or a
83
+ # `local_to_global` that no definition can declare any more.
84
+ body = section("9.1 Stage ownership (which transformations belong to this project)")
85
+ generator = GENERATOR_PY.read_text(encoding="utf-8")
86
+
87
+ for key in CITED_STAGE_KEYS:
88
+ assert f"`{key}`" in body, f"§9.1 no longer argues from '{key}'"
89
+ assert f'"{key}"' in generator, (
90
+ f"§9.1 argues from '{key}', which the session generator no longer knows as a processing key"
91
+ )
92
+
93
+
94
+ def test_the_falsifiable_test_names_assertions_a_session_may_declare():
95
+ body = section("9.1 Stage ownership (which transformations belong to this project)")
96
+ evaluator = STATUS_EVAL.read_text(encoding="utf-8")
97
+
98
+ for key in CITED_EXPECTATIONS:
99
+ assert f"`{key}`" in body, f"§9.1 no longer offers '{key}'"
100
+ for part in key.split("."):
101
+ assert f'"{part}"' in evaluator, (
102
+ f"§9.1 offers '{key}' as an expectation, but status_eval does not know '{part}'"
103
+ )