Card Evolution Phase 1c: bot integration → next-release #96

Closed
cal wants to merge 17 commits from card-evolution-phase1c into main
Owner

Summary

Merges all Phase 1c bot integration work into next-release for testing.

  • WP-11: /evo status slash command with progress bars, filters (type/tier/progress/page)
  • WP-12: Tier badge on card embeds ([T1]/[T2]/[T3]/[EVO])
  • WP-13: Post-game callback hook — calls update-game + evaluate-game after every game
  • WP-14: Tier completion notification embeds (color-coded by tier)

Context

The database API (paper-dynasty-database) already has all evolution endpoints deployed on next-release. This PR adds the Discord bot side so we can test the full end-to-end flow.

Test plan

  • .sync ~ to register /evo commands in dev guild
  • /evo status shows team evolution progress with player names and progress bars
  • Card embeds show tier badge for players with tier > 0
  • Play a game — verify post-game callback triggers season stats + evolution eval
  • Tier-up notification embeds appear in game channel
## Summary Merges all Phase 1c bot integration work into `next-release` for testing. - **WP-11:** `/evo status` slash command with progress bars, filters (type/tier/progress/page) - **WP-12:** Tier badge on card embeds (`[T1]`/`[T2]`/`[T3]`/`[EVO]`) - **WP-13:** Post-game callback hook — calls `update-game` + `evaluate-game` after every game - **WP-14:** Tier completion notification embeds (color-coded by tier) ## Context The database API (paper-dynasty-database) already has all evolution endpoints deployed on `next-release`. This PR adds the Discord bot side so we can test the full end-to-end flow. ## Test plan - [ ] `.sync ~` to register `/evo` commands in dev guild - [ ] `/evo status` shows team evolution progress with player names and progress bars - [ ] Card embeds show tier badge for players with tier > 0 - [ ] Play a game — verify post-game callback triggers season stats + evolution eval - [ ] Tier-up notification embeds appear in game channel
cal added 5 commits 2026-03-19 18:33:34 +00:00
fix: explicitly exclude cogs/gameplay_legacy.py from Docker image (#42)
All checks were successful
Build Docker Image / build (pull_request) Successful in 1m16s
3fa28d9df2
The wildcard *_legacy.py pattern already covered this file, but adding
an explicit entry makes the exclusion unambiguous and self-documenting.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
feat: implement run-decision algorithm in gb_decide_run (#18)
All checks were successful
Build Docker Image / build (pull_request) Successful in 1m19s
6c4ff3bd27
Replace placeholder formula with tier-based algorithm modeled after
tag_from_second and tag_from_third. Uses self.running + aggression_mod
(abs deviation from neutral) for adjusted_running, then brackets into
three min_safe tiers (4/6/8), with a ±2 adjustment for 2-out and 0-out
situations respectively.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reviewed-on: #52
Reviewed-on: #72
Claude added the
ai-reviewing
label 2026-03-19 18:45:51 +00:00
cal added 1 commit 2026-03-19 18:55:07 +00:00
- Import notify_tier_completion from helpers.evolution_notifs instead of
  using the local stub in logic_gameplay.py (WP-14 embeds were dead code)
- Add module-level logger to helpers/main.py, replace bare logging.warning()
- Remove duplicate @pytest.mark.asyncio decorator in test_card_embed_evolution.py
- Fix progress='close' filter to use filtered count in pagination footer

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
cal reviewed 2026-03-19 18:58:29 +00:00
cal left a comment
Author
Owner

AI Code Review

Files Reviewed

  • .dockerignore (modified)
  • cogs/players_new/evolution.py (modified)
  • command_logic/logic_gameplay.py (modified)
  • helpers/main.py (modified)
  • helpers/evolution_notifs.py (present in repo, added in earlier commit on branch)
  • in_game/gameplay_models.py (modified — formatting only)
  • tests/gameplay_models/test_managerai_model.py (modified — formatting only)
  • tests/test_card_embed_evolution.py (modified)

Previous Issues — All 4 Resolved

1. Dead-code stub replaced with real import
logic_gameplay.py now imports notify_tier_completion from helpers.evolution_notifs. The 19-line local stub has been deleted. helpers/evolution_notifs.py is fully implemented: it builds tier-colored Discord embeds and wraps channel.send in its own try/except so notification failures are non-fatal at the helper level as well.

2. Module-level logger in helpers/main.py
logger = logging.getLogger("discord_app") is now declared at module level and the logging.warning() call is correctly updated to logger.warning(). The placement between import groups is slightly non-standard but is definitively module-level and not a mid-file lazy import.

3. Duplicate @pytest.mark.asyncio removed
The duplicate decorator on test_no_evolution_state_shows_plain_name has been removed. The remaining single @pytest.mark.asyncio per test method is correct throughout the class.

4. Pagination count fixed for progress='close'
total_count = len(items) is now reassigned immediately after the client-side filter (line 177), before the empty-check early return. The footer Page X/Y - N total cards correctly reflects the filtered count.

Findings

Correctness

  • Post-game hook ordering is correct: season-stats/update-game/{id} is called first, then evolution/evaluate-game/{id}. The evaluate call therefore operates on up-to-date season stats.
  • The entire evolution post-game block is wrapped in a single try/except Exception with logger.warning, making all failures non-fatal.
  • notify_tier_completion in helpers/evolution_notifs.py has its own inner try/except, providing a second layer of protection against Discord API failures propagating up.
  • build_tier_up_embed accesses tier_up["player_name"], tier_up["new_tier"], and tier_up["track_name"] with direct key access. A missing key raises KeyError, but this is caught by the try/except in notify_tier_completion and degrades to a logged error. Acceptable.

Security

  • No hardcoded credentials, tokens, or secrets.
  • API calls use the existing authenticated db_post helper.
  • No new user-controlled input reaches any query or shell command.

Style & Conventions

  • helpers/evolution_notifs.py correctly uses logger = logging.getLogger("discord_app").
  • TIER_NAMES and TIER_COLORS are clean module-level constants.
  • Formatting-only changes in gameplay_models.py are correct and inert.

Suggestions (non-blocking)

  • The logger declaration in helpers/main.py sits between two import blocks rather than after all imports. A future cleanup pass could move it to follow the full import block per PEP 8 convention.
  • build_tier_up_embed could use .get() with defaults for player_name/track_name to be fully defensive, but the outer try/except makes this optional.

Verdict: APPROVED

All 4 previously flagged issues are correctly resolved. The post-game hook correctly sequences update-game before evaluate-game, all evolution API calls are non-fatal, no secrets are present, and the base branch is next-release. Ready to merge.


Automated review by Claude PR Reviewer

## AI Code Review ### Files Reviewed - `.dockerignore` (modified) - `cogs/players_new/evolution.py` (modified) - `command_logic/logic_gameplay.py` (modified) - `helpers/main.py` (modified) - `helpers/evolution_notifs.py` (present in repo, added in earlier commit on branch) - `in_game/gameplay_models.py` (modified — formatting only) - `tests/gameplay_models/test_managerai_model.py` (modified — formatting only) - `tests/test_card_embed_evolution.py` (modified) ### Previous Issues — All 4 Resolved **1. Dead-code stub replaced with real import** `logic_gameplay.py` now imports `notify_tier_completion` from `helpers.evolution_notifs`. The 19-line local stub has been deleted. `helpers/evolution_notifs.py` is fully implemented: it builds tier-colored Discord embeds and wraps `channel.send` in its own try/except so notification failures are non-fatal at the helper level as well. **2. Module-level logger in helpers/main.py** `logger = logging.getLogger("discord_app")` is now declared at module level and the `logging.warning()` call is correctly updated to `logger.warning()`. The placement between import groups is slightly non-standard but is definitively module-level and not a mid-file lazy import. **3. Duplicate @pytest.mark.asyncio removed** The duplicate decorator on `test_no_evolution_state_shows_plain_name` has been removed. The remaining single `@pytest.mark.asyncio` per test method is correct throughout the class. **4. Pagination count fixed for progress='close'** `total_count = len(items)` is now reassigned immediately after the client-side filter (line 177), before the empty-check early return. The footer `Page X/Y - N total cards` correctly reflects the filtered count. ### Findings #### Correctness - Post-game hook ordering is correct: `season-stats/update-game/{id}` is called first, then `evolution/evaluate-game/{id}`. The evaluate call therefore operates on up-to-date season stats. - The entire evolution post-game block is wrapped in a single `try/except Exception` with `logger.warning`, making all failures non-fatal. - `notify_tier_completion` in `helpers/evolution_notifs.py` has its own inner try/except, providing a second layer of protection against Discord API failures propagating up. - `build_tier_up_embed` accesses `tier_up["player_name"]`, `tier_up["new_tier"]`, and `tier_up["track_name"]` with direct key access. A missing key raises `KeyError`, but this is caught by the try/except in `notify_tier_completion` and degrades to a logged error. Acceptable. #### Security - No hardcoded credentials, tokens, or secrets. - API calls use the existing authenticated `db_post` helper. - No new user-controlled input reaches any query or shell command. #### Style & Conventions - `helpers/evolution_notifs.py` correctly uses `logger = logging.getLogger("discord_app")`. - `TIER_NAMES` and `TIER_COLORS` are clean module-level constants. - Formatting-only changes in `gameplay_models.py` are correct and inert. #### Suggestions (non-blocking) - The `logger` declaration in `helpers/main.py` sits between two import blocks rather than after all imports. A future cleanup pass could move it to follow the full import block per PEP 8 convention. - `build_tier_up_embed` could use `.get()` with defaults for `player_name`/`track_name` to be fully defensive, but the outer try/except makes this optional. ### Verdict: APPROVED All 4 previously flagged issues are correctly resolved. The post-game hook correctly sequences update-game before evaluate-game, all evolution API calls are non-fatal, no secrets are present, and the base branch is `next-release`. Ready to merge. --- *Automated review by Claude PR Reviewer*
cal changed target branch from next-release to main 2026-03-23 04:14:36 +00:00
Author
Owner

Closing — this aggregation PR is superseded by the individual WP PRs:

  • WP-14: #89 (merged)
  • WP-11: #87 (pending review)
  • WP-12: #88 (on hold, reconsidering approach)
  • WP-13: will be handled separately

The next-release branch pattern is retired; all work now targets main directly.

Closing — this aggregation PR is superseded by the individual WP PRs: - WP-14: #89 (merged) - WP-11: #87 (pending review) - WP-12: #88 (on hold, reconsidering approach) - WP-13: will be handled separately The `next-release` branch pattern is retired; all work now targets `main` directly.
cal closed this pull request 2026-03-23 04:15:19 +00:00

Pull request closed

Sign in to join this conversation.
No reviewers
No Milestone
No project
No Assignees
1 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#96
No description provided.