Labwire 0.4.0
Protocol version "0.4": cancellation made honest. Driven by field
reports from an Opentrons Flex owner (vcjdeboer on the PyLabRobot forum)
and the PyLabRobot maintainer: a stop request returning does not mean
motion stopped, and a Hamilton STAR command is on the wire before any
cancel can matter. SPEC-FINDINGS F10 documents both reports and the
resolution; F8 is superseded by it.
Breaking
interruptibleis removed from command capabilities; its
cancellable-by-default abandon-the-handler semantics are the behavior
the field reports indicted.cancel_semantics("abort",
"between_steps","none") replaces it, and undeclared commands
default to"none": not cancellable mid-run.- Cancelling a running
"none"command is refused with-32007, never
accepted-and-ignored. Completion now wins the race: a run that
finishes whilecancelingsettlessucceededwith a
ran_to_completionblock, where 0.3 reportedcanceledafter a
completed action.
Added
- Settlement (SPEC 8.3): acknowledgment is not settlement. Every run
that ends by or during cancellation carries a signedcancellation
block:never_started,halted(backend-confirmed only),
halted_at_boundary(only from a boundary checkpoint itself),
ran_to_completion, orunconfirmed, the honest first-class case.
Handler API:ctx.boundary()for between-steps commands,
ctx.confirm_halted()for aborts. 0.4 manifests record each command's
declared semantics, andlabwire verifyrejects offline what the
spec forbids: blocklesscanceledrecords,haltedclaims from
non-abort commands, boundary claims from commands with no boundaries.
A 24-agent adversarial review closed nine settlement holes (blockless
shutdown records, pre-start cancels claiming halts, boundary claims
from mid-step abandonment, and others) before release. - Bridge truth: PyLabRobot's abandon-the-await cancel is gone; every
atomic call declares"none", andtransfer, now sequenced by the
bridge, stops between steps with the boundary named in the record.
Ophyd declares"abort"only forEpicsMotor-family devices
(TODO-VERIFY on real EPICS) with a settlement window on the status
object;ophyd.simaxes are"none"because theirstop()is
literallypass. The syringe-pump driver earns"abort": STP then a
confirmed IDLE before any halt is claimed. MCP tool descriptions state
each tool's cancel semantics; the demos show a refused cancel, an
earned halt, and a boundary settlement.
Added in the adoption-engineering cycle
-
labwire-conformance(SPEC §15.3): an executable conformance suite
that points at ANY server over WebSocket and checks the spec's normative
requirements: handshake and version negotiation, descriptor validity and
mandatory units, S2/S3 refusal semantics, resource reads and reference
validation, error taxonomy, and signed-bundle verification including
tamper detection. Binary pass/fail per check with spec references; the
verdict is the §15.1 level actually earned. Command-executing checks are
opt-in; everything else stops at refusals servers must issue before
running anything. CI runs it against the reference server. -
Property-based wire fuzzing (hypothesis, deterministic in CI):
arbitrary JSON-RPC envelopes and submit params never kill a session and
always draw a taxonomy-tagged answer; pathologically deep payloads
survive; any content-changing byte flip or truncation of a signed bundle
fails verification (formatting-only flips legitimately still verify,
since signatures bind RFC 8785 canonical content, not raw bytes), and
unparseable or non-UTF-8 manifests get a verdict, not a traceback.
Honest result: the fuzz found no new breaks; the one wire gap of the
day (below) was found by the conformance suite first. -
Hardware-ready transports in
labwire-drivers: the line-protocol
link is now pluggable, TCP (as before) or USB-serial via the
labwire-drivers[serial]extra (pyserial-asyncio-fast, BSD-3-Clause,
the maintained successor of pyserial-asyncio; optional, never
vendored). Drivers accept a prebuiltlink=. New: an endpoint file
format (load_endpoints, strict, unknown keys are errors), a
labwire probecommand that asks a SCPI endpoint*IDN?and drafts
its annotation file with TODOs for everything a probe cannot know, and
docs/HARDWARE.md, the walkthrough for the day real equipment arrives.
Status stated everywhere it matters: real transports, tested against
simulators (TCP against the sims, serial against a PTY responder),
awaiting hardware; no vendor compatibility is claimed.
Fixed
- The WebSocket transport silently dropped unparseable frames instead of
answering-32700(and non-object JSON instead of-32600) as SPEC §12
requires. Found by running the new conformance suite against the
reference server on its first day. - Both bridge CLIs (
labwire-pylabrobot check,labwire-ophyd) failed to
importmodule:factorytargets relative to the working directory, which
broke the READMEs' own quickstart commands from a fresh clone. Targets
now resolve with the current directory onsys.path,python -m
style. Caught by the stranger test; covered by a regression test.
Full changelog: https://github.com/benchwire/labwire/blob/main/CHANGELOG.md