Context
#2735 shipped the hot-path recheck in PR (coming shortly): `sendChannelMessage({ requirePrivate: true })` calls `verifyChannelStillPrivate` which piggybacks on the existing 30-minute channel-info cache. A channel toggled public stops receiving sensitive posts within one cache TTL.
The issue flagged a backstop as optional: a daily audit that scans the six admin-configured channels, detects drift proactively (even for channels that haven't been written to recently), and either clears the setting or notifies an admin.
Scope
- Background job, runs once per day.
- Reads all six rows from `system_settings` (`billing_slack_channel`, `escalation_slack_channel`, `admin_slack_channel`, `prospect_slack_channel`, `error_slack_channel`, `editorial_slack_channel`).
- For each, call `slack/client.getChannelInfo(channel_id)` (cache-aware) and check `is_private`.
- On drift:
- Emit structured audit log (`event: 'channel_privacy_drift_audit'`).
- Post a Slack DM to the admin owner (if known) — NOT to the drifted channel itself.
- Optionally auto-null the setting so subsequent sends fail hard rather than being caught by the recheck.
Acceptance
- Audit runs on a schedule (cron).
- Detects drift for channels that haven't been written to recently (the hot-path recheck only detects drift at send time).
- Notifies a human without using the drifted channel as the notification surface.
Context
#2735 shipped the hot-path recheck in PR (coming shortly): `sendChannelMessage({ requirePrivate: true })` calls `verifyChannelStillPrivate` which piggybacks on the existing 30-minute channel-info cache. A channel toggled public stops receiving sensitive posts within one cache TTL.
The issue flagged a backstop as optional: a daily audit that scans the six admin-configured channels, detects drift proactively (even for channels that haven't been written to recently), and either clears the setting or notifies an admin.
Scope
Acceptance