rosotacom-dev 2.5.dev62__tar.gz → 2.5.dev65__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.
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/PKG-INFO +2 -2
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/README.md +1 -1
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/findings/README.md +1 -0
- rosotacom_dev-2.5.dev65/docs/findings/cyclone-fragment-equal-to-max-drops-fragmented-samples.md +89 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/findings/fastdds-datagram-cap-drops-large-samples.md +1 -1
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/forensics-report.md +1 -1
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/link-trace.md +10 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/cli.py +59 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template +12 -1
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_trace.py +33 -3
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom_dev.egg-info/PKG-INFO +2 -2
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom_dev.egg-info/SOURCES.txt +1 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom_dev.egg-info/scm_file_list.json +1 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom_dev.egg-info/scm_version.json +2 -2
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_cli.py +78 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_link_trace.py +72 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_ota_link_configs.py +12 -2
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.devcontainer/devcontainer.json.template +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.devcontainer/re_generate_devcontainer_json.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/CODEOWNERS +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/ISSUE_TEMPLATE/documentation-audit.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/ISSUE_TEMPLATE/implementation-cleanup.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/ISSUE_TEMPLATE/quality-workflow.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/ISSUE_TEMPLATE/redesign.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/ISSUE_TEMPLATE/release-process.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/ISSUE_TEMPLATE/repository-diagnosis.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/ISSUE_TEMPLATE/test-ci-audit.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/ISSUE_TEMPLATE/work-item.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/actions/setup-just/action.yml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/dependabot.yml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/workflows/benchmark-calibrate.yml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/workflows/benchmark-gate.yml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/workflows/dev-release.yml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/workflows/image-scan.yml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/workflows/nightly-e2e.yml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/workflows/pr-lightweight.yml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/workflows/pr-merge-gate.yml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/workflows/release.yml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.pre-commit-config.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/AGENTS.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/CONCURRENCY.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/CONTRIBUTING.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/DEVELOPMENT_PRINCIPLES.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/MANIFEST.in +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/budgets.jsonl +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/calibration/README.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/calibration/capacity-size-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/calibration/probe-loss-gop-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/calibration/probe-loss-nominal-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/calibration/probe-loss-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/calibration/probe-loss-tight-fastdds.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/calibration/probe-loss-tight-zenoh.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/codecov.yml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/deployment-configuration.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/benchmark-ab.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/benchmark-bag-as-load.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/ci.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/ffmpeg-keyframes.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/findings/a-transport-element-doubles-every-fastdds-sample.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/findings/cyclone-spdp-discovery-bursts.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/findings/delay-alone-no-loss.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/findings/graph-derived-types-block-a-non-graph-transport.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/findings/head-of-line-irregularity.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/findings/jitter-loss-bandwidth-latency.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/findings/keyframe-loss-kills-the-next-deltas.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/findings/lifespan-is-enforced-by-one-reader-and-not-the-other.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/findings/lighter-message-loss.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/findings/oversubscription-queues-not-losses.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/findings/reorder-becomes-reader-loss.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/findings/repro/decode_chain_repro.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/findings/repro/reorder_drop_repro.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/findings/sender-rows-make-a-dead-link-look-loss-free.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/findings/zero-loss-boundaries-18kb-20hz.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/geo-link-map.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/github-repository-settings.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/link-bandwidth.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/owner-runbook.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/performance-bands.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/playbooks/README.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/quality-model.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/release-notes/TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/release-notes/v2.1.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/release-notes/v2.2.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/release-notes/v2.3.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/release-notes/v2.4.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/release.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/rfcs/0001-expectation-driven-test-suite.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/rfcs/0002-expectation-concepts.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/rfcs/0003-metric-backbone.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/rfcs/0004-network-profiles.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/rfcs/0005-benchmark-genres-and-ci.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/rfcs/0006-dynamic-qos.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/rfcs/0007-regression-gate.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/rfcs/README.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/testing.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/docs/work-items.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/install.sh +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/justfile +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/media/control_center.png +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/media/echo_test.png +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/media/forensics-report-example.png +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/media/host.png +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/media/vehicle.png +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/pyproject.toml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/requirements.txt +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/session-configuration.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/__init__.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/__main__.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/anonymize.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/benched_set.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/benchmark.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/benchmark_delta.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/deployment.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/forensics.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/geomap.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/image_cache.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/netem_dist.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/network_preflight.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/plots.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/py.typed +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/benched-set.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/.gitignore +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/README.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/__init__.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/bags/8_drop_reference/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/deployment.example.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/dist/field-20260817.dist +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/profiles.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/ros2docker.lyrical.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scenarios/2_native_chatter/scenario-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_a.sh +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_b.sh +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.lyrical.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/wait_for_echo_topic.sh +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.lyrical.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/10_restamp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/11_trickle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/12_content_integrity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/13_link_latency/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/14_remote_assist_anonymized/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/15_remote_assist_anonymized_costmap/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/16_remote_assist_anonymized_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/17_synthetic_camera_quality/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/1_heartbeat/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/1_heartbeat_status/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/2_native_chatter/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/3_comp_occ_grid/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/4_comp_occ_grid_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/5_sized_payload/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/6_sized_payload_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/7_latched_static/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/8_drop/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/9_throttle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/bench_1_1_capacity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/bench_1_2_load_sweep/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/bench_1_3_ramp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/bench_1_4_recovery/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/examples/sessions/bench_1_5_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ros2docker.json.example +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ros2docker.lyrical.json.example +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/.vscode/c_cpp_properties.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/.vscode/settings.json +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_easy_mode.xml.template +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_initial_peer_list.xml.template +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v2.xml.template +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v3.xml.template +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v4.xml.template +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v5.xml.template +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ota_configs/cyclonedds_local_participants.xml.template +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ota_configs/fastdds_easy_mode.xml.template +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ota_configs/fastdds_local.xml.template +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ota_configs/fastdds_tuned.xml.template +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ota_configs/fastdds_unicast.xml.template +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ota_configs/get_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ota_configs/utils.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ota_configs/zenoh.json5.template +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/.gitkeep +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_cpp/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_cpp/COLCON_IGNORE +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_cpp/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_cpp/package.xml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_cpp/src/hz_monitor.cpp +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_compressor.cpp +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_decompressor.cpp +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_msgs/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_msgs/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/CompressedData.msg +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/EchoHeartbeat.msg +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/OtaStamped.msg +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/SizedPayload.msg +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_msgs/package.xml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/__init__.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/base_bridge_relay.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_in.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_out.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/ffmpeg_flags.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/heartbeat_echo.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/hz_monitor.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_bandwidth_reducer.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_pixel_capper.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/lanelet_saver.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/latch_relay.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/costmap_remapper.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/marker_remapper.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/speed_test.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/tf_remapper.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/traffic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/wifi_network_analysis_1.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/local_global_frame_bridge.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/localization_map_split_reduce_saver.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/msg_transform.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pair_management.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer_core.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pub_sub_pair.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/qos.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_in.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_out.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/restamp.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/sized_publisher.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency_core.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview_core.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/tf_map_to_cart_saver.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_resolution.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/trickle.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_compressor.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_decompressor.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/package.xml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/resource/com_py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/setup.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/test/test_copyright.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/test/test_flake8.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/ros2src/com_py/test/test_pep257.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/session/content/base/session_plugin_base.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/session/content/network/up_connectivity.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/session/content/network/wifi_network_analysis_2.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/session/creation/anonymize_bag.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/session/creation/catmux_log_setup.sh +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/session/creation/create_session_yaml.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/session/creation/generate_session_files.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/session/creation/run_session.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/session/creation/run_session_in_external_terminal.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/resources/ws/session/creation/strip_ansi.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/status_eval.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/transit.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom/video_quality.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom_dev.egg-info/dependency_links.txt +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom_dev.egg-info/entry_points.txt +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom_dev.egg-info/requires.txt +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom_dev.egg-info/top_level.txt +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/terminology.md +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/contract/test_benched_set_registry.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/contract/test_findings.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/contract/test_generated_topics_have_a_producer.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/contract/test_lyrical_runtime_compat.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/contract/test_markdown_links.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/contract/test_ota_source_bundle.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/contract/test_package_metadata.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/contract/test_packaged_resources.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/contract/test_profile_covers_generated_commands.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/contract/test_pytest_policy.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/contract/test_readme_examples.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/contract/test_security_maintenance_config.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/contract/test_session_configuration_doc.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/contract/test_session_template_substitution.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/contract/test_workflow_contracts.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/e2e/conftest.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/e2e/test_anonymize_e2e.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/e2e/test_benchmark_ab.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/e2e/test_benchmark_capacity.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/e2e/test_benchmark_replay.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/e2e/test_parallel_smoke.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/e2e/test_smoke.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/e2e/test_timeline_stepping.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/e2e/test_video_quality_e2e.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/sessions/generate_rmw_matrix.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-local_zenoh-ros2dds-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota-tuned/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/sessions/rmw_matrix/1_heartbeat_fastdds/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/sessions/rmw_matrix/1_heartbeat_fastdds-default/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/sessions/rmw_matrix/1_heartbeat_zen-endpoints/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_anonymize.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_benched_set.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_benchmark_delta.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_catmux_pane_logging.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_concurrency.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_container_shaping.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_deployment.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_ffmpeg_flags.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_field_profiles.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_forensics.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_geomap.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_image_cache.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_netem_dist.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_network_preflight.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_playout_pacer.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_plots.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_pub_sub_pair_types.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_qos_fallback_logging.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_relay_optional_parameters.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_ros_node_entity_ownership.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_session_pipeline.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_status_eval.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_status_overview.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_status_overview_observer.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/tests/unit/test_transit.py +0 -0
- {rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/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.
|
|
3
|
+
Version: 2.5.dev65
|
|
4
4
|
Summary: Host CLI for ROS OTA communication sessions.
|
|
5
5
|
Author: develNor
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -367,7 +367,7 @@ Peer reachability is opt-in because some valid networks block ICMP and peers may
|
|
|
367
367
|
be started in either order. `rosotacom start` accepts the same
|
|
368
368
|
`--require-peer-reachable` policy when a deployment does require it.
|
|
369
369
|
|
|
370
|
-
`rosotacom` reads the static session input and creates generated files under `session-instances/<date>/<session>_<timestamp>_<id>/config/`, including per-peer plugin/session specs, topic lists, optional QoS, and optional `domain_bridge.yaml`. Catmux pane output is logged under the same instance in `logs/<peer>/catmux/`.
|
|
370
|
+
`rosotacom` reads the static session input and creates generated files under `session-instances/<date>/<session>_<timestamp>_<id>/config/`, including per-peer plugin/session specs, topic lists, optional QoS, and optional `domain_bridge.yaml`. The instance's `manifest.yaml` records what produced it: `rosotacom_version`, the effective config SHA, and `source_revision` — the commit, branch and tracked-dirtiness of the session source directory at creation time, so a recording stays attributable to a revision after the checkout has moved on (`null` when the source is not a git repository). Catmux pane output is logged under the same instance in `logs/<peer>/catmux/`.
|
|
371
371
|
|
|
372
372
|
What else a run leaves under `logs/<peer>/`, and which file to open first when a
|
|
373
373
|
peer looked healthy but did nothing:
|
|
@@ -322,7 +322,7 @@ Peer reachability is opt-in because some valid networks block ICMP and peers may
|
|
|
322
322
|
be started in either order. `rosotacom start` accepts the same
|
|
323
323
|
`--require-peer-reachable` policy when a deployment does require it.
|
|
324
324
|
|
|
325
|
-
`rosotacom` reads the static session input and creates generated files under `session-instances/<date>/<session>_<timestamp>_<id>/config/`, including per-peer plugin/session specs, topic lists, optional QoS, and optional `domain_bridge.yaml`. Catmux pane output is logged under the same instance in `logs/<peer>/catmux/`.
|
|
325
|
+
`rosotacom` reads the static session input and creates generated files under `session-instances/<date>/<session>_<timestamp>_<id>/config/`, including per-peer plugin/session specs, topic lists, optional QoS, and optional `domain_bridge.yaml`. The instance's `manifest.yaml` records what produced it: `rosotacom_version`, the effective config SHA, and `source_revision` — the commit, branch and tracked-dirtiness of the session source directory at creation time, so a recording stays attributable to a revision after the checkout has moved on (`null` when the source is not a git repository). Catmux pane output is logged under the same instance in `logs/<peer>/catmux/`.
|
|
326
326
|
|
|
327
327
|
What else a run leaves under `logs/<peer>/`, and which file to open first when a
|
|
328
328
|
peer looked healthy but did nothing:
|
|
@@ -31,6 +31,7 @@ living verification hook.
|
|
|
31
31
|
- [Sender-side transit rows made a dead link report zero loss](sender-rows-make-a-dead-link-look-loss-free.md) - `delivered = rows - lost` counted the sender's own `sent` rows as deliveries, so a topic the receiver never saw summarised as `delivered == expected` at 0.0% loss, with the publisher's timer reported as arrival spacing.
|
|
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
|
+
- [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.
|
|
34
35
|
- [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.
|
|
35
36
|
- [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.
|
|
36
37
|
- [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.
|
rosotacom_dev-2.5.dev65/docs/findings/cyclone-fragment-equal-to-max-drops-fragmented-samples.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# A Fragment Sized Exactly Like the Datagram Cap Stops Every Fragmented Sample
|
|
2
|
+
|
|
3
|
+
## Claim
|
|
4
|
+
|
|
5
|
+
Setting CycloneDDS's `FragmentSize` **equal to** `MaxMessageSize` makes every
|
|
6
|
+
sample large enough to fragment **never arrive** on CycloneDDS 11.0.1, while the
|
|
7
|
+
identical profile carries them on 0.10.5. Samples small enough to fit in one
|
|
8
|
+
fragment keep flowing on the same link, which is what makes it dangerous: the
|
|
9
|
+
endpoints match, neither side logs anything, and the reader simply never sees a
|
|
10
|
+
sample.
|
|
11
|
+
|
|
12
|
+
An RTPS message carries headers as well as the fragment, so a fragment of
|
|
13
|
+
exactly `MaxMessageSize` cannot be put into a message of `MaxMessageSize`.
|
|
14
|
+
0.10.5 evidently coped with that arithmetic; 11.0.1 does not, and drops
|
|
15
|
+
silently.
|
|
16
|
+
|
|
17
|
+
This is the CycloneDDS sibling of
|
|
18
|
+
[the Fast DDS datagram cap](fastdds-datagram-cap-drops-large-samples.md), found
|
|
19
|
+
from the opposite direction: there the cap was a value copied *from* this
|
|
20
|
+
profile, here the profile's own two values were equal to each other.
|
|
21
|
+
|
|
22
|
+
## Setup
|
|
23
|
+
|
|
24
|
+
- Host pair / topology: two hosts joined by a point-to-point VPN (`/24`,
|
|
25
|
+
1.3 ms RTT, 0.0% loss measured with three probes each way), one container per
|
|
26
|
+
host from the packaged communication image, `--network host --ipc host`, one
|
|
27
|
+
ROS domain. Not the local smoke rig: on a single host nothing fragments far
|
|
28
|
+
enough to show it.
|
|
29
|
+
- Session: none. A bare `ros2 topic pub -r 1` of a 64 kB
|
|
30
|
+
`std_msgs/msg/String` against a subscriber given the type explicitly — with
|
|
31
|
+
`EnableTopicDiscoveryEndpoints false` a bare `ros2 topic echo <topic>`
|
|
32
|
+
resolves no type and reports nothing, in both versions, which is a trap worth
|
|
33
|
+
naming because it looks exactly like the failure under test.
|
|
34
|
+
- rosotacom SHA: measured on the packaged 2.5.dev61 images; re-runs record
|
|
35
|
+
theirs.
|
|
36
|
+
- Profile: none — no impairment. The failure needs none, which is what makes it
|
|
37
|
+
attributable to the configuration rather than to the link.
|
|
38
|
+
- Seed policy: deterministic (no netem, no random load), `n=1` per variant; the
|
|
39
|
+
effect is present/absent, not a distribution.
|
|
40
|
+
- Stacks: `ros-kilted-cyclonedds` 0.10.5-2noble against
|
|
41
|
+
`ros-lyrical-cyclonedds` 11.0.1-4resolute.
|
|
42
|
+
|
|
43
|
+
## Evidence
|
|
44
|
+
|
|
45
|
+
| profile | 0.10.5 | 11.0.1 |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| `FragmentSize` 1200 B, `MaxMessageSize` 1200 B | arrives | **nothing** |
|
|
48
|
+
| no size limits at all | — | arrives |
|
|
49
|
+
| `FragmentSize` 1024 B, `MaxMessageSize` 1200 B | — | arrives |
|
|
50
|
+
|
|
51
|
+
- A 40 B string crosses on 11.0.1 with the 1200/1200 profile, so the trigger is
|
|
52
|
+
fragmentation and not the link.
|
|
53
|
+
- The discovery trace of a failing run rules out everything above the data path:
|
|
54
|
+
both participants discover each other across the hosts, both sides announce
|
|
55
|
+
their endpoints, the reading side builds proxy writers for the remote
|
|
56
|
+
participants, and neither side logs a QoS incompatibility or a rejection.
|
|
57
|
+
|
|
58
|
+
Verification: automated:
|
|
59
|
+
`pytest tests/unit/test_ota_link_configs.py::test_only_cyclone_caps_the_datagram_and_fast_dds_must_not`
|
|
60
|
+
asserts the fragment stays strictly below the datagram cap, which is the
|
|
61
|
+
invariant the two numbers exist for. Manual, for the effect itself: one
|
|
62
|
+
container per host from the communication image on one ROS domain, the shipped
|
|
63
|
+
OTA profile with only the three size elements varied, a 64 kB string at 1 Hz,
|
|
64
|
+
and `ros2 topic echo <topic> std_msgs/msg/String --once` on the other side.
|
|
65
|
+
|
|
66
|
+
## Status
|
|
67
|
+
|
|
68
|
+
confirmed, 2026-08-20.
|
|
69
|
+
|
|
70
|
+
Fixed by making `FragmentSize` strictly smaller than `MaxMessageSize` (1024 B
|
|
71
|
+
against 1200 B) in `cyclonedds_tuned.xml.template`. The datagram stays inside
|
|
72
|
+
the same MTU budget the 1200 B was chosen for — only the header room is added —
|
|
73
|
+
and the value works on both versions, so it is one number rather than a branch
|
|
74
|
+
on the distribution.
|
|
75
|
+
|
|
76
|
+
## Publication notes
|
|
77
|
+
|
|
78
|
+
A distribution bump silently changed what a profile *means*, and the profile
|
|
79
|
+
text did not move. That is the reportable part: measurements taken under one ROS
|
|
80
|
+
distribution cannot be presented as the other's on the strength of an identical
|
|
81
|
+
configuration file, because identical configuration is not identical behaviour
|
|
82
|
+
across a DDS major version. State the middleware version beside the profile
|
|
83
|
+
wherever OTA numbers are reported.
|
|
84
|
+
|
|
85
|
+
The second consequence is about what counts as evidence that a link works. A
|
|
86
|
+
heartbeat crossing at 10 Hz with 0.0% loss certified nothing here — the small
|
|
87
|
+
samples were exactly the ones that could not fail. A link check that does not
|
|
88
|
+
include a sample past the fragment threshold does not test the transport the
|
|
89
|
+
payload uses.
|
|
@@ -10,7 +10,7 @@ this dangerous: an 84 B heartbeat crossing at 10 Hz with 0.0% loss is a link
|
|
|
10
10
|
that looks alive from every direction except the one that matters.
|
|
11
11
|
|
|
12
12
|
The obvious reason to set it is symmetry with CycloneDDS, whose OTA profile
|
|
13
|
-
carries this link at
|
|
13
|
+
carries this link at a 1024 B fragment inside a 1200 B datagram and works. The
|
|
14
14
|
symmetry does not transfer: on ROS 2 Kilted with Fast DDS 3.2.4 the cap is the
|
|
15
15
|
single knob that breaks the link, at 1200 B and at 8192 B, with a synchronous
|
|
16
16
|
writer and with an asynchronous one.
|
|
@@ -37,7 +37,7 @@ gracefully when absent:
|
|
|
37
37
|
|---|---|
|
|
38
38
|
| `status.json` | declared topic types (FFMPEGPacket detection) |
|
|
39
39
|
| `link_trace.jsonl` ([link trace recorder](link-trace.md)) | link state around each incident |
|
|
40
|
-
| `manifest.yaml` | instance id
|
|
40
|
+
| `manifest.yaml` | instance id, config SHA, and `source_revision` — the commit of the session source at instance creation |
|
|
41
41
|
| `--profile NAME --profiles-file FILE` | RFC 0004 environment context (static params or timeline steps) |
|
|
42
42
|
| `state_transition` rows in `events.jsonl` | pipeline diagnoses around each incident |
|
|
43
43
|
|
|
@@ -30,6 +30,16 @@ rosotacom ota-smoke 13_link_latency --link-trace
|
|
|
30
30
|
`--link-trace-interval` and `--link-trace-modem-command` also enable the
|
|
31
31
|
recorder and force `shared.use_status_overview: true` for the generated instance.
|
|
32
32
|
|
|
33
|
+
`interval_s` is the period between rows, and the status-overview node is ticked
|
|
34
|
+
at the same period when the trace is enabled. Those two being equal is what
|
|
35
|
+
makes the trace continuous: each row's `passive_counter_delta` covers one tick,
|
|
36
|
+
so consecutive rows meet rather than leaving traffic between them. The recorder
|
|
37
|
+
therefore schedules against an advancing deadline with a small tolerance instead
|
|
38
|
+
of a stopwatch since the last row — without that, a tick landing a hair early is
|
|
39
|
+
rejected and waits a whole further period, which halves the trace and leaves
|
|
40
|
+
every second interval described by no row at all (measured on a 5 h drive:
|
|
41
|
+
1.984 s between rows carrying 1.002 s windows).
|
|
42
|
+
|
|
33
43
|
## Row Schema
|
|
34
44
|
|
|
35
45
|
Each line is one JSON object:
|
|
@@ -882,6 +882,61 @@ def _append_log(path: Path, text: str) -> None:
|
|
|
882
882
|
fp.write("\n")
|
|
883
883
|
|
|
884
884
|
|
|
885
|
+
#: A provenance read must never be what makes an instance fail to start.
|
|
886
|
+
_SOURCE_REVISION_TIMEOUT_S = 5.0
|
|
887
|
+
|
|
888
|
+
|
|
889
|
+
def _source_revision(path: Path | str) -> dict[str, Any] | None:
|
|
890
|
+
"""The VCS revision of the directory this session was taken from.
|
|
891
|
+
|
|
892
|
+
`rosotacom_version` pins the tool. This pins its *input*: the session source
|
|
893
|
+
is normally a checkout of a deployment repository, and that checkout moves.
|
|
894
|
+
A consumer reading the manifest later cannot recover the revision by looking
|
|
895
|
+
at the machine, because looking at the machine answers a different question —
|
|
896
|
+
on one two-machine drive the vehicle had been synced by the time the
|
|
897
|
+
recording was consolidated the next morning, so the only commit anybody
|
|
898
|
+
could still read was not the commit that ran. The manifest is written once
|
|
899
|
+
at creation and never rewritten, which is exactly what such a fact needs.
|
|
900
|
+
|
|
901
|
+
`dirty` deliberately ignores untracked files: deployment checkouts routinely
|
|
902
|
+
carry recordings, logs and scratch files that are not the code, so counting
|
|
903
|
+
them would make every real deployment permanently dirty and the flag
|
|
904
|
+
meaningless. What it reports is tracked content differing from the commit.
|
|
905
|
+
|
|
906
|
+
Best effort throughout — not a directory, no git, not a repository, a git
|
|
907
|
+
that hangs: all yield None.
|
|
908
|
+
"""
|
|
909
|
+
directory = Path(path)
|
|
910
|
+
if not directory.is_dir():
|
|
911
|
+
return None
|
|
912
|
+
|
|
913
|
+
def git(*args: str) -> str | None:
|
|
914
|
+
try:
|
|
915
|
+
result = subprocess.run(
|
|
916
|
+
["git", "-C", str(directory), *args],
|
|
917
|
+
capture_output=True,
|
|
918
|
+
text=True,
|
|
919
|
+
check=False,
|
|
920
|
+
timeout=_SOURCE_REVISION_TIMEOUT_S,
|
|
921
|
+
)
|
|
922
|
+
except (OSError, subprocess.SubprocessError):
|
|
923
|
+
return None
|
|
924
|
+
return result.stdout.strip() if result.returncode == 0 else None
|
|
925
|
+
|
|
926
|
+
commit = git("rev-parse", "HEAD")
|
|
927
|
+
if not commit:
|
|
928
|
+
return None
|
|
929
|
+
branch = git("rev-parse", "--abbrev-ref", "HEAD")
|
|
930
|
+
tracked_changes = git("status", "--porcelain", "--untracked-files=no")
|
|
931
|
+
return {
|
|
932
|
+
"vcs": "git",
|
|
933
|
+
"commit": commit,
|
|
934
|
+
"branch": None if branch in (None, "HEAD") else branch,
|
|
935
|
+
"dirty": None if tracked_changes is None else bool(tracked_changes),
|
|
936
|
+
"root": git("rev-parse", "--show-toplevel"),
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
|
|
885
940
|
def _effective_config_sha256(cfg: dict[str, Any]) -> str:
|
|
886
941
|
text = yaml.safe_dump(cfg, sort_keys=True, default_flow_style=False, allow_unicode=True)
|
|
887
942
|
return hashlib.sha256(text.encode("utf-8")).hexdigest()
|
|
@@ -908,6 +963,7 @@ def _write_instance_manifest(
|
|
|
908
963
|
"instance_id": instance.instance_id,
|
|
909
964
|
"rosotacom_version": __version__,
|
|
910
965
|
"source_session_host_dir": str(session.host_dir),
|
|
966
|
+
"source_revision": _source_revision(session.host_dir),
|
|
911
967
|
"source_session_container_dir": session.container_dir,
|
|
912
968
|
"source": session.source,
|
|
913
969
|
"config_dir": str(instance.config_host_dir),
|
|
@@ -962,6 +1018,7 @@ def _write_scenario_manifest(
|
|
|
962
1018
|
"instance_id": instance.instance_id,
|
|
963
1019
|
"rosotacom_version": __version__,
|
|
964
1020
|
"source_session_host_dir": str(session.host_dir),
|
|
1021
|
+
"source_revision": _source_revision(session.host_dir),
|
|
965
1022
|
"source_session_container_dir": session.container_dir,
|
|
966
1023
|
"source": session.source,
|
|
967
1024
|
"config_dir": str(instance.config_host_dir),
|
|
@@ -1028,6 +1085,7 @@ def _write_interactive_smoke_manifest(
|
|
|
1028
1085
|
"instance_id": instance.instance_id,
|
|
1029
1086
|
"rosotacom_version": __version__,
|
|
1030
1087
|
"source_session_host_dir": str(target.session.host_dir),
|
|
1088
|
+
"source_revision": _source_revision(target.session.host_dir),
|
|
1031
1089
|
"source_session_container_dir": target.session.container_dir,
|
|
1032
1090
|
"source": target.session.source,
|
|
1033
1091
|
"config_dir": str(instance.config_host_dir),
|
|
@@ -2445,6 +2503,7 @@ def _ota_write_manifest(
|
|
|
2445
2503
|
"instance_id": instance.instance_id,
|
|
2446
2504
|
"rosotacom_version": __version__,
|
|
2447
2505
|
"source_session_host_dir": str(target.session.host_dir),
|
|
2506
|
+
"source_revision": _source_revision(target.session.host_dir),
|
|
2448
2507
|
"source_session_container_dir": target.session.container_dir,
|
|
2449
2508
|
"source": target.session.source,
|
|
2450
2509
|
"config_dir": str(instance.config_host_dir),
|
|
@@ -6,7 +6,18 @@
|
|
|
6
6
|
<NetworkInterface address="#host_ip"/>
|
|
7
7
|
</Interfaces>
|
|
8
8
|
<MulticastRecvNetworkInterfaceAddresses>none</MulticastRecvNetworkInterfaceAddresses>
|
|
9
|
-
|
|
9
|
+
<!-- Strictly below MaxMessageSize, and that is the whole point: an RTPS
|
|
10
|
+
message carries headers as well as the fragment, so a fragment of
|
|
11
|
+
exactly MaxMessageSize cannot be sent at all. Both were 1200B, which
|
|
12
|
+
CycloneDDS 0.10.5 coped with and 11.0.1 does not — under Lyrical no
|
|
13
|
+
fragmented sample crossed, silently: the endpoints matched and the
|
|
14
|
+
reader never saw a sample, while a sample small enough not to
|
|
15
|
+
fragment arrived normally. Measured between two hosts with a 64 kB
|
|
16
|
+
sample: 1200/1200 delivers nothing on 11.0.1 and everything on
|
|
17
|
+
0.10.5; 1024/1200 delivers on both. The datagram stays inside the
|
|
18
|
+
same MTU budget the 1200B was chosen for; only the header room is
|
|
19
|
+
added. -->
|
|
20
|
+
<FragmentSize>1024B</FragmentSize>
|
|
10
21
|
<MaxMessageSize>1200B</MaxMessageSize>
|
|
11
22
|
<MaxRexmitMessageSize>1200B</MaxRexmitMessageSize>
|
|
12
23
|
</General>
|
|
@@ -152,6 +152,12 @@ def build_link_trace_sample(
|
|
|
152
152
|
class LinkTraceRecorder:
|
|
153
153
|
"""Write link trace rows as append-only JSONL."""
|
|
154
154
|
|
|
155
|
+
#: How early a tick may be and still count as on time. The caller ticks at
|
|
156
|
+
#: the same nominal period, so its jitter is the whole question; a tenth of
|
|
157
|
+
#: the interval absorbs that without ever letting rows run at half the
|
|
158
|
+
#: configured period.
|
|
159
|
+
_TOLERANCE_FRACTION = 0.1
|
|
160
|
+
|
|
155
161
|
def __init__(
|
|
156
162
|
self,
|
|
157
163
|
path: str,
|
|
@@ -166,13 +172,37 @@ class LinkTraceRecorder:
|
|
|
166
172
|
self.modem_metrics_command = modem_metrics_command
|
|
167
173
|
self.modem_metrics_timeout_s = modem_metrics_timeout_s
|
|
168
174
|
self._clock = clock
|
|
169
|
-
self.
|
|
175
|
+
self._due_at: Optional[float] = None
|
|
170
176
|
|
|
171
177
|
def maybe_write(self, snapshot: Dict[str, Any], link_sample: Optional[Dict[str, Any]]) -> bool:
|
|
178
|
+
"""Write one row if this tick is the one the schedule was waiting for.
|
|
179
|
+
|
|
180
|
+
The schedule is a *deadline that advances*, not a stopwatch since the
|
|
181
|
+
last row, and the tolerance is not cosmetic. The caller is deliberately
|
|
182
|
+
ticking at the same period as this one — `generate_session_files` sets
|
|
183
|
+
`status_write_interval_s` to the trace interval — so a plain
|
|
184
|
+
"never faster than interval_s" gate rejects every tick that lands a hair
|
|
185
|
+
early and, with no catch-up, makes it wait a whole further period.
|
|
186
|
+
|
|
187
|
+
That halves the trace, and it does not merely halve its resolution: the
|
|
188
|
+
passive counter delta in a row covers the caller's own tick, so with
|
|
189
|
+
rows twice as far apart every second of traffic is described by no row
|
|
190
|
+
at all. Measured on the 2026-08-19 drive before this fix: rows 1.984 s
|
|
191
|
+
apart carrying 1.002 s windows.
|
|
192
|
+
"""
|
|
172
193
|
now = self._clock()
|
|
173
|
-
if self.
|
|
194
|
+
if self._due_at is None:
|
|
195
|
+
self._due_at = now
|
|
196
|
+
if now < self._due_at - self._TOLERANCE_FRACTION * self.interval_s:
|
|
174
197
|
return False
|
|
175
|
-
|
|
198
|
+
# Advance the deadline rather than restarting it from now, so the rows
|
|
199
|
+
# stay on one cadence instead of drifting by the jitter of every tick.
|
|
200
|
+
# After a stall long enough that the next deadline is already behind us,
|
|
201
|
+
# start a fresh interval from the present rather than bursting through
|
|
202
|
+
# the deadlines that were missed: the rows describe the link now, and a
|
|
203
|
+
# burst of them would describe nothing.
|
|
204
|
+
next_due = self._due_at + self.interval_s
|
|
205
|
+
self._due_at = next_due if next_due > now else now + self.interval_s
|
|
176
206
|
modem = run_modem_metrics_hook(
|
|
177
207
|
self.modem_metrics_command,
|
|
178
208
|
timeout_s=self.modem_metrics_timeout_s,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rosotacom-dev
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.dev65
|
|
4
4
|
Summary: Host CLI for ROS OTA communication sessions.
|
|
5
5
|
Author: develNor
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -367,7 +367,7 @@ Peer reachability is opt-in because some valid networks block ICMP and peers may
|
|
|
367
367
|
be started in either order. `rosotacom start` accepts the same
|
|
368
368
|
`--require-peer-reachable` policy when a deployment does require it.
|
|
369
369
|
|
|
370
|
-
`rosotacom` reads the static session input and creates generated files under `session-instances/<date>/<session>_<timestamp>_<id>/config/`, including per-peer plugin/session specs, topic lists, optional QoS, and optional `domain_bridge.yaml`. Catmux pane output is logged under the same instance in `logs/<peer>/catmux/`.
|
|
370
|
+
`rosotacom` reads the static session input and creates generated files under `session-instances/<date>/<session>_<timestamp>_<id>/config/`, including per-peer plugin/session specs, topic lists, optional QoS, and optional `domain_bridge.yaml`. The instance's `manifest.yaml` records what produced it: `rosotacom_version`, the effective config SHA, and `source_revision` — the commit, branch and tracked-dirtiness of the session source directory at creation time, so a recording stays attributable to a revision after the checkout has moved on (`null` when the source is not a git repository). Catmux pane output is logged under the same instance in `logs/<peer>/catmux/`.
|
|
371
371
|
|
|
372
372
|
What else a run leaves under `logs/<peer>/`, and which file to open first when a
|
|
373
373
|
peer looked healthy but did nothing:
|
|
@@ -62,6 +62,7 @@ docs/testing.md
|
|
|
62
62
|
docs/work-items.md
|
|
63
63
|
docs/findings/README.md
|
|
64
64
|
docs/findings/a-transport-element-doubles-every-fastdds-sample.md
|
|
65
|
+
docs/findings/cyclone-fragment-equal-to-max-drops-fragmented-samples.md
|
|
65
66
|
docs/findings/cyclone-spdp-discovery-bursts.md
|
|
66
67
|
docs/findings/delay-alone-no-loss.md
|
|
67
68
|
docs/findings/fastdds-datagram-cap-drops-large-samples.md
|
{rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/src/rosotacom_dev.egg-info/scm_file_list.json
RENAMED
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"docs/ffmpeg-keyframes.md",
|
|
48
48
|
"docs/findings/README.md",
|
|
49
49
|
"docs/findings/a-transport-element-doubles-every-fastdds-sample.md",
|
|
50
|
+
"docs/findings/cyclone-fragment-equal-to-max-drops-fragmented-samples.md",
|
|
50
51
|
"docs/findings/cyclone-spdp-discovery-bursts.md",
|
|
51
52
|
"docs/findings/delay-alone-no-loss.md",
|
|
52
53
|
"docs/findings/fastdds-datagram-cap-drops-large-samples.md",
|
|
@@ -3721,3 +3721,81 @@ def test_ota_cleanup_refuses_to_act_on_a_guessed_plan(capsys: pytest.CaptureFixt
|
|
|
3721
3721
|
|
|
3722
3722
|
assert calls == []
|
|
3723
3723
|
assert "no deployment state" in capsys.readouterr().out
|
|
3724
|
+
|
|
3725
|
+
|
|
3726
|
+
def _git_repo(path: Path) -> None:
|
|
3727
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
3728
|
+
env = {
|
|
3729
|
+
**os.environ,
|
|
3730
|
+
"GIT_AUTHOR_NAME": "t",
|
|
3731
|
+
"GIT_AUTHOR_EMAIL": "t@example.invalid",
|
|
3732
|
+
"GIT_COMMITTER_NAME": "t",
|
|
3733
|
+
"GIT_COMMITTER_EMAIL": "t@example.invalid",
|
|
3734
|
+
}
|
|
3735
|
+
for args in (
|
|
3736
|
+
["init", "--initial-branch", "main"],
|
|
3737
|
+
["config", "commit.gpgsign", "false"],
|
|
3738
|
+
):
|
|
3739
|
+
subprocess.run(["git", "-C", str(path), *args], check=True, capture_output=True, env=env)
|
|
3740
|
+
(path / "session-definition.yaml").write_text("shared: {}\n", encoding="utf-8")
|
|
3741
|
+
subprocess.run(["git", "-C", str(path), "add", "-A"], check=True, capture_output=True, env=env)
|
|
3742
|
+
subprocess.run(["git", "-C", str(path), "commit", "-m", "seed"], check=True, capture_output=True, env=env)
|
|
3743
|
+
|
|
3744
|
+
|
|
3745
|
+
def test_the_manifest_records_the_revision_of_the_session_it_was_built_from(
|
|
3746
|
+
tmp_path: Path,
|
|
3747
|
+
) -> None:
|
|
3748
|
+
"""rosotacom_version pins the tool; this pins its input.
|
|
3749
|
+
|
|
3750
|
+
Without it the only recoverable commit is whatever the machine holds when
|
|
3751
|
+
somebody looks, which is a different fact — and a wrong one as soon as the
|
|
3752
|
+
machine has been synced in between.
|
|
3753
|
+
"""
|
|
3754
|
+
session = tmp_path / "sessions" / "demo"
|
|
3755
|
+
_git_repo(session)
|
|
3756
|
+
|
|
3757
|
+
revision = rosotacom._source_revision(session)
|
|
3758
|
+
|
|
3759
|
+
assert revision is not None
|
|
3760
|
+
assert revision["vcs"] == "git"
|
|
3761
|
+
assert re.fullmatch(r"[0-9a-f]{40}", revision["commit"])
|
|
3762
|
+
assert revision["branch"] == "main"
|
|
3763
|
+
assert revision["dirty"] is False
|
|
3764
|
+
assert Path(revision["root"]).resolve() == session.resolve()
|
|
3765
|
+
|
|
3766
|
+
|
|
3767
|
+
def test_a_session_source_that_differs_from_its_commit_says_so(tmp_path: Path) -> None:
|
|
3768
|
+
session = tmp_path / "sessions" / "demo"
|
|
3769
|
+
_git_repo(session)
|
|
3770
|
+
(session / "session-definition.yaml").write_text("shared: {changed: true}\n", encoding="utf-8")
|
|
3771
|
+
|
|
3772
|
+
assert rosotacom._source_revision(session)["dirty"] is True
|
|
3773
|
+
|
|
3774
|
+
|
|
3775
|
+
def test_untracked_files_beside_a_session_do_not_make_it_dirty(tmp_path: Path) -> None:
|
|
3776
|
+
"""A deployment checkout carries recordings, logs and scratch files.
|
|
3777
|
+
|
|
3778
|
+
Counting those would leave every real deployment permanently dirty, which is
|
|
3779
|
+
the same as reporting nothing.
|
|
3780
|
+
"""
|
|
3781
|
+
session = tmp_path / "sessions" / "demo"
|
|
3782
|
+
_git_repo(session)
|
|
3783
|
+
(session / "rosbag2_2026_01_01-00_00_00").mkdir()
|
|
3784
|
+
(session / "rosbag2_2026_01_01-00_00_00" / "metadata.yaml").write_text("x\n", encoding="utf-8")
|
|
3785
|
+
|
|
3786
|
+
assert rosotacom._source_revision(session)["dirty"] is False
|
|
3787
|
+
|
|
3788
|
+
|
|
3789
|
+
@pytest.mark.parametrize("case", ["not_a_repository", "not_a_directory", "missing"])
|
|
3790
|
+
def test_a_source_without_a_revision_is_null_and_not_an_error(tmp_path: Path, case: str) -> None:
|
|
3791
|
+
"""An instance must never fail to start over a provenance read."""
|
|
3792
|
+
if case == "not_a_repository":
|
|
3793
|
+
target = tmp_path / "plain"
|
|
3794
|
+
target.mkdir()
|
|
3795
|
+
elif case == "not_a_directory":
|
|
3796
|
+
target = tmp_path / "file"
|
|
3797
|
+
target.write_text("x\n", encoding="utf-8")
|
|
3798
|
+
else:
|
|
3799
|
+
target = tmp_path / "gone"
|
|
3800
|
+
|
|
3801
|
+
assert rosotacom._source_revision(target) is None
|
|
@@ -129,3 +129,75 @@ def test_link_trace_recorder_appends_jsonl_on_interval(tmp_path: Path) -> None:
|
|
|
129
129
|
|
|
130
130
|
rows = [json.loads(line) for line in trace_path.read_text(encoding="utf-8").splitlines()]
|
|
131
131
|
assert [row["kind"] for row in rows] == ["link_trace", "link_trace"]
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _recorder(tmp_path: Path, ticks: list[float], interval_s: float = 1.0) -> tuple[LinkTraceRecorder, list[float]]:
|
|
135
|
+
remaining = iter(ticks)
|
|
136
|
+
path = tmp_path / "status" / "link_trace.jsonl"
|
|
137
|
+
return LinkTraceRecorder(str(path), interval_s=interval_s, clock=lambda: next(remaining)), ticks
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
SNAPSHOT = {"generated_at": "2026-08-19T13:52:11.000", "peer": "a", "remote": "b", "topics": []}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def test_a_caller_ticking_at_the_configured_period_gets_a_row_per_tick(tmp_path: Path) -> None:
|
|
144
|
+
"""The caller ticks at exactly this period, so its jitter is the whole question.
|
|
145
|
+
|
|
146
|
+
`generate_session_files` sets `status_write_interval_s` to the trace
|
|
147
|
+
interval, so every tick lands one period after the last — sometimes a
|
|
148
|
+
millisecond early. A gate that rejects those outright makes each of them
|
|
149
|
+
wait a further full period, which is how the 2026-08-19 drive ended up with
|
|
150
|
+
rows 1.984 s apart at `interval_s: 1.0`.
|
|
151
|
+
"""
|
|
152
|
+
ticks = [100.0, 100.999, 101.998, 102.997, 103.996]
|
|
153
|
+
recorder, _ = _recorder(tmp_path, ticks)
|
|
154
|
+
|
|
155
|
+
written = [recorder.maybe_write(SNAPSHOT, None) for _ in ticks]
|
|
156
|
+
|
|
157
|
+
assert written == [True] * len(ticks)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def test_half_the_traffic_is_not_left_between_two_rows(tmp_path: Path) -> None:
|
|
161
|
+
"""Why the tick above matters more than resolution.
|
|
162
|
+
|
|
163
|
+
A row's passive counter delta covers the caller's own tick. With rows twice
|
|
164
|
+
as far apart as the ticks, every second interval is described by no row at
|
|
165
|
+
all — so the trace undercounts the bytes it exists to account for.
|
|
166
|
+
"""
|
|
167
|
+
ticks = [0.0, 0.999, 1.998, 2.997]
|
|
168
|
+
recorder, _ = _recorder(tmp_path, ticks)
|
|
169
|
+
for _ in ticks:
|
|
170
|
+
recorder.maybe_write(SNAPSHOT, {"passive_counter_delta": {"window_s": 1.0}})
|
|
171
|
+
|
|
172
|
+
rows = [
|
|
173
|
+
json.loads(line) for line in (tmp_path / "status" / "link_trace.jsonl").read_text(encoding="utf-8").splitlines()
|
|
174
|
+
]
|
|
175
|
+
stamps = [row["monotonic_s"] for row in rows]
|
|
176
|
+
gaps = [b - a for a, b in zip(stamps, stamps[1:], strict=False)]
|
|
177
|
+
assert gaps, "more than one row"
|
|
178
|
+
assert max(gaps) < 1.5, "no second of the drive falls between two rows"
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def test_a_much_faster_caller_is_still_held_to_the_interval(tmp_path: Path) -> None:
|
|
182
|
+
"""The tolerance must not turn the interval into a suggestion."""
|
|
183
|
+
ticks = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2]
|
|
184
|
+
recorder, _ = _recorder(tmp_path, ticks)
|
|
185
|
+
|
|
186
|
+
written = [recorder.maybe_write(SNAPSHOT, None) for _ in ticks]
|
|
187
|
+
|
|
188
|
+
assert written == [True, False, False, False, False, True, False]
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def test_a_stall_resynchronises_instead_of_bursting(tmp_path: Path) -> None:
|
|
192
|
+
"""After a gap, the rows describe the link now.
|
|
193
|
+
|
|
194
|
+
Emitting the deadlines that were missed would produce a burst of rows that
|
|
195
|
+
describe nothing, and would make the trace's own timestamps disagree with
|
|
196
|
+
the counters in it.
|
|
197
|
+
"""
|
|
198
|
+
ticks = [0.0, 30.0, 30.2, 31.0]
|
|
199
|
+
recorder, _ = _recorder(tmp_path, ticks)
|
|
200
|
+
|
|
201
|
+
written = [recorder.maybe_write(SNAPSHOT, None) for _ in ticks]
|
|
202
|
+
|
|
203
|
+
assert written == [True, True, False, True]
|
|
@@ -28,7 +28,9 @@ PLUGIN_BASE = (
|
|
|
28
28
|
REPO_ROOT / "src" / "rosotacom" / "resources" / "ws" / "session" / "content" / "base" / "session_plugin_base.yaml"
|
|
29
29
|
)
|
|
30
30
|
|
|
31
|
-
OTA_FRAGMENT_BYTES =
|
|
31
|
+
OTA_FRAGMENT_BYTES = 1024
|
|
32
|
+
#: The datagram cap the fragment has to fit inside, headers included.
|
|
33
|
+
OTA_DATAGRAM_BYTES = 1200
|
|
32
34
|
|
|
33
35
|
|
|
34
36
|
def _load(path: Path, name: str) -> ModuleType:
|
|
@@ -73,7 +75,15 @@ def test_only_cyclone_caps_the_datagram_and_fast_dds_must_not() -> None:
|
|
|
73
75
|
cyclone = _resolved("cyclonedds_tuned.xml")
|
|
74
76
|
|
|
75
77
|
assert f"<FragmentSize>{OTA_FRAGMENT_BYTES}B</FragmentSize>" in cyclone
|
|
76
|
-
assert f"<MaxMessageSize>{
|
|
78
|
+
assert f"<MaxMessageSize>{OTA_DATAGRAM_BYTES}B</MaxMessageSize>" in cyclone
|
|
79
|
+
|
|
80
|
+
# Strictly smaller, not equal, and this is the assertion the numbers exist
|
|
81
|
+
# for: an RTPS message carries headers as well as the fragment, so a
|
|
82
|
+
# fragment of exactly MaxMessageSize cannot be sent. Both were 1200 B, which
|
|
83
|
+
# CycloneDDS 0.10.5 coped with and 11.0.1 does not — no fragmented sample
|
|
84
|
+
# arrived at all, silently, while a 40 B one kept crossing
|
|
85
|
+
# (docs/findings/cyclone-fragment-equal-to-max-drops-fragmented-samples.md).
|
|
86
|
+
assert OTA_FRAGMENT_BYTES < OTA_DATAGRAM_BYTES
|
|
77
87
|
|
|
78
88
|
for config in ("fastdds_tuned.xml", "fastdds_easy_mode.xml"):
|
|
79
89
|
resolved = _without_comments(_resolved(config))
|
{rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.devcontainer/devcontainer.json.template
RENAMED
|
File without changes
|
{rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.devcontainer/re_generate_devcontainer_json.py
RENAMED
|
File without changes
|
|
File without changes
|
{rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/ISSUE_TEMPLATE/documentation-audit.md
RENAMED
|
File without changes
|
{rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/ISSUE_TEMPLATE/implementation-cleanup.md
RENAMED
|
File without changes
|
{rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/ISSUE_TEMPLATE/quality-workflow.md
RENAMED
|
File without changes
|
|
File without changes
|
{rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/ISSUE_TEMPLATE/release-process.md
RENAMED
|
File without changes
|
{rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/ISSUE_TEMPLATE/repository-diagnosis.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rosotacom_dev-2.5.dev62 → rosotacom_dev-2.5.dev65}/.github/workflows/benchmark-calibrate.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|