Skip to content

fix: decode SYSTEM_DEFAULT QoS history in compact liveliness tokens - #337

Merged
YuanYuYuan merged 3 commits into
mainfrom
fix/qos-system-default
Sep 1, 2026
Merged

YuanYuYuan merged 3 commits into
mainfrom
fix/qos-system-default

Conversation

@YuanYuYuan

Copy link
Copy Markdown
Collaborator

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_cpp participants using default QoS become invisible to hiroz's graph. Root cause: rmw_zenoh_cpp omits 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::decode split that segment on ,, required at least two parts, and always parsed part two as a usize, so the omitted-history case failed to parse and the whole liveliness token was rejected.

Before and after

today with this change
rmw_zenoh_cpp participant with default QoS QosProfile::decode returns Err(InvalidHistory) on the omitted , history field decodes to the default history
QosProfile::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 convention

What the tests do

today with this change
QosProfile::decode against the compact-form corpus, including the SYSTEM_DEFAULT , case no test existed new tests in crates/hiroz-protocol/tests/qos.rs: decode_rmw_compact_qos_corpus, qos_round_trip, reject_invalid_history
parsing a real liveliness token carrying the SYSTEM_DEFAULT , history field no test existed; the equivalent hand-built key expression failed to parse (InvalidHistory) before this change new test in the existing crates/hiroz-protocol/tests/key_expr.rs: test_parse_liveliness_with_verbatim_rmw_system_default_qos, reusing that file's parse_liveliness helper

Both new test files live in hiroz-protocol's existing tests/ integration directory rather than an inline mod 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.

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.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 on fields.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.

Comment thread crates/hiroz-protocol/src/qos.rs Outdated
…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().
@YuanYuYuan
YuanYuYuan merged commit 0787b2a into main Sep 1, 2026
30 checks passed
@YuanYuYuan
YuanYuYuan deleted the fix/qos-system-default branch September 1, 2026 14:30
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants