> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ionworks.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 2026 07 23 schedule channel context auto watch design

# Schedule channel context + auto-watch requester design

## Summary

Two Lab scheduling UX fixes:

1. **Enriched Schedule channel dropdown** — each option shows live availability
   state and electrical ratings (A / V) so schedulers do not bounce to the Lab
   wall to judge fit.
2. **Auto-watch requester on start** — when a scheduled planned measurement
   links to a started `cell_measurement`, the backend silently watches that
   measurement for `requested_by` only.

No protocol auto-filter, mismatch badges, toasts, or auto-watch for
`scheduled_by` / operators.

## Problem

* The Schedule dialog (`SchedulePlannedMeasurementDialog`) Autocomplete lists
  only `cycler / channel` (and disables out-of-commission). Availability and
  ratings already exist on the Lab wall via `GET .../lab/status`, but not in the
  picker, so schedulers context-switch to Lab view.
* Watching is manual. When a requested test finally starts, the requester does
  not appear on “My Channels” until they find the channel and click Watch.

## Current state (references)

* Schedule dialog:
  `frontend/src/sections/lab/schedule-planned-measurement-dialog.tsx`
* Lab status types + query: `frontend/src/redux/api/lab-api.ts`
  (`LabChannel.state`, `max_amps`, `min_volts`, `max_volts`)
* Lab wall tiles already format ratings:
  `frontend/src/sections/lab/channel-tile.tsx`, `wall-scope.ts`
  (`formatRatingRange`)
* Planned measurements overview: `dev-docs/planned-measurements.md`
* Link on measurement create:
  `CellMeasurementService` →
  `PlannedMeasurementRepository.link_started_measurement`
  (`backend/src/services/cell_measurements.py` \~2107)
* Alternate path: PATCH planned measurement to `in_progress` +
  `started_measurement_id` via `PlannedMeasurementService`
* Watches: `UserWatchedMeasurementService.watch(user_id, measurement_id)`
  (idempotent) in `backend/src/services/user_watched_measurements.py`
* Planned row fields: `requested_by`, `scheduled_by`

## Design

### 1. Enriched channel Autocomplete (frontend only)

**File:** `schedule-planned-measurement-dialog.tsx`

When flattening `labStatus.sites → cyclers → channels`, keep:

* `id`, label (`${cycler.name} / ${channel.name}`)
* `outOfCommission` (still disables the option)
* `state` (`free` | `occupied` | `stale` | `out_of_commission`)
* `max_amps`, `min_volts`, `max_volts`

**Option rendering:**

* Primary: `cycler / channel`
* Secondary: ratings via existing `formatRatingRange` (same string shape as Lab
  tiles, e.g. `40 A · 0–5 V`; omit empty parts)
* Trailing / muted: human state label (`free`, `occupied`, `stale`; out of
  commission already in the disabled label today)

**Behavior unchanged:**

* All non–out-of-commission channels remain selectable (including occupied /
  stale).
* Selecting a channel still fetches next available start and prefills / shows
  the existing helper text.
* No comparison against protocol voltage/current; no sorting or filtering by
  “fit”.

**API:** reuse `useGetProjectLabStatusQuery` — no backend change.

**Tests:** lightweight unit/render test that option content includes state +
ratings when lab status fixture supplies them (follow existing lab section test
patterns).

### 2. Auto-watch requester when plan becomes in progress (backend)

**Trigger (both paths):**

1. **Primary:** after a successful
   `link_started_measurement` (returns a linked plan, not `None`) in
   `CellMeasurementService`’s planned-measurement link helper.
2. **Secondary:** when `PlannedMeasurementService` update transitions a row to
   `in_progress` with a new `started_measurement_id` (logger PATCH path).

**Action:**

* Resolve `requested_by` from the linked/updated planned measurement.
* Call `UserWatchedMeasurementService.watch(requested_by, started_measurement_id)`
  (or equivalent repo call with org resolved as today).
* Idempotent: already-watching is a no-op.

**Failure policy:**

* Watch errors must **not** fail measurement create or plan update.
* Log at warning/exception level and continue (same spirit as today’s
  “created measurement but failed to link plan” handling).

**Not in this change:**

* Auto-watch `scheduled_by`
* Client-side watch after polling status
* Toast / email / push notification
* Unwatch previous measurements for the requester

**Dependency wiring:** inject
`UserWatchedMeasurementService` (or its repository) into
`CellMeasurementService` / `PlannedMeasurementService` as needed; prefer the
service so org resolution and idempotency stay centralized.

**Tests:**

* Link scheduled plan → measurement: assert a
  `user_watched_measurements` row for `(requested_by, measurement_id)`.
* Second link/watch is idempotent (no error).
* Forced watch failure still leaves measurement created / plan `in_progress`.
* PATCH-to-`in_progress` path also creates the watch.

## Out of scope

* Protocol envelope vs channel rating auto-check or disable
* Embedding Lab wall / mini channel grid in the Schedule dialog
* Auto-watch for anyone other than `requested_by`
* Realtime push to open Lab wall clients (cache invalidation remains as today
  when the requester next loads lab status)
* Changing next-available slot UX beyond current helper text

## Success criteria

* Scheduler can see free/occupied/stale and A/V ratings in the Schedule channel
  list without opening the Lab wall.
* When a scheduled test starts and links to a measurement, that measurement is
  watched for the requester so it can show under “My Channels” on their next
  Lab status fetch.
