// SPDX-License-Identifier: MIT // SpatialDDS Specification 1.5 (© Open AR Cloud Initiative)
3. IDL Profiles
The SpatialDDS IDL bundle defines the schemas used to exchange real-world spatial data over DDS. It is organized into complementary profiles: Core, which provides the backbone for pose graphs, geometry, and geo-anchoring; Discovery, which enables lightweight announcements of services, coverage, anchors, and content; and Anchors, which adds support for publishing and updating sets of durable world-locked anchors. Together, these profiles give devices, services, and applications a common language for building, sharing, and aligning live world models—while staying codec-agnostic, forward-compatible, and simple enough to extend for domains such as robotics, AR/XR, IoT, and smart cities.
See §2 Conventions for global normative rules.
3.1 IDL Profile Versioning & Negotiation (Normative)
SpatialDDS uses semantic versioning tokens of the form name@MAJOR.MINOR.
- MAJOR increments for breaking schema or wire changes.
- MINOR increments for additive, compatible changes.
Identifier conventions: Profile tokens use name@MAJOR.MINOR (e.g., core@1.5). Module identifiers use spatial.<profile>/MAJOR.MINOR (e.g., spatial.core/1.5). These are canonically related: core@1.5 ⇔ spatial.core/1.5.
Participants advertise supported ranges via caps.supported_profiles (discovery) and manifest capabilities blocks. Consumers select the highest compatible minor within any shared major. Backward-compatibility clauses from 1.3 are retired; implementations only negotiate within their common majors. SpatialDDS 1.5 uses a single canonical quaternion order (x, y, z, w) across manifests, discovery payloads, and IDL messages.
3.2 Core SpatialDDS
The Core profile defines the essential building blocks for representing and sharing a live world model over DDS. It focuses on a small, stable set of concepts: pose graphs, 3D geometry tiles, blob transport for large payloads, and geo-anchoring primitives such as anchors, transforms, and simple GeoPoses. The design is deliberately lightweight and codec-agnostic: tiles reference payloads but do not dictate mesh formats, and anchors define stable points without tying clients to a specific localization method. All quaternion fields follow the OGC GeoPose component order (x, y, z, w) so orientation data can flow between GeoPose-aware systems without reordering. By centering on graph + geometry + anchoring, the Core profile provides a neutral foundation that can support diverse pipelines across robotics, AR, IoT, and smart city contexts.
GNSS diagnostics (Normative): NavSatStatus is a companion to GeoPose that carries GNSS receiver diagnostics (fix type, DOP, satellite count, ground velocity) on a parallel topic. It is published alongside GNSS-derived GeoPoses and MUST NOT be used to annotate non-GNSS localization outputs.
NavSatStatus Topic (Normative): NavSatStatus SHOULD be published on the topic spatialdds/geo/<gnss_id>/navsat_status/v1, where <gnss_id> matches the @key gnss_id in the struct and identifies the GNSS receiver. NavSatStatus SHOULD use the same QoS profile as the associated GeoPose stream. Producers publishing GNSS-derived GeoPoses SHOULD co-publish NavSatStatus at the same cadence. NavSatStatus is not a registered discovery type and does not require a TopicMeta entry in Announce.topics[].
Blob Reassembly (Normative)
Blob payloads are transported as BlobChunk sequences. Consumers MUST be prepared for partial delivery and SHOULD apply a per-blob timeout window based on expected rate and total_chunks.
- Timeout guidance: Consumers SHOULD apply a per-blob timeout of at least
2 × (total_chunks / expected_rate)seconds when an expected rate is known. - Failure handling: If all chunks have not arrived within this window under RELIABLE QoS, the consumer SHOULD discard the partial blob and MAY re-request it via
SnapshotRequest. - BEST_EFFORT behavior: Under BEST_EFFORT QoS, consumers MUST NOT assume complete delivery and SHOULD treat blobs as opportunistic.
- Memory pressure: Consumers MAY discard partial blobs early under memory pressure, but MUST NOT treat them as valid payloads.
Frame Identifiers (Reference)
SpatialDDS uses structured frame references via the FrameRef { uuid, fqn } type.
See Appendix G Frame Identifiers (Informative Reference) for the complete definition and naming rules.
Each Transform expresses a pose that maps coordinates from the from frame into the to frame (parent → child).
3.3 Discovery
Discovery is how SpatialDDS peers find each other, advertise what they publish, and select compatible streams. Deployments can expose discovery using a DDS binding (query/announce on well-known topics), an HTTP binding (a REST endpoint that accepts spatial queries and returns service manifests), or both. HTTP resolvers may act as gateways to a DDS bus without changing the client-facing contract.
How it works (at a glance)
- Announce — each node periodically publishes an announcement with capabilities and topics (DDS), or registers its manifest with an HTTP discovery service.
- Query — clients publish spatial filters on the DDS bus (
CoverageQuery), or issue an HTTP search request to/.well-known/spatialdds/search. - Select — clients subscribe to chosen topics; negotiation picks the highest compatible minor per profile.
3.3.0 Discovery Layers & Bootstrap (Normative)
SpatialDDS distinguishes three discovery layers:
- Layer 1 — Network Bootstrap: how a device discovers that a SpatialDDS deployment exists and obtains initial connection parameters. This is transport and access-network dependent (mDNS, Geospatial DNS-SD, QR codes, HTTPS well-known path).
- Layer 1.5 — HTTP Discovery (optional): how a device, without joining a DDS domain, queries for services by spatial region via an HTTP endpoint. This is the bridge between bootstrap and on-bus discovery for Internet-scale deployments where the client and service may be on different networks.
- Layer 2 — On-Bus Discovery: how a device, once connected to a DDS domain, discovers services, coverage, and streams via DDS topics. This is what the Discovery profile's IDL types define.
Layer 1 mechanisms deliver a Bootstrap Manifest that provides the parameters needed to transition to Layer 1.5 or Layer 2. Layer 1.5 delivers Service Manifests (§8.2.3) that provide the DDS connection parameters needed to transition to Layer 2. Clients MAY skip Layer 1.5 if Layer 1 already provides sufficient connection information (e.g., local mDNS bootstrap on the venue LAN).
Bootstrap Manifest (Normative)
A bootstrap manifest is a small JSON document resolved by Layer 1 mechanisms:
{
"spatialdds_bootstrap": "1.5",
"domain_id": 42,
"initial_peers": [
"udpv4://192.168.1.100:7400",
"udpv4://10.0.0.50:7400"
],
"partitions": ["venue/museum-west"],
"discovery_topic": "spatialdds/discovery/announce/v1",
"manifest_uri": "spatialdds://museum.example.org/west/service/discovery",
"auth": {
"method": "none"
}
}
Field definitions
| Field | Required | Description |
|---|---|---|
spatialdds_bootstrap |
REQUIRED | Bootstrap schema version (e.g., "1.5") |
domain_id |
REQUIRED | DDS domain ID to join |
initial_peers |
REQUIRED | One or more DDS peer locators for initial discovery |
partitions |
OPTIONAL | DDS partition(s) to join. Empty or absent means default partition. |
discovery_topic |
OPTIONAL | Override for the well-known announce topic. Defaults to spatialdds/discovery/announce/v1. |
manifest_uri |
OPTIONAL | A spatialdds:// URI for the deployment's root manifest. |
auth |
OPTIONAL | Authentication hint. method is one of "none", "dds-security", "token". |
Normative rules
domain_idMUST be a valid DDS domain ID (0–232 per the RTPS specification; higher values may require non-standard configuration).initial_peersMUST contain at least one locator. Locator format follows the DDS implementation's peer descriptor syntax.- Consumers SHOULD attempt all listed peers and use the first that responds.
- The bootstrap manifest is a discovery aid, not a security boundary. Deployments requiring authentication MUST use DDS Security or an equivalent transport-level mechanism.
Well-Known HTTPS Path (Normative)
Clients MAY fetch the bootstrap manifest from:
https://{authority}/.well-known/spatialdds
The response MUST be application/json using the bootstrap manifest schema. Servers SHOULD set Cache-Control headers appropriate to their deployment (e.g., max-age=300).
Note: Three well-known paths are defined under the /.well-known/spatialdds namespace. The bootstrap path (/.well-known/spatialdds) returns a Bootstrap Manifest. The resolver metadata path (/.well-known/spatialdds-resolver) returns resolver metadata for URI resolution (§7.5.2). The search path (/.well-known/spatialdds/search) accepts spatial discovery queries and returns matching service manifests. All three serve distinct functions and MAY coexist on the same authority.
HTTP Discovery Search Binding (Normative)
The HTTP discovery search binding allows clients to query for SpatialDDS services by spatial region without joining a DDS domain. It mirrors the on-bus CoverageQuery / CoverageResponse pattern over HTTP, using the same coverage semantics (§3.3.4) and returning standard service manifests (§8.2.3).
Endpoint:
POST https://{authority}/.well-known/spatialdds/search
Content-Type: application/json
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
coverage |
array of CoverageElement | REQUIRED | One or more spatial regions of interest. Uses the same CoverageElement schema as CoverageQuery.coverage — type, bbox, aabb, crs, frame_ref, global. |
filter |
CoverageFilter | OPTIONAL | Structured filter matching CoverageFilter — type_in, qos_profile_in, module_id_in. Empty arrays mean "match all." |
kind |
array of string | OPTIONAL | Filter by service kind: "VPS", "MAPPING", "RELOCAL", "SEMANTICS", "STORAGE", "CONTENT", "ANCHOR_REGISTRY", "OTHER". Empty or absent means all kinds. |
geohash |
string | OPTIONAL | Geohash string (3–7 characters). Shorthand for an earth-fixed bbox query. When present, the server expands the geohash to its bounding box and treats it as an additional coverage element. |
max_results |
integer | OPTIONAL | Maximum number of results to return (default: server-defined, recommended ≤100). |
page_token |
string | OPTIONAL | Opaque token from a previous response for pagination. |
Minimal example — query by geohash:
POST /.well-known/spatialdds/search
Content-Type: application/json
{
"geohash": "9q8yy"
}
Full example — query by bbox with service kind filter:
POST /.well-known/spatialdds/search
Content-Type: application/json
{
"coverage": [
{
"type": "bbox",
"crs": "EPSG:4979",
"bbox": [-122.420, 37.785, -122.405, 37.800]
}
],
"kind": ["VPS"],
"filter": {
"type_in": ["geopose"],
"qos_profile_in": [],
"module_id_in": []
},
"max_results": 10
}
Response body:
On success, the server MUST return HTTP 200 OK with Content-Type: application/json. The body is a JSON object:
| Field | Type | Required | Description |
|---|---|---|---|
results |
array of Manifest | REQUIRED | Array of service manifests (§8.2.3 schema). Empty array if no services match. |
next_page_token |
string | OPTIONAL | Opaque token for fetching the next page. Absent or empty string means no more results. |
{
"results": [
{
"id": "spatialdds://acme-vps.example/sf-downtown/service/vps-main",
"profile": "spatial.manifest@1.5",
"rtype": "service",
"service": {
"service_id": "vps-main",
"kind": "VPS",
"name": "SF Downtown Visual Positioning",
"org": "acme-vps.example",
"version": "2025-q4",
"connection": {
"domain_id": 100,
"initial_peers": ["tcpv4://vps.acme-vps.example:7400"],
"partitions": ["sf/downtown"]
},
"topics": [
{ "name": "spatialdds/vps/query/v1", "type": "vps_query", "version": "v1", "qos_profile": "VPS_REQ" },
{ "name": "spatialdds/vps/result/v1", "type": "geopose", "version": "v1", "qos_profile": "VPS_RESP" }
]
},
"coverage": {
"frame_ref": { "uuid": "ae6f0a3e-7a3e-4b1e-9b1f-0e9f1b7c1a10", "fqn": "earth-fixed" },
"has_bbox": true,
"bbox": [-122.420, 37.785, -122.405, 37.800],
"global": false
},
"stamp": { "sec": 1735689600, "nanosec": 0 },
"ttl_sec": 3600
}
],
"next_page_token": ""
}
GET convenience form:
For simple geohash-based queries (e.g., from a Geospatial DNS-SD muri), servers MUST also support:
GET https://{authority}/.well-known/spatialdds/search?geohash={geohash}
GET https://{authority}/.well-known/spatialdds/search?geohash={geohash}&kind={kind}
The GET form is equivalent to a POST with {"geohash": "{geohash}"} (and optional kind filter). The response format is identical.
Spatial matching semantics:
The server evaluates spatial overlap using the same intersects predicate as the on-bus CoverageQuery: a service matches if its coverage region intersects any of the requested coverage elements. When geohash is provided, the server expands it to its bounding box and applies the same intersection test. Services with coverage.global == true match all queries.
Error handling:
| Status | Meaning |
|---|---|
200 |
Success. Body contains results (may be empty). |
400 |
Malformed request (invalid geohash, missing coverage, bad JSON). |
401 / 403 |
Authentication required or insufficient. |
404 |
The /.well-known/spatialdds/search endpoint is not supported by this authority. |
429 |
Rate limited. Client SHOULD retry with exponential backoff. |
5xx |
Server error. |
Normative rules:
- Servers implementing the HTTP discovery search binding MUST support the POST form. The GET convenience form is also REQUIRED for interoperability with the Geospatial DNS-SD binding.
- The response MUST use the §8.2.3 service manifest schema for each result. Clients MUST be able to extract
service.connectionfrom any result and use it to join the service's DDS domain. - Servers MUST respect the Coverage Model (§3.3.4) when evaluating spatial overlap:
coverage_frame_ref,bbox,aabb, andglobalflags all apply. - Servers SHOULD set
Cache-Controlheaders appropriate to the deployment. Responses to geohash queries at precision 5 (city-district scale) MAY be cached for 60–300 seconds. - Pagination follows the same contract as on-bus
CoverageResponse: tokens are opaque, results are best-effort, and an emptynext_page_tokenmeans no further pages. - Servers MAY return results for all resource types (services, content, anchor sets) or restrict to services only. When
kindis absent, servers SHOULD return services only unless the client explicitly requests other types via thefilterfield. - The HTTP search endpoint and the on-bus
CoverageQueryare independent mechanisms. Servers MAY implement one or both. Servers that implement both SHOULD return consistent results for equivalent queries. - HTTPS with TLS is REQUIRED. Authentication follows the same rules as §7.5.4.
Relationship to other well-known paths:
| Path | Function | Returns |
|---|---|---|
/.well-known/spatialdds |
Bootstrap manifest | Bootstrap Manifest (domain_id, peers, partitions) |
/.well-known/spatialdds-resolver |
Resolver metadata | Resolver metadata (https_base, cache_ttl) |
/.well-known/spatialdds/search |
Spatial discovery query | Array of service manifests |
All three paths MAY coexist on the same authority. They serve distinct functions and do not conflict.
Relationship to Geospatial DNS-SD:
The Geospatial DNS-SD binding's muri TXT record value SHOULD point to the search endpoint's GET convenience form:
muri=https://discovery.example.org/.well-known/spatialdds/search?geohash=9q8yy
This directly connects the DNS bootstrap (Layer 1) to HTTP discovery (Layer 1.5) without requiring any intermediate resolution step.
DNS-SD Binding (Normative)
DNS-SD is the recommended first binding for local bootstrap.
Service type: _spatialdds._udp
TXT record keys
| Key | Maps to | Example |
|---|---|---|
ver |
spatialdds_bootstrap |
1.5 |
did |
domain_id |
42 |
part |
partitions (comma-separated) |
venue/museum-west |
muri |
manifest_uri |
spatialdds://museum.example.org/west/service/discovery |
Resolution flow
- Device queries for
_spatialdds._udp.local(mDNS) or_spatialdds._udp.<domain>(wide-area DNS-SD). - SRV record provides host and port for the initial DDS peer.
- TXT record provides domain ID, partitions, and optional manifest URI.
- Device constructs a bootstrap manifest from the SRV + TXT data and joins the DDS domain.
- On-bus Discovery (Layer 2) takes over.
Normative rules
didis REQUIRED in the TXT record.- The SRV target and port MUST resolve to a reachable DDS peer locator.
- If
muriis present, clients SHOULD resolve it after joining the domain to obtain full deployment metadata.
Geospatial DNS-SD Binding (Normative)
The geospatial DNS-SD binding allows a client with a GPS fix to discover SpatialDDS services by encoding its location as a geohash subdomain. This binding targets Internet-scale deployments where clients and services are on different networks.
Subdomain pattern:
_spatialdds._udp.<geohash>.geo.<authority>
where <geohash> is a standard base32 geohash [8] of the client's position and <authority> is the DNS zone hosting the discovery registry.
Geohash precision levels
| Characters | Cell size (approx.) | Typical use |
|---|---|---|
| 3 | ~156 km × 156 km | Metro region / country subdivision |
| 4 | ~39 km × 20 km | City |
| 5 | ~5 km × 5 km | District / neighborhood |
| 6 | ~1.2 km × 0.6 km | Block / venue cluster |
| 7 | ~153 m × 153 m | Single venue |
Clients SHOULD query at precision 5 (neighborhood scale) by default. Finer precision (6–7) is appropriate when the client has high-accuracy GNSS (RTK or similar).
TXT record keys
The TXT record uses the same key set as the local DNS-SD binding, with one addition:
| Key | Required | Description |
|---|---|---|
ver |
REQUIRED | Bootstrap schema version (e.g., 1.5) |
did |
OPTIONAL | DDS domain ID. OPTIONAL because the geospatial binding's primary role is to hand off to an HTTP discovery service via muri, not to provide direct DDS connection. |
muri |
REQUIRED | HTTPS URL or spatialdds:// URI for the discovery service, with the geohash passed as a query parameter or path segment. |
part |
OPTIONAL | DDS partition hint (comma-separated). |
Resolution flow
- Client obtains its position (GPS, network location, or manual entry).
- Client computes the base32 geohash at precision 5 (e.g.,
37.7749°N, 122.4194°W→9q8yy). - Client issues a DNS TXT query for
_spatialdds._udp.9q8yy.geo.<authority>. - If the query returns
NXDOMAIN, the client truncates to precision 4 (9q8y) and retries. This continues down to precision 3. If precision 3 also returnsNXDOMAIN, bootstrap fails for this authority. - On success, the client extracts
murifrom the TXT record. - Client issues an HTTPS GET to the
muriURL, which returns one or more SpatialDDS service manifests (§8.2.3) for services covering that geohash cell. - Client selects a service and connects using the
connectionhints in the manifest.
Example DNS records (Route 53 / authoritative DNS)
;; San Francisco downtown (~5 km² cell)
_spatialdds._udp.9q8yy.geo.spatialdds.example.org. TXT "ver=1.5" "muri=https://discovery.spatialdds.example.org/v1/services?geohash=9q8yy"
;; San Francisco marina district
_spatialdds._udp.9q8yk.geo.spatialdds.example.org. TXT "ver=1.5" "muri=https://discovery.spatialdds.example.org/v1/services?geohash=9q8yk"
;; London Soho
_spatialdds._udp.gcpvj.geo.spatialdds.example.org. TXT "ver=1.5" "muri=https://discovery.spatialdds.example.org/v1/services?geohash=gcpvj"
Example HTTPS response (from the muri endpoint)
The discovery service returns an array of standard SpatialDDS service manifests (§8.2.3):
[
{
"id": "spatialdds://provider-a.example/sf-downtown/service/vps-main",
"profile": "spatial.manifest@1.5",
"rtype": "service",
"service": {
"service_id": "vps-main",
"kind": "VPS",
"name": "SF Downtown Visual Positioning",
"org": "provider-a.example",
"connection": {
"domain_id": 100,
"initial_peers": ["tcpv4://vps.provider-a.example:7400"]
},
"topics": [
{ "name": "spatialdds/vps/pose/v1", "type": "geopose", "version": "v1", "qos_profile": "POSE_RT" }
]
},
"coverage": {
"frame_ref": { "uuid": "ae6f0a3e-7a3e-4b1e-9b1f-0e9f1b7c1a10", "fqn": "earth-fixed" },
"has_bbox": true,
"bbox": [-122.420, 37.785, -122.405, 37.800],
"global": false
},
"stamp": { "sec": 1714070400, "nanosec": 0 },
"ttl_sec": 3600
}
]
DNS zone delegation for federated operation
Operators MAY delegate geohash-prefixed subdomains to independent authorities, enabling federated discovery where different organizations manage different geographic regions:
;; Top-level authority delegates San Francisco (geohash prefix "9q8") to provider A
9q8.geo.spatialdds.example.org. NS ns1.provider-a.example.
;; Top-level authority delegates London (geohash prefix "gcpv") to provider B
gcpv.geo.spatialdds.example.org. NS ns1.provider-b.example.
Each delegate manages all geohash cells under its prefix using standard DNS zone management. This mirrors the hierarchical structure of the DNS itself.
Normative rules
muriis REQUIRED in the TXT record for geospatial bindings. The geospatial binding's purpose is to locate an HTTP discovery endpoint; direct DDS connection viadid+ SRV alone is NOT sufficient because the client's network path to the DDS domain is not implied by geographic proximity.veris REQUIRED and MUST match the local DNS-SD binding's version key.- The geohash MUST be a valid base32 geohash [8] of 3–7 characters. Clients MUST reject TXT records found under geohash subdomains shorter than 3 characters or longer than 7 characters.
- The fallback-to-shorter-prefix algorithm MUST NOT retry below precision 3 to avoid excessive DNS queries.
- The
muriendpoint MUST returnapplication/jsoncontaining either a single service manifest (§8.2.3) or a JSON array of service manifests. An empty array indicates no services in the requested cell. - DNS operators SHOULD populate records at precision 5 for general use. Finer precision (6–7) MAY be added for dense urban areas with multiple providers per neighborhood.
- Clients MUST validate the
coveragefield in returned manifests against their actual position. A geohash cell is an approximation; the manifest'sbboxorcoverageelements are authoritative for determining whether a service actually covers the client's location. - DNS TTLs SHOULD be set appropriately for the deployment's dynamism. Static deployments (fixed VPS infrastructure) MAY use TTLs of 3600 seconds or more. Dynamic deployments (pop-up events, temporary coverage) SHOULD use shorter TTLs (60–300 seconds).
Relationship to local DNS-SD
The geospatial and local DNS-SD bindings serve different deployment scales and MAY coexist:
| Binding | Network scope | Client prerequisite | Primary output |
|---|---|---|---|
| Local DNS-SD (mDNS) | Same LAN | WiFi connection | DDS domain_id + peer locator |
| Local DNS-SD (wide-area) | Known authority | Domain name (from QR, app config) | DDS domain_id + peer locator |
| Geospatial DNS-SD | Internet | GPS fix | HTTP discovery URL → service manifests |
A client arriving at a venue MAY try local mDNS first (fastest, no Internet dependency), fall back to geospatial DNS if mDNS yields no results (works over cellular, finds services across networks), and finally fall back to the HTTPS well-known path if a venue domain is available.
Other Bootstrap Mechanisms (Informative)
- DHCP: vendor-specific option carrying a URL to the bootstrap manifest.
- QR / NFC / BLE beacons: encode a
spatialdds://URI or direct URL to the bootstrap manifest. - Mobile / MEC: edge discovery APIs provide a URL to the bootstrap manifest.
Complete Bootstrap Chain (Informative)
Path A — Local bootstrap (same LAN)
Access Network Bootstrap DDS Domain On-Bus Discovery
│ │ │ │
│ WiFi/5G/BLE/QR │ │ │
├─────────────────────► │ │ │
│ │ DNS-SD (mDNS) / │ │
│ │ .well-known / QR │ │
│ ├─────────────────────► │ │
│ │ Bootstrap Manifest │ │
│ │ (domain_id, peers, │ │
│ │ partitions) │ │
│ │ ◄─────────────────────┤ │
│ │ │ Join DDS domain │
│ │ ├─────────────────────► │
│ │ │ Subscribe to │
│ │ │ .../announce/v1 │
│ │ │ Receive Announce │
│ │ │ Issue CoverageQuery │
│ │ │ Select streams │
│ │ │ Begin operation │
Path B — Internet bootstrap (cross-network, geospatial)
GPS Fix Geo DNS-SD HTTP Discovery DDS Domain
│ │ │ │
│ Compute geohash │ │ │
├─────────────────────►│ │ │
│ │ TXT query: │ │
│ │ _spatialdds._udp │ │
│ │ .<geohash>.geo.<auth> │ │
│ ├──────────────────────►│ │
│ │ TXT: muri=https://… │ │
│ │◄──────────────────────┤ │
│ │ │ │
│ HTTPS GET muri │ │ │
├──────────────────────────────────────────────►│ │
│ │ │ Service manifest(s) │
│ │ │ (domain_id, peers, │
│ │ │ topics, coverage) │
│◄──────────────────────────────────────────────┤ │
│ │ │ │
│ Select service, connect via TCP/TLS │ │
├──────────────────────────────────────────────────────────────────────►│
│ │ │ Begin operation │
Key messages (abridged IDL)
(Abridged IDL — see Appendix B for full definitions.)
// ABRIDGED — see Appendix B for normative definitions
// Message shapes shown for orientation only
@extensibility(APPENDABLE) struct ProfileSupport { string name; uint32 major; uint32 min_minor; uint32 max_minor; boolean preferred; }
@extensibility(APPENDABLE) struct Capabilities { sequence<ProfileSupport,64> supported_profiles; sequence<string,32> preferred_profiles; sequence<FeatureFlag,64> features; }
@extensibility(APPENDABLE) struct TopicMeta { string name; string type; string version; string qos_profile; float32 target_rate_hz; uint32 max_chunk_bytes; }
@extensibility(APPENDABLE) struct Announce {
// ... node identity, endpoints ...
Capabilities caps; // profiles, preferences, features
sequence<TopicMeta,128> topics; // typed topics offered by this node
}
@extensibility(APPENDABLE) struct CoverageFilter {
sequence<string,16> type_in;
sequence<string,16> qos_profile_in;
sequence<string,16> module_id_in;
}
@extensibility(APPENDABLE) struct CoverageQuery {
// minimal illustrative fields
boolean has_filter;
CoverageFilter filter; // preferred in 1.5
string expr; // deprecated in 1.5; Appendix F.X grammar
string reply_topic; // topic to receive results
string query_id; // correlate request/response
}
The expression syntax is retained for legacy deployments and defined in Appendix F.X; `expr` is deprecated in 1.5 in favor of `filter`.
@extensibility(APPENDABLE) struct CoverageResponse {
string query_id;
sequence<Announce,256> results;
string next_page_token;
}
Minimal examples (JSON)
Announce (capabilities + topics)
{
"caps": {
"supported_profiles": [
{ "name": "core", "major": 1, "min_minor": 0, "max_minor": 3 },
{ "name": "discovery", "major": 1, "min_minor": 1, "max_minor": 2 }
],
"preferred_profiles": ["discovery@1.2"],
"features": ["blob.crc32"]
},
"topics": [
{ "name": "spatialdds/perception/cam_front/video_frame/v1", "type": "video_frame", "version": "v1", "qos_profile": "VIDEO_LIVE" },
{ "name": "spatialdds/perception/radar_1/radar_detection/v1", "type": "radar_detection", "version": "v1", "qos_profile": "RADAR_RT" },
{ "name": "spatialdds/perception/radar_1/radar_tensor/v1", "type": "radar_tensor", "version": "v1", "qos_profile": "RADAR_RT" }
]
}
Query + Response
{
"query_id": "q1",
"has_filter": true,
"filter": {
"type_in": ["radar_detection", "radar_tensor"],
"qos_profile_in": [],
"module_id_in": ["spatial.discovery/1.4", "spatial.discovery/1.5"]
},
"expr": "",
"reply_topic": "spatialdds/discovery/response/q1",
"stamp": { "sec": 1714070400, "nanosec": 0 },
"ttl_sec": 30
}
{ "query_id": "q1", "results": [ { "caps": { "supported_profiles": [ { "name": "discovery", "major": 1, "min_minor": 1, "max_minor": 2 } ] }, "topics": [ { "name": "spatialdds/perception/radar_1/radar_detection/v1", "type": "radar_detection", "version": "v1", "qos_profile": "RADAR_RT" }, { "name": "spatialdds/perception/radar_1/radar_tensor/v1", "type": "radar_tensor", "version": "v1", "qos_profile": "RADAR_RT" } ] } ], "next_page_token": "" }
Norms & filters
- Announces MUST include
caps.supported_profiles; peers choose the highest compatible minor within a shared major. - Each advertised topic MUST declare
name,type,version, andqos_profileper Topic Identity (§3.3.1); optional throughput hints (target_rate_hz,max_chunk_bytes) are additive. - Discovery topics SHALL restrict
typeto {geometry_tile,video_frame,radar_detection,radar_tensor,seg_mask,desc_array,rf_beam,radio_scan},versiontov1, andqos_profileto {GEOM_TILE,VIDEO_LIVE,RADAR_RT,SEG_MASK_RT,DESC_BATCH,RF_BEAM_RT,RADIO_SCAN_RT}. caps.preferred_profilesis an optional tie-breaker within the same major.caps.featurescarries namespaced feature flags; unknown flags MUST be ignored.FeatureFlagis a struct (not a raw string) to allow future appended fields (e.g., version or parameters) without breaking wire compatibility.CoverageQuery.filterprovides structured matching fortype,qos_profile, andmodule_id.- Empty sequences in
CoverageFiltermean “match all” for that field. - When multiple filter fields are populated, they are ANDed; a result MUST match at least one value in every non-empty sequence.
- Version range matching stays in profile negotiation (
supported_profileswithmin_minor/max_minor), not in coverage queries. CoverageQuery.expris deprecated in 1.5. Ifhas_filteris true, responders MUST ignoreexpr.- Responders page large result sets via
next_page_token; every response MUST echo the caller’squery_id.
Pagination Contract (Normative)
- Opacity. Page tokens are opaque strings produced by the responder. Consumers MUST NOT parse, construct, or modify them.
- Consistency. Results are best-effort. Pages may include duplicates or miss nodes that arrived/departed between pages. Consumers SHOULD deduplicate by
service_id. - Expiry. Responders SHOULD honor page tokens for at least
ttl_secseconds from the originating query’sstamp. After expiry, responders MAY return an empty result set rather than an error. - Termination. An empty string in
next_page_tokenmeans no further pages remain. - Page size. Responders choose page size. Consumers MUST accept any non-zero page size.
Announce Lifecycle (Normative)
- Departure: A node that leaves the bus gracefully SHOULD publish a
Departmessage. Consumers MUST remove the correspondingservice_idfrom their local directory upon receivingDepart.Departdoes not replace TTL-based expiry. - Staleness: Consumers SHOULD discard Announce samples where
now - stamp > 2 * ttl_sec. - Re-announce cadence: Producers SHOULD re-announce at intervals no greater than
ttl_sec / 2to prevent premature expiry. - Rate limiting: Producers SHOULD NOT re-announce more frequently than once per second unless capabilities, coverage, or topics have changed. Consumers MAY rate-limit processing per
service_id.
Well-Known Discovery Topics (Normative)
| Message Type | Topic Name |
|---|---|
Announce |
spatialdds/discovery/announce/v1 |
Depart |
spatialdds/discovery/depart/v1 |
CoverageQuery |
spatialdds/discovery/query/v1 |
CoverageHint |
spatialdds/discovery/coverage_hint/v1 |
ContentAnnounce |
spatialdds/discovery/content/v1 |
CoverageResponse uses the reply_topic specified in the originating CoverageQuery.
QoS defaults for discovery topics
| Topic | Reliability | Durability | History |
|---|---|---|---|
announce |
RELIABLE | TRANSIENT_LOCAL | KEEP_LAST(1) per key |
depart |
RELIABLE | VOLATILE | KEEP_LAST(1) per key |
query |
RELIABLE | VOLATILE | KEEP_ALL |
coverage_hint |
BEST_EFFORT | VOLATILE | KEEP_LAST(1) per key |
content |
RELIABLE | TRANSIENT_LOCAL | KEEP_LAST(1) per key |
CoverageResponse reply topic QoS (Normative)
The writer for reply_topic SHOULD use RELIABLE, VOLATILE, KEEP_ALL.
The querier SHOULD create a matching reader before publishing the CoverageQuery.
Discovery trust (Normative)
ANNOUNCE messages provide discovery convenience and are not, by themselves, authoritative. Clients MUST apply the Security Model requirements in §2.7 before trusting advertised URIs, topics, or services.
Asset references
Discovery announcements and manifests share a single AssetRef structure composed of URI, media type, integrity hash, and optional MetaKV metadata bags. AssetRef and MetaKV are normative types for asset referencing in the Discovery profile.
auth_hint (Normative)
auth_hint provides a machine-readable hint describing how clients can authenticate and authorize access to the service or resolve associated resources. auth_hint does not replace deployment policy; clients may enforce stricter requirements than indicated.
- If
auth_hintis empty or omitted, it means “no authentication hint provided.” Clients MUST fall back to deployment policy (e.g., DDS Security configuration, trusted network assumptions, or authenticated manifest retrieval). - If
auth_hintis present, it MUST be interpreted as one or more auth URIs encoded as a comma-separated list.
Grammar (normative):
auth_hint := auth-uri ("," auth-uri)*
auth-uri := scheme ":" scheme-specific
Required schemes (minimum set):
- ddssec: indicates that the DDS transport uses OMG DDS Security (governance/permissions) for authentication and access control.
- Example: ddssec:profile=default
- Example: ddssec:governance=spatialdds://auth.example/…/governance.xml;permissions=spatialdds://auth.example/…/permissions.xml
- oauth2: indicates OAuth2-based access for HTTP(S) resolution or service APIs.
- Example: oauth2:issuer=https://auth.example.com;aud=spatialdds;scope=vps.localize
- mtls: indicates mutual TLS for HTTP(S) resolution endpoints.
- Example: mtls:https://resolver.example.com
Client behavior (normative):
- A client MUST treat auth_hint as advisory configuration and MUST still validate the authenticity of the service/authority via a trusted mechanism (DDS Security identity or authenticated artifact retrieval).
- If the client does not support any scheme listed in auth_hint, it MUST fail gracefully and report “unsupported authentication scheme.”
Examples (informative):
- auth_hint="ddssec:profile=city-austin"
- auth_hint="ddssec:governance=spatialdds://city.example/…/gov.xml,oauth2:issuer=https://auth.city.example;aud=spatialdds;scope=catalog.read"
What fields mean (quick reference)
| Field | Use |
|---|---|
caps.supported_profiles |
Version ranges per profile. Peers select the highest compatible minor within a shared major. |
caps.preferred_profiles |
Optional tie-breaker hint (only within a major). |
caps.features |
Optional feature flags (namespaced strings). Unknown flags can be ignored. |
topics[].type / version / qos_profile |
Topic Identity keys used to filter and match streams; see the allowed sets above. |
reply_topic, query_id |
Allows asynchronous, paged responses and correlation. |
Practical notes
- Announce messages stay small and periodic; re-announce whenever capabilities, coverage, or topics change.
- Queries are stateless filters. Responders may page through results; clients track
next_page_tokenuntil empty. - Topic names follow
spatialdds/<domain>/<stream>/<type>/<version>per §3.3.1; filter bytypeandqos_profileinstead of parsing payloads. - Negotiation is automatic once peers see each other’s
supported_profiles; emit diagnostics likeNO_COMMON_MAJOR(name)when selection fails.
Summary
Discovery keeps the wire simple: nodes publish what they have, clients filter for what they need, and the system converges on compatible versions. Use typed topic metadata to choose streams, rely on capabilities to negotiate versions without additional application-level handshakes, and treat discovery traffic as the lightweight directory for every SpatialDDS deployment.
3.3.1 Topic Naming (Normative)
SpatialDDS topics are identified by a structured name, a type, a version, and a declared Quality-of-Service (QoS) profile. Together these define both what a stream carries and how it behaves on the wire.
Each topic follows this pattern:
spatialdds/<domain>/<stream>/<type>/<version>
| Segment | Meaning | Example |
|----------|----------|----------|
| <domain> | Logical app domain | perception |
| <stream> | Sensor or stream ID | cam_front |
| <type> | Registered data type | video_frame |
| <version> | Schema or message version | v1 |
Example
{
"name": "spatialdds/perception/radar_1/radar_detection/v1",
"type": "radar_detection",
"version": "v1",
"qos_profile": "RADAR_RT"
}
3.3.2 Typed Topics Registry
| Type | Typical Payload | Notes |
|---|---|---|
geometry_tile |
3D tile data (GLB, 3D Tiles) | Large, reliable transfers |
video_frame |
Encoded video/image | Real-time camera streams |
radar_detection |
Per-frame detection set | Structured radar detections |
radar_tensor |
N-D float/int tensor | Raw/processed radar data cube |
rf_beam |
Beam sweep power vectors | Phased-array beam power measurements |
radio_scan |
Per-scan radio observations | WiFi/BLE/UWB/cellular fingerprint observations |
seg_mask |
Binary or PNG mask | Frame-aligned segmentation |
desc_array |
Feature descriptor sets | Vector or embedding batches |
map_meta |
Map lifecycle descriptor | Latched; TRANSIENT_LOCAL |
map_alignment |
Inter-map transform | Latched; TRANSIENT_LOCAL |
map_event |
Map lifecycle event | Lightweight notifications |
spatial_zone |
Named zone definition | Latched; TRANSIENT_LOCAL |
spatial_event |
Spatially-scoped event | Typed alerts and anomalies |
zone_state |
Zone occupancy snapshot | Periodic dashboard feed |
agent_status |
Agent availability advertisement | Latched; TRANSIENT_LOCAL (provisional) |
task_offer |
Agent bid on a task | Volatile offer with TTL (provisional) |
task_assignment |
Coordinator task binding | Latched; TRANSIENT_LOCAL (provisional) |
These registered types ensure consistent topic semantics without altering wire framing. New types can be registered additively through this table or extensions.
Implementations defining custom type and qos_profile values SHOULD follow the naming pattern (myorg.depth_frame, DEPTH_LIVE) and document their DDS QoS mapping.
3.3.3 QoS Profiles
QoS profiles define delivery guarantees and timing expectations for each topic type.
| Profile | Reliability | Ordering | Typical Deadline | Use Case |
|---|---|---|---|---|
GEOM_TILE |
Reliable | Ordered | 200 ms | 3D geometry, large tile data |
VIDEO_LIVE |
Best-effort | Ordered | 33 ms | Live video feeds |
VIDEO_ARCHIVE |
Reliable | Ordered | 200 ms | Replay or stored media |
RADAR_RT |
Partial | Ordered | 20 ms | Real-time radar data (detections or tensors) |
RF_BEAM_RT |
Best-effort | Ordered | 20 ms | Real-time beam sweep data |
RADIO_SCAN_RT |
Best-effort | Ordered | 500 ms | Radio fingerprint scans (WiFi/BLE/UWB) |
SEG_MASK_RT |
Best-effort | Ordered | 33 ms | Live segmentation masks |
DESC_BATCH |
Reliable | Ordered | 100 ms | Descriptor or feature batches |
MAP_META |
Reliable | Ordered | 1000 ms | Map descriptors, alignments, events |
ZONE_META |
Reliable | Ordered | 1000 ms | Zone definitions, zone state |
EVENT_RT |
Reliable | Ordered | 100 ms | Spatial events and alerts |
Notes
- Each topic advertises its
qos_profileduring discovery. - Profiles capture trade-offs between latency, reliability, and throughput.
- Implementations may tune low-level DDS settings, but the profile name is canonical.
- Mixing unrelated data (e.g., radar + video) in a single QoS lane is discouraged.
Discovery and Manifest Integration
Every Announce.topics[] entry and manifest topic reference SHALL include:
- type — one of the registered type values
- version — the schema or message version
- qos_profile — one of the standard or extended QoS names
For each advertised topic, type, version, and qos_profile MUST be present and MUST either match a registered value in this specification or a documented deployment-specific extension.
Consumers use these three keys to match and filter streams without inspecting payload bytes. Brokers and routers SHOULD isolate lanes by (topic, stream_id, qos_profile) to avoid head-of-line blocking.
3.3.4 Coverage Model (Normative)
coverage_frame_refis the canonical frame for an announcement.CoverageElement.frame_refMAY override it, but SHOULD be used sparingly (e.g., mixed local frames). If absent, consumers MUST usecoverage_frame_ref.- When
coverage_eval_timeis present, consumers SHALL evaluate any referenced transforms at that instant before interpretingcoverage_frame_ref. global == truemeans worldwide coverage regardless of regional hints. Producers MAY omitbbox,geohash, orelementsin that case.- When
global == false, producers MAY supply any combination of regional hints; consumers SHOULD treat the union of all regions as the effective coverage. - Manifests MAY provide any combination of
bbox,geohash, andelements. Discovery coverage MAY omitgeohashand rely solely onbboxandaabb. Consumers SHALL treat all hints consistently according to the Coverage Model. - When
has_bbox == true,bboxMUST contain finite coordinates; consumers SHALL reject non-finite values. Whenhas_bbox == false, consumers MUST ignorebboxentirely. Same rules apply tohas_aabbandaabb. - Earth-fixed frames (
fqnrooted atearth-fixed) encode WGS84 longitude/latitude/height. Local frames MUST reference anchors or manifests that describe the transform back to an earth-fixed root (Appendix G). - Discovery announces and manifests share the same coverage semantics and flags.
CoverageQueryresponders SHALL apply these rules consistently when filtering or paginating results. - See §2 Conventions for global normative rules.
Earth-fixed roots and local frames
For global interoperability, SpatialDDS assumes that earth-fixed frames (e.g., WGS84 longitude/latitude/height) form the root of the coverage hierarchy. Local frames (for devices, vehicles, buildings, or ships) may appear in coverage elements, but if the coverage is intended to be globally meaningful, these local frames must be relatable to an earth-fixed root through declared transforms or manifests.
Implementations are not required to resolve every local frame at runtime, but when they do, the resulting coverage must be interpretable in an earth-fixed reference frame.
Local-Frame Datasets Without GPS (Informative)
Some datasets and deployments operate entirely in a local metric coordinate frame without a known WGS84 origin. In this case:
- The
coverage_frame_refSHOULD reference a local frame (e.g.,fqn = "map/local"), notearth-fixed. GeoPosefields (lat_deg, lon_deg, alt_m) MUST NOT be populated with fabricated values. Use localFrameTransforminstead.- The Anchors profile can bridge local and earth-fixed frames when a GPS fix or survey becomes available.
coverage.globalMUST befalsefor local-frame-only deployments.
This is the expected path for indoor robotics, warehouse automation, and datasets recorded without RTK-GPS.
Coverage Evaluation Pseudocode (Informative)
if coverage.global:
regions = WORLD
else:
regions = union(bbox, geohash, elements[*].aabb)
frame = coverage_frame_ref unless element.frame_ref present
evaluate transforms at coverage_eval_time if present
Implementation Guidance (Non-Normative)
- No change to on-wire framing — this metadata lives at the discovery layer.
- Named QoS profiles simplify cross-vendor interoperability and diagnostics.
- For custom types, follow the same naming pattern and document new QoS presets.
- All examples and tables herein are additive.
Discovery recipe (tying the examples together)
- Announce — the producer sends
Announce(see JSON example above) to advertisecapsandtopics. - CoverageQuery — the consumer issues a
CoverageQuery(see query JSON) to filter by profile, topic type, or QoS. - CoverageResponse — the Discovery producer replies with
CoverageResponse(see response JSON), returning results plus an optionalnext_page_tokenfor pagination.
3.4 Anchors
The Anchors profile provides a structured way to share and update collections of durable, world-locked anchors. While Core includes individual GeoAnchor messages, this profile introduces constructs such as AnchorSet for publishing bundles (e.g., a venue’s anchor pack) and AnchorDelta for lightweight updates. This makes it easy for clients to fetch a set of anchors on startup, stay synchronized through incremental changes, and request full snapshots when needed. Anchors complement VPS results by providing the persistent landmarks that make AR content and multi-device alignment stable across sessions and users.
3.5 Profiles Summary
The complete SpatialDDS IDL bundle is organized into the following profiles:
- Core Profile
Fundamental building blocks: pose graphs, geometry tiles, anchors, transforms, and blob transport. - Discovery Profile Lightweight announce messages plus active query/response bindings for services, coverage areas, anchors, and spatial content or experiences.
- Anchors Profile
Durable anchors and the Anchor Registry, enabling persistent world-locked reference points.
Together, Core, Discovery, and Anchors form the foundation of SpatialDDS, providing the minimal set required for interoperability.
- Extensions
- Sensing Module Family:
sensing.commondefines shared frame metadata, calibration, QoS hints, and codec descriptors. Radar, lidar, and vision profiles inherit those types and layer on their minimal deltas—RadSensorMeta/RadDetectionSet/RadTensorMeta/RadTensorFramefor radar,PointCloud/ScanBlock/return_typefor lidar, andImageFrame/SegMask/FeatureArrayfor vision. The provisionalrf_beamextension addsRfBeamMeta/RfBeamFrame/RfBeamArraySetfor phased-array beam power measurements, and the provisionalradioextension addsRadioSensorMeta/RadioScanfor WiFi/BLE/UWB fingerprint transport. Deployments MAY import the specialized profiles independently but SHOULD declare thesensing.common@1.xdependency when they do. - VIO Profile: Raw and fused IMU and magnetometer samples for visual-inertial pipelines.
- SLAM Frontend Profile: Features, descriptors, and keyframes for SLAM and SfM pipelines.
- Semantics Profile: 2D and 3D detections for AR occlusion, robotics perception, and analytics.
- AR+Geo Profile: GeoPose, frame transforms, and geo-anchoring structures for global alignment and persistent AR content.
- Mapping Profile: Map lifecycle descriptors (
MapMeta), extended multi-source edge types, inter-map alignment transforms (MapAlignment), and lifecycle events for multi-agent map exchange. - Spatial Events Profile: Typed zone definitions (
SpatialZone), spatially-scoped events (SpatialEvent), and periodic zone state summaries (ZoneState) for smart infrastructure and safety monitoring. - Provisional Extensions (Optional)
- Neural Profile: Metadata for neural fields (e.g., NeRFs, Gaussian splats) and optional view-synthesis requests.
- Agent Profile: Generic task and status messages for AI agents and planners.
Together, these profiles give SpatialDDS the flexibility to support robotics, AR/XR, digital twins, IoT, and AI world models—while ensuring that the wire format remains lightweight, codec-agnostic, and forward-compatible.
Profile Matrix (SpatialDDS 1.5)
- spatial.core/1.5
- spatial.discovery/1.5
- spatial.anchors/1.5
- spatial.manifest/1.5 (manifest schema profile for SpatialDDS 1.5)
- spatial.argeo/1.5
- spatial.sensing.common/1.5
- spatial.sensing.rad/1.5
- spatial.sensing.lidar/1.5
- spatial.sensing.vision/1.5
- spatial.slam_frontend/1.5
- spatial.vio/1.5
- spatial.semantics/1.5
- spatial.mapping/1.5
- spatial.events/1.5
- spatial.neural/1.5 (Provisional; Appendix E)
- spatial.agent/1.5 (Provisional; Appendix E)
- spatial.sensing.rf_beam/1.5 (Provisional; Appendix E)
- spatial.sensing.radio/1.5 (Provisional; Appendix E)
spatial.manifest/1.5defines the JSON schema for SpatialDDS manifests, not an IDL module. It does not have a correspondingMODULE_IDdeclaration in the IDL. Provisional profile definitions and examples are specified in Appendix E.
The Sensing module family keeps sensor data interoperable: sensing.common unifies pose stamps, calibration blobs, ROI negotiation, and quality reporting. Radar, lidar, and vision modules extend that base without redefining shared scaffolding, ensuring multi-sensor deployments can negotiate payload shapes and interpret frame metadata consistently.