Skip to main content
Glama

peek_dds_samples

Read-onlyIdempotent

Read recent samples from a raw DDS topic, including builtin discovery records for live participants and endpoints, to inspect DDS state without ROS 2.

Instructions

Peek recent samples on a raw DDS topic as a SampleResult, like sample_messages but read from the DDS layer (works without ROS 2). count defaults to 5, clamped to 50. (a) The builtin discovery topics (DCPSParticipant, DCPSSubscription, DCPSPublication) return structured discovery records: on Cyclone the CURRENT state (one per live participant or endpoint), not recent events (use participant_events); DCPSPublication / DCPSSubscription are the raw data behind list_endpoints. The topic may be /scan, scan or rt/scan. (b) User topics: payload decoding is DISABLED on every backend, so the call returns count 0, empty samples and a note; that does NOT mean the topic is silent. Use list_endpoints for its presence, writers, readers and QoS. A user topic not announced on the bus raises an error. Right after start the call waits up to 3 s for discovery. Read-only by architecture: it cannot publish. Raises an MCP error when no DDS module is active or the topic is not announced. Duration: DDS binding behind the DDS lock, one call at a time; ends within 45 s; busy error if the lock is held (retry).

Input Schema

NameRequiredDescriptionDefault
countNoMessages to return, default 5, at most 50 (`health_check.max_sample_count`): more is capped to 50, negative raises an error. The result's `count` may be lower.
topicYesDDS topic name: bare (`scan`), ROS 2 mangled (`rt/scan`) or a builtin discovery topic (`DCPSParticipant`, `DCPSSubscription`, `DCPSPublication`). Letters, digits, `_`, `/` and `::` only.

Output Schema

NameRequiredDescriptionDefault
noteNoWhy `samples` is empty or limited, when not obvious; else `None`.
rateNoHow the topic delivered the messages, with a verdict; `null` for `peek_dds_samples`. Use `count` >= 10.
countYesNumber of samples in `samples`: fewer than requested when the topic gave fewer, never more than 50 (a larger request is capped to 50).
topicYes
samplesYesThe samples, in backend order.
mode_effectiveYes`live` or `mock` (fixtures).

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed42 schema fields changedv0.8.0
    • removedOutput schema / $defs / ImageSummary
      Removed value: -{
      -  "additionalProperties": false,
      -  "properties": {
      -    "data_length": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Pixel buffer size in bytes (see `data_length_basis`)."
      -    },
      -    "data_length_basis": {
      -      "anyOf": [
      -        {
      -          "enum": [
      -            "payload",
      -            "step_x_height"
      -          ],
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`payload` (counted) or `step_x_height` (array cut, so step times height)."
      -    },
      -    "encoding": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Pixel encoding, e.g. `rgb8`."
      -    },
      -    "frame_id": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`header.frame_id` of the camera."
      -    },
      -    "height": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Pixels."
      -    },
      -    "is_bigendian": {
      -      "anyOf": [
      -        {
      -          "type": "boolean"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Big-endian pixels."
      -    },
      -    "note": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "One sentence when partial; else `null`."
      -    },
      -    "step": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Row length, bytes."
      -    },
      -    "summary_type": {
      -      "const": "image",
      -      "type": "string"
      -    },
      -    "width": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Pixels."
      -    }
      -  },
      -  "required": [
      -    "summary_type",
      -    "frame_id",
      -    "width",
      -    "height",
      -    "encoding",
      -    "step",
      -    "is_bigendian",
      -    "data_length",
      -    "data_length_basis"
      -  ],
      -  "type": "object"
      -}
    • removedOutput schema / $defs / ImuSummary
      Removed value: -{
      -  "additionalProperties": false,
      -  "properties": {
      -    "angular_velocity_norm": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Norm of `angular_velocity`, rad/s."
      -    },
      -    "frame_id": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`header.frame_id` of the IMU."
      -    },
      -    "linear_acceleration_norm": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Norm of `linear_acceleration`, m/s^2."
      -    },
      -    "note": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "One sentence when a value is unusable; else `null`."
      -    },
      -    "orientation_valid": {
      -      "description": "False when the IMU gives no orientation: `roll`, `pitch`, `yaw` are `null`.",
      -      "type": "boolean"
      -    },
      -    "pitch": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Rotation about y, radians."
      -    },
      -    "roll": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Rotation about x, radians."
      -    },
      -    "summary_type": {
      -      "const": "imu",
      -      "type": "string"
      -    },
      -    "yaw": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Rotation about z, radians."
      -    }
      -  },
      -  "required": [
      -    "summary_type",
      -    "frame_id",
      -    "orientation_valid",
      -    "roll",
      -    "pitch",
      -    "yaw",
      -    "angular_velocity_norm",
      -    "linear_acceleration_norm"
      -  ],
      -  "type": "object"
      -}
    • removedOutput schema / $defs / LaserScanSummary
      Removed value: -{
      -  "additionalProperties": false,
      -  "properties": {
      -    "angle_increment": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Angle between beams, rad."
      -    },
      -    "angle_max": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Bearing of the last beam, rad."
      -    },
      -    "angle_min": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Bearing of beam 0, rad."
      -    },
      -    "beam_count": {
      -      "description": "Beams in `ranges`.",
      -      "minimum": 0,
      -      "type": "integer"
      -    },
      -    "closest_obstacle": {
      -      "anyOf": [
      -        {
      -          "$ref": "#/$defs/ScanReturn"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Closest valid return of the scan; `null` with `note`."
      -    },
      -    "finite_count": {
      -      "description": "Beams with a finite range.",
      -      "minimum": 0,
      -      "type": "integer"
      -    },
      -    "frame_id": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`header.frame_id`; every angle is in this sensor frame, not the base frame."
      -    },
      -    "inf_count": {
      -      "description": "Beams at `+inf`.",
      -      "minimum": 0,
      -      "type": "integer"
      -    },
      -    "nan_count": {
      -      "description": "Beams at `nan`.",
      -      "minimum": 0,
      -      "type": "integer"
      -    },
      -    "neg_inf_count": {
      -      "description": "Beams at `-inf`.",
      -      "minimum": 0,
      -      "type": "integer"
      -    },
      -    "note": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "One sentence when the summary is partial; else `null`."
      -    },
      -    "out_of_range_count": {
      -      "description": "Finite ranges outside `range_min`..`range_max` (not valid).",
      -      "minimum": 0,
      -      "type": "integer"
      -    },
      -    "range_max": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Largest valid range, m."
      -    },
      -    "range_min": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Smallest valid range, m."
      -    },
      -    "sectors": {
      -      "$ref": "#/$defs/ScanSectors",
      -      "description": "Closest valid return per sector."
      -    },
      -    "summary_type": {
      -      "const": "laser_scan",
      -      "type": "string"
      -    }
      -  },
      -  "required": [
      -    "summary_type",
      -    "frame_id",
      -    "beam_count",
      -    "angle_min",
      -    "angle_max",
      -    "angle_increment",
      -    "range_min",
      -    "range_max",
      -    "finite_count",
      -    "inf_count",
      -    "neg_inf_count",
      -    "nan_count",
      -    "out_of_range_count",
      -    "closest_obstacle",
      -    "sectors"
      -  ],
      -  "type": "object"
      -}
    • removedOutput schema / $defs / MessageSample / properties / received_ns / anyOf
      Removed value: -[
      -  {
      -    "type": "integer"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / $defs / MessageSample / properties / received_ns / default
      Removed value: -null
    • addedOutput schema / $defs / MessageSample / properties / received_ns / type
      Added value: +[
      +  "integer",
      +  "null"
      +]
    • removedOutput schema / $defs / MessageSample / properties / recorded_ns / anyOf
      Removed value: -[
      -  {
      -    "type": "integer"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / $defs / MessageSample / properties / recorded_ns / default
      Removed value: -null
    • addedOutput schema / $defs / MessageSample / properties / recorded_ns / type
      Added value: +[
      +  "integer",
      +  "null"
      +]
    • removedOutput schema / $defs / MessageSample / properties / summary / anyOf
      Removed value: -[
      -  {
      -    "discriminator": {
      -      "mapping": {
      -        "image": "#/$defs/ImageSummary",
      -        "imu": "#/$defs/ImuSummary",
      -        "laser_scan": "#/$defs/LaserScanSummary",
      -        "odometry": "#/$defs/OdometrySummary",
      -        "point_cloud2": "#/$defs/PointCloud2Summary"
      -      },
      -      "propertyName": "summary_type"
      -    },
      -    "oneOf": [
      -      {
      -        "$ref": "#/$defs/LaserScanSummary"
      -      },
      -      {
      -        "$ref": "#/$defs/OdometrySummary"
      -      },
      -      {
      -        "$ref": "#/$defs/ImuSummary"
      -      },
      -      {
      -        "$ref": "#/$defs/ImageSummary"
      -      },
      -      {
      -        "$ref": "#/$defs/PointCloud2Summary"
      -      }
      -    ]
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / $defs / MessageSample / properties / summary / default
      Removed value: -null
    • addedOutput schema / $defs / MessageSample / properties / summary / properties
      Added value: +{
      +  "summary_type": {
      +    "enum": [
      +      "laser_scan",
      +      "odometry",
      +      "imu",
      +      "image",
      +      "point_cloud2"
      +    ],
      +    "type": "string"
      +  }
      +}
    • addedOutput schema / $defs / MessageSample / properties / summary / required
      Added value: +[
      +  "summary_type"
      +]
    • addedOutput schema / $defs / MessageSample / properties / summary / type
      Added value: +[
      +  "object",
      +  "null"
      +]
    • removedOutput schema / $defs / OdometrySummary
      Removed value: -{
      -  "additionalProperties": false,
      -  "properties": {
      -    "angular_z": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`twist.twist.angular.z`, rad/s."
      -    },
      -    "child_frame_id": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`child_frame_id` (frame of the twist)."
      -    },
      -    "frame_id": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`header.frame_id` (frame of the pose)."
      -    },
      -    "linear_speed": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Norm of `twist.twist.linear`, m/s."
      -    },
      -    "note": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "One sentence when a value is missing; else `null`."
      -    },
      -    "position_x": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`pose.pose.position.x`, m."
      -    },
      -    "position_y": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`pose.pose.position.y`, m."
      -    },
      -    "position_z": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`pose.pose.position.z`, m."
      -    },
      -    "summary_type": {
      -      "const": "odometry",
      -      "type": "string"
      -    },
      -    "yaw": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Heading from the pose quaternion, radians."
      -    }
      -  },
      -  "required": [
      -    "summary_type",
      -    "frame_id",
      -    "child_frame_id",
      -    "linear_speed",
      -    "angular_z",
      -    "position_x",
      -    "position_y",
      -    "position_z",
      -    "yaw"
      -  ],
      -  "type": "object"
      -}
    • removedOutput schema / $defs / PointCloud2Summary
      Removed value: -{
      -  "additionalProperties": false,
      -  "properties": {
      -    "fields": {
      -      "description": "Point layout.",
      -      "items": {
      -        "$ref": "#/$defs/PointFieldSummary"
      -      },
      -      "type": "array"
      -    },
      -    "frame_id": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`header.frame_id` of the cloud."
      -    },
      -    "height": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Rows (1: unorganized)."
      -    },
      -    "is_dense": {
      -      "anyOf": [
      -        {
      -          "type": "boolean"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "True when no point is invalid."
      -    },
      -    "note": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "One sentence when partial; else `null`."
      -    },
      -    "point_count": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`width` times `height`."
      -    },
      -    "point_step": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Bytes per point."
      -    },
      -    "row_step": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Bytes per row."
      -    },
      -    "summary_type": {
      -      "const": "point_cloud2",
      -      "type": "string"
      -    },
      -    "width": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Points per row."
      -    }
      -  },
      -  "required": [
      -    "summary_type",
      -    "frame_id",
      -    "width",
      -    "height",
      -    "point_count",
      -    "point_step",
      -    "row_step",
      -    "is_dense",
      -    "fields"
      -  ],
      -  "type": "object"
      -}
    • removedOutput schema / $defs / PointFieldSummary
      Removed value: -{
      -  "additionalProperties": false,
      -  "properties": {
      -    "count": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Elements per point."
      -    },
      -    "datatype": {
      -      "description": "Element type, e.g. `FLOAT32`.",
      -      "type": "string"
      -    },
      -    "name": {
      -      "description": "Field name, e.g. `x`.",
      -      "type": "string"
      -    },
      -    "offset": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Byte offset in a point."
      -    }
      -  },
      -  "required": [
      -    "name",
      -    "datatype",
      -    "offset",
      -    "count"
      -  ],
      -  "type": "object"
      -}
    • removedOutput schema / $defs / ScanReturn
      Removed value: -{
      -  "additionalProperties": false,
      -  "properties": {
      -    "beam_index": {
      -      "description": "Index in `ranges`.",
      -      "minimum": 0,
      -      "type": "integer"
      -    },
      -    "bearing": {
      -      "description": "Beam direction in radians, sensor frame: 0 is +x, counter-clockwise positive.",
      -      "type": "number"
      -    },
      -    "range": {
      -      "description": "Distance, meters.",
      -      "type": "number"
      -    }
      -  },
      -  "required": [
      -    "range",
      -    "bearing",
      -    "beam_index"
      -  ],
      -  "type": "object"
      -}
    • removedOutput schema / $defs / ScanSector
      Removed value: -{
      -  "additionalProperties": false,
      -  "properties": {
      -    "beam_count": {
      -      "description": "Beams inside the sector (0: not covered).",
      -      "minimum": 0,
      -      "type": "integer"
      -    },
      -    "closest": {
      -      "anyOf": [
      -        {
      -          "$ref": "#/$defs/ScanReturn"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Closest valid return in the sector; `null` with `note`."
      -    },
      -    "note": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Why `closest` is `null`; `null` when it is set."
      -    }
      -  },
      -  "required": [
      -    "beam_count",
      -    "closest"
      -  ],
      -  "type": "object"
      -}
    • removedOutput schema / $defs / ScanSectors
      Removed value: -{
      -  "additionalProperties": false,
      -  "properties": {
      -    "front": {
      -      "$ref": "#/$defs/ScanSector",
      -      "description": "Bearings within +-45 degrees of +x."
      -    },
      -    "left": {
      -      "$ref": "#/$defs/ScanSector",
      -      "description": "Bearings from 45 to 135 degrees."
      -    },
      -    "rear": {
      -      "$ref": "#/$defs/ScanSector",
      -      "description": "Bearings beyond +-135 degrees."
      -    },
      -    "right": {
      -      "$ref": "#/$defs/ScanSector",
      -      "description": "Bearings from -135 to -45 degrees."
      -    }
      -  },
      -  "required": [
      -    "front",
      -    "left",
      -    "right",
      -    "rear"
      -  ],
      -  "type": "object"
      -}
    • addedOutput schema / $defs / TopicRate / properties / clock_basis
      Added value: +{
      +  "description": "Stamp clock: `wall` (stamps are dates), `sim` (since a start), `none` (no stamps), `mixed` (several kinds, e.g. two publishers).",
      +  "enum": [
      +    "wall",
      +    "sim",
      +    "none",
      +    "mixed"
      +  ],
      +  "type": "string"
      +}
    • removedOutput schema / $defs / TopicRate / properties / interval_cv / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / $defs / TopicRate / properties / interval_cv / type
      Added value: +[
      +  "number",
      +  "null"
      +]
    • removedOutput schema / $defs / TopicRate / properties / interval_median_s / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / $defs / TopicRate / properties / interval_median_s / type
      Added value: +[
      +  "number",
      +  "null"
      +]
    • removedOutput schema / $defs / TopicRate / properties / max_gap_s / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / $defs / TopicRate / properties / max_gap_s / type
      Added value: +[
      +  "number",
      +  "null"
      +]
    • removedOutput schema / $defs / TopicRate / properties / mean_interval_s / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / $defs / TopicRate / properties / mean_interval_s / type
      Added value: +[
      +  "number",
      +  "null"
      +]
    • removedOutput schema / $defs / TopicRate / properties / observed_frequency_hz / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / $defs / TopicRate / properties / observed_frequency_hz / type
      Added value: +[
      +  "number",
      +  "null"
      +]
    • removedOutput schema / $defs / TopicRate / properties / sim_frequency_hz / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / $defs / TopicRate / properties / sim_frequency_hz / type
      Added value: +[
      +  "number",
      +  "null"
      +]
    • addedOutput schema / $defs / TopicRate / properties / stamp_age_median_s
      Added value: +{
      +  "description": "Median of arrival minus stamp, s, if `wall`; negative = publisher ahead.",
      +  "type": [
      +    "number",
      +    "null"
      +  ]
      +}
    • addedOutput schema / $defs / TopicRate / properties / stamp_age_p95_s
      Added value: +{
      +  "description": "95th percentile of that age (max under 20 messages).",
      +  "type": [
      +    "number",
      +    "null"
      +  ]
      +}
    • addedOutput schema / $defs / TopicRate / properties / stamp_regression_count
      Added value: +{
      +  "description": "Times a stamp went back versus the previous one.",
      +  "minimum": 0,
      +  "type": "integer"
      +}
    • removedOutput schema / $defs / TopicRate / properties / trailing_gap_s / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / $defs / TopicRate / properties / trailing_gap_s / type
      Added value: +[
      +  "number",
      +  "null"
      +]
    • removedOutput schema / properties / note / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / properties / note / default
      Removed value: -null
    • addedOutput schema / properties / note / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • removedOutput schema / properties / rate / default
      Removed value: -null
  2. Changed49 schema fields changedv0.7.1
    • changedInput schema / properties / count / description
      Previous value: -"Maximum number of recent messages to return. Defaults to 5; silently clamped to 50 (the hard cap that keeps tool output bounded; read it from `health_check.max_sample_count`). Negative values raise an error. The returned `SampleResult.count` reflects the actual number of samples produced: it can be lower than the request (empty topic, timeout, mock fixture shorter than requested)."New value: +"Messages to return, default 5, at most 50 (`health_check.max_sample_count`): more is capped to 50, negative raises an error. The result's `count` may be lower."
    • removedInput schema / properties / count / title
      Removed value: -"Count"
    • changedInput schema / properties / topic / description
      Previous value: -"DDS topic name. Bare DDS names such as `scan` are valid, as are ROS 2 mangled names such as `rt/scan` and the builtin discovery topics `DCPSParticipant`, `DCPSSubscription`, `DCPSPublication`. Letters, digits, `_`, `/` and `::` are allowed; anything else is rejected."New value: +"DDS topic name: bare (`scan`), ROS 2 mangled (`rt/scan`) or a builtin discovery topic (`DCPSParticipant`, `DCPSSubscription`, `DCPSPublication`). Letters, digits, `_`, `/` and `::` only."
    • removedInput schema / properties / topic / title
      Removed value: -"Topic"
    • removedInput schema / title
      Removed value: -"peek_dds_samplesArguments"
    • addedOutput schema / $defs / ImageSummary
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "data_length": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Pixel buffer size in bytes (see `data_length_basis`)."
      +    },
      +    "data_length_basis": {
      +      "anyOf": [
      +        {
      +          "enum": [
      +            "payload",
      +            "step_x_height"
      +          ],
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`payload` (counted) or `step_x_height` (array cut, so step times height)."
      +    },
      +    "encoding": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Pixel encoding, e.g. `rgb8`."
      +    },
      +    "frame_id": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`header.frame_id` of the camera."
      +    },
      +    "height": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Pixels."
      +    },
      +    "is_bigendian": {
      +      "anyOf": [
      +        {
      +          "type": "boolean"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Big-endian pixels."
      +    },
      +    "note": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "description": "One sentence when partial; else `null`."
      +    },
      +    "step": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Row length, bytes."
      +    },
      +    "summary_type": {
      +      "const": "image",
      +      "type": "string"
      +    },
      +    "width": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Pixels."
      +    }
      +  },
      +  "required": [
      +    "summary_type",
      +    "frame_id",
      +    "width",
      +    "height",
      +    "encoding",
      +    "step",
      +    "is_bigendian",
      +    "data_length",
      +    "data_length_basis"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / $defs / ImuSummary
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "angular_velocity_norm": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Norm of `angular_velocity`, rad/s."
      +    },
      +    "frame_id": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`header.frame_id` of the IMU."
      +    },
      +    "linear_acceleration_norm": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Norm of `linear_acceleration`, m/s^2."
      +    },
      +    "note": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "description": "One sentence when a value is unusable; else `null`."
      +    },
      +    "orientation_valid": {
      +      "description": "False when the IMU gives no orientation: `roll`, `pitch`, `yaw` are `null`.",
      +      "type": "boolean"
      +    },
      +    "pitch": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Rotation about y, radians."
      +    },
      +    "roll": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Rotation about x, radians."
      +    },
      +    "summary_type": {
      +      "const": "imu",
      +      "type": "string"
      +    },
      +    "yaw": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Rotation about z, radians."
      +    }
      +  },
      +  "required": [
      +    "summary_type",
      +    "frame_id",
      +    "orientation_valid",
      +    "roll",
      +    "pitch",
      +    "yaw",
      +    "angular_velocity_norm",
      +    "linear_acceleration_norm"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / $defs / LaserScanSummary
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "angle_increment": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Angle between beams, rad."
      +    },
      +    "angle_max": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Bearing of the last beam, rad."
      +    },
      +    "angle_min": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Bearing of beam 0, rad."
      +    },
      +    "beam_count": {
      +      "description": "Beams in `ranges`.",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "closest_obstacle": {
      +      "anyOf": [
      +        {
      +          "$ref": "#/$defs/ScanReturn"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Closest valid return of the scan; `null` with `note`."
      +    },
      +    "finite_count": {
      +      "description": "Beams with a finite range.",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "frame_id": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`header.frame_id`; every angle is in this sensor frame, not the base frame."
      +    },
      +    "inf_count": {
      +      "description": "Beams at `+inf`.",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "nan_count": {
      +      "description": "Beams at `nan`.",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "neg_inf_count": {
      +      "description": "Beams at `-inf`.",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "note": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "description": "One sentence when the summary is partial; else `null`."
      +    },
      +    "out_of_range_count": {
      +      "description": "Finite ranges outside `range_min`..`range_max` (not valid).",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "range_max": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Largest valid range, m."
      +    },
      +    "range_min": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Smallest valid range, m."
      +    },
      +    "sectors": {
      +      "$ref": "#/$defs/ScanSectors",
      +      "description": "Closest valid return per sector."
      +    },
      +    "summary_type": {
      +      "const": "laser_scan",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "summary_type",
      +    "frame_id",
      +    "beam_count",
      +    "angle_min",
      +    "angle_max",
      +    "angle_increment",
      +    "range_min",
      +    "range_max",
      +    "finite_count",
      +    "inf_count",
      +    "neg_inf_count",
      +    "nan_count",
      +    "out_of_range_count",
      +    "closest_obstacle",
      +    "sectors"
      +  ],
      +  "type": "object"
      +}
    • removedOutput schema / $defs / MessageSample / description
      Removed value: -"A single sampled message on a topic."
    • removedOutput schema / $defs / MessageSample / properties / message_type / description
      Removed value: -"ROS2 message type of this sample, e.g. `geometry_msgs/msg/Twist`."
    • removedOutput schema / $defs / MessageSample / properties / message_type / title
      Removed value: -"Message Type"
    • changedOutput schema / $defs / MessageSample / properties / payload / description
      Previous value: -"Message fields as nested named values, e.g. `{\"header\": {\"stamp\": {\"sec\": 12, \"nanosec\": 5}, \"frame_id\": \"base_laser\"}, \"ranges\": [1.0, 1.001]}`. Non-finite floats are the strings `nan`, `inf`, `-inf`. Live `sample_messages` adds `_truncated_fields` (dotted paths of arrays, strings or bytes cut at `max_array_length`; a string of exactly that length plus `...` that was not cut is listed too) when something was cut, and `_raw_text` (the unparsed output) only when a message could not be parsed. With `arrays_summary_only` an array is a string like `<sequence type: float, length: 541>`. Large messages may be dropped to keep tool output bounded."New value: +"Message fields as nested values; `nan`/`inf` are strings. Live `sample_messages` adds `_truncated_fields` (cut paths) and `_raw_text` (unparsable output)."
    • removedOutput schema / $defs / MessageSample / properties / payload / title
      Removed value: -"Payload"
    • changedOutput schema / $defs / MessageSample / properties / received_ns / description
      Previous value: -"Wall-clock nanoseconds since epoch at which the `ros2` CLI printed this message, after it deserialized and formatted it: not the network receive time, and it lags more for large messages. Accurate to a fraction of a second. Live `sample_messages` only; `None` otherwise."New value: +"Wall-clock ns when the `ros2` CLI printed the message (live `sample_messages` only)."
    • removedOutput schema / $defs / MessageSample / properties / received_ns / title
      Removed value: -"Received Ns"
    • changedOutput schema / $defs / MessageSample / properties / recorded_ns / description
      Previous value: -"Nanoseconds at which the recorder wrote this message into the bag (the bag's own record time, wall clock unless the recorder ran on simulated time). `peek_bag_samples` only; `None` for live samples, where `received_ns` plays that role."New value: +"Bag record time in ns (`peek_bag_samples` only)."
    • removedOutput schema / $defs / MessageSample / properties / recorded_ns / title
      Removed value: -"Recorded Ns"
    • removedOutput schema / $defs / MessageSample / properties / stamp_source / anyOf
      Removed value: -[
      -  {
      -    "enum": [
      -      "header",
      -      "none",
      -      "recorded"
      -    ],
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / $defs / MessageSample / properties / stamp_source / default
      Removed value: -null
    • changedOutput schema / $defs / MessageSample / properties / stamp_source / description
      Previous value: -"Where `timestamp_ns` comes from: `header` (the message's `header.stamp`), `none` (headerless live message, `timestamp_ns` is 0) or `recorded` (headerless message from a bag, `timestamp_ns` is the bag record time). `None` when the backend does not say."New value: +"Origin of `timestamp_ns`: `header`, `payload`, `recorded` (bag record time), `dds_source` or `none` (0)."
    • addedOutput schema / $defs / MessageSample / properties / stamp_source / enum
      Added value: +[
      +  "header",
      +  "payload",
      +  "recorded",
      +  "dds_source",
      +  "none"
      +]
    • removedOutput schema / $defs / MessageSample / properties / stamp_source / title
      Removed value: -"Stamp Source"
    • addedOutput schema / $defs / MessageSample / properties / stamp_source / type
      Added value: +"string"
    • addedOutput schema / $defs / MessageSample / properties / summary
      Added value: +{
      +  "anyOf": [
      +    {
      +      "discriminator": {
      +        "mapping": {
      +          "image": "#/$defs/ImageSummary",
      +          "imu": "#/$defs/ImuSummary",
      +          "laser_scan": "#/$defs/LaserScanSummary",
      +          "odometry": "#/$defs/OdometrySummary",
      +          "point_cloud2": "#/$defs/PointCloud2Summary"
      +        },
      +        "propertyName": "summary_type"
      +      },
      +      "oneOf": [
      +        {
      +          "$ref": "#/$defs/LaserScanSummary"
      +        },
      +        {
      +          "$ref": "#/$defs/OdometrySummary"
      +        },
      +        {
      +          "$ref": "#/$defs/ImuSummary"
      +        },
      +        {
      +          "$ref": "#/$defs/ImageSummary"
      +        },
      +        {
      +          "$ref": "#/$defs/PointCloud2Summary"
      +        }
      +      ]
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Condensed reading of the whole message (see `summary_type`); `null` for other types and DDS peeks."
      +}
    • changedOutput schema / $defs / MessageSample / properties / timestamp_ns / description
      Previous value: -"Nanoseconds from the message's own top-level `header.stamp` (`stamp_source` `header`), or 0 when the message has no header (`stamp_source` `none`, e.g. `std_msgs/String`, `geometry_msgs/Twist`). It is the publisher's clock, not the arrival time: on simulated time it is sim time since the simulation started (a few seconds, not a date) and 0 is a valid value. From `peek_bag_samples` a message without a header gets the bag record time instead (`stamp_source` `recorded`), also given in `recorded_ns`. Use `received_ns` for when the CLI printed the message. Mock samples with a header carry synthetic increasing values."New value: +"Publisher-clock ns: `header.stamp`, else the time in the body of `Clock`, `TFMessage` or `Log`, else 0 (see `stamp_source`); not the arrival time."
    • removedOutput schema / $defs / MessageSample / properties / timestamp_ns / title
      Removed value: -"Timestamp Ns"
    • removedOutput schema / $defs / MessageSample / properties / topic / description
      Removed value: -"Fully qualified topic name the sample was taken from, e.g. `/cmd_vel`."
    • removedOutput schema / $defs / MessageSample / properties / topic / title
      Removed value: -"Topic"
    • changedOutput schema / $defs / MessageSample / required
      Previous value: -[
      -  "topic",
      -  "message_type",
      -  "timestamp_ns"
      -]New value: +[
      +  "topic",
      +  "message_type",
      +  "timestamp_ns",
      +  "stamp_source"
      +]
    • removedOutput schema / $defs / MessageSample / title
      Removed value: -"MessageSample"
    • addedOutput schema / $defs / OdometrySummary
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "angular_z": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`twist.twist.angular.z`, rad/s."
      +    },
      +    "child_frame_id": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`child_frame_id` (frame of the twist)."
      +    },
      +    "frame_id": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`header.frame_id` (frame of the pose)."
      +    },
      +    "linear_speed": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Norm of `twist.twist.linear`, m/s."
      +    },
      +    "note": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "description": "One sentence when a value is missing; else `null`."
      +    },
      +    "position_x": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`pose.pose.position.x`, m."
      +    },
      +    "position_y": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`pose.pose.position.y`, m."
      +    },
      +    "position_z": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`pose.pose.position.z`, m."
      +    },
      +    "summary_type": {
      +      "const": "odometry",
      +      "type": "string"
      +    },
      +    "yaw": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Heading from the pose quaternion, radians."
      +    }
      +  },
      +  "required": [
      +    "summary_type",
      +    "frame_id",
      +    "child_frame_id",
      +    "linear_speed",
      +    "angular_z",
      +    "position_x",
      +    "position_y",
      +    "position_z",
      +    "yaw"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / $defs / PointCloud2Summary
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "fields": {
      +      "description": "Point layout.",
      +      "items": {
      +        "$ref": "#/$defs/PointFieldSummary"
      +      },
      +      "type": "array"
      +    },
      +    "frame_id": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`header.frame_id` of the cloud."
      +    },
      +    "height": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Rows (1: unorganized)."
      +    },
      +    "is_dense": {
      +      "anyOf": [
      +        {
      +          "type": "boolean"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "True when no point is invalid."
      +    },
      +    "note": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "description": "One sentence when partial; else `null`."
      +    },
      +    "point_count": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`width` times `height`."
      +    },
      +    "point_step": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Bytes per point."
      +    },
      +    "row_step": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Bytes per row."
      +    },
      +    "summary_type": {
      +      "const": "point_cloud2",
      +      "type": "string"
      +    },
      +    "width": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Points per row."
      +    }
      +  },
      +  "required": [
      +    "summary_type",
      +    "frame_id",
      +    "width",
      +    "height",
      +    "point_count",
      +    "point_step",
      +    "row_step",
      +    "is_dense",
      +    "fields"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / $defs / PointFieldSummary
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "count": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Elements per point."
      +    },
      +    "datatype": {
      +      "description": "Element type, e.g. `FLOAT32`.",
      +      "type": "string"
      +    },
      +    "name": {
      +      "description": "Field name, e.g. `x`.",
      +      "type": "string"
      +    },
      +    "offset": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Byte offset in a point."
      +    }
      +  },
      +  "required": [
      +    "name",
      +    "datatype",
      +    "offset",
      +    "count"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / $defs / ScanReturn
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "beam_index": {
      +      "description": "Index in `ranges`.",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "bearing": {
      +      "description": "Beam direction in radians, sensor frame: 0 is +x, counter-clockwise positive.",
      +      "type": "number"
      +    },
      +    "range": {
      +      "description": "Distance, meters.",
      +      "type": "number"
      +    }
      +  },
      +  "required": [
      +    "range",
      +    "bearing",
      +    "beam_index"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / $defs / ScanSector
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "beam_count": {
      +      "description": "Beams inside the sector (0: not covered).",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "closest": {
      +      "anyOf": [
      +        {
      +          "$ref": "#/$defs/ScanReturn"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Closest valid return in the sector; `null` with `note`."
      +    },
      +    "note": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "description": "Why `closest` is `null`; `null` when it is set."
      +    }
      +  },
      +  "required": [
      +    "beam_count",
      +    "closest"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / $defs / ScanSectors
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "front": {
      +      "$ref": "#/$defs/ScanSector",
      +      "description": "Bearings within +-45 degrees of +x."
      +    },
      +    "left": {
      +      "$ref": "#/$defs/ScanSector",
      +      "description": "Bearings from 45 to 135 degrees."
      +    },
      +    "rear": {
      +      "$ref": "#/$defs/ScanSector",
      +      "description": "Bearings beyond +-135 degrees."
      +    },
      +    "right": {
      +      "$ref": "#/$defs/ScanSector",
      +      "description": "Bearings from -135 to -45 degrees."
      +    }
      +  },
      +  "required": [
      +    "front",
      +    "left",
      +    "right",
      +    "rear"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / $defs / TopicRate
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "basis": {
      +      "description": "Clock the rate is measured on: `received_ns` (live) or `recorded_ns` (bag).",
      +      "enum": [
      +        "received_ns",
      +        "recorded_ns"
      +      ],
      +      "type": "string"
      +    },
      +    "interval_cv": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Interval standard deviation over mean; `null` under 2 messages."
      +    },
      +    "interval_median_s": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Median interval; `null` under 2 messages."
      +    },
      +    "max_gap_s": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Longest interval; `null` under 2 messages."
      +    },
      +    "mean_interval_s": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Mean interval; `null` under 2 messages."
      +    },
      +    "message_count": {
      +      "description": "Messages the rate is computed from.",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "observed_frequency_hz": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Messages per second on `basis`, drain excluded; the rate the caller received. `null` under 2 messages."
      +    },
      +    "sim_frequency_hz": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Same rate on the messages' own stamps (publisher clock); `null` without advancing stamps."
      +    },
      +    "startup_burst_count": {
      +      "description": "Leading messages set aside as a start-up drain (live only); still in `message_count`.",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "trailing_gap_s": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Time from the last message to the end of a live observation; else `null`."
      +    },
      +    "verdict": {
      +      "description": "First match: `silent` (none), `insufficient` (under 5), `intermittent` (an interval over 3x the median), `stable` (cv < 0.2), `jittery` (< 0.5), `erratic`. Describes this window, not a diagnosis.",
      +      "enum": [
      +        "silent",
      +        "insufficient",
      +        "intermittent",
      +        "stable",
      +        "jittery",
      +        "erratic"
      +      ],
      +      "type": "string"
      +    },
      +    "verdict_note": {
      +      "description": "The verdict in plain words.",
      +      "type": "string"
      +    },
      +    "window_s": {
      +      "description": "Observation length, seconds.",
      +      "minimum": 0,
      +      "type": "number"
      +    }
      +  },
      +  "required": [
      +    "basis",
      +    "message_count",
      +    "startup_burst_count",
      +    "window_s",
      +    "mean_interval_s",
      +    "interval_median_s",
      +    "max_gap_s",
      +    "interval_cv",
      +    "observed_frequency_hz",
      +    "sim_frequency_hz",
      +    "trailing_gap_s",
      +    "verdict",
      +    "verdict_note"
      +  ],
      +  "type": "object"
      +}
    • changedOutput schema / description
      Previous value: -"Envelope returned by the `sample_messages` tool."New value: +"Samples returned by `sample_messages`, `peek_dds_samples` and `peek_bag_samples`."
    • changedOutput schema / properties / count / description
      Previous value: -"Number of samples actually returned. May be 0 (no publisher active in live mode, or empty mock fixture), less than the requested count (topic yielded fewer messages within the timeout), or capped by the the silent maximum of 50: request `count > 50` and you will receive at most 50 without warning."New value: +"Number of samples in `samples`: fewer than requested when the topic gave fewer, never more than 50 (a larger request is capped to 50)."
    • removedOutput schema / properties / count / title
      Removed value: -"Count"
    • changedOutput schema / properties / mode_effective / description
      Previous value: -"Runtime mode the adapter served this response in: `live` (real ROS2 introspection) or `mock` (deterministic fixtures). Lets a caller tell a real graph from a demo one without calling `health_check`."New value: +"`live` or `mock` (fixtures)."
    • removedOutput schema / properties / mode_effective / title
      Removed value: -"Mode Effective"
    • changedOutput schema / properties / note / description
      Previous value: -"Why `samples` is empty or limited, when the cause is not obvious (for example payload decoding is disabled for DDS user topics). `None` when there is nothing to add."New value: +"Why `samples` is empty or limited, when not obvious; else `None`."
    • removedOutput schema / properties / note / title
      Removed value: -"Note"
    • addedOutput schema / properties / rate
      Added value: +{
      +  "anyOf": [
      +    {
      +      "$ref": "#/$defs/TopicRate"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "How the topic delivered the messages, with a verdict; `null` for `peek_dds_samples`. Use `count` >= 10."
      +}
    • changedOutput schema / properties / samples / description
      Previous value: -"The sampled messages, ordered as received from the backend."New value: +"The samples, in backend order."
    • removedOutput schema / properties / samples / title
      Removed value: -"Samples"
    • removedOutput schema / properties / topic / description
      Removed value: -"Topic the samples were taken from, echoed from the request."
    • removedOutput schema / properties / topic / title
      Removed value: -"Topic"
  3. Changed5 schema fields changedv0.6.3
    • changedOutput schema / $defs / MessageSample / properties / payload / description
      Previous value: -"Structured message payload. **In live mode the parser exposes the message fields as positional CSV columns** keyed as `col_0`, `col_1`, ... (`header.stamp.sec`/`nanosec` are stripped out into `timestamp_ns` when detected). The raw CSV row is preserved verbatim under the reserved `_raw_text` key so clients can re-parse against the message's IDL when needed. In mock mode the payload is fully structured and `_raw_text` is absent. Large messages (e.g. images) may be summarized to keep tool output bounded."New value: +"Message fields as nested named values, e.g. `{\"header\": {\"stamp\": {\"sec\": 12, \"nanosec\": 5}, \"frame_id\": \"base_laser\"}, \"ranges\": [1.0, 1.001]}`. Non-finite floats are the strings `nan`, `inf`, `-inf`. Live `sample_messages` adds `_truncated_fields` (dotted paths of arrays, strings or bytes cut at `max_array_length`; a string of exactly that length plus `...` that was not cut is listed too) when something was cut, and `_raw_text` (the unparsed output) only when a message could not be parsed. With `arrays_summary_only` an array is a string like `<sequence type: float, length: 541>`. Large messages may be dropped to keep tool output bounded."
    • addedOutput schema / $defs / MessageSample / properties / received_ns
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "integer"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Wall-clock nanoseconds since epoch at which the `ros2` CLI printed this message, after it deserialized and formatted it: not the network receive time, and it lags more for large messages. Accurate to a fraction of a second. Live `sample_messages` only; `None` otherwise.",
      +  "title": "Received Ns"
      +}
    • addedOutput schema / $defs / MessageSample / properties / recorded_ns
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "integer"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Nanoseconds at which the recorder wrote this message into the bag (the bag's own record time, wall clock unless the recorder ran on simulated time). `peek_bag_samples` only; `None` for live samples, where `received_ns` plays that role.",
      +  "title": "Recorded Ns"
      +}
    • addedOutput schema / $defs / MessageSample / properties / stamp_source
      Added value: +{
      +  "anyOf": [
      +    {
      +      "enum": [
      +        "header",
      +        "none",
      +        "recorded"
      +      ],
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Where `timestamp_ns` comes from: `header` (the message's `header.stamp`), `none` (headerless live message, `timestamp_ns` is 0) or `recorded` (headerless message from a bag, `timestamp_ns` is the bag record time). `None` when the backend does not say.",
      +  "title": "Stamp Source"
      +}
    • changedOutput schema / $defs / MessageSample / properties / timestamp_ns / description
      Previous value: -"Timestamp in nanoseconds since epoch. In live mode this is the `header.stamp` of the sampled message when present: the live adapter invokes `ros2 topic echo --csv --once`, whose flattened CSV exposes `header.stamp.sec`/`nanosec` as the first two columns for any `Header`-stamped message. **Headerless message types** (e.g. `std_msgs/String`, `geometry_msgs/Twist`) carry no embedded timestamp, and `timestamp_ns` falls back to 0; an rclpy-backed adapter will eventually expose rmw receive times for those. Mock mode emits monotonically increasing values for deterministic ordering."New value: +"Nanoseconds from the message's own top-level `header.stamp` (`stamp_source` `header`), or 0 when the message has no header (`stamp_source` `none`, e.g. `std_msgs/String`, `geometry_msgs/Twist`). It is the publisher's clock, not the arrival time: on simulated time it is sim time since the simulation started (a few seconds, not a date) and 0 is a valid value. From `peek_bag_samples` a message without a header gets the bag record time instead (`stamp_source` `recorded`), also given in `recorded_ns`. Use `received_ns` for when the CLI printed the message. Mock samples with a header carry synthetic increasing values."
  4. First observedv0.5.6

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the read-only and open-world annotations, the description discloses important behavior: payload decoding is disabled for user topics, such calls return a note and empty samples rather than proving silence, discovery can wait up to 3 seconds, and lock contention produces a retryable busy error. It also explains that the tool cannot publish and raises MCP errors when no DDS module is active or the topic is not announced.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with purpose and sibling differentiation, then organized into builtin-topic and user-topic cases. It is dense and long, with some repetition of schema details, but most clauses carry operationally important edge cases.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity, error modes, discovery timing, and lock behavior, the description covers what an agent needs to call it correctly. An output schema exists, so return-value structure does not need to be spelled out further.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents both parameters, including the default, cap, and accepted topic forms. The description reinforces this with examples like `/scan`, `scan`, and `rt/scan`, but adds little meaning beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: peeking recent samples on a raw DDS topic, returning a SampleResult. It explicitly distinguishes itself from `sample_messages` by reading from the DDS layer and working without ROS 2.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit branching guidance: builtin discovery topics return current-state records and should use `participant_events` for recent events, while `list_endpoints` should be used for user-topic presence, writers, readers, and QoS. It also explains error conditions and retry behavior when the DDS lock is busy.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.