Site-admin DeepAlert routing switch (PUT /cameras/{id}/detection-mode).
Kept off the general camera edit payload for the same reason agent-config
is: this is a safety control, not routine camera config. "ii_gated" moves
the DeepAlert object-of-interest gate out of ingestion-server and into
incident-intelligence for this camera's clips, and a wrong value here
leaves a camera with NO object detection anywhere (see the guards in
CamerasService.update_detection_mode and the DB CHECK
ck_cameras_ii_gated_requires_ii).
WHY Literal HERE, when detection_mode is a plain str everywhere else.
The accept-then-inspect widening on the wire — interpretation_results
.terminal_stage, gate_outcome.reason, and detection_mode on
CreateEventRequest — exists so INBOUND MACHINE traffic from
incident-intelligence / ingestion-server can never 422 and lose a row
(0059_camera_detection_mode's docstring; gate_outcome_model.py). This
field is the opposite trust boundary: a human-driven config write where an
unrecognized value must fail loudly. Storing e.g. "ii-gated" would read as
NOT ii_gated at every consumer (the CHECK's IS DISTINCT FROM 'ii_gated',
EventsService.create_event, PipelineTelemetryService._state_for,
camera_health_derivations.derive_issues) and leave the camera silently
legacy while the UI reported otherwise. A closed set here and an open set
there is not an inconsistency — it is the trust boundary being different.