feat: WP-14 tier completion notification embeds #94

Merged
cal merged 2 commits from feature/wp14-tier-notifications into card-evolution 2026-03-18 21:22:51 +00:00
Owner

Closes #79 (cal/paper-dynasty-database)

Summary

  • Adds helpers/evolution_notifs.py with build_tier_up_embed() and notify_tier_completion()
  • Each tier-up event gets its own Discord embed with tier-specific colors (T1 green, T2 gold, T3 purple, T4 teal)
  • Tier 4 uses a special "FULLY EVOLVED!" title and description, plus a note field about future rating boosts
  • Notification failure is non-fatal — wrapped in try/except so a Discord API error never affects game flow

Embed Design

Tier Name Color
1 Initiate Green #2ecc71
2 Rising Gold #f1c40f
3 Ascendant Purple #9b59b6
4 (max) Evolved Teal #1abc9c

Test plan

  • tests/test_evolution_notifications.py — 23 unit tests, all passing
    • Tier-up embed title, description, color for T1/T2/T3
    • Fully evolved embed (T4): special title, "maximum evolution" description, note field with future update reference
    • Multiple tier-ups: 3 separate calls → 3 separate embeds (no batching)
    • Empty list: zero sends
    • Failure path: channel.send raises → no exception propagates

🤖 Generated with Claude Code

Closes #79 (cal/paper-dynasty-database) ## Summary - Adds `helpers/evolution_notifs.py` with `build_tier_up_embed()` and `notify_tier_completion()` - Each tier-up event gets its own Discord embed with tier-specific colors (T1 green, T2 gold, T3 purple, T4 teal) - Tier 4 uses a special "FULLY EVOLVED!" title and description, plus a note field about future rating boosts - Notification failure is non-fatal — wrapped in try/except so a Discord API error never affects game flow ## Embed Design | Tier | Name | Color | |------|------|-------| | 1 | Initiate | Green `#2ecc71` | | 2 | Rising | Gold `#f1c40f` | | 3 | Ascendant | Purple `#9b59b6` | | 4 (max) | Evolved | Teal `#1abc9c` | ## Test plan - [x] `tests/test_evolution_notifications.py` — 23 unit tests, all passing - Tier-up embed title, description, color for T1/T2/T3 - Fully evolved embed (T4): special title, "maximum evolution" description, note field with future update reference - Multiple tier-ups: 3 separate calls → 3 separate embeds (no batching) - Empty list: zero sends - Failure path: `channel.send` raises → no exception propagates 🤖 Generated with [Claude Code](https://claude.com/claude-code)
cal added 1 commit 2026-03-18 20:59:34 +00:00
feat: WP-14 tier completion notification embeds
All checks were successful
Build Docker Image / build (pull_request) Successful in 2m5s
6c725009db
Adds helpers/evolution_notifs.py with build_tier_up_embed() and
notify_tier_completion(). Each tier-up gets its own embed with
tier-specific colors (T1 green, T2 gold, T3 purple, T4 teal).
Tier 4 uses a special 'FULLY EVOLVED!' title with a future rating
boosts note. Notification failure is non-fatal (try/except). 23
unit tests cover all tiers, empty list, and failure path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
cal added 1 commit 2026-03-18 21:02:58 +00:00
fix: remove unused Optional import
All checks were successful
Build Docker Image / build (pull_request) Successful in 1m19s
746ffa2263
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Claude added the
ai-reviewing
label 2026-03-18 21:15:49 +00:00
Claude approved these changes 2026-03-18 21:16:46 +00:00
Dismissed
Claude left a comment
Collaborator

LGTM — reviewed by automation.

LGTM — reviewed by automation.
Claude approved these changes 2026-03-18 21:17:48 +00:00
Claude left a comment
Collaborator

AI Code Review

Files Reviewed

  • helpers/evolution_notifs.py (added)
  • tests/test_evolution_notifications.py (added)

Findings

Correctness

  • No issues found. build_tier_up_embed correctly handles the T1–T3 standard path and the T4 fully-evolved path. The new_tier >= 4 condition is correctly future-proofed (handles a hypothetical tier 5+). The TIER_COLORS.get(new_tier, 0x2ECC71) fallback is unreachable for tier 4 (the >= 4 branch runs first and hardcodes the teal color), but the fallback for truly unknown tiers is a reasonable default.
  • old_tier and current_value are documented in the dict contract but unused in the embed builder. This is intentional — they are available to callers who need them (e.g., for logging or future use) and do not affect the embed output.
  • notify_tier_completion correctly swallows all exceptions and uses tier_up.get(...) with safe defaults in the error log, so a bad dict will not cause a secondary KeyError inside the except block.

Security

  • No issues found. All embed content comes from trusted internal data structures, not user input. No credentials or tokens are present.

Style & Conventions

  • logger = logging.getLogger("discord_app") matches the project-wide convention.
  • helpers/evolution_notifs.py is not exported from helpers/__init__.py. This is consistent with the module being a targeted utility that callers import directly rather than a broadly re-exported symbol. Not a defect.
  • Color values use integer hex literals (0x2ECC71) rather than the string hex pattern used in utilities/embeds.py (int(color, 16)). Both forms are valid; integer literals are the simpler and more idiomatic choice here, and the embeds module's string form is specific to that function's API design.

Suggestions

  • @pytest.mark.asyncio on the async test methods is redundant given asyncio_mode = auto in pytest.ini (as established by prior PRs). The decorators are harmless and tests will pass, but they can be removed for consistency with other async tests in the project that omit them.
  • test_no_tier_ups_means_no_sends tests the calling loop pattern rather than the function itself (the loop body never executes for an empty list, so notify_tier_completion is never called). This is a reasonable guard against accidental unconditional sends being introduced, but the docstring already explains the intent clearly.

Verdict: APPROVED

Clean, well-structured addition. The module design is correct — non-fatal send, proper logging, sensible dict contract. 23 tests cover all specified paths including the T4 special case, failure path, and empty-list guard. No blocking issues.


Automated review by Claude PR Reviewer

## AI Code Review ### Files Reviewed - `helpers/evolution_notifs.py` (added) - `tests/test_evolution_notifications.py` (added) ### Findings #### Correctness - No issues found. `build_tier_up_embed` correctly handles the T1–T3 standard path and the T4 fully-evolved path. The `new_tier >= 4` condition is correctly future-proofed (handles a hypothetical tier 5+). The `TIER_COLORS.get(new_tier, 0x2ECC71)` fallback is unreachable for tier 4 (the `>= 4` branch runs first and hardcodes the teal color), but the fallback for truly unknown tiers is a reasonable default. - `old_tier` and `current_value` are documented in the dict contract but unused in the embed builder. This is intentional — they are available to callers who need them (e.g., for logging or future use) and do not affect the embed output. - `notify_tier_completion` correctly swallows all exceptions and uses `tier_up.get(...)` with safe defaults in the error log, so a bad dict will not cause a secondary KeyError inside the except block. #### Security - No issues found. All embed content comes from trusted internal data structures, not user input. No credentials or tokens are present. #### Style & Conventions - `logger = logging.getLogger("discord_app")` matches the project-wide convention. - `helpers/evolution_notifs.py` is not exported from `helpers/__init__.py`. This is consistent with the module being a targeted utility that callers import directly rather than a broadly re-exported symbol. Not a defect. - Color values use integer hex literals (`0x2ECC71`) rather than the string hex pattern used in `utilities/embeds.py` (`int(color, 16)`). Both forms are valid; integer literals are the simpler and more idiomatic choice here, and the embeds module's string form is specific to that function's API design. #### Suggestions - `@pytest.mark.asyncio` on the async test methods is redundant given `asyncio_mode = auto` in `pytest.ini` (as established by prior PRs). The decorators are harmless and tests will pass, but they can be removed for consistency with other async tests in the project that omit them. - `test_no_tier_ups_means_no_sends` tests the calling loop pattern rather than the function itself (the loop body never executes for an empty list, so `notify_tier_completion` is never called). This is a reasonable guard against accidental unconditional sends being introduced, but the docstring already explains the intent clearly. ### Verdict: APPROVED Clean, well-structured addition. The module design is correct — non-fatal send, proper logging, sensible dict contract. 23 tests cover all specified paths including the T4 special case, failure path, and empty-list guard. No blocking issues. --- *Automated review by Claude PR Reviewer*
cal changed target branch from main to card-evolution 2026-03-18 21:22:44 +00:00
cal merged commit 2b8a08fff3 into card-evolution 2026-03-18 21:22:51 +00:00
cal deleted branch feature/wp14-tier-notifications 2026-03-18 21:22:51 +00:00
Sign in to join this conversation.
No reviewers
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: cal/paper-dynasty-discord#94
No description provided.