feat: body types, and Slack meeting reminders for committees (#95) - #100
Merged
Conversation
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Committees were distinguished from boards, teams and working groups by their name and nothing else, so no query could ask for "the committees" without pattern-matching a string. bodies.body_type is that distinction, backfilled from the names that have been carrying it: 9 Committee, 9 Board, 3 Advisory Board, 5 Team, 3 Working Group, and Senate and SGA General on Other, which is correct for them rather than a failed match. Advisory Board is tested before Board, or the three advisory boards would come out as plain boards. Committees get the reminder: the day before each weekly meeting, the bot posts the date, time, room, purpose and -- only when it is unusual -- the status, to the channel named by bodies.slack_channel_id. An id and not a name, because channels get renamed and a reminder that stops posting because someone tidied up a channel name is worse than no reminder. A week's overrides resolve against its series the same way My Rooms and the update emails resolve them, and a hidden booking is never announced: a channel is a wider audience than the people who can manage it. Anything Cancelled, Repurposed or Missed is skipped, but Pending Cancellation is posted with its status shown -- the people in the channel are exactly the ones who need to know a meeting is in doubt. Leadership turns the reminders off from inside their own channel, with /chambers-reminders off. The channel identifies the committee, so there is no body to pick and no way to reach another committee's settings; changing it additionally requires Leadership of that committee, checked against board_memberships rather than anything Slack asserts. With no argument the command reports the current state, which anyone in the channel may ask. Scheduled from a GitHub Action like the keep-warm ping, for the reason that one is: Hobby plans cap Vercel crons at one a day and this needs to retry, since GitHub schedules lag and are occasionally skipped. It fires five times across the morning; a 9am-Eastern gate keeps it from posting overnight when the date rolls over, and a recorded row per reminder keeps the later firings from posting twice. That row is keyed on (weekly_booking_id, occurrence_date) rather than an occurrence id, because the weekly PATCH regenerates its occurrences on every save and a key on their ids would forget every reminder the next time anyone made an edit. Slack answers a post to a channel the bot was never invited to with ok:false and HTTP 200, so lib/slack.ts checks the body rather than the status -- a reminder that silently never arrives is the failure this is most likely to have. A refused post deliberately writes no row, so the next run of the morning tries again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both pin America/New_York, and dev grew lib/boston-time.ts (#87) while this branch was open, so the next reader meets two modules that look interchangeable and are not. APP_TIME_ZONE is about DATE columns -- which calendar day a booking falls on. bostonWallClockNow is about SGA Spaces timestamps, which store wall-clock digits labelled Z and need a "now" in that same shape to compare against. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
pataniaeli
force-pushed
the
feat/issue-95-committee-slack-reminders
branch
from
September 9, 2026 22:39
5838d42 to
0b79754
Compare
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #95.
Body types
bodies.body_type, constrained to the six types in the issue. Backfilled from the names that have been carrying the distinction — checked against the 31 bodies live today:Advisory Board is tested before Board, or the three advisory boards come out as plain boards. Senate and SGA General are genuinely none of the six, so Other is right for them rather than a failure to match. Management can change any of them in the Bodies tab, which now shows the type on every row.
The reminder
The day before each weekly meeting, the bot posts to the channel named by
bodies.slack_channel_id:Status appears only when it is not ordinary, so a status line always means something needs attention. A week's overrides resolve against its series exactly as My Rooms and the update emails resolve them. A hidden booking is never announced — a channel is a much wider audience than the people who can manage it. Cancelled, Repurposed and Missed are skipped; Pending Cancellation is posted, with its status shown, because the people in the channel are the ones who need to know a meeting is in doubt.
A channel ID, not a name: channels get renamed, and a reminder that quietly stops because someone tidied up a name is worse than no reminder. The API rejects anything that isn't ID-shaped with an explanation rather than storing
#committee-chatand never resolving it.Turning it off
/chambers-reminders off, run in the committee's own channel. The channel is what identifies the committee, so there is no body to pick and no way to reach another committee's settings — which is the gating you asked for. Changing it additionally requires Leadership of that committee, checked againstboard_membershipsrather than anything Slack asserts. With no argument it reports the current state, which anyone in the channel may ask. Management can also toggle it from the Bodies tab.Scheduling
A GitHub Action, like the keep-warm ping and for the same reason (
382c2af): Hobby plans cap Vercel crons at one a day, and this needs to retry because GitHub schedules lag and are occasionally skipped. It fires five times across the morning, and two things make the repeats harmless — a 9am-Eastern gate so nothing posts overnight when the date rolls over, and a recorded row per reminder so later firings find the work done. That row is keyed on(weekly_booking_id, occurrence_date)and not an occurrence id, because the weekly PATCH regenerates its occurrences on every save; a key on their ids would forget every reminder the next time anyone edited the booking and re-post the lot.Verification
npm run build,tscandeslintclean (the onebodies-tab.tsxerror is pre-existing).<!channel>typed into a booking purpose cannot make the bot ping everyone.Before this works in production
SLACK_BOT_TOKENneedschat:write, and the bot must be invited to each committee's channel — Slack refuses a post to a channel it isn't in withok: falseand HTTP 200, which is whylib/slack.tschecks the body and logs. Or addchat:write.public./chambers-remindersas a slash command on the Slack app, pointed at the existing/api/slack/commandendpoint.CRON_SECRETrepo secret (the keep-warm action already uses it).I could not click through the Management UI: the dev server is behind a login wall.
🤖 Generated with Claude Code