fix: decode SYSTEM_DEFAULT QoS history in compact liveliness tokens - #337
Merged
Merged
Conversation
Part of circle/hiroz#143 (D1). rmw_zenoh_cpp omits a QoS sub-field when it is SYSTEM_DEFAULT, so the history segment of a liveliness token can be the literal `,` with both kind and depth empty. QosProfile::decode always parsed the depth as a usize and rejected the token outright, making any rmw_zenoh_cpp participant using default QoS invisible to hiroz's graph.
…s folder Both new tests reached into private-free but nonetheless src-inline mod tests, when hiroz-protocol already has a tests/ integration directory covering exactly this surface (RmwZenohFormatter, QosProfile). Moved the QosProfile::decode corpus into a new tests/qos.rs, and the verbatim SYSTEM_DEFAULT liveliness-token test into the existing tests/key_expr.rs, reusing its parse_liveliness helper instead of duplicating key-expr construction inline.
There was a problem hiding this comment.
Pull request overview
Updates compact QoS decoding to recognize RMW default sentinels and omitted history fields.
Changes:
- Handles
"0"reliability/durability sentinels and omitted history values. - Adds compact QoS corpus and round-trip tests.
- Adds coverage for a real SYSTEM_DEFAULT liveliness token.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
crates/hiroz-protocol/src/qos.rs |
Expands compact QoS decoding. |
crates/hiroz-protocol/tests/qos.rs |
Tests compact decoding and validation. |
crates/hiroz-protocol/tests/key_expr.rs |
Tests parsing a captured liveliness token. |
Suppressed comments (1)
crates/hiroz-protocol/src/qos.rs:109
- Empty depths now fall back regardless of field count, so truncated inputs such as
::1,decode successfully; the special,arm also accepts::,. Both were previously rejected, and this contradicts the six-field completeness rule above. Gate every omitted-depth form onfields.len() >= 6.
let depth = if encoded_depth.is_empty() {
default_qos.history.depth()
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…wire default, not hiroz's Copilot review on GH#337: an omitted/zero history depth in a compact liveliness token decoded to hiroz's own QosHistory::default() (10), not the value rmw_zenoh_cpp actually substitutes on the wire for SYSTEM_DEFAULT (42, RMW_ZENOH_DEFAULT_HISTORY_DEPTH in rmw_zenoh_cpp/src/detail/qos.cpp). Every peer relying on that SYSTEM_DEFAULT omission had its depth misreported. Added a named RMW_ZENOH_DEFAULT_HISTORY_DEPTH constant, distinct from QosHistory::default()'s unrelated depth, and used it for every omitted/zero-depth wire substitution in decode().
0x53A
added a commit
to 0x53A/hiroz
that referenced
this pull request
Sep 1, 2026
Upstream extracted both defects from the draft PR ZettaScaleLabs#331 into ZettaScaleLabs#336 and ZettaScaleLabs#337 and merged them, so every native change on this branch is now superseded. Resolved by taking upstream verbatim everywhere the two sides overlapped: - hiroz-protocol/src/qos.rs: upstream's parser is ours plus a real correction -- an omitted history depth resolves to rmw_zenoh_cpp's wire default RMW_ZENOH_DEFAULT_HISTORY_DEPTH (42), not hiroz's own unrelated QosProfile default of 10. Ours misreported the depth of every peer that relied on the SYSTEM_DEFAULT omission. - parameter/service.rs and node.rs: upstream is a strict superset, additionally propagating the node's enclave, which we had dropped. - tests/graph.rs: upstream's version, with the shared TestRouter in tests/common/mod.rs replacing our inline DomainTestRouter. - Dropped our inline tests in qos.rs and format/rmw_zenoh.rs; upstream adopted the same cases into tests/qos.rs and tests/key_expr.rs. Ours would now fail anyway, having asserted the pre-ZettaScaleLabs#337 depth of 10. - Dropped docs/patches/, an artifact of the draft PR. Two wasm-only fixes were needed on top: - ZContextBuilder's new hand-written Default impl initialises shm_config, which does not exist on wasm32; cfg it out to match the field. - build_async() now has to resolve the DomainId enum ZettaScaleLabs#336 introduced. It rejects an unparseable ROS_DOMAIN_ID exactly as build() does, rather than silently falling back to domain 0 and landing the node on the wrong ROS graph. Verified: cargo test -p hiroz-protocol (51 tests), cargo test -p hiroz --test graph --test domain_id (28 tests), and cargo check -p hiroz --target wasm32-unknown-unknown --no-default-features --features rmw-zenoh,jazzy.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A thorough solution to part of #331 — the compact QoS parser half. Sibling fix (built-in service domain propagation,
ROS_DOMAIN_ID) already merged as #336.#331 reported that
rmw_zenoh_cppparticipants using default QoS become invisible to hiroz's graph. Root cause:rmw_zenoh_cppomits a QoS sub-field entirely when its value is SYSTEM_DEFAULT, rather than encoding an explicit default — for the history sub-field this produces the literal text,(kind and depth both empty) inside the six-field QoS segment of a liveliness key expression.QosProfile::decodesplit that segment on,, required at least two parts, and always parsed part two as ausize, so the omitted-history case failed to parse and the whole liveliness token was rejected.Before and after
rmw_zenoh_cppparticipant with default QoSQosProfile::decodereturnsErr(InvalidHistory)on the omitted,history fieldQosProfile::decode("0")-style RMW zero sentinels"0"was not treated as "unset" for reliability/durability"0"and""both mean "use default", matching RMW's sentinel conventionWhat the tests do
QosProfile::decodeagainst the compact-form corpus, including the SYSTEM_DEFAULT,casecrates/hiroz-protocol/tests/qos.rs:decode_rmw_compact_qos_corpus,qos_round_trip,reject_invalid_history,history fieldInvalidHistory) before this changecrates/hiroz-protocol/tests/key_expr.rs:test_parse_liveliness_with_verbatim_rmw_system_default_qos, reusing that file'sparse_livelinesshelperBoth new test files live in
hiroz-protocol's existingtests/integration directory rather than an inlinemod tests, alongside its other integration coverage of the same formatter/QoS surface.Verified standalone:
cargo test -p hiroz-protocol --lib --tests— 56 tests, 0 failed.cargo clippy -p hiroz-protocol --all-targets -- -D warnings— clean.Breaking changes
None.