Skip to content

Send both morning reports at one configurable time, as Block Kit - #16

Merged
tytremblay merged 1 commit into
mainfrom
report-time-and-blocks
Sep 1, 2026
Merged

Send both morning reports at one configurable time, as Block Kit#16
tytremblay merged 1 commit into
mainfrom
report-time-and-blocks

Conversation

@tytremblay

Copy link
Copy Markdown
Contributor

What

The two morning reports — the daily open-findings digest (was 8:00 via DIGEST_CRON) and the quarterly audit reminder (was 9:00 via QUARTERLY_CRON) — now both fire at a single report-time setting, and both are rendered as Block Kit instead of walls of text.

One time, one setting

  • New report-time setting (HH:MM, 24-hour, workspace TZ), following the existing resolution rule: database → REPORT_TIME env seed → 08:00 default. DIGEST_CRON and QUARTERLY_CRON are gone from config.ts, .env.example, and docker-compose.yml.
  • The quarterly reminder keeps its own calendar (first of Jan/Apr/Jul/Oct) and borrows only the clock time.
  • Editable from the web /config page and /hawkmod config set report-time 07:30 — both doors go through the one validator in settingsAdmin.ts (new time kind; normalizes 7:3007:30, refuses non-times).
  • Saving a new time reschedules the cron jobs immediately (rescheduleReports()), same argument as the role-group re-sync: leaving it until tomorrow would mean the setting looked applied and was not. The confirmation names the next run.
  • A hand-set invalid REPORT_TIME env var falls back to the default with a warning rather than silencing the reports.

Prettier reports

  • Digest: header with the open-finding count, findings grouped by severity (🚨 / ⚠️ / ℹ️) with counts, shorter per-finding lines (the snake_case kind is dropped — the finding's own alert carries kind, buttons, and detail), 20-item cap with "…and N more", lines chunked into sections to stay under Slack's 3000-char limit, context footer pointing at /hawkmod status.
  • Quarterly reminder: header plus a field grid (students, adults expected to enroll, last sign-off, open findings) and the runbook in a context line.
  • Unchanged: findings are named, content never appears, and a clean day still posts nothing.

Notes for review

  • parseReportTime is pure and lives in settings.ts next to parseHandles; the scheduler and validator share it. Tests in test/settings.test.ts.
  • One capability is deliberately lost: a host that had set the old cron vars to something non-daily (e.g. weekdays only) can't express that anymore — it's a time of day now.

npm run typecheck && npm test && npm run format:check && npm run build all pass (117 tests).

🤖 Generated with Claude Code

The daily digest and the quarterly reminder each had their own cron
expression (DIGEST_CRON, QUARTERLY_CRON), which let the two drift
apart. Both now fire at a single `report-time` setting — HH:MM in the
workspace timezone, resolved database -> REPORT_TIME env seed -> 08:00
— editable from the web configuration page and `/hawkmod config`
through the shared validator. Saving a new time reschedules the cron
jobs immediately, the same argument as the role-group re-sync: leaving
it until tomorrow would mean the setting looked applied and was not.
The quarterly reminder keeps its own calendar and borrows only the
clock time.

Both reports also move from walls of mrkdwn to Block Kit: the digest
groups findings by severity under a header, with per-finding lines
shortened (the finding's own alert carries the kind, buttons, and
detail) and long lists chunked under Slack's section limit; the
quarterly reminder gets a field grid for the roster and sign-off
numbers. Same rule as before: findings are named, content never
appears, and a clean day still posts nothing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@tytremblay
tytremblay merged commit 66e0691 into main Sep 1, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant