Second slice on the per-resource operator-state feature: the API
surface that the storage foundation from slice 29 was designed to
support. A frontend, pulse-cli, or Assistant tool call can now read
the operator-set state for a resource, replace it with PUT, or clear
it with DELETE.
Contract decisions worth preserving:
- GET 404s with stable error code operator_state_not_set when no
entry exists, distinct from a 200 with default (all-zero) fields.
- PUT replaces the entire record. URL canonicalId wins over body to
prevent body-manipulation retargeting; server-side setAt/setBy
populate from request time and authenticated identity, ignoring
client values so the audit trail stays honest.
- Validation rejections surface 400 with operator_state_invalid so
frontend can branch on the code without string-matching messages.
- DELETE is idempotent — 204 whether or not an entry was present.
- GET runs under monitoring:read; PUT and DELETE under
monitoring:write because the state modulates Patrol's behavior.
Finding-suppression and action-broker integrations land in subsequent
slices that consume the same ResourceOperatorState shape.