Problem
Manager review is manual, and this station has a documented history of limbo states going unnoticed — a migration backfill predicate drift stranded ~17 DJs at /login?incomplete=true until someone noticed (#1451 lineage). "A manager will review it" is not a safe assumption, and the whole point of this feature is that it runs during weeks when nobody is watching.
Without this job, a self-signed account keeps dj — and flowsheet write access — indefinitely if the queue is ignored.
Desired end state
A jobs/station-signup-review workspace doing two things daily:
- Digest — while any accounts are pending, email a summary to
STATION_SIGNUP_ALERT_EMAIL. Follow jobs/metadata-no-match-digest/ as the template, including resolveDigestRecipient()'s shape in its email.ts and the EMAIL_ENABLED kill switch.
- Downgrade — accounts pending review for more than 30 days drop
dj -> member. Reversible with one roster edit; never deletes, never bans.
Both live in one workspace because they read the same rows, which lets the digest name the accounts about to be downgraded rather than re-deriving the other job's cutoff.
Why 30 days: it exceeds any holiday break, so it cannot fire mid-break and strand a working DJ. It only ever catches accounts nobody reviewed after the break ended.
The downgrade write path
Write auth_member.role directly via @wxyc/database, as jobs do. This is safe for this specific pair because grantsAdminFlag is normalizeRole(role) === 'stationManager', so neither dj nor member touches the auth_user.role='admin' flag and no hook needs to fire.
State that invariant in the job. Reusing this path for a different role pair would desync the admin flag silently. See #2171 for the standing auth_user.role / auth_member.role drift this relies on not making worse.
Recipient
STATION_SIGNUP_ALERT_EMAIL, pointed at a station alias rather than a personal inbox — this feature exists for weeks when individuals are away. Mirrors DIGEST_RECIPIENT_EMAIL in jobs/metadata-no-match-digest/email.ts.
Cron registration
docs/ops-cron-scheduling.md under "Excluded / DB-only" (line 46), not the LML slot table.
Acceptance criteria
Context
Plan: ~/Downloads/wxyc-station-passcode-signup-plan.md.
Related
Blocked by the schema issue.
Blocked by
Problem
Manager review is manual, and this station has a documented history of limbo states going unnoticed — a migration backfill predicate drift stranded ~17 DJs at
/login?incomplete=trueuntil someone noticed (#1451 lineage). "A manager will review it" is not a safe assumption, and the whole point of this feature is that it runs during weeks when nobody is watching.Without this job, a self-signed account keeps
dj— and flowsheet write access — indefinitely if the queue is ignored.Desired end state
A
jobs/station-signup-reviewworkspace doing two things daily:STATION_SIGNUP_ALERT_EMAIL. Followjobs/metadata-no-match-digest/as the template, includingresolveDigestRecipient()'s shape in itsemail.tsand theEMAIL_ENABLEDkill switch.dj->member. Reversible with one roster edit; never deletes, never bans.Both live in one workspace because they read the same rows, which lets the digest name the accounts about to be downgraded rather than re-deriving the other job's cutoff.
Why 30 days: it exceeds any holiday break, so it cannot fire mid-break and strand a working DJ. It only ever catches accounts nobody reviewed after the break ended.
The downgrade write path
Write
auth_member.roledirectly via@wxyc/database, as jobs do. This is safe for this specific pair becausegrantsAdminFlagisnormalizeRole(role) === 'stationManager', so neitherdjnormembertouches theauth_user.role='admin'flag and no hook needs to fire.State that invariant in the job. Reusing this path for a different role pair would desync the admin flag silently. See #2171 for the standing
auth_user.role/auth_member.roledrift this relies on not making worse.Recipient
STATION_SIGNUP_ALERT_EMAIL, pointed at a station alias rather than a personal inbox — this feature exists for weeks when individuals are away. MirrorsDIGEST_RECIPIENT_EMAILinjobs/metadata-no-match-digest/email.ts.Cron registration
docs/ops-cron-scheduling.mdunder "Excluded / DB-only" (line 46), not the LML slot table.Acceptance criteria
jobs/*footprint (seejobs/flowsheet-ghost-row-sweep/)EMAIL_ENABLEDauth_user.roleuntouched, with a test pinning the invariantSTATION_SIGNUP_ALERT_EMAILdocumented indocs/env-vars.mdContext
Plan:
~/Downloads/wxyc-station-passcode-signup-plan.md.Related
Blocked by the schema issue.
Blocked by