Skip to content

OpentronsOT2ChatterboxBackend: a dry-run OT-2 backend with I/O logging, via a transport seam#1132

Open
BioCam wants to merge 5 commits into
PyLabRobot:mainfrom
BioCam:ot2-transport-seam
Open

OpentronsOT2ChatterboxBackend: a dry-run OT-2 backend with I/O logging, via a transport seam#1132
BioCam wants to merge 5 commits into
PyLabRobot:mainfrom
BioCam:ot2-transport-seam

Conversation

@BioCam

@BioCam BioCam commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Adds OpentronsOT2ChatterboxBackend, a dry-run backend for the OT-2 that runs the real backend logic with no hardware and no ot_api library, mirroring how STARChatterboxBackend dry-runs STARBackend. Unlike OpentronsOT2Simulator (which overrides the high-level methods with single-channel stubs), the chatterbox replaces only the transport, so pipette selection, tip/volume tracking, and the per-operation wire calls all run unchanged.

To enable that, the backend routes every ot_api call - including the run-cancel calls in stop() - through a single self._ot transport handle. The real handle wraps ot_api in a transparent _IOLogger proxy that logs every HTTP call at LOG_LEVEL_IO, like other backends get from their io object; the chatterbox swaps the handle for a recorder that logs the same way, so a dry run captures the same wire trace as a real run.

Characterization tests pin the existing wire calls (home / stop-cancel / list_connected_modules / addressable-area trash drop) so the seam refactor cannot change them silently; chatterbox tests run a full protocol with no ot_api installed and assert the recorded calls.

Foundation of the OT-2 series; depends on nothing else in it.

🤖 Generated with Claude Code

BioCam and others added 4 commits June 29, 2026 22:56
Characterization tests ahead of the transport-seam refactor (Phase 0). The
existing suite already asserts the pickup/drop/aspirate/dispense wire calls;
this adds the four remaining ot_api call sites so the seam refactor cannot
change them silently:

- home() issues one ot_api.health.home()
- list_connected_modules() returns ot_api.modules.list_connected_modules() verbatim
- stop() cancels the active run via the requestor and clears mounted pipettes
- a discard to the deck trash at api_version >= 7.1.0 routes through the
  addressable area (move_to_addressable_area_for_drop_tip + drop_tip_in_place),
  not drop_tip

No production code changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Introduces a single transport seam (Phase 1): every ot_api call - including the
run-cancel requestor calls in stop() - now goes through self._ot, set to the
ot_api module in __init__. Behaviour is unchanged (self._ot is ot_api), but a
subclass can now dry-run the backend by swapping the handle for a recording
stand-in, the way STARChatterboxBackend overrides STAR's transport.

The dedicated `import ot_api.requestor as _req` is dropped; ot_api.requestor is
reachable through the handle (self._ot.requestor).

Guarded by the Phase 0 characterization tests, which patch ot_api.* and stay
green because self._ot is the same module object.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nsport seam

Phase 2. A chatterbox sibling to OpentronsOT2Backend that swaps the self._ot
transport handle for a recorder, so the real backend logic - pipette selection,
tip and volume tracking, the per-operation wire calls - runs unchanged with no
hardware and no ot_api library. Mirrors STARChatterboxBackend (transport-only
override) rather than OpentronsOT2Simulator (which reimplements the high-level
methods single-channel).

Issued calls are printed and collected in .commands. The recorder returns canned
data for the reads setup() and the operations make back (mounted pipettes, api
version, labware define, save_position, modules). Exported from backends/__init__.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…mulator

Phase 3. Direct tests run the chatterbox with no ot_api installed: setup resolves
both mounts, a pickup -> aspirate -> dispense -> trash-discard records exactly one
wire call per operation, an unknown pipette name raises, and serialize() captures
the mounts. A differential audit runs the same single-channel protocol through the
chatterbox and the reference OpentronsOT2Simulator and asserts identical tracked
outcomes (tip mounted, source/destination volumes). The audit is scoped to the
single-channel overlap, since the simulator cannot represent a multi-channel head.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@BioCam BioCam changed the title OpentronsOT2Backend: route all ot_api I/O through a self._ot handle OpentronsOT2ChatterboxBackend: a dry-run OT-2 backend, via a transport seam Jun 30, 2026
The OT-2 talks HTTP through ot_api rather than a pylabrobot.io transport, so its
wire traffic never reached the IO log other backends produce. Wrap the real ot_api
handle in a transparent _IOLogger proxy that logs every call (submodules recursed,
plain attributes passed through) at LOG_LEVEL_IO. The chatterbox recorder logs the
same way, so a dry run captures the same wire trace as a real run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@BioCam BioCam changed the title OpentronsOT2ChatterboxBackend: a dry-run OT-2 backend, via a transport seam OpentronsOT2ChatterboxBackend: a dry-run OT-2 backend with I/O logging, via a transport seam Jun 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant