Runtime diagnostics (SOVD-aligned)¶
taktora-medkit is a runtime-diagnostics surface for taktora: it presents
the running system as a SOVD
-aligned entity tree (Area / Component / Function / App) carrying a DTC/fault
model with freeze-frames, and serves it over a REST surface that is drop-in
compatible with the wire contract of the C++ project selfpatch/ros2_medkit.
It is a clean-room Rust take on that diagnostic contract — not a port of its ROS 2 internals. Where ros2_medkit reads a ROS 2 graph, taktora-medkit sources its model from taktora’s own runtime (connector health, executor timing) through non-blocking, off-the-control-path hooks, so diagnostics can never perturb the bounded-time WaitSet path that drives the machine.
This umbrella is a peer of PLC runtime heart on iceoryx2 (FEAT_0010) “PLC runtime heart” and Connector framework (FEAT_0030) “Connector framework”; medkit is a general-purpose diagnostics mechanism layered on the taktora runtime, not bound to any one protocol or to the PLC use case.
A runtime-diagnostics surface that models the live taktora system as a SOVD-aligned entity tree (Area / Component / Function / App) with a DTC/fault model (status sub-object, occurrence counts, reporting sources, freeze-frames / snapshots), a worst-wins health rollup across the tree, and a REST surface that is drop-in compatible with the ros2_medkit wire contract. The diagnostics surface attaches to taktora through non-blocking callback hooks only and runs off the control path, on its own runtime and allocator. The crates are split so the diagnostic model, provider seam, and
gateway carry zero taktora dependencies and can be extracted as a
standalone project, with all taktora coupling quarantined in |
Requirements¶
The diagnostics gateway shall never execute inside taktora-executor’s
bounded-time WaitSet path. It shall attach only through non-blocking
|
A diagnostic client written against the ros2_medkit REST contract shall work unchanged against the taktora-medkit backend: the served JSON shapes (field names, casing, collection envelope, DTC status sub-object, freeze-frame structure) shall match the captured contract corpus for every family v1 serves. Divergence from the corpus shall be a failing test, not a field report. |
Each entity’s aggregated health shall be the worst (most severe) health of itself and all entities it contains. Rolling a child into a fault state shall roll its ancestors at least to that state; clearing the last faulting child shall be required before an ancestor can return to healthy. |
v1 shall source its model exclusively from in-process taktora callback hooks. It shall not attach over iceoryx2 shared memory and shall not stand up its own iceoryx2 node; a shared-memory attach path is explicitly deferred to a later revision. |
The model shall represent the system as a tree of typed entities — Area, Component, Function, App — each carrying a stable id, a human-readable name, its place in the hierarchy, and the diagnostic capabilities it exposes, matching the SOVD entity collections of the wire contract. |
A fault shall be modelled as a DTC carrying a fault code, a SOVD/UDS-style status sub-object, severity, occurrence count, the set of reporting sources, and environment data — first/last occurrence records plus zero or more freeze-frame / snapshot captures of the system state at fault time. |
The core crates — model, provider seam, gateway, and HTTP gateway — shall
carry zero |
The gateway shall serve the SOVD read-diagnostic core over HTTP on the
|
For the families v1 does not implement — operations, configuration writes,
bulk-data, locks, scripts, updates / OTA, triggers, cyclic-subscriptions,
logs, status actions, auth, and the |
The HTTP surface shall offer configurable CORS, a token-bucket rate limit,
and optional TLS, each with a documented default (permissive CORS, rate
limit disabled, TLS disabled, bind |
The executor binding shall implement the taktora-executor |
The binding shall expose the recorded liveness, health, and timing to the
gateway through the |
The hooks run on the executor |
Because v1 does no service discovery, the Area/Component grouping shall come
from a manifest, supplied over two surfaces that build one identical value: a
type-safe builder core ( |
Folding the read-model through a non-empty manifest shall materialise the
declared Areas and Components as entities and re-parent the binding-emitted
raw entities ( |
A missing or empty manifest shall not be an error: the pipeline shall fall
back to the flat provider grouping (the pre-manifest behaviour) without
panicking, so a deployment that has not yet authored a |
The connector binding shall present each connector as a SOVD Component (the
bridge / |
Across repeated health transitions the binding shall maintain per-DTC
lifecycle state: the SOVD/UDS status bits ( |
Each confirmed DTC shall carry a freeze-frame captured at confirmation time
under the contract’s |
A fault’s freeze-frame environment data shall be reachable through the proper
SOVD fault-detail endpoint ( |
The gateway shall run a refresh-and-diff loop on the off-path tokio runtime
that re-polls and re-merges the provider snapshot on a configurable cadence,
hot-swapping the served |
Diffing two successive merged views shall emit a |
When an entity’s worst-wins health level changes between two successive merged
views, the loop shall emit a |
The gateway shall expose a basic subscription surface under
|
|
The gateway shall expose the SOVD authentication endpoints a drop-in client
calls before it reads any diagnostics: |
The default authenticator shall be permissive (dev mode): any credentials
succeed at the token endpoint, and any or no |
Token issuance and bearer verification shall flow through a single
|
Resource (read-core) routes shall run enforcement = none in v1: a presented
|
A drop-in client shall be able to complete the full shape against a live
gateway: |
The gateway shall expose SOVD diagnostic-scoped exclusive access on the entity
kinds the contract defines |
A lock shall auto-release once its TTL elapses: after expiry the resource shall be freely re-acquirable by any client without an explicit release. TTL shall be evaluated against an injectable wall-clock source so expiry is deterministic and testable without sleeping on real time. |
A |
The required |
The lock registry shall be in-memory and off the control path, guarding no safety-critical resource and adding no edge to the executor/connector binding crates or the taktora runtime (preserving the extractable core, Extractable diagnostic core (REQ_0916)). Locks shall coordinate diagnostic clients against each other only; the moment a lock guards an SC resource, the write-surface safety gate (Diagnostic write surface ga... (ADR_0119)) applies. |
Wire-compatibility parity pass (Tier A)¶
The fixes below close gaps inside the already-served surface — places a
path/field-hardcoding ros2_medkit client would break even though the family
is nominally implemented (Tier-A wire-compatibility p... (ADR_0125)). They add no write to a
safety-critical resource (Diagnostic write surface ga... (ADR_0119) is untouched).
The gateway shall serve the contract’s canonical global fault event
stream at |
The gateway shall expose triggers per entity at
|
The gateway shall serve |
The gateway shall answer |
The root document ( |
Every SSE endpoint shall hold the connection open with a |
The |
The |
Write plane — operations (simulation-backed)¶
The first write family, built on a command-side seam that mirrors the read
Provider seam. v1 is backed by an in-memory simulation that performs no
real effect, so it touches no safety-critical resource and the write-surface
safety gate (Diagnostic write surface ga... (ADR_0119)) is not yet engaged; the gate re-enters at the
seam when a real-effect binding lands (Write plane as a port/adapt... (ADR_0126)).
The gateway shall perform every write through an |
The gateway shall serve the SOVD operations family on every entity kind:
|
The gateway shall serve the SOVD configurations family on every entity kind
through the |
The gateway shall serve the SOVD bulk-data family on apps and components:
|
The gateway shall serve the SOVD scripts family on apps and components: upload
( |
The gateway shall serve the SOVD software-update family as a global
surface (not entity-scoped): |
The gateway shall serve entity lifecycle transitions on apps and components:
|
Read-family completion¶
The remaining read thin spots: the two deferred read families (logs, cyclic-subscriptions) and two best-effort served surfaces (health telemetry, single-entity catalogue), brought to contract fidelity (Read-family completion — se... (ADR_0127)).
The gateway shall serve the SOVD logs family on every entity kind:
|
The gateway shall serve the SOVD cyclic-subscriptions family on apps,
components, and functions: CRUD over a subscription (entity-scoped, pinned to
the path entity, cross-entity access |
The |
The single-entity detail ( |
Build identity¶
The read surface advertised only the crate semver, so a field issue could not be tied back to the exact source a binary was built from. This pins the build — the commit, whether the tree was clean, and when it was built — into the version catalogue, captured at compile time and injected as data so the extractable core stays dependency-clean (Compile-time build identity... (ADR_0132)).
The |
Requirements at a glance¶
ID |
Title |
Status |
Satisfies |
|---|---|---|---|
Off-path / freedom from interference |
open |
||
Drop-in client compatibility |
implemented |
||
Worst-wins health rollup |
open |
||
Callback-hooks-only attach in v1 |
open |
||
SOVD entity-tree model |
implemented |
||
DTC / fault model with freeze-frames |
implemented |
||
Extractable diagnostic core |
open |
||
Read-diagnostic core HTTP surface |
implemented |
||
Deferred families decline with a contract-shaped 501 |
implemented |
||
Baseline transport hardening, off the control path |
implemented |
||
Mandatory Area/Component grouping manifest |
implemented |
||
Merge pipeline applies the manifest |
implemented |
||
Empty or absent manifest falls back to flat grouping |
implemented |
||
Executor liveness and timing from the hook seam |
implemented |
||
Executor binding exposed through the provider seam |
implemented |
||
Non-blocking, bounded hook write path |
implemented |
||
Connector health maps to a SOVD Component and DTCs |
implemented |
||
DTC lifecycle and occurrence bookkeeping |
implemented |
||
Last-sample freeze-frame at confirmation |
implemented |
||
Freeze-frame surfaced through the SOVD fault-detail endpoint |
implemented |
||
Off-path refresh-and-diff loop |
implemented |
||
Diff-derived fault change events |
implemented |
||
Health-transition change events |
implemented |
||
Trigger subscription surface |
implemented |
||
SSE event stream framed per the captured contract |
implemented |
||
Auth-light token endpoints preserve the client login flow |
implemented |
||
Permissive dev-mode authenticator is the default |
implemented |
||
Authentication flows through a substitutable Authenticator seam |
implemented |
||
Resource routes run enforcement = none in v1 |
implemented |
||
Full client login-to-read flow over the live gateway |
implemented |
||
Diagnostic lock lifecycle — acquire, extend, release |
implemented |
||
Lock TTL expiry auto-releases |
implemented |
||
break_lock supervisor override |
implemented |
||
X-Client-Id lock ownership |
implemented |
||
Locks are diagnostic-coordination-only QM metadata |
implemented |
||
Global fault SSE stream |
implemented |
||
Entity-scoped triggers |
implemented |
||
Lock read endpoints |
implemented |
||
Global fault clear-all |
implemented |
||
Honest capability advertisement |
implemented |
||
SSE keep-alive and reconnect replay |
implemented |
||
Health telemetry shape |
implemented |
||
Auth disable parity |
implemented |
||
Write/action seam |
implemented |
||
Operations family with async executions |
implemented |
||
Configurations family |
implemented |
||
Bulk-data family |
implemented |
||
Scripts family |
implemented |
||
Software-update family |
implemented |
||
Lifecycle-status family |
implemented |
||
Logs family |
implemented |
||
Cyclic-subscriptions family |
implemented |
||
Provider-sourced health telemetry |
implemented |
||
Single-entity capability catalogue |
implemented |
||
Build identity in the version catalogue |
implemented |