Topic · Spec-Referenz

QoS Reference — alle 22 Policies durchgekaut

Pro Policy: Spec-Anker, Felder, Default-Werte, Mutability nach enable, RxO-Verhalten und ein Wenn-nutzen-Tipp. Plus eine vollständige Compatibility-Matrix der 9 RxO-Pairs aus DDS 1.4 §2.2.3 und die within-entity-Konsistenzregeln. Wer Rezepte sucht, findet sie im QoS Cookbook.

Spec: DDS 1.4 §2.2.3 · 22 Policies Crate: zerodds-qos RxO-Check: compatibility.rs

Überblick

Jede DDS-Entity (DomainParticipant, Topic, Publisher/Subscriber, DataWriter/DataReader) trägt einen QoS-Block aus den anwendbaren Policies. Die Policies sind in drei Achsen organisiert:

  • RxO-Compatibility — beim Match werden Writer-„offered" und Reader-„requested" verglichen. Mismatch blockt Discovery-Match und triggert OFFERED_INCOMPATIBLE_QOS/REQUESTED_INCOMPATIBLE_QOS. Betrifft 9 von 22 Policies (siehe Compatibility-Matrix).
  • Within-Entity-Konsistenz — gewisse Policies haben Wechselwirkungen innerhalb einer Entity (z.B. HistoryQos.depth ≤ ResourceLimits.max_samples_per_instance). set_qos() lehnt inkonsistente Sets mit InconsistentPolicy ab.
  • Mutability — manche Policies dürfen nach enable() nicht mehr geändert werden (immutable). Setzen vor dem ersten Sample-Schreiben/-Lesen.

Default-Werte folgen exakt der Spec (DDS 1.4 §2.2.3). Pro Policy-Block unten: Spec-§, Felder, Default, RxO-Verhalten, Mutability und Wenn-nutzen.

Compatibility-Matrix — die 9 RxO-Pairs

Reader „requests" einen Wert, Writer „offers" einen. Diese 9 Policies haben eine RxO-Rule aus DDS 1.4 §2.2.3 — alle anderen 13 Policies haben kein Compatibility-Verhalten.

PolicySpec §Match-Rule (offered vs. requested)RxO-Enum
Reliability§2.2.3.14Reliable offered ≥ BestEffort requested. Reader Reliable matched nur Writer Reliable.IncompatibleReason::Reliability
Durability§2.2.3.4offered ≥ requested in Volatile < TransientLocal < Transient < Persistent.IncompatibleReason::Durability
Deadline§2.2.3.7offered ≤ requested (Writer-Period muss ≤ Reader-Erwartung sein).IncompatibleReason::Deadline
LatencyBudget§2.2.3.8offered ≤ requested. Hint-Charakter, aber RxO-relevant.IncompatibleReason::LatencyBudget
Liveliness§2.2.3.11offered.kind ≥ requested.kind in Automatic < ManualByParticipant < ManualByTopic, UND offered.lease_duration ≤ requested.lease_duration.IncompatibleReason::Liveliness
DestinationOrder§2.2.3.17offered ≥ requested in ByReceptionTimestamp < BySourceTimestamp.IncompatibleReason::DestinationOrder
Presentation§2.2.3.6offered.access_scope ≥ requested in Instance < Topic < Group, plus coherent/ordered offered ⊇ requested.IncompatibleReason::Presentation
Ownership§2.2.3.9offered.kind == requested.kind (Shared/Exclusive müssen identisch sein).IncompatibleReason::Ownership
Partition§2.2.3.13mindestens eine Partition-Sequence muss zwischen Writer und Reader matchen (Glob-Pattern via POSIX-fnmatch).IncompatibleReason::Partition

Compute-Function im Code: crates/qos/src/compatibility.rs · compute_compatibility(offered, requested) -> CompatibilityResult

Within-Entity-Konsistenzregeln

Manche Policy-Kombinationen sind innerhalb einer Entity inkonsistent — set_qos() lehnt sie mit InconsistentPolicy ab, bevor sie überhaupt am Wire landen.

RegelSpec §Bedingung
History.depth ≤ ResourceLimits.max_samples_per_instance§2.2.3.18 + §2.2.3.19Wenn History=KeepLast(N), darf N nicht max_samples_per_instance übersteigen.
History=KeepAll erfordert ResourceLimits.max_samples_per_instance=UNLIMITED§2.2.3.18KeepAll kann ohne UNLIMITED in OutOfResources-State laufen.
OwnershipStrength gilt nur wenn Ownership=Exclusive§2.2.3.10Setting Strength bei Ownership=Shared ist No-Op (kein Fehler).
LivelinessQos.lease_duration > 0 wenn kind≠Automatic§2.2.3.11ManualByParticipant/Topic mit lease=0 ist degenerated.
DurabilityServiceQos.history_depth ≤ DurabilityServiceQos.max_samples_per_instance§2.2.3.5Wie History/ResourceLimits, aber für den Persistence-Service.
ResourceLimits.max_samples_per_instance ≤ ResourceLimits.max_samples§2.2.3.19Per-Instance-Cap darf nicht über das Total-Cap.

Mutability nach enable()

DDS 1.4 §2.2.3 markiert jede Policy als mutable (kann nach enable() via set_qos() geändert werden) oder immutable (nur vor enable() setzbar; danach wirft set_qos() einen ImmutablePolicy-Error).

PolicyMutable nach enable?Grund
UserData / TopicData / GroupData✓ mutableOpaque Bytes, nur Discovery-Side-Effect.
Durability✗ immutableBeeinflusst Writer-Cache-Backing — kann nicht im Flug geändert werden.
DurabilityService✗ immutablePersistence-Service-Konfig.
Presentation✗ immutableCoherent/ordered-Modus an Topic gebunden.
Deadline✓ mutableReine Status-Trigger-Logik.
LatencyBudget✓ mutableScheduler-Hint.
Ownership✗ immutableBestimmt Instance-Routing.
OwnershipStrength✓ mutableDynamisches Strength-Voting.
Liveliness✗ immutableLease-Watchdog kann nicht im Flug umgeschaltet werden.
TimeBasedFilter✓ mutableReader-Side-Sampling-Filter.
Partition✓ mutableDynamische Re-Matching mit anderen Partitionen.
Reliability✗ immutableWire-Protokoll-Modus (RTPS Best-Effort vs. Reliable).
TransportPriority✓ mutableHint für Transport-Scheduling.
Lifespan✓ mutableGilt nur für nachfolgende Samples.
DestinationOrder✗ immutableSample-Ordering-Modus.
History✗ immutableCache-Backing-Strategie.
ResourceLimits✗ immutableCache-Allokation.
EntityFactory✓ mutableBeeinflusst nur Neu-Erzeugung untergeordneter Entities.
WriterDataLifecycle✓ mutableReine Verhaltens-Flag.
ReaderDataLifecycle✓ mutableAuto-Purge-Timer.

Data-Payload-Policies (3)

Drei opaque sequence<octet>-Slots, die im Discovery ausgetauscht werden. Keine RxO-Compatibility, kein Match-Effekt — nutzbar für eigene Metadata-Übertragung am Discovery-Kanal.

1 · UserDataQosPolicy §2.2.3.1 · auf Participant/DataReader/DataWriter

Felder: value: Vec<u8> · Default: empty · RxO: kein · Mutable: ✓ ja

Wenn nutzen: Application-spezifische Metadata, die der Discovery-Layer transportiert (Custom-Auth-Tokens, Build-Version, Deployment-Identifier). Aufpassen bei DDS-Security — der Inhalt ist sichtbar für jeden, der Discovery sehen darf.

Repo: crates/qos/src/policies/generic_data.rs (gemeinsam mit TopicData + GroupData)

2 · TopicDataQosPolicy §2.2.3.2 · auf Topic

Felder: value: Vec<u8> · Default: empty · RxO: kein · Mutable: ✓ ja

Wenn nutzen: Topic-spezifische Metadata (z.B. Schema-Hash, OEM-Topic-ID). Wird mit dem Topic-Discovery-Eintrag propagiert.

Repo: crates/qos/src/policies/generic_data.rs

3 · GroupDataQosPolicy §2.2.3.3 · auf Publisher/Subscriber

Felder: value: Vec<u8> · Default: empty · RxO: kein · Mutable: ✓ ja

Wenn nutzen: Group-Level-Metadata bei Coherent/Ordered Sets — z.B. Transaktions-ID einer kohärenten Sample-Gruppe.

Repo: crates/qos/src/policies/generic_data.rs

Durability-Policies (2)

Bestimmt, ob und wie Samples für Late-Joiner verfügbar bleiben.

4 · DurabilityQosPolicy §2.2.3.4 · auf Topic/DataReader/DataWriter

Felder: kind: DurabilityKind (Volatile · TransientLocal · Transient · Persistent) · Default: Volatile · RxO: offered ≥ requested · Mutable: ✗ nein

Wenn nutzen: Volatile für Telemetry (Verlust OK). TransientLocal für State-Topics (Setpoints, Mode), damit Late-Joiner den letzten Wert sehen. Transient/Persistent liefert der eingebaute DurabilityService: Transient hält die History in-memory, Persistent on-disk (übersteht einen Neustart) — Late-Joiner-Replay ist für beide Stufen end-to-end getestet. Cross-Vendor-Replay von Transient/Persistent ist eine OMG-Spec-Lücke (RTPS spezifiziert dafür keine Wire-Mechanik), heute also ZeroDDS↔ZeroDDS.

Repo: crates/qos/src/policies/durability.rs

5 · DurabilityServiceQosPolicy §2.2.3.5 · auf Topic/DataWriter

Felder: service_cleanup_delay: Duration · history_kind: HistoryKind · history_depth: i32 · max_samples / max_instances / max_samples_per_instance: i32 · Default: KeepLast(1) + UNLIMITED · RxO: kein · Mutable: ✗ nein

Wenn nutzen: Konfiguriert den Persistence-Service hinter Transient/Persistent Durability. Wird nur ausgewertet, wenn Durability=Transient/Persistent gesetzt ist.

Repo: crates/qos/src/policies/durability_service.rs

Liveliness & Health (2)

Failure-Detection: Reader will wissen, ob Writer noch "lebt". Deadline ist die Sample-Frequenz-Garantie.

6 · LivelinessQosPolicy §2.2.3.11 · auf Topic/DataReader/DataWriter

Felder: kind: LivelinessKind (Automatic · ManualByParticipant · ManualByTopic) · lease_duration: Duration · Default: Automatic/INFINITE · RxO: offered.kind ≥ requested.kind UND offered.lease ≤ requested.lease · Mutable: ✗ nein

Wenn nutzen: Automatic für Telemetry (DDS-Stack pingt selbst). ManualByParticipant wenn die App durch assert_liveliness() oder regelmäßiges write() Liveness signalisieren will (Heartbeat-Modell). ManualByTopic für Failover-Patterns (siehe Cookbook §3).

Repo: crates/qos/src/policies/liveliness.rs

7 · DeadlineQosPolicy §2.2.3.7 · auf Topic/DataReader/DataWriter

Felder: period: Duration · Default: INFINITE · RxO: offered ≤ requested · Mutable: ✓ ja

Wenn nutzen: Control-Loops mit Frequenz-Garantie. Writer-Deadline-Miss triggert OfferedDeadlineMissedStatus, Reader-Side RequestedDeadlineMissedStatus. Listener-Callback (siehe DCPS) reagiert auf Misses.

Repo: crates/qos/src/policies/deadline.rs

Reliability & Order (3)

Wire-Garantien: ob Samples ankommen müssen, in welcher Reihenfolge sie auf der Reader-Side liegen.

8 · ReliabilityQosPolicy §2.2.3.14 · auf Topic/DataReader/DataWriter

Felder: kind: ReliabilityKind (BestEffort · Reliable) · max_blocking_time: Duration · Default: Writer Reliable, Reader BestEffort · RxO: offered ≥ requested · Mutable: ✗ nein

Wenn nutzen: BestEffort für Telemetry (kein ACK, kein Retransmit). Reliable für Commands, State-Updates, Config-Topics — ACK/NACK über RTPS, Retransmit auf Daten-Loss. max_blocking_time ist die Wartezeit auf write() bei vollem Cache.

Repo: crates/qos/src/policies/reliability.rs

9 · DestinationOrderQosPolicy §2.2.3.17 · auf Topic/DataReader/DataWriter

Felder: kind: DestinationOrderKind (ByReceptionTimestamp · BySourceTimestamp) · Default: ByReceptionTimestamp · RxO: offered ≥ requested · Mutable: ✗ nein

Wenn nutzen: ByReceptionTimestamp ist der Default — Sample-Order ergibt sich aus Reader-Ankunft. BySourceTimestamp wenn Writer-seitige Zeitstempel logisch korrekt sind (Clock-synced Cluster, Replay-Szenarien).

Repo: crates/qos/src/policies/destination_order.rs

10 · LatencyBudgetQosPolicy §2.2.3.8 · auf Topic/DataReader/DataWriter

Felder: duration: Duration · Default: 0 ns · RxO: offered ≤ requested · Mutable: ✓ ja

Wenn nutzen: Hint für den Transport-Scheduler — wieviel Zeit der Sample-Pfad maximal nutzen darf. Kein direkter Wire-Effekt; eher Optimierungs-Indikator (Batching, Priorisierung).

Repo: crates/qos/src/policies/latency_budget.rs

Ownership (2)

Wer darf schreiben? Bei Exclusive: nur der stärkste Writer ist aktiv.

11 · OwnershipQosPolicy §2.2.3.9 · auf Topic/DataReader/DataWriter

Felder: kind: OwnershipKind (Shared · Exclusive) · Default: Shared · RxO: offered.kind == requested.kind · Mutable: ✗ nein

Wenn nutzen: Shared erlaubt mehrere Writer pro Instance (Standard). Exclusive für Hot-Standby-Failover — nur der Writer mit höchster OwnershipStrength ist aktiv (siehe Cookbook §3).

Repo: crates/qos/src/policies/ownership.rs

12 · OwnershipStrengthQosPolicy §2.2.3.10 · auf DataWriter

Felder: value: i32 · Default: 0 · RxO: kein · Mutable: ✓ ja

Wenn nutzen: Strength-Voting bei Ownership=Exclusive. Höchster Wert gewinnt. Mutable-Setter erlaubt dynamische Re-Election (Heartbeat-basiertes Promote/Demote).

Repo: crates/qos/src/policies/ownership_strength.rs

History & Resources (2)

Wie viele Samples werden im Writer/Reader-Cache gehalten?

13 · HistoryQosPolicy §2.2.3.18 · auf Topic/DataReader/DataWriter

Felder: kind: HistoryKind (KeepLast · KeepAll) · depth: i32 · Default: KeepLast(1) · RxO: kein · Mutable: ✗ nein

Wenn nutzen: KeepLast(N) für Sliding-Window (älteste werden überschrieben). KeepAll für Audit-Log-Pattern — alles bis ResourceLimits halten. Bei KeepAll + Reliable: Writer blockt bei vollem Cache (siehe Reliability.max_blocking_time).

Repo: crates/qos/src/policies/history.rs

14 · ResourceLimitsQosPolicy §2.2.3.19 · auf Topic/DataReader/DataWriter

Felder: max_samples: i32 · max_instances: i32 · max_samples_per_instance: i32 (UNLIMITED = -1) · Default: 1000 / 10 / 100 · RxO: kein · Mutable: ✗ nein

Wenn nutzen: Hard-Cap auf Cache-Allokation. Bei Reliable + KeepAll erreicht das Cache-Limit, blockt Writer (OutOfResources). Setze passend zur erwarteten Daten-Rate und Reader-Verzögerung.

Repo: crates/qos/src/policies/resource_limits.rs

Presentation (1)

15 · PresentationQosPolicy §2.2.3.6 · auf Publisher/Subscriber

Felder: access_scope: PresentationAccessScope (Instance · Topic · Group) · coherent_access: bool · ordered_access: bool · Default: Instance/false/false · RxO: offered.scope ≥ requested.scope, coherent/ordered offered ⊇ requested · Mutable: ✗ nein

Wenn nutzen: Coherent-Sets gruppieren Samples zu einer atomar-sichtbaren Einheit (alle oder keine). Ordered-Sets garantieren Sample-Order über mehrere Topics einer Group (Multi-Topic-Transaktion). Höhere Scopes (Topic, Group) sind teurer und erfordern Coordination-Overhead.

Repo: crates/qos/src/policies/presentation.rs

Partition (1)

16 · PartitionQosPolicy §2.2.3.13 · auf Publisher/Subscriber

Felder: names: Vec<String> (POSIX-fnmatch-Glob-Pattern erlaubt) · Default: [""] (Default-Partition) · RxO: mindestens eine Partition muss zwischen Writer und Reader matchen · Mutable: ✓ ja

Wenn nutzen: Logische Mandantentrennung im selben Domain (z.B. customer-A/odom vs. customer-B/odom). Glob-Pattern wie customer-* erlauben dynamisches Subscriber-Matching ohne Topic-Umkonfiguration. Wichtig: Partition ist Match-Filter, kein Network-Isolation — Discovery sieht trotzdem alle.

Repo: crates/qos/src/policies/partition.rs

Filter & Lifespan (2)

Reader-seitige Sample-Filter (Time-Based) und Writer-seitige Sample-Verfallszeit.

17 · TimeBasedFilterQosPolicy §2.2.3.12 · auf DataReader

Felder: minimum_separation: Duration · Default: 0 ns · RxO: kein · Mutable: ✓ ja

Wenn nutzen: Reader-Side-Downsampling. Mindest-Abstand zwischen empfangenen Samples derselben Instance. Spart Reader-Verarbeitungs-CPU bei Hochfrequenz-Topics, wenn der Konsument nur eine Subset-Rate braucht.

Repo: crates/qos/src/policies/time_based_filter.rs

18 · LifespanQosPolicy §2.2.3.16 · auf Topic/DataWriter

Felder: duration: Duration · Default: INFINITE · RxO: kein · Mutable: ✓ ja

Wenn nutzen: Samples, die älter als duration sind, werden automatisch aus dem Cache entfernt (Writer-Seite und Reader-Seite, wenn TransientLocal). Nützlich für State-Topics mit "stale data is bad data"-Semantik (z.B. Setpoint > 30s alt = ignorieren).

Repo: crates/qos/src/policies/lifespan.rs

Entity & Lifecycle (3)

Auto-Enable-Verhalten und Instance-Lifecycle-Reaktionen.

19 · EntityFactoryQosPolicy §2.2.3.20 · auf Participant/Publisher/Subscriber/DomainParticipantFactory

Felder: autoenable_created_entities: bool · Default: true · RxO: kein · Mutable: ✓ ja

Wenn nutzen: Wenn true, werden neu erzeugte Sub-Entities sofort enable'd. Wenn false, muss der Anwender manuell enable() rufen — nützlich um QoS-Sets vor dem ersten Discovery-Beacon zu finalisieren.

Repo: crates/qos/src/policies/entity_factory.rs

20 · WriterDataLifecycleQosPolicy §2.2.3.21 · auf DataWriter

Felder: autodispose_unregistered_instances: bool · Default: true · RxO: kein · Mutable: ✓ ja

Wenn nutzen: Wenn true, wird unregister_instance() implizit als dispose() behandelt (Reader sieht NOT_ALIVE_DISPOSED). Wenn false, nur NOT_ALIVE_NO_WRITERS ohne Dispose-Marker.

Repo: crates/qos/src/policies/data_lifecycle.rs

21 · ReaderDataLifecycleQosPolicy §2.2.3.22 · auf DataReader

Felder: autopurge_nowriter_samples_delay: Duration · autopurge_disposed_samples_delay: Duration · Default: INFINITE / INFINITE · RxO: kein · Mutable: ✓ ja

Wenn nutzen: Reader-seitige Auto-Purge-Timer für ungenutzte/disposed Samples. Verhindert, dass der Reader-Cache mit alten/toten Instances vollläuft. Standard-INFINITE = nie auto-purge.

Repo: crates/qos/src/policies/data_lifecycle.rs

Transport (1)

22 · TransportPriorityQosPolicy §2.2.3.15 · auf Topic/DataWriter

Felder: value: i32 · Default: 0 · RxO: kein · Mutable: ✓ ja

Wenn nutzen: Hint für den Transport-Layer-Scheduler (z.B. UDP DSCP-Tag, TSN-Stream-Priorität). Implementierungs-spezifisch — Wert ohne Wire-Garantie. Wichtig in Mixed-Critical-Setups (Control + Telemetry auf gleichem Link).

Repo: crates/qos/src/policies/transport_priority.rs · Auswertung im Transport-Layer: zerodds-transport

Topic · Spec reference

QoS Reference — all 22 policies, chewed through

Per policy: spec anchor, fields, default values, mutability after enable, RxO behaviour and a when-to-use tip. Plus a full compatibility matrix of the 9 RxO pairs from DDS 1.4 §2.2.3 and the within-entity consistency rules. If you're after recipes, find them in the QoS Cookbook.

Spec: DDS 1.4 §2.2.3 · 22 policies Crate: zerodds-qos RxO check: compatibility.rs

Overview

Every DDS entity (DomainParticipant, Topic, Publisher/Subscriber, DataWriter/DataReader) carries a QoS block of the applicable policies. The policies are organised along three axes:

  • RxO compatibility — at match, the writer's "offered" and the reader's "requested" are compared. A mismatch blocks the discovery match and triggers OFFERED_INCOMPATIBLE_QOS/REQUESTED_INCOMPATIBLE_QOS. Affects 9 of 22 policies (see the compatibility matrix).
  • Within-entity consistency — certain policies interact within one entity (e.g. HistoryQos.depth ≤ ResourceLimits.max_samples_per_instance). set_qos() rejects inconsistent sets with InconsistentPolicy.
  • Mutability — some policies may no longer be changed after enable() (immutable). Set them before the first sample write/read.

Default values follow the spec exactly (DDS 1.4 §2.2.3). Per policy block below: spec §, fields, default, RxO behaviour, mutability and when-to-use.

Compatibility matrix — the 9 RxO pairs

The reader "requests" a value, the writer "offers" one. These 9 policies have an RxO rule from DDS 1.4 §2.2.3 — all the other 13 policies have no compatibility behaviour.

PolicySpec §Match rule (offered vs. requested)RxO enum
Reliability§2.2.3.14Reliable offered ≥ BestEffort requested. A Reliable reader matches only a Reliable writer.IncompatibleReason::Reliability
Durability§2.2.3.4offered ≥ requested in Volatile < TransientLocal < Transient < Persistent.IncompatibleReason::Durability
Deadline§2.2.3.7offered ≤ requested (the writer period must be ≤ the reader expectation).IncompatibleReason::Deadline
LatencyBudget§2.2.3.8offered ≤ requested. Hint in character, but RxO-relevant.IncompatibleReason::LatencyBudget
Liveliness§2.2.3.11offered.kind ≥ requested.kind in Automatic < ManualByParticipant < ManualByTopic, AND offered.lease_duration ≤ requested.lease_duration.IncompatibleReason::Liveliness
DestinationOrder§2.2.3.17offered ≥ requested in ByReceptionTimestamp < BySourceTimestamp.IncompatibleReason::DestinationOrder
Presentation§2.2.3.6offered.access_scope ≥ requested in Instance < Topic < Group, plus coherent/ordered offered ⊇ requested.IncompatibleReason::Presentation
Ownership§2.2.3.9offered.kind == requested.kind (Shared/Exclusive must be identical).IncompatibleReason::Ownership
Partition§2.2.3.13at least one partition sequence must match between writer and reader (glob patterns via POSIX fnmatch).IncompatibleReason::Partition

Compute function in the code: crates/qos/src/compatibility.rs · compute_compatibility(offered, requested) -> CompatibilityResult

Within-entity consistency rules

Some policy combinations are inconsistent within one entityset_qos() rejects them with InconsistentPolicy before they ever hit the wire.

RuleSpec §Condition
History.depth ≤ ResourceLimits.max_samples_per_instance§2.2.3.18 + §2.2.3.19With History=KeepLast(N), N must not exceed max_samples_per_instance.
History=KeepAll requires ResourceLimits.max_samples_per_instance=UNLIMITED§2.2.3.18KeepAll can run into an OutOfResources state without UNLIMITED.
OwnershipStrength applies only when Ownership=Exclusive§2.2.3.10Setting strength with Ownership=Shared is a no-op (no error).
LivelinessQos.lease_duration > 0 when kind≠Automatic§2.2.3.11ManualByParticipant/Topic with lease=0 is degenerate.
DurabilityServiceQos.history_depth ≤ DurabilityServiceQos.max_samples_per_instance§2.2.3.5Like History/ResourceLimits, but for the persistence service.
ResourceLimits.max_samples_per_instance ≤ ResourceLimits.max_samples§2.2.3.19The per-instance cap must not exceed the total cap.

Mutability after enable()

DDS 1.4 §2.2.3 marks each policy as mutable (can be changed after enable() via set_qos()) or immutable (settable only before enable(); after that set_qos() throws an ImmutablePolicy error).

PolicyMutable after enable?Reason
UserData / TopicData / GroupData✓ mutableOpaque bytes, only a discovery side-effect.
Durability✗ immutableAffects writer cache backing — can't be changed in flight.
DurabilityService✗ immutablePersistence-service config.
Presentation✗ immutableCoherent/ordered mode bound to the topic.
Deadline✓ mutablePure status-trigger logic.
LatencyBudget✓ mutableScheduler hint.
Ownership✗ immutableDetermines instance routing.
OwnershipStrength✓ mutableDynamic strength voting.
Liveliness✗ immutableThe lease watchdog can't be switched in flight.
TimeBasedFilter✓ mutableReader-side sampling filter.
Partition✓ mutableDynamic re-matching with other partitions.
Reliability✗ immutableWire-protocol mode (RTPS best-effort vs. reliable).
TransportPriority✓ mutableHint for transport scheduling.
Lifespan✓ mutableApplies only to subsequent samples.
DestinationOrder✗ immutableSample-ordering mode.
History✗ immutableCache-backing strategy.
ResourceLimits✗ immutableCache allocation.
EntityFactory✓ mutableOnly affects the creation of new sub-entities.
WriterDataLifecycle✓ mutablePure behaviour flag.
ReaderDataLifecycle✓ mutableAuto-purge timer.

Data payload policies (3)

Three opaque sequence<octet> slots exchanged during discovery. No RxO compatibility, no match effect — usable for your own metadata transfer on the discovery channel.

1 · UserDataQosPolicy §2.2.3.1 · on Participant/DataReader/DataWriter

Fields: value: Vec<u8> · Default: empty · RxO: none · Mutable: ✓ yes

When to use: application-specific metadata carried by the discovery layer (custom auth tokens, build version, deployment identifier). Beware with DDS-Security — the content is visible to anyone allowed to see discovery.

Repo: crates/qos/src/policies/generic_data.rs (shared with TopicData + GroupData)

2 · TopicDataQosPolicy §2.2.3.2 · on Topic

Fields: value: Vec<u8> · Default: empty · RxO: none · Mutable: ✓ yes

When to use: topic-specific metadata (e.g. a schema hash, OEM topic ID). Propagated with the topic discovery entry.

Repo: crates/qos/src/policies/generic_data.rs

3 · GroupDataQosPolicy §2.2.3.3 · on Publisher/Subscriber

Fields: value: Vec<u8> · Default: empty · RxO: none · Mutable: ✓ yes

When to use: group-level metadata for coherent/ordered sets — e.g. the transaction ID of a coherent sample group.

Repo: crates/qos/src/policies/generic_data.rs

Durability policies (2)

Determines whether and how samples remain available for late joiners.

4 · DurabilityQosPolicy §2.2.3.4 · on Topic/DataReader/DataWriter

Fields: kind: DurabilityKind (Volatile · TransientLocal · Transient · Persistent) · Default: Volatile · RxO: offered ≥ requested · Mutable: ✗ no

When to use: Volatile for telemetry (loss OK). TransientLocal for state topics (setpoints, mode) so late joiners see the last value. Transient/Persistent are provided by the built-in DurabilityService: Transient keeps history in memory, Persistent on disk (survives a restart) — late-joiner replay is tested end-to-end for both levels. Cross-vendor replay of Transient/Persistent is an OMG spec gap (RTPS specifies no wire mechanics for it), so today it is ZeroDDS↔ZeroDDS.

Repo: crates/qos/src/policies/durability.rs

5 · DurabilityServiceQosPolicy §2.2.3.5 · on Topic/DataWriter

Fields: service_cleanup_delay: Duration · history_kind: HistoryKind · history_depth: i32 · max_samples / max_instances / max_samples_per_instance: i32 · Default: KeepLast(1) + UNLIMITED · RxO: none · Mutable: ✗ no

When to use: configures the persistence service behind Transient/Persistent durability. Only evaluated when Durability=Transient/Persistent is set.

Repo: crates/qos/src/policies/durability_service.rs

Liveliness & health (2)

Failure detection: the reader wants to know whether the writer is still "alive". Deadline is the sample-frequency guarantee.

6 · LivelinessQosPolicy §2.2.3.11 · on Topic/DataReader/DataWriter

Fields: kind: LivelinessKind (Automatic · ManualByParticipant · ManualByTopic) · lease_duration: Duration · Default: Automatic/INFINITE · RxO: offered.kind ≥ requested.kind AND offered.lease ≤ requested.lease · Mutable: ✗ no

When to use: Automatic for telemetry (the DDS stack pings itself). ManualByParticipant when the app wants to signal liveness via assert_liveliness() or regular write() (heartbeat model). ManualByTopic for failover patterns (see Cookbook §3).

Repo: crates/qos/src/policies/liveliness.rs

7 · DeadlineQosPolicy §2.2.3.7 · on Topic/DataReader/DataWriter

Fields: period: Duration · Default: INFINITE · RxO: offered ≤ requested · Mutable: ✓ yes

When to use: control loops with a frequency guarantee. A writer deadline miss triggers OfferedDeadlineMissedStatus, the reader side RequestedDeadlineMissedStatus. A listener callback (see DCPS) reacts to misses.

Repo: crates/qos/src/policies/deadline.rs

Reliability & order (3)

Wire guarantees: whether samples must arrive, and in what order they sit on the reader side.

8 · ReliabilityQosPolicy §2.2.3.14 · on Topic/DataReader/DataWriter

Fields: kind: ReliabilityKind (BestEffort · Reliable) · max_blocking_time: Duration · Default: writer Reliable, reader BestEffort · RxO: offered ≥ requested · Mutable: ✗ no

When to use: BestEffort for telemetry (no ACK, no retransmit). Reliable for commands, state updates, config topics — ACK/NACK over RTPS, retransmit on data loss. max_blocking_time is the wait on write() when the cache is full.

Repo: crates/qos/src/policies/reliability.rs

9 · DestinationOrderQosPolicy §2.2.3.17 · on Topic/DataReader/DataWriter

Fields: kind: DestinationOrderKind (ByReceptionTimestamp · BySourceTimestamp) · Default: ByReceptionTimestamp · RxO: offered ≥ requested · Mutable: ✗ no

When to use: ByReceptionTimestamp is the default — sample order follows reader arrival. BySourceTimestamp when writer-side timestamps are logically correct (clock-synced cluster, replay scenarios).

Repo: crates/qos/src/policies/destination_order.rs

10 · LatencyBudgetQosPolicy §2.2.3.8 · on Topic/DataReader/DataWriter

Fields: duration: Duration · Default: 0 ns · RxO: offered ≤ requested · Mutable: ✓ yes

When to use: a hint for the transport scheduler — how much time the sample path may take at most. No direct wire effect; more of an optimisation indicator (batching, prioritisation).

Repo: crates/qos/src/policies/latency_budget.rs

Ownership (2)

Who may write? With Exclusive: only the strongest writer is active.

11 · OwnershipQosPolicy §2.2.3.9 · on Topic/DataReader/DataWriter

Fields: kind: OwnershipKind (Shared · Exclusive) · Default: Shared · RxO: offered.kind == requested.kind · Mutable: ✗ no

When to use: Shared allows multiple writers per instance (standard). Exclusive for hot-standby failover — only the writer with the highest OwnershipStrength is active (see Cookbook §3).

Repo: crates/qos/src/policies/ownership.rs

12 · OwnershipStrengthQosPolicy §2.2.3.10 · on DataWriter

Fields: value: i32 · Default: 0 · RxO: none · Mutable: ✓ yes

When to use: strength voting with Ownership=Exclusive. Highest value wins. The mutable setter allows dynamic re-election (heartbeat-based promote/demote).

Repo: crates/qos/src/policies/ownership_strength.rs

History & resources (2)

How many samples are kept in the writer/reader cache?

13 · HistoryQosPolicy §2.2.3.18 · on Topic/DataReader/DataWriter

Fields: kind: HistoryKind (KeepLast · KeepAll) · depth: i32 · Default: KeepLast(1) · RxO: none · Mutable: ✗ no

When to use: KeepLast(N) for a sliding window (oldest get overwritten). KeepAll for an audit-log pattern — keep everything up to ResourceLimits. With KeepAll + Reliable: the writer blocks when the cache is full (see Reliability.max_blocking_time).

Repo: crates/qos/src/policies/history.rs

14 · ResourceLimitsQosPolicy §2.2.3.19 · on Topic/DataReader/DataWriter

Fields: max_samples: i32 · max_instances: i32 · max_samples_per_instance: i32 (UNLIMITED = -1) · Default: 1000 / 10 / 100 · RxO: none · Mutable: ✗ no

When to use: a hard cap on cache allocation. With Reliable + KeepAll reaching the cache limit blocks the writer (OutOfResources). Set it to match the expected data rate and reader lag.

Repo: crates/qos/src/policies/resource_limits.rs

Presentation (1)

15 · PresentationQosPolicy §2.2.3.6 · on Publisher/Subscriber

Fields: access_scope: PresentationAccessScope (Instance · Topic · Group) · coherent_access: bool · ordered_access: bool · Default: Instance/false/false · RxO: offered.scope ≥ requested.scope, coherent/ordered offered ⊇ requested · Mutable: ✗ no

When to use: coherent sets group samples into an atomically visible unit (all or none). Ordered sets guarantee sample order across multiple topics of a group (multi-topic transaction). Higher scopes (Topic, Group) are more expensive and require coordination overhead.

Repo: crates/qos/src/policies/presentation.rs

Partition (1)

16 · PartitionQosPolicy §2.2.3.13 · on Publisher/Subscriber

Fields: names: Vec<String> (POSIX fnmatch glob patterns allowed) · Default: [""] (default partition) · RxO: at least one partition must match between writer and reader · Mutable: ✓ yes

When to use: logical tenant separation within the same domain (e.g. customer-A/odom vs. customer-B/odom). Glob patterns like customer-* allow dynamic subscriber matching without reconfiguring topics. Important: partition is a match filter, not network isolation — discovery still sees everyone.

Repo: crates/qos/src/policies/partition.rs

Filter & lifespan (2)

Reader-side sample filters (time-based) and writer-side sample expiry.

17 · TimeBasedFilterQosPolicy §2.2.3.12 · on DataReader

Fields: minimum_separation: Duration · Default: 0 ns · RxO: none · Mutable: ✓ yes

When to use: reader-side downsampling. A minimum gap between received samples of the same instance. Saves reader processing CPU on high-frequency topics when the consumer only needs a subset rate.

Repo: crates/qos/src/policies/time_based_filter.rs

18 · LifespanQosPolicy §2.2.3.16 · on Topic/DataWriter

Fields: duration: Duration · Default: INFINITE · RxO: none · Mutable: ✓ yes

When to use: samples older than duration are automatically removed from the cache (writer side, and reader side if TransientLocal). Useful for state topics with "stale data is bad data" semantics (e.g. a setpoint > 30s old = ignore).

Repo: crates/qos/src/policies/lifespan.rs

Entity & lifecycle (3)

Auto-enable behaviour and instance-lifecycle reactions.

19 · EntityFactoryQosPolicy §2.2.3.20 · on Participant/Publisher/Subscriber/DomainParticipantFactory

Fields: autoenable_created_entities: bool · Default: true · RxO: none · Mutable: ✓ yes

When to use: if true, newly created sub-entities are enable'd immediately. If false, the user must call enable() manually — useful to finalise QoS sets before the first discovery beacon.

Repo: crates/qos/src/policies/entity_factory.rs

20 · WriterDataLifecycleQosPolicy §2.2.3.21 · on DataWriter

Fields: autodispose_unregistered_instances: bool · Default: true · RxO: none · Mutable: ✓ yes

When to use: if true, unregister_instance() is implicitly treated as dispose() (the reader sees NOT_ALIVE_DISPOSED). If false, only NOT_ALIVE_NO_WRITERS without a dispose marker.

Repo: crates/qos/src/policies/data_lifecycle.rs

21 · ReaderDataLifecycleQosPolicy §2.2.3.22 · on DataReader

Fields: autopurge_nowriter_samples_delay: Duration · autopurge_disposed_samples_delay: Duration · Default: INFINITE / INFINITE · RxO: none · Mutable: ✓ yes

When to use: reader-side auto-purge timers for unused/disposed samples. Prevents the reader cache from filling up with old/dead instances. Default INFINITE = never auto-purge.

Repo: crates/qos/src/policies/data_lifecycle.rs

Transport (1)

22 · TransportPriorityQosPolicy §2.2.3.15 · on Topic/DataWriter

Fields: value: i32 · Default: 0 · RxO: none · Mutable: ✓ yes

When to use: a hint for the transport-layer scheduler (e.g. a UDP DSCP tag, TSN stream priority). Implementation-specific — a value with no wire guarantee. Important in mixed-critical setups (control + telemetry on the same link).

Repo: crates/qos/src/policies/transport_priority.rs · evaluated in the transport layer: zerodds-transport