Every operator action and configuration change on the robotics fleet lands in a single append-only table, fact_robotics_audit. The console renders it at Audit log · Robotics. This page describes the record itself so that you can read it outside the console, correlate it with telemetry, and understand how the console derives what it shows.

What gets recorded

The log covers operator and system actions against robots in an org: teleop sessions, e-stops, control transfers, alerts, and deploys. Rows are written as the action happens, by the service that performs it — the log is not reconstructed after the fact. Every row is scoped to an org. fleetRobotics.auditLog takes orgId and returns only rows for that org, so a caller cannot read another tenant’s actions through it.

The audit row: actor, kind, target, detail

A row as returned by fleetRobotics.auditLog carries these fields: Two of these are nullable, and the console substitutes placeholders rather than blanking the cell:
  • actor_label missing → the console displays system and swaps the avatar for a CPU glyph. Treat system as “no human actor recorded on this row”, not as the name of a principal.
  • robot_id missing → the Target column shows —.
  • kind missing → the Action column shows —.
detail has no fixed schema. When it is an object, the console JSON-stringifies it for the Detail column; when it is a string it is rendered verbatim. Write your own consumers to handle both shapes.

Action kinds and severity

kind is the vocabulary you filter and alert on. The audit table itself stores no severity or verdict column. Severity is derived from the kind string, and the console does that derivation client-side: Matching is substring-based on the lowercased kind, so estop_engaged and fleet_estop_clear both derive bad. Kinds whose name begins with estop are additionally rendered in the danger colour in the Action column. Because this mapping is a naming convention rather than a stored column, a new kind inherits its severity from how it is named. If you emit or parse kinds yourself, keep the convention: put estop, error, alert, warn or flag in the name when the action deserves attention. The verdict input on the procedure applies the same classification server-side, so filtering by bad and colouring a row bad always agree.

Retention and append-only guarantees

The table is append-only. There is no procedure to edit or delete a row, and the console exposes none — the log is the compliance artefact for ISO 27001 and SOC 2 controls over operator actions on physical hardware. Corrections are made by appending a new action, not by rewriting history. The log’s window is bounded by what the query range covers, not by the console’s default range. The screen opens on the last six hours purely as a default; supply a wider fromMs / toMs to read further back.

Reading the log over the API

The console screen is a thin client over one procedure. You can call it directly:
The response is { rows, total }. Filtering, searching and pagination all happen server-side, so total counts the rows matching the full predicate — range, verdict and search — not just the rows on the current page. Derive page count as ceil(total / perPage). Two details worth copying from the console when you build your own poller:
  • Round your range bounds. The console floors fromMs and ceils toMs to the minute so that a relative range like now-6h → now produces a stable query key instead of a new one every render.
  • Debounce search. The console waits 300 ms after the last keystroke before issuing a query, and resets to page 1 whenever the range, verdict or search changes.
The console refetches on a 60 s interval, which is a reasonable cadence for a live view of an append-only table.

Correlating an e-stop with robot telemetry

An audit row gives you three join keys: ts, robot_id, and kind. To investigate an e-stop:
  1. Filter the log to verdict: "bad" over the window in question, or search for estop directly.
  2. Take robot_id and ts from the matching row.
  3. Query your telemetry store for that robot around that timestamp. The audit row tells you who commanded the stop and when; the metrics and traces tell you what the robot was doing either side of it. See Telemetry for the stream shapes and how to correlate them.
  4. Read actor_label to distinguish an operator-initiated stop from one with no recorded human actor.
Because severity is derived from the kind name, a bad verdict alone does not tell you whether the event was an e-stop or an error. Read kind for that distinction, and detail for the context the emitting service attached.
  • Telemetry — metrics, traces and capture streams to correlate against
  • Authentication — how a caller is authorised for control-plane procedures