Skip to content

fix: refine candidate match formatting#177

Closed
michaelmwu wants to merge 1 commit into
mainfrom
michaelmwu/match-format
Closed

fix: refine candidate match formatting#177
michaelmwu wants to merge 1 commit into
mainfrom
michaelmwu/match-format

Conversation

@michaelmwu
Copy link
Copy Markdown
Member

@michaelmwu michaelmwu commented Mar 8, 2026

Description

This change improves /match-candidates output by preferring CRM full names for the displayed person title and linking the name to the CRM record when available.
It now includes a non-mention Discord username in the same result line for easy identity context, with no fallback to Discord ID in normal output.
search_candidates now returns both crm_name and discord_username from the matching query so the bot can render those fields separately and consistently.
Unit tests were added for both the new candidate mapping fields and the formatter behavior.

How Has This Been Tested?

uv run pytest tests/unit/test_candidate_search.py tests/unit/test_jobs.py (29 passed)

Summary by CodeRabbit

  • New Features

    • Added display of Discord usernames in candidate information when available.
    • Improved candidate profile display to prioritize CRM names for better accuracy and consistency.
  • Tests

    • Added test coverage for candidate display formatting with various member and prospect scenarios.

Copilot AI review requested due to automatic review settings March 8, 2026 20:09
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 8, 2026

📝 Walkthrough

Walkthrough

The pull request adds two new fields (crm_name and discord_username) to the CandidateMatch model and updates the SQL query and result mapping to compute and expose these fields. The Jobs cog is updated to use these fields for improved candidate display formatting, replacing previous display logic with the new fields.

Changes

Cohort / File(s) Summary
Candidate Search Model & Query
packages/shared/src/five08/candidate_search.py
Adds crm_name and discord_username fields to CandidateMatch, updates SQL query aliases and result mapping to expose these new fields from database results.
Jobs Cog Display Logic
apps/discord_bot/src/five08/discord_bot/cogs/jobs.py
Updates _build_match_candidate_lines to use crm_name for display when available, appends Discord username as a separate formatted line when present, removes previous inline Discord ID display.
Test Coverage
tests/unit/test_candidate_search.py, tests/unit/test_jobs.py
Updates candidate_search test to verify crm_name and discord_username field mapping; adds two new unit tests for JobsCog's candidate line formatting with CRM member and prospect scenarios.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A rabbit hops through CRM fields anew,
crm_name and discord_username shine bright,
Display logic blooms with candidates true,
From query to cog, each profile takes flight,
Tests verify all, the formatting's right! 🐇✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly summarizes the main change: refining how candidate match information is formatted in the output by preferring CRM names, adding discord usernames, and improving the display presentation.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch michaelmwu/match-format

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.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refines the /match-candidates output formatting by preferring CRM full names (and linking to CRM when possible) and by showing a non-mention Discord username alongside the candidate entry, supported by expanding the shared candidate search result model.

Changes:

  • Extend CandidateMatch / search_candidates to return both crm_name and discord_username.
  • Update /match-candidates line formatter to render a CRM-linked display name (when available) and append a non-mention Discord username, removing “Discord ID” from normal output.
  • Add/update unit tests for the new mapping fields and formatting behavior.

Reviewed changes

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

File Description
apps/discord_bot/src/five08/discord_bot/cogs/jobs.py Adjusts match output formatting to prefer CRM name + CRM link and include a non-mention Discord username.
packages/shared/src/five08/candidate_search.py Expands CandidateMatch and SQL selection/mapping to provide crm_name and discord_username.
tests/unit/test_candidate_search.py Updates row→CandidateMatch mapping test to assert new fields.
tests/unit/test_jobs.py Adds unit tests validating the updated match-candidate line formatting behavior.

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

Comment on lines +514 to +523
crm_name = discord.utils.escape_mentions(
candidate.crm_name or candidate.name or "Unknown"
)
discord_username = (
discord.utils.escape_mentions(
str(candidate.discord_username).lstrip("@")
)
if candidate.discord_username
else None
)
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

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

_build_match_candidate_lines now assumes candidate.crm_name and candidate.discord_username are present and string-like. In existing unit tests that patch search_candidates with plain Mock() candidates, missing attributes evaluate to truthy Mock objects and will flow into escape_mentions, producing incorrect output. Consider guarding with isinstance(..., str) (or explicitly coercing/normalizing) and/or tightening the expected candidate type so callers/tests must provide these fields (e.g., set them to None).

Suggested change
crm_name = discord.utils.escape_mentions(
candidate.crm_name or candidate.name or "Unknown"
)
discord_username = (
discord.utils.escape_mentions(
str(candidate.discord_username).lstrip("@")
)
if candidate.discord_username
else None
)
# Normalize CRM/display name to a safe string.
raw_crm_name: Any = getattr(candidate, "crm_name", None)
if not isinstance(raw_crm_name, str) or not raw_crm_name.strip():
raw_crm_name = getattr(candidate, "name", None)
if not isinstance(raw_crm_name, str) or not raw_crm_name.strip():
raw_crm_name = "Unknown"
crm_name = discord.utils.escape_mentions(raw_crm_name)
# Normalize Discord username to a safe string, or omit if not a string.
raw_discord_username: Any = getattr(candidate, "discord_username", None)
if isinstance(raw_discord_username, str) and raw_discord_username.strip():
discord_username = discord.utils.escape_mentions(
raw_discord_username.lstrip("@")
)
else:
discord_username = None

Copilot uses AI. Check for mistakes.
Comment thread tests/unit/test_jobs.py
Comment on lines +5 to +14
import os
from types import SimpleNamespace

os.environ.setdefault("DISCORD_BOT_TOKEN", "test")
os.environ.setdefault("ESPO_API_KEY", "test")
os.environ.setdefault("ESPO_BASE_URL", "https://crm.example.invalid")
os.environ.setdefault("KIMAI_BASE_URL", "https://kimai.example.invalid")
os.environ.setdefault("KIMAI_API_TOKEN", "test")

from five08.discord_bot.cogs.jobs import JobsCog
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

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

This test module sets environment variables at import time to allow importing JobsCog (which imports settings). That makes test order/import behavior matter and duplicates the repo-wide mock_env_vars autouse fixture in tests/conftest.py. Prefer moving the JobsCog import inside the test functions (after fixtures run) or using monkeypatch in a fixture so env setup is centralized and doesn't leak across modules.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/unit/test_candidate_search.py (1)

193-218: Consider adding missing fields to _make_row base dict.

The base dict doesn't include crm_name, discord_username, has_crm_link, or discord_user_id. While search_candidates handles missing keys gracefully via row.get(), adding explicit defaults would improve test maintainability and make the test data structure align with the actual CandidateMatch fields.

♻️ Suggested addition to base dict
 def _make_row(**overrides: object) -> dict:
     """Build a minimal fake DB row dict."""
     base: dict = {
         "crm_contact_id": "c1",
         "name": "Alice",
+        "crm_name": "Alice CRM",
+        "discord_username": None,
+        "discord_user_id": None,
+        "has_crm_link": True,
         "email_508": "alice@508.dev",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/test_candidate_search.py` around lines 193 - 218, The _make_row
helper is missing several fields used by CandidateMatch; update the base dict
inside _make_row(**overrides) to include explicit default keys crm_name (empty
string), discord_username (None or empty string), has_crm_link (False), and
discord_user_id (None) so tests mirror the real CandidateMatch shape; keep
overrides behavior intact so callers can still override these defaults and
ensure any code referencing row.get(...) still passes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests/unit/test_candidate_search.py`:
- Around line 193-218: The _make_row helper is missing several fields used by
CandidateMatch; update the base dict inside _make_row(**overrides) to include
explicit default keys crm_name (empty string), discord_username (None or empty
string), has_crm_link (False), and discord_user_id (None) so tests mirror the
real CandidateMatch shape; keep overrides behavior intact so callers can still
override these defaults and ensure any code referencing row.get(...) still
passes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d1c23263-7960-4e91-9544-edae21cbbb95

📥 Commits

Reviewing files that changed from the base of the PR and between 3ba4c6e and 79e5031.

📒 Files selected for processing (4)
  • apps/discord_bot/src/five08/discord_bot/cogs/jobs.py
  • packages/shared/src/five08/candidate_search.py
  • tests/unit/test_candidate_search.py
  • tests/unit/test_jobs.py

@michaelmwu michaelmwu closed this Mar 9, 2026
@michaelmwu michaelmwu deleted the michaelmwu/match-format branch May 8, 2026 18:54
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