LiquidHandler: gate aspirate96 tip volume tracking on does_volume_tracking()#1095
Merged
BioCam merged 1 commit intoJun 22, 2026
Merged
Conversation
…tracking()` aspirate96 gated the source remove_liquid on does_volume_tracking() but added to the 96-head tip trackers unconditionally, so with volume tracking globally off the wells were left untouched while the tips were still loaded. Restructure both aspirate96 branches to match single-channel aspirate: the whole tracker block, tip included, under one does_volume_tracking() guard, with is_disabled checked only on the container. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
aspirate96 gated the source
remove_liquidondoes_volume_tracking()but added to the 96-head tip trackers unconditionally, so with volume tracking globally off the wells were left untouched while the tips were still loaded - tip state drifting away from a source that never changed.Single-channel
aspirateis the canonical pattern: the whole tracker block, tip included, sits under onedoes_volume_tracking()guard, andis_disabledis checked only on the container (tips are never disabled). This restructures both aspirate96 branches - single-container and 96-well - to the same shape, so the global flag governs the tip side as well as the source. When tracking is on, behavior is unchanged.Test: with tracking off, aspirate96 leaves the 96-head tip trackers untouched.
The matching cleanup of the tip commit/rollback loops in aspirate96 and dispense96 - currently ungated but a no-op once the queue is gated - is left to a follow-up consistency PR.
Problem deep-dive
Disabling volume tracking is meant to turn off all liquid bookkeeping, but aspirate96 kept writing to the tip trackers anyway. The numbers below are from a run against
hamilton_96_tiprack_300uL_filter, whose tips track to a 360 uL ceiling:After that single call, before this change:
The source says nothing was removed, the tips claim to hold 200, and the books do not balance - even though tracking was explicitly off. Single-channel
aspiratein the same scenario leaves the tips at 0.The sharp, throwable consequence shows up on the next aspirate:
VolumeTracker.add_liquidruns its capacity check unconditionally, so the phantom 200 uL leaves only 160 uL free and the next 200 uL overflows the tip, raisingTooLittleVolumeError- the precise class of error the user disabled tracking to avoid. After this change the tip tracker is never written while tracking is off, so neither the divergence nor the spurious error occurs.It only ever affected the tracking-off path; with tracking on the tip add fired in both versions, so normal workflows were unaffected, which is why it went unnoticed.