Update an audit definition.
name is required and always overwritten; every other field is optional and
an omitted one keeps its current value — there is no way to clear a field
back to NULL here. The same ranges as create apply. A changed
schedule_interval_secs or schedule_anchor takes effect at the next
reschedule, not on the run already queued.
Authorizations
A scoped AgentEye API key. Mint one in the dashboard under Settings → API keys, or with POST /v1/keys. Each endpoint names the permission it requires; a key without it gets 403 and a required_permission field naming what was missing.
Path Parameters
The audit's id.
Body
NOT writable here — see PUT /audits/{id}/context.
Present ONLY so a client that sends it gets a loud 422 instead of serde's default of silently ignoring an unknown field, which is how a whole feature goes missing with a green test suite.
Reference context to store WITH the definition. Create only — an update sending it gets the same 422 as the two fields above.
It lives here for one reason, and the reason is a race, not convenience:
the insert trigger queues an eval job whose next_attempt_at defaults to
now(), so a new enabled audit is due the instant its row commits. A
client that created the audit and then wrote its context in a second
request could be overtaken by the dispatcher, and the first run — the one
an operator watches — would argue without the brief they just typed.
Writing both in one transaction removes the window rather than narrowing
it: the job row and the context rows become visible together.
Why an update must NOT accept it: _audit_to_body (CLI) and
auditToInput (dashboard) rebuild this whole body from an allowlist
before every save, so a context field on the update path would be wiped
by any unrelated edit — 200 OK, no error, brief gone. Create has no
read-merge step and therefore no such hazard. See the module comment in
routes/audit_context.rs.
NOT writable here — see PUT /audits/{id}/context.
Fixed phase for the schedule: runs land on anchor + N * interval.
Omitted on create → default_schedule_anchor() (next 09:00 UTC, matching
the 09:00 backfill in 20260721000200). Omitted on update → unchanged.
NULL in the DB is still tolerated by the dispatcher (legacy drift path)
but nothing this route writes can produce it any more.
Response
Audit updated.

