Skip to content

feat(operate): target a subset of embryos for a run - #161

Merged
pskeshu merged 1 commit into
gently-project:developmentfrom
pskeshu:feat/target-selection
Sep 6, 2026
Merged

feat(operate): target a subset of embryos for a run#161
pskeshu merged 1 commit into
gently-project:developmentfrom
pskeshu:feat/target-selection

Conversation

@pskeshu

@pskeshu pskeshu commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator

Answers the question directly: yes, you can target one embryo — and the capability was in the orchestrator all along.

orchestrator.start(embryo_ids=[...]) images exactly those, and the route passes it straight through. The UI never offered it: adaptive and library sent every non-reference embryo.

The only workaround was to mark the others as references, and role is not a selection mechanism. It decides what an embryo is forexpression_monitoring scopes to role == 'test', and _is_eligible reads role.photodose_budget_multiplier for the dose budget. So excluding an embryo from tonight's run by demoting it also changed its monitoring and its exposure allowance. Two different facts, one field.

Selection is a set

_selected stays the primary — the one the instrument panes act on, unchanged in meaning. _targets is every member.

gesture
click replaces the set
Ctrl/Cmd-click toggles membership
Shift-click range from the primary

The interaction every file manager, DAW and photo library already teaches, so the set needs no chrome of its own. With one embryo selected the two coincide — single-embryo work is identical to before. Two row states, deliberately distinct: is-sel is membership, is-primary is the cursor.

Narrowing is a thing you say

Targets deliberately do not follow the selection implicitly. If they did, a plain click in the roster would narrow a timelapse from every subject to one, silently — a worse failure than not having the feature.

So Acquisition carries a two-state control, All subjects (n) / Selected (n), defaulting to All, which is exactly what this pane has always done. It also means the modifier keys need not be discovered for the scope to be readable, and Selected is disabled until something is.

A reference is never a target however it is selected. And the set drops members that no longer exist on a roster refresh, or it would silently target ghosts — the same class as the phantom row in #126.

Verified live

Plain/Ctrl/Shift produce [2], [2,4], [1,2,3,4]. The payload sent to timelapse/start is all three subjects under All, exactly the two selected under Selected, and all three again on switching back. Counts exclude a selected reference.

Next: the orchestrator's live per-embryo state in the same pane — three fields (cadence_phase, next_due_at, is_complete) are missing from EmbryoState.to_dict(), and everything else it knows is already on the wire.

The orchestrator and the route have always taken an explicit `embryo_ids` list
— `orchestrator.start(embryo_ids=[...])` images exactly those, and the route
passes it straight through. The UI never offered it: `adaptive` and `library`
sent every non-reference embryo, and there was no way to say "just this one".

The only workaround was to mark the others as references, and `role` is not a
selection mechanism. It decides what an embryo is FOR: `expression_monitoring`
scopes to `role == 'test'`, and the orchestrator's `_is_eligible` reads
`role.photodose_budget_multiplier` for the dose budget. So excluding an embryo
from tonight's run by demoting it also changed its monitoring and its exposure
allowance. Two different facts, one field.

## Selection is a set

`_selected` stays the primary — the one the instrument panes act on, which is
what it has always meant. `_targets` is every member. Plain click replaces,
Ctrl/Cmd-click toggles, Shift-click ranges: the interaction every file manager,
DAW and photo library already teaches, so the set needs no chrome of its own.
With one embryo selected the two coincide, so single-embryo work is unchanged.

Two row states, deliberately distinct: `is-sel` is membership, `is-primary` is
the cursor.

## Narrowing is a thing you say

Targets deliberately do NOT follow the selection implicitly. If they did, a
plain click in the roster would narrow a timelapse from every subject to one,
silently — a worse failure than not having the feature at all. So Acquisition
carries a two-state control, `All subjects (n)` / `Selected (n)`, defaulting to
All, which is exactly what this pane has always done. It also means the
modifier keys do not have to be discovered for the scope to be readable, and
"Selected" is disabled until something is.

A reference is never a target however it is selected — role still decides what
an embryo is for.

The set drops members that no longer exist on a roster refresh, or it would
silently target ghosts: the same class as the phantom row in gently-project#126.

Verified live: plain/ctrl/shift produce `[2]`, `[2,4]`, `[1,2,3,4]`; the
payload sent to `timelapse/start` is all three subjects under All, exactly the
two selected under Selected, and all three again on switching back. The counts
exclude a selected reference.

Answers the question directly: yes, you can target one embryo — and the
capability was in the orchestrator all along.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@pskeshu
pskeshu merged commit 60a5297 into gently-project:development Sep 6, 2026
2 checks passed
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