Skip to content

Tip: add nominal_volume, the rated working volume distinct from physical capacity#1102

Merged
rickwierenga merged 1 commit into
PyLabRobot:mainfrom
BioCam:tip-nominal-volume
Jun 22, 2026
Merged

Tip: add nominal_volume, the rated working volume distinct from physical capacity#1102
rickwierenga merged 1 commit into
PyLabRobot:mainfrom
BioCam:tip-nominal-volume

Conversation

@BioCam

@BioCam BioCam commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Adds a nominal_volume field to Tip - the tip's rated working volume (what it is sold and named as), distinct from maximal_volume, the physical brim-full capacity.

The rated volume previously lived only in the creator names and was discarded: hamilton_tip_300uL stored maximal_volume=400, so the "300" - the number a user thinks in, and the natural basis for default volumes and capacity checks - was unreadable from the Tip.

  • nominal_volume: Optional[float] = None; falls back to maximal_volume in __post_init__ when omitted, so every tip always has a sensible value.
  • Informational only: the VolumeTracker is still bound by maximal_volume. No tracking or validation behaviour changes.
  • Added to serialize, __hash__, and __eq__. The TipTracker carries it through pickup/drop (it holds the Tip by reference) and across save/load (serialize now emits it, deserialize reads it).
  • Threaded through HamiltonTip and set on all 15 Hamilton creators, e.g. nominal_volume=300 on hamilton_tip_300uL (max 400). Values are the manufacturer's rated volume, cross-checked against the Hamilton catalog (the CO-RE tip families are named by rated volume; cat. nos. 235966/235948 -> 50 uL, 235900/235901 -> 10 uL confirm it).

Backward compatible: optional with a default, so no call site changes and no current tip's reported numbers change. Payloads predating the field deserialize fine (the missing key falls back to maximal_volume). It now participates in equality/hashing, but since the fallback makes an unset nominal equal to maximal_volume, only tips with a genuinely distinct rating differ.

Follow-up (not in this PR): the same rated-vs-physical split applies to Container. Two pre-existing maximal_volume data questions surfaced while setting the values and are left untouched here - hamilton_tip_10uL_filter has maximal_volume=10 (equal to its nominal, below the 15 uL non-filter), and hamilton_tip_5000uL / _filter share an identical max.

Tests: defaults to maximal_volume when omitted; a payload missing the key falls back on deserialize; the updated serialize snapshots include the field.

🤖 Generated with Claude Code

…hysical capacity

Adds a `nominal_volume` field to `Tip` - the tip's rated working volume (what it is sold and named as), distinct from `maximal_volume`, the physical brim-full capacity.

The rated volume previously lived only in the creator names and was discarded: `hamilton_tip_300uL` stored `maximal_volume=400`, so the "300" - the number a user thinks in, and the natural basis for default volumes and capacity checks - was unreadable from the `Tip`.

- `nominal_volume: Optional[float] = None`; falls back to `maximal_volume` in `__post_init__` when omitted, so every tip always has a sensible value.
- Informational only: the `VolumeTracker` is still bound by `maximal_volume`. No tracking or validation behaviour changes.
- Added to `serialize`, `__hash__`, and `__eq__`. The `TipTracker` carries it through pickup/drop (it holds the `Tip` by reference) and across save/load (serialize now emits it, deserialize reads it).
- Threaded through `HamiltonTip` and set on all 15 Hamilton creators, e.g. `nominal_volume=300` on `hamilton_tip_300uL` (max 400). Values are the manufacturer's rated volume, cross-checked against the Hamilton catalog (the CO-RE tip families are named by rated volume; cat. nos. 235966/235948 -> 50 uL, 235900/235901 -> 10 uL confirm it).

Backward compatible: optional with a default, so no call site changes and no current tip's reported numbers change. Payloads predating the field deserialize fine (the missing key falls back to `maximal_volume`). It now participates in equality/hashing, but since the fallback makes an unset nominal equal to `maximal_volume`, only tips with a genuinely distinct rating differ.

Follow-up (not in this PR): the same rated-vs-physical split applies to `Container`. Two pre-existing `maximal_volume` data questions surfaced while setting the values and are left untouched here - `hamilton_tip_10uL_filter` has `maximal_volume=10` (equal to its nominal, below the 15 uL non-filter), and `hamilton_tip_5000uL` / `_filter` share an identical max.

Tests: defaults to `maximal_volume` when omitted; a payload missing the key falls back on deserialize; the updated serialize snapshots include the field.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@BioCam BioCam requested a review from rickwierenga June 22, 2026 15:53
@rickwierenga rickwierenga merged commit bee77e7 into PyLabRobot:main Jun 22, 2026
21 checks passed
@rickwierenga

Copy link
Copy Markdown
Member

nice

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.

2 participants