Skip to content

Slack auto-linkifies email-shaped setting values (mailto: corruption in calendar ids), and hides it on re-render #30

Description

@rachmo

Bug, not yet spec'd

Found 2026-08-16 while troubleshooting "/hawkbot calendar returns Not Found for every calendar" on the production workspace, despite /hawkbot config showing correct-looking calendar ids and all three calendars confirmed shared with the service account. Logging it as a note to revisit with a grilling session later, not ready for implementation.

Root cause (found with help from Ty Tremblay, see Slack thread): Google Calendar ids look like email addresses (c_xxx@group.calendar.google.com). When a coach types one into /hawkbot config set team_meeting_calendar_id <id>, Slack's client auto-converts the email-shaped text into a mailto: link before the server ever sees it — the command payload arrives as <mailto:c_xxx@group.calendar.google.com|c_xxx@group.calendar.google.com>. checkSetting in src/domain/settings.ts already unwraps Slack's escaping for two other formats — <#C0123|name> channels via unwrapChannel and <!subteam^S0123|@handle> user groups via unwrapUserGroupHandle — but has no equivalent unwrap for Slack's link/mailto format. So the stored value became mailto:c_xxx@group.calendar.google.com, which isn't a valid calendar id, and fetchCalendarEvents in src/calendar/client.ts got a 404 Not Found from Google for a calendar that doesn't exist under that literal string.

Why it took so long to find: the corruption was invisible in Slack's UI. Once the bad value was stored, every place that echoed it back — /hawkbot config's display, and the bot's own error message (mailto:c_xxx@... doesn't exist as a calendar id) — got the mailto: prefix re-rendered by Slack as a link, which displays as just the plain id. So the displayed text looked identical to a correct calendar id in every surface we checked; only right-clicking the rendered link and choosing "Remove Link" (or reading the raw value server-side) revealed the prefix.

Affected settings today: the three calendar ids (team_meeting_calendar_id, informational_calendar_id, mentor_calendar_id) — the only settings shaped like an email address. Worth checking the rest of the SETTINGS list for anything else that could be URL-shaped (Slack also auto-links bare URLs, not just emails) and hit the same trap.

Why it's not simple — a few open questions for the grilling session:

  • What's the general fix: a targeted unwrapMailto-style helper applied only to the calendar-id settings (matching how unwrapChannel/unwrapUserGroupHandle are targeted), or a blanket unwrap-any-Slack-link step applied to every setting value in checkSetting, since we can't fully predict which future settings might be email/URL-shaped?
  • Slack's link syntax varies (<mailto:x|y> for auto-linked emails, <http://x|y> / <https://x|y> for auto-linked URLs) — does the unwrap need to handle both, or just mailto for now?
  • Should /hawkbot config set silently unwrap (like the existing channel/usergroup unwraps do), or tell the coach it detected and stripped a link wrapper, so they know Slack did something to their input?
  • Three settings in the production DB were already corrupted this way before we caught it — worth a one-off audit/fix of existing stored values (or a migration), not just fixing new writes.

Not scoped or prioritized — just don't want to lose the finding or make someone else rediscover it the hard way.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions