Skip to content

[codex] Add onboarding email command#330

Open
michaelmwu wants to merge 1 commit into
mainfrom
michaelmwu/onboarding-email-automation
Open

[codex] Add onboarding email command#330
michaelmwu wants to merge 1 commit into
mainfrom
michaelmwu/onboarding-email-automation

Conversation

@michaelmwu

@michaelmwu michaelmwu commented Jun 6, 2026

Copy link
Copy Markdown
Member

Summary

  • Add a shared deterministic onboarding email builder with HTML, text, and Discord Markdown output.
  • Add a Discord /onboarding-email command that looks up candidate data from CRM, prompts with a selector for multiple matches, and labels/blocks already-onboarded contacts.
  • Render dry-run drafts directly as ephemeral Discord rich text for copy/paste instead of HTML/TXT attachments.
  • Format the greeting as Great Talking, plus the candidate first name on the next line; default sender signature comes from the command user's CRM first name.
  • Link #prospective-members to the Discord channel URL in Markdown/HTML drafts.
  • Limit command use to Steering Committee+ or the candidate's designated CRM onboarder.
  • Configure onboarding SMTP settings for Migadu-style sending from onboarding@508.dev with command-user Reply-To, plus docs and tests.

Validation

  • uv run pytest tests/unit/test_bot.py tests/unit/test_onboarding_email.py tests/unit/test_onboarding_email_cog.py tests/unit/test_discord_command_metadata.py
  • uv run ruff check packages/shared/src/five08/onboarding_email.py apps/discord_bot/src/five08/discord_bot/cogs/onboarding_email.py tests/unit/test_onboarding_email.py tests/unit/test_onboarding_email_cog.py apps/discord_bot/src/five08/discord_bot/config.py tests/unit/test_bot.py
  • uv run ruff format --check packages/shared/src/five08/onboarding_email.py apps/discord_bot/src/five08/discord_bot/cogs/onboarding_email.py tests/unit/test_onboarding_email.py tests/unit/test_onboarding_email_cog.py apps/discord_bot/src/five08/discord_bot/config.py tests/unit/test_bot.py
  • uv run mypy apps/discord_bot/src/five08/discord_bot/config.py apps/discord_bot/src/five08/discord_bot/cogs/onboarding_email.py packages/shared/src/five08/onboarding_email.py
  • pre-commit hook during commit/amend: ruff, ruff format, mypy

Summary by CodeRabbit

  • New Features

    • Added a Discord slash command to draft and optionally send 508.dev onboarding emails.
    • Added deterministic onboarding email generation (plain, markdown, and HTML) and sender/recipient handling.
  • Documentation

    • Added onboarding-email SMTP environment variables to examples and environment docs; documented usage, permissions, and reply-to behavior.
  • Tests

    • Added extensive unit tests for email generation, command flows, authorization, reply-to validation, chunking, and SMTP sending.

Copilot AI review requested due to automatic review settings June 6, 2026 03:07
@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a deterministic onboarding email builder, onboarding SMTP configuration, a Discord cog exposing /onboarding-email that resolves CRM contacts and enforces authorization, SMTP send/draft handling, and unit tests covering builder and cog behaviors.

Changes

Onboarding Email Feature

Layer / File(s) Summary
Shared email generation and rendering
packages/shared/src/five08/onboarding_email.py
Adds TriState, OnboardingEmailRequest, OnboardingEmailDraft, URL constants, and build_onboarding_email producing text, markdown, and HTML drafts with input validation.
Email builder unit tests
tests/unit/test_onboarding_email.py
Tests prospective-member vs new-member outputs and tri-state input validation.
SMTP configuration
apps/discord_bot/src/five08/discord_bot/config.py, .env.example, ENVIRONMENT.md
Adds onboarding_email_* SMTP settings to Settings, .env.example entries, and ENVIRONMENT.md documentation including fallback env var behavior.
Discord cog scaffolding and UI
apps/discord_bot/src/five08/discord_bot/cogs/onboarding_email.py
Introduces cog module, input state, truncation helper, selection UI, and setup(bot).
Cog helpers and CRM lookup
apps/discord_bot/src/.../onboarding_email.py
Implements sender/display normalization, strict email validation, Reply-To resolution, CRM contact search/dedup, and preferred-contact derivation.
Authorization and filtering
apps/discord_bot/src/.../onboarding_email.py
Enforces Steering Committee bypass or designated-onboarder checks and filters candidate contacts accordingly.
Error handling
apps/discord_bot/src/.../onboarding_email.py
Adds exception classification, public-text normalization, centralized error handler, and audited ephemeral followups.
Email construction and SMTP send
apps/discord_bot/src/.../onboarding_email.py
Builds multipart EmailMessage bodies, validates SMTP config, supports SSL/STARTTLS, and formats chunked draft responses.
Completion flow and slash command handler
apps/discord_bot/src/.../onboarding_email.py
Implements end-to-end flow: candidate status checks, reply-to resolution, conditional send/draft, auditing, and the onboarding_email slash command with UI selection handling.
Discord cog unit tests
tests/unit/test_onboarding_email_cog.py, tests/unit/test_bot.py
Comprehensive tests covering draft generation, send flow, CRM failure handling, multiple-match selector UI, designated-onboarder authorization and denials, reply-to/send validation, draft chunking, SMTP TLS/context behavior, and Settings env-fallback test.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I stitched a draft with care and zeal,
A subject crisp, a friendly feel;
CRM peeks and SMTP keys,
Send or save—whichever you please.
Hop! The bot delivers tidy mail.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title '[codex] Add onboarding email command' clearly and concisely describes the main change: adding a new Discord slash command for onboarding emails, which is the primary feature introduced across all the modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch michaelmwu/onboarding-email-automation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a shared, deterministic onboarding email generator (HTML + plain text) and exposes it via a new Admin-only Discord slash command to draft downloadable email files and optionally send them over SMTP, along with configuration/docs and unit tests.

Changes:

  • Introduces five08.onboarding_email with deterministic, state-driven email rendering for consistent onboarding messaging.
  • Adds an Admin-only /onboarding-email Discord command that generates drafts and can send via configured SMTP (send=true).
  • Documents and wires new onboarding SMTP configuration, plus unit tests for the builder and cog behavior.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/shared/src/five08/onboarding_email.py New deterministic onboarding email builder producing text + HTML drafts.
apps/discord_bot/src/five08/discord_bot/cogs/onboarding_email.py New Discord cog implementing /onboarding-email draft + SMTP send flow.
apps/discord_bot/src/five08/discord_bot/config.py Adds onboarding email SMTP/sender settings (with fallbacks/aliases).
tests/unit/test_onboarding_email.py Unit tests for deterministic draft content and validation.
tests/unit/test_onboarding_email_cog.py Unit tests for draft generation, Reply-To resolution behavior, and send gating.
ENVIRONMENT.md Documents onboarding email SMTP environment variables and behavior.
.env.example Adds example onboarding SMTP configuration entries.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +136 to +148
port = settings.onboarding_email_smtp_port
timeout = settings.onboarding_email_smtp_timeout_seconds
if settings.onboarding_email_smtp_use_ssl:
with smtplib.SMTP_SSL(smtp_server, port, timeout=timeout) as smtp:
smtp.login(smtp_username, smtp_password)
smtp.send_message(message)
return

with smtplib.SMTP(smtp_server, port, timeout=timeout) as smtp:
if settings.onboarding_email_smtp_starttls:
smtp.starttls()
smtp.login(smtp_username, smtp_password)
smtp.send_message(message)
Comment thread tests/unit/test_onboarding_email_cog.py Outdated
Comment on lines +20 to +39
def onboarding_cog(mock_bot: Mock) -> OnboardingEmailCog:
with patch("five08.discord_bot.cogs.onboarding_email.settings") as mock_settings:
mock_settings.espo_api_key = "token"
mock_settings.espo_base_url = "https://crm.example.com"
mock_settings.audit_api_base_url = "https://audit.example.com"
mock_settings.api_shared_secret = "secret"
mock_settings.audit_api_timeout_seconds = 5.0
mock_settings.discord_logs_webhook_url = None
mock_settings.discord_logs_webhook_wait = False
mock_settings.onboarding_email_sender_email = "onboarding@508.dev"
mock_settings.onboarding_email_smtp_server = "smtp.migadu.com"
mock_settings.onboarding_email_smtp_port = 465
mock_settings.onboarding_email_smtp_use_ssl = True
mock_settings.onboarding_email_smtp_starttls = False
mock_settings.onboarding_email_smtp_username = "onboarding@508.dev"
mock_settings.onboarding_email_smtp_password = "secret"
mock_settings.onboarding_email_smtp_timeout_seconds = 20.0
cog = OnboardingEmailCog(mock_bot)
cog.crm = Mock()
return cog

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Comment on lines +330 to +332
resolved_sender_name = sender_name.strip() if sender_name else ""
if not resolved_sender_name:
resolved_sender_name = self._display_name(interaction)
Comment on lines +427 to +448
except (PermissionError, ValueError, EspoAPIError) as exc:
self._audit_command_safe(
interaction=interaction,
action="onboarding.email",
result="denied",
metadata={
"candidate_name": candidate_name,
"recipient_email": recipient_email,
"has_contributed": has_contributed,
"discord_joined": discord_joined,
"agreement_signed": agreement_signed,
"send": send,
"error": str(exc),
},
resource_type="onboarding_email",
resource_id=recipient_email,
)
await interaction.followup.send(
f"⚠️ {exc}",
allowed_mentions=NO_MENTIONS,
ephemeral=True,
)
@michaelmwu michaelmwu force-pushed the michaelmwu/onboarding-email-automation branch from 850070a to 568deac Compare June 6, 2026 09:40
Copilot AI review requested due to automatic review settings June 7, 2026 09:03
@michaelmwu michaelmwu force-pushed the michaelmwu/onboarding-email-automation branch from 568deac to 1d6dd98 Compare June 7, 2026 09:03
@michaelmwu michaelmwu force-pushed the michaelmwu/onboarding-email-automation branch from 1d6dd98 to 2204102 Compare June 7, 2026 09:05

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Comment on lines +813 to +828
if len(candidate_contacts) > 1:
view = OnboardingEmailContactSelectView(
cog=self,
requester_id=interaction.user.id,
state=state,
contacts=candidate_contacts,
)
await interaction.followup.send(
"⚠️ Multiple CRM contacts match this onboarding email. "
"Select the candidate to continue. Already-onboarded contacts "
"are labelled with `status: onboarded`.",
allowed_mentions=NO_MENTIONS,
view=view,
ephemeral=True,
)
return
Comment on lines +564 to +573
chunks = [
draft_message[index : index + 1900]
for index in range(0, len(draft_message), 1900)
]
for index, chunk in enumerate(chunks, 1):
await interaction.followup.send(
f"**Copy/paste draft ({index}/{len(chunks)}):**\n{chunk}",
allowed_mentions=NO_MENTIONS,
ephemeral=True,
)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2204102a64

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +119 to +123
await self.view.cog._complete_onboarding_email(
interaction,
state=self.view.state,
selected_contact=contact,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Catch selector-path errors before returning

When the command finds multiple CRM matches, this component callback defers the interaction and calls _complete_onboarding_email without the error handling used by the slash-command path. If the selected contact is not assigned to the requester, send=true is missing a Reply-To, or CRM/SMTP raises, the exception escapes after the defer, so the user gets a failed interaction instead of the warning/audit response and the selector remains usable. Wrap this call in the same PermissionError/ValueError/EspoAPIError/SMTP handling used by onboarding_email.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/discord_bot/src/five08/discord_bot/cogs/onboarding_email.py`:
- Around line 118-123: The contact selector callback currently calls
_complete_onboarding_email directly and therefore bypasses the centralized
try/except + auditing used by onboarding_email; modify the code so both
onboarding_email and OnboardingEmailContactSelect.callback call a
new/centralized helper _run_onboarding_email_flow that wraps the call to
_complete_onboarding_email in the existing try/except and uses
_audit_command_safe for PermissionError/ValueError/EspoAPIError/SMTP errors, and
ensure interaction responses are resolved in the same error paths as the slash
command so selector failures are audited and the interaction is not left
unresolved.
- Around line 521-530: The SMTP calls in onboarding_email.py currently
instantiate smtplib.SMTP_SSL(...) and call smtp.starttls() without an explicit
SSLContext; create a secure context via ssl.create_default_context() and pass it
to SMTP_SSL as the context argument when settings.onboarding_email_smtp_use_ssl
is true, and pass the same context to smtp.starttls(context=...) when
settings.onboarding_email_smtp_starttls is true; ensure the new context is used
before any login/send_message calls (refer to the SMTP_SSL(...) call, the
starttls() call, and the blocks guarded by
settings.onboarding_email_smtp_use_ssl and
settings.onboarding_email_smtp_starttls).

In `@tests/unit/test_onboarding_email_cog.py`:
- Around line 23-42: The patch of settings in the onboarding_cog fixture
currently uses a with block that stops before tests run; change it to start the
patcher for the lifetime of the fixture and stop it in teardown so module-level
reads see the mocked values. Replace the with
patch("five08.discord_bot.cogs.onboarding_email.settings") as mock_settings
block by creating a patcher =
patch("five08.discord_bot.cogs.onboarding_email.settings"), calling
mock_settings = patcher.start(), constructing the OnboardingEmailCog(mock_bot),
yield or return the cog from the fixture, and ensure patcher.stop() runs after
the test (e.g., in a finally block or fixture teardown) so onboarding_cog,
mock_settings and the module-level settings remain mocked for the whole test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9388397f-79db-4acb-ba0b-67cfa3ea0d46

📥 Commits

Reviewing files that changed from the base of the PR and between c41076c and 1d6dd98.

📒 Files selected for processing (8)
  • .env.example
  • ENVIRONMENT.md
  • apps/discord_bot/src/five08/discord_bot/cogs/onboarding_email.py
  • apps/discord_bot/src/five08/discord_bot/config.py
  • packages/shared/src/five08/onboarding_email.py
  • tests/unit/test_bot.py
  • tests/unit/test_onboarding_email.py
  • tests/unit/test_onboarding_email_cog.py
✅ Files skipped from review due to trivial changes (1)
  • ENVIRONMENT.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/discord_bot/src/five08/discord_bot/config.py
  • tests/unit/test_onboarding_email.py

Comment thread apps/discord_bot/src/five08/discord_bot/cogs/onboarding_email.py
Comment thread apps/discord_bot/src/five08/discord_bot/cogs/onboarding_email.py
Comment thread tests/unit/test_onboarding_email_cog.py Outdated
Copilot AI review requested due to automatic review settings June 7, 2026 09:40
@michaelmwu michaelmwu force-pushed the michaelmwu/onboarding-email-automation branch from 2204102 to 5f656ec Compare June 7, 2026 09:40

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5f656ec3e2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +260 to +263
username_candidates = {
str(getattr(interaction.user, "name", "") or "").strip(),
str(getattr(interaction.user, "display_name", "") or "").strip(),
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Require immutable Discord IDs for onboarder authorization

When a Discord ID lookup misses, this fallback trusts interaction.user.name/display_name to resolve the CRM contact, and _requester_508_username() then uses that contact's c508Email for the designated-onboarder authorization check. In servers where members can change their nickname/display name, an unlinked user can set it to a real onboarder's stored cDiscordUsername, run /onboarding-email for that onboarder's assigned contact, and be authorized as them (including send flows if they provide a Reply-To). Authorization should only use the immutable Discord user ID, or otherwise require a verified link before granting onboarder privileges.

Useful? React with 👍 / 👎.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Comment on lines +675 to +679
await interaction.followup.send(
summary,
allowed_mentions=NO_MENTIONS,
ephemeral=True,
)
Comment on lines +336 to +340
def _contact_for_recipient_email(
self, recipient_email: str
) -> dict[str, object] | None:
response = self.crm.list_contacts(
{
Comment on lines +751 to +779
draft = build_onboarding_email(
OnboardingEmailRequest(
candidate_name=candidate_name,
sender_name=state.signature_name,
has_contributed=state.has_contributed,
discord_joined=state.discord_joined, # type: ignore[arg-type]
membership_agreement_signed=state.agreement_signed, # type: ignore[arg-type]
)
)
try:
resolved_reply_to = await asyncio.to_thread(
self._reply_to_email_for_user,
interaction=interaction,
override=state.reply_to_email,
)
except EspoAPIError:
if state.send and not state.reply_to_email:
raise
logger.warning(
"Unable to resolve onboarding email Reply-To from CRM",
exc_info=True,
)
resolved_reply_to = None

authorization_source = await asyncio.to_thread(
self._authorize_onboarding_email,
interaction=interaction,
selected_contact=selected_contact,
)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9e8697c7eb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +120 to +125
await interaction.response.defer(ephemeral=True)
await self.view.cog._run_onboarding_email_flow(
interaction,
state=self.view.state,
selected_contact=contact,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Re-fetch the selected CRM contact before sending

In the selector path, this passes the contact snapshot captured when the menu was rendered directly into _run_onboarding_email_flow. If the candidate is marked onboarded, reassigned, or has their email changed during the 5-minute selection window, _complete_onboarding_email trusts the stale cOnboardingState, cOnboarder, and email fields and can generate/send an onboarding email that the current CRM state would block or route differently. Re-fetch the selected contact by ID in the callback before continuing so authorization and already-onboarded checks use fresh CRM data.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/discord_bot/src/five08/discord_bot/cogs/onboarding_email.py`:
- Around line 849-874: The try/except in the onboarding wrapper only catches a
fixed set of exceptions and misses other runtime errors; update the error
handling around the call to _complete_onboarding_email so any unexpected
Exception is also caught and forwarded to _handle_onboarding_email_error (use
"except Exception as exc:" after the existing specific except block or add a
final broad except) and pass the same parameters (interaction, exc, state,
candidate_name, recipient_email, has_contributed, discord_joined,
agreement_signed, send, selected_contact) to ensure deferred interactions are
resolved and audit/error classification runs; apply the same change to the
second wrapper that calls _complete_onboarding_email (the block mirrored around
lines ~1017) so both paths use the generic Exception handler.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c70c6525-e3ac-432c-9194-7c7fc44e1a64

📥 Commits

Reviewing files that changed from the base of the PR and between 1d6dd98 and 9e8697c.

📒 Files selected for processing (8)
  • .env.example
  • ENVIRONMENT.md
  • apps/discord_bot/src/five08/discord_bot/cogs/onboarding_email.py
  • apps/discord_bot/src/five08/discord_bot/config.py
  • packages/shared/src/five08/onboarding_email.py
  • tests/unit/test_bot.py
  • tests/unit/test_onboarding_email.py
  • tests/unit/test_onboarding_email_cog.py
✅ Files skipped from review due to trivial changes (1)
  • ENVIRONMENT.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/unit/test_bot.py
  • tests/unit/test_onboarding_email.py
  • apps/discord_bot/src/five08/discord_bot/config.py
  • packages/shared/src/five08/onboarding_email.py

Comment on lines +849 to +874
try:
await self._complete_onboarding_email(
interaction,
state=state,
selected_contact=selected_contact,
)
except (
PermissionError,
ValueError,
EspoAPIError,
OSError,
smtplib.SMTPException,
) as exc:
await self._handle_onboarding_email_error(
interaction,
exc,
state=state,
candidate_name=state.candidate_name,
recipient_email=state.recipient_email,
has_contributed=state.has_contributed,
discord_joined=state.discord_joined,
agreement_signed=state.agreement_signed,
send=state.send,
selected_contact=selected_contact,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Catch unexpected exceptions in the onboarding flow wrapper.

Line 849 and Line 1017 only catch a fixed exception set. Any other runtime exception bypasses _handle_onboarding_email_error, which can leave deferred interactions without a user-visible failure message and skip the standardized audit/error classification path.

Proposed minimal fix
@@
-        except (
-            PermissionError,
-            ValueError,
-            EspoAPIError,
-            OSError,
-            smtplib.SMTPException,
-        ) as exc:
+        except Exception as exc:
             await self._handle_onboarding_email_error(
                 interaction,
                 exc,
@@
-        except (
-            PermissionError,
-            ValueError,
-            EspoAPIError,
-            OSError,
-            smtplib.SMTPException,
-        ) as exc:
+        except Exception as exc:
             await self._handle_onboarding_email_error(
                 interaction,
                 exc,

Also applies to: 1017-1034

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/discord_bot/src/five08/discord_bot/cogs/onboarding_email.py` around
lines 849 - 874, The try/except in the onboarding wrapper only catches a fixed
set of exceptions and misses other runtime errors; update the error handling
around the call to _complete_onboarding_email so any unexpected Exception is
also caught and forwarded to _handle_onboarding_email_error (use "except
Exception as exc:" after the existing specific except block or add a final broad
except) and pass the same parameters (interaction, exc, state, candidate_name,
recipient_email, has_contributed, discord_joined, agreement_signed, send,
selected_contact) to ensure deferred interactions are resolved and audit/error
classification runs; apply the same change to the second wrapper that calls
_complete_onboarding_email (the block mirrored around lines ~1017) so both paths
use the generic Exception handler.

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.

2 participants