`registerAuditedModels()` (#4781) declared four models. The Settings page
has seven tabs, and a sweep found Groups and Agents fully audited beside
Priorities, Statuses, Projects, Email connections and Automation writing
nothing at all — zero rows for any of their routes in the whole store.
`PriorityLevel`, `TicketStatus` and `TicketingProject` are now declared,
in the shape the existing four use. `color` and `description` are left
out of all three for the reason the group's colour is.
The Email tab could not be declared. Its mailbox host, port, username and
PASSWORD live in one `config` JSON column, and `Audit::redact()` masks by
top-level field name only — `normalize()` walks into an array and never
redacts inside one — so declaring `config` would write the school's
mailbox credential in clear into a table read under `logs.view` alone.
Declaring only the scalar columns is the other trap: an update that moved
no declared field records nothing, so re-pointing a connection at a
different mailbox would still have been silent, which is the write the
card was filed about. `EmailConnectionAudit` is therefore the one writer
for that tab, flattening `config` into `config.host` / `config.password`
keys — the spelling the central redaction masks — and masking the secret
at source as well, so the credential never reaches the logger at all.
`EmailConnectionAuditLabels` declares the label with no observer, the
shape `PulseAuditLabels` and `GroupAuditLabels` use, so those rows are
not doubled.
The Automation tab writes shell `Setting` rows, which no declaration here
could reach; `AutomationSettingsAudit` records one row per save naming
only what moved.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>