Conformance and Roadmap#
The COO Command-and-Control Design Specification and Message Envelope and Payload Design define the architecture HISPEC is building toward. This page tracks the instrument against them, requirement by requirement: what is in place, what HISPEC adapts to its own needs, and what is planned next.
It is maintained as a working tracker rather than a one-off audit. Each iteration of the architecture (see Architecture Evolution) has closed items on this page, and the order of the roadmap at the end reflects what the next one should close.
Legend: In place · Partial · Planned · Adapted (deliberate instrument-specific difference, with the reason given).
Summary#
The specification’s foundation is in place, and it is the part that matters most during AIT: hardware is owned by daemons, the command interface is uniform and self-describing, safety is enforced next to the hardware, and configuration is data. HISPEC built these first deliberately, because they are the requirements that are expensive to retrofit.
What remains concerns operating the instrument at scale — command traceability, published status, daemon readiness, ownership. None of it has been exercised yet, because the clients that need it (a sequencer, a GUI) are themselves planned rather than built. The architectural priority is to put these in place before those clients exist, since each one changes the contract they would be written against.
The next item to close is command traceability: the transport already carries a transaction ID, and surfacing it costs little compared to what it returns.
Required components (§5)#
Requirement |
Status |
Detail |
|---|---|---|
§5.1 Device daemons own hardware |
In place |
One daemon per controller, sole owner of the connection. No client path bypasses a daemon. |
§5.1 Daemons validate against state and limits |
In place |
Per-keyword validators, soft-limit checks, connection checks before every hardware call. |
§5.1 Daemons publish status and telemetry |
Partial |
Status is available as keywords, but nothing is published — all monitoring is polled. |
§5.1 Daemons report command completion or failure |
Partial |
A modify returns the applied value or raises. There is no distinct completion event for a long-running operation; a move reports through |
§5.1 Daemons enter fault or safe states |
Planned |
No fault state. A daemon that has recorded an error will accept the next command. |
§5.2 Command transport |
In place |
RabbitMQ, brokered, uniform across the instrument. |
§5.2 Associate replies and events with a command identifier |
Planned |
See Command identity. |
§5.3 Status and event transport independent of replies |
Planned |
libby supports pub/sub; HISPEC uses none of it. |
§5.3 Minimum published status (heartbeat, state, mode, readiness, fault) |
Planned |
Of the required set, only liveness ( |
§5.4 Configuration and limits as structured data |
In place |
Per-instance YAML, versioned in |
§5.4 Named operating modes |
Planned |
No mode concept at all — no science/calibration/engineering/safe mode. |
§5.5 Command and event logging |
Partial |
Everything is logged to journald with a timestamp and daemon identity. Of the specification’s minimum command-log fields, the ones that identify a command — command ID, requester, parameters, accept/reject, start/end, duration, final result — are absent. |
Command contract (§6)#
Requirement |
Status |
Detail |
|---|---|---|
Uniform command envelope |
Adapted |
HISPEC has no command envelope because it has no commands. Everything is a keyword |
Request fields ( |
Adapted |
The keyword name and target are carried in the routing key; |
Response fields ( |
Partial |
Success returns the value; failure raises with a message. No |
Completion fields ( |
Planned |
Not produced. |
Command identity (§6.4)#
The specification is unambiguous here: “A command shall not disappear into the system without a traceable identifier.”
The transport already complies. bamboo’s envelope carries transid, a UUID
reused across the ACK and response of one transaction. What is missing is
everything above it: libby does not pass the transaction ID to the keyword
handler, HISPEC daemons never see it, and nothing writes it to a log line.
The practical consequence: given a failure report of the form “the mask selector didn’t move last Tuesday”, there is no way to find which client asked, what it asked for, whether the daemon accepted it, or how long it ran. The journal shows what the daemon did, not what it was asked to do or by whom.
Closing this needs work in libby, not in HISPEC — surfacing transid in the
handler context, and logging one structured line per keyword modify with the
transaction ID, the requester, the keyword, the value, the outcome and the
duration. It is first in the Roadmap for that reason: a small
change with disproportionate operational value, and cheaper to make before the
sequencer exists than after.
State models (§7)#
Requirement |
Status |
Detail |
|---|---|---|
§7.1 Command lifecycle ( |
Planned |
No representation. A modify is synchronous from the client’s perspective; a long operation is tracked through a separate |
§7.2 Daemon lifecycle ( |
Planned |
Not exposed. A client infers liveness from |
Of the two, the daemon lifecycle is the one to build first. “Are all required daemons ready?” is the precondition a sequencer asks before it does anything else, and it is inexpensive to expose, since every daemon already tracks the answer internally — it simply has no keyword to report it through.
The command lifecycle follows from the keyword model and needs more thought.
HISPEC’s show/modify contract has no natural place for accepted versus
running, so representing a long-running operation properly means either a
split-phase keyword convention or per-operation state keywords. The current
approach — a separate ismoving keyword plus waitfor — covers motion, and
generalising it is the open design question.
Safety (§8)#
Requirement |
Status |
Detail |
|---|---|---|
§8.1 Local safety enforcement |
In place |
Soft limits, named-position validation, type coercion and connection checks all run in the daemon. Clients are never the only check. |
§8.1 Reject commands while in fault state |
Planned |
No fault state to reject from. |
§8.1 Reject commands from unauthorised clients |
Planned |
No authorisation — see §9. |
§8.2 Defined safe state per subsystem |
Partial |
|
§8.3 Fault handling (inhibit, enter fault state, publish, require explicit recovery) |
Planned |
A fault is logged and recorded in |
One interlock does exist and is worth noting as the pattern to generalise: the
PI daemon refuses shutdown while a stage is moving.
Sequencer (§10)#
Planned. The sequencer, the procedure library and the orchestration layer
are the next major architectural addition; src/hispec/api/ is the placeholder
reserved for them. The shape is set by the COO model and sketched in
Architecture Overview — procedures coordinate, algorithms decide, and the daemons
stay thin.
The groundwork for it is already done, and deliberately so: because every daemon is reachable through the same keyword contract, a sequencer needs no new control path. The specification’s rule that sequencers use the same API as other clients is satisfied by construction — there is no private path for one to take.
Simulation (§11)#
Planned. No daemon supports a simulated backend yet; hardware-free testing
is limited to tests/util/, which covers drivers rather than daemons.
The degraded-start behaviour is not a substitute. A daemon with no hardware
reports isconnected = false and refuses operations, which exercises the error
paths but cannot exercise a successful move, a completing home or a stable
temperature. That makes simulation a dependency of the layers above rather than
a testing refinement: a GUI and a sequencer cannot be meaningfully developed
until it exists, which is why it is placed ahead of them in the roadmap.
Design rules (§14) and anti-patterns (§15)#
Rule |
Status |
|---|---|
Hardware is owned by daemons, not GUIs |
In place |
Commands must be traceable |
Planned |
Status published independently of replies |
Planned |
Safety checks belong near the hardware |
In place |
Sequencers use the same API as other clients |
In place by construction — there is no private path a sequencer could take |
Configuration should be data, not hidden code |
In place |
Simulation should use the same interfaces |
Planned |
Against the specification’s anti-pattern list, HISPEC has avoided the ones that are structural and hard to undo: the GUI does not control hardware, status is not GUI-local text, there is a shared state model for keywords, configuration is not hardcoded, and there are no private control paths. Those were the expensive ones to get right, and the iterations described in Architecture Evolution are what bought them.
Four remain on the list — commands have no IDs, no standard error model, no ownership rules, no simulator. Each is additive rather than structural, which is why they can be sequenced deliberately in the roadmap below instead of forcing a redesign.
Message envelope conformance#
HISPEC inherits the envelope through libby → bamboo rather than implementing it, so conformance is bamboo’s. Field-by-field against the specification:
Spec field |
bamboo |
Note |
|---|---|---|
|
|
✅ |
|
|
Name differs. Values |
|
|
Name differs. |
|
|
✅ |
|
|
Names differ. |
|
|
Name differs; string rather than numeric epoch. |
|
— |
Not implemented. |
|
— |
Not implemented. |
|
|
✅ |
|
|
Carried on the message rather than in the envelope. |
Structurally conformant; the naming differs throughout and two QoS fields are absent. Since no HISPEC code constructs envelopes, renaming is a libby/bamboo concern and invisible to this repository. It only becomes a problem if another COO system implements the specification literally and expects to interoperate on the wire — worth resolving in bamboo before that happens.
The one behavioural difference to resolve is ERROR: bamboo has no error message type, which
is consistent with HISPEC having no structured error model. Failures travel as
raised exceptions rather than as typed error messages.
Roadmap#
The order below is the intended sequence of work, chosen by leverage rather than by severity. It is grouped by what each stage unlocks.
Stage 1 — make the control layer observable#
These change the contract that every future client is written against, so they come before the clients.
Surface and log the transaction ID. The transport already carries it. One structured log line per keyword modify — transaction ID, requester, keyword, value, outcome, duration — turns the journal from a record of what daemons did into a record of what they were asked to do. Requires a libby change; highest leverage item on this list.
Add a daemon state keyword.
starting/idle/busy/ready/fault, exposed like any other keyword. Each daemon already tracks its state; this publishes it. Precondition for any readiness check and for the sequencer.Add a fault state that inhibits commands. Once (2) exists, a faulted daemon should refuse non-recovery commands until explicitly cleared, rather than accepting the next write as if nothing happened.
Adopt structured error codes. A small enumeration —
NOT_CONNECTED,LIMIT_EXCEEDED,INVALID_NAME,HARDWARE_ERROR,BUSY— lets a client branch on a failure instead of matching strings.
Stage 2 — make the instrument developable without hardware#
Add a simulation backend, starting with one daemon. The filter wheel is the natural first: small keyword set, five deployed instances, and it proves the pattern for the rest. Everything in Stage 3 is gated on this.
Stage 3 — build the layers above#
Define ownership before the sequencer exists. The minimum — a read-only role, and a long-running command owning its device for its duration — is far cheaper to adopt now than to retrofit around an operating sequencer.
Build the procedure and algorithm library, then the orchestration daemon that calls it. Reusable behaviour goes in the library; daemons stay thin.
Build the operator and engineering GUIs as keyword clients.
Ongoing#
Publish telemetry rather than polling it. Thermal and vacuum keywords are the first candidates: slow-changing, many potential consumers, and no path to archiving them today.
Detect config drift.
config/is the versioned source of truth,/etc/hispec/is what runs, and nothing compares them. A daemon reporting the checksum of its loaded config as a keyword would make drift visible.Reconcile envelope field naming with the specification in bamboo, before another COO system implements it literally and expects to interoperate on the wire.
Stage 1 is the current priority. Each item there is small on its own, and together they are what turn a set of working daemons into an instrument that can be operated and diagnosed by someone who was not in the room when it was built.