Merge branch 'main' into issue/138-feat-collection-view-refractor-card-images-in-web
All checks were successful
Ruff Lint / lint (pull_request) Successful in 27s

This commit is contained in:
cal 2026-04-08 01:45:19 +00:00
commit 435bfd376f
5 changed files with 61 additions and 38 deletions

View File

@ -31,7 +31,7 @@ pip install -r requirements.txt # Install dependencies
- **Path**: `/home/cal/container-data/paper-dynasty`
- **Container**: `paper-dynasty_discord-app_1`
- **Image**: `manticorum67/paper-dynasty-discordapp`
- **Health**: `GET http://localhost:8080/health` (HTTP server in `health_server.py`)
- **Health**: `GET http://localhost:8081/health` (HTTP server in `health_server.py`)
- **Versioning**: CalVer (`YYYY.M.BUILD`) — manually tagged when ready to release
### Logs
@ -46,7 +46,7 @@ pip install -r requirements.txt # Install dependencies
- Bot not responding → check `docker logs`, verify `BOT_TOKEN` and `GUILD_ID`
- API errors → verify `DATABASE` is set to `Prod` or `Dev`, check `API_TOKEN` matches the database API
- Game engine errors → check `/usr/src/app/logs/discord.log` for detailed tracebacks
- Health endpoint not responding → `health_server.py` runs on port 8080 inside the container
- Health endpoint not responding → `health_server.py` runs on port 8081 inside the container
### CI/CD
Ruff lint on PRs. Docker image built on CalVer tag push only.

View File

@ -370,6 +370,18 @@ class Refractor(commands.Cog):
total_count = (
data.get("count", len(items)) if isinstance(data, dict) else len(items)
)
# If the requested page is beyond the last page, clamp and re-fetch.
if not items and total_count > 0:
total_pages = max(1, (total_count + PAGE_SIZE - 1) // PAGE_SIZE)
page = total_pages
clamped_params = [(k, v) for k, v in params if k != "offset"]
clamped_params.append(("offset", (page - 1) * PAGE_SIZE))
data = await db_get("refractor/cards", params=clamped_params)
if isinstance(data, dict):
items = data.get("items", [])
total_count = data.get("count", total_count)
logger.debug(
"Refractor status for team %s: %d items returned, %d total (page %d)",
team["id"],

View File

@ -17,14 +17,14 @@ logger = logging.getLogger("discord_app.health")
class HealthServer:
"""HTTP server for health checks and metrics."""
def __init__(self, bot: commands.Bot, host: str = "0.0.0.0", port: int = 8080):
def __init__(self, bot: commands.Bot, host: str = "0.0.0.0", port: int = 8081):
"""
Initialize health server.
Args:
bot: Discord bot instance to monitor
host: Host to bind to (default: 0.0.0.0 for container access)
port: Port to listen on (default: 8080)
port: Port to listen on (default: 8081)
"""
self.bot = bot
self.host = host
@ -148,7 +148,7 @@ class HealthServer:
logger.info("Health check server stopped")
async def run_health_server(bot: commands.Bot, host: str = "0.0.0.0", port: int = 8080):
async def run_health_server(bot: commands.Bot, host: str = "0.0.0.0", port: int = 8081):
"""
Run health server as a background task.

View File

@ -32,7 +32,7 @@ the expected bot response, and pass/fail criteria.
Before running these tests, ensure the following state exists:
### Bot State
- [ ] Bot is online and healthy: `GET http://sba-bots:8080/health` returns 200
- [ ] Bot is online and healthy: `GET http://sba-bots:8081/health` returns 200
- [ ] Refractor cog is loaded: check bot logs for `Loaded extension 'cogs.refractor'`
- [ ] Test user has the `PD Players` role on the dev server
@ -72,7 +72,7 @@ API layer is functional. Execute via shell or Playwright network interception.
### REF-API-01: Bot health endpoint
| Field | Value |
|---|---|
| **Command** | `curl -sf http://sba-bots:8080/health` |
| **Command** | `curl -sf http://sba-bots:8081/health` |
| **Expected** | HTTP 200, body contains health status |
| **Pass criteria** | Non-empty 200 response |
@ -382,11 +382,11 @@ API layer is functional. Execute via shell or Playwright network interception.
These tests verify that tier badges appear in card embed titles across all
commands that display card embeds via `get_card_embeds()`.
### REF-40: Tier badge on /card command (player lookup)
### REF-40: Tier badge on /player command (player lookup)
| Field | Value |
|---|---|
| **Description** | Look up a card that has a refractor tier > 0 |
| **Discord command** | `/card {player_name}` (use a player known to have refractor state) |
| **Discord command** | `/player {player_name}` (use a player known to have refractor state) |
| **Expected result** | Embed title is `[BC] Player Name` (or appropriate badge for their tier) |
| **Pass criteria** | 1. Embed title starts with the correct tier badge in brackets |
| | 2. Player name follows the badge |
@ -396,7 +396,7 @@ commands that display card embeds via `get_card_embeds()`.
| Field | Value |
|---|---|
| **Description** | Look up a card with current_tier=0 |
| **Discord command** | `/card {player_name}` (use a player at T0) |
| **Discord command** | `/player {player_name}` (use a player at T0) |
| **Expected result** | Embed title is just `Player Name` with no bracket prefix |
| **Pass criteria** | Title does not contain `[BC]`, `[R]`, `[GR]`, or `[SF]` |
@ -404,7 +404,7 @@ commands that display card embeds via `get_card_embeds()`.
| Field | Value |
|---|---|
| **Description** | Look up a card that has no RefractorCardState row |
| **Discord command** | `/card {player_name}` (use a player with no refractor state) |
| **Discord command** | `/player {player_name}` (use a player with no refractor state) |
| **Expected result** | Embed title is just `Player Name` with no bracket prefix |
| **Pass criteria** | 1. Title has no badge prefix |
| | 2. No error in bot logs about the refractor API call |
@ -414,7 +414,7 @@ commands that display card embeds via `get_card_embeds()`.
| Field | Value |
|---|---|
| **Description** | Start a card purchase for a player with refractor state |
| **Discord command** | `/buy {player_name}` |
| **Discord command** | `/buy card-by-name {player_name}` |
| **Expected result** | The card embed shown during purchase confirmation includes the tier badge |
| **Pass criteria** | Embed title includes tier badge if the player has refractor state |
| **Notes** | The buy flow uses `get_card_embeds(get_blank_team_card(...))`. Since blank team cards have no team association, the refractor lookup by card_id may 404. Verify graceful fallback. |
@ -423,16 +423,16 @@ commands that display card embeds via `get_card_embeds()`.
| Field | Value |
|---|---|
| **Description** | Open a pack and check if revealed cards show tier badges |
| **Discord command** | `/openpack` (or equivalent pack opening command) |
| **Discord command** | `/open-packs` |
| **Expected result** | Cards displayed via `display_cards()` -> `get_card_embeds()` show tier badges if applicable |
| **Pass criteria** | Cards with refractor state show badges; cards without state show no badge and no error |
### REF-45: Badge consistency between /card and /refractor status
### REF-45: Badge consistency between /player and /refractor status
| Field | Value |
|---|---|
| **Description** | Compare the badge shown for the same player in both views |
| **Discord command** | Run both `/card {player}` and `/refractor status` for the same player |
| **Expected result** | The badge in the `/card` embed title (`[BC]`, `[R]`, etc.) matches the tier shown in `/refractor status` |
| **Discord command** | Run both `/player {player}` and `/refractor status` for the same player |
| **Expected result** | The badge in the `/player` embed title (`[BC]`, `[R]`, etc.) matches the tier shown in `/refractor status` |
| **Pass criteria** | Tier badge letter matches: T1=[BC], T2=[R], T3=[GR], T4=[SF] |
---
@ -568,11 +568,11 @@ REF-55, REF-60 through REF-64) can be validated via API calls and bot logs.
These tests verify that tier badges appear (or correctly do not appear) in all
commands that display card information.
### REF-70: /roster command -- cards show tier badges
### REF-70: /team command -- cards show tier badges
| Field | Value |
|---|---|
| **Discord command** | `/roster` or equivalent command that lists team cards |
| **Expected result** | If roster display uses `get_card_embeds()`, cards with refractor state show tier badges |
| **Discord command** | `/team` |
| **Expected result** | If team/roster display uses `get_card_embeds()`, cards with refractor state show tier badges |
| **Pass criteria** | Cards at T1+ have badges; T0 cards have none |
### REF-71: /show-card defense (in-game) -- no badge expected
@ -584,12 +584,13 @@ commands that display card information.
| **Pass criteria** | This is EXPECTED behavior -- in-game card display does not fetch refractor state |
| **Notes** | This is a known limitation, not a bug. Document for future consideration. |
### REF-72: /scouting view -- badge on scouted cards
### REF-72: /scout-tokens -- no badge expected
| Field | Value |
|---|---|
| **Discord command** | `/scout {player_name}` (if the scouting cog uses get_card_embeds) |
| **Expected result** | If the scouting view calls get_card_embeds, badges should appear |
| **Pass criteria** | Verify whether scouting uses get_card_embeds or its own embed builder |
| **Discord command** | `/scout-tokens` |
| **Expected result** | Scout tokens display does not show card embeds, so no badges are expected |
| **Pass criteria** | Command responds with token count; no card embeds or badges displayed |
| **Notes** | `/scout-tokens` shows remaining daily tokens, not card embeds. Badge propagation is not applicable here. |
---
@ -663,28 +664,38 @@ design but means tier-up notifications are best-effort.
Run order for Playwright automation:
1. [~] Execute REF-API-01 through REF-API-10 (API health + list endpoint)
1. [x] Execute REF-API-01 through REF-API-10 (API health + list endpoint)
- Tested 2026-03-25: REF-API-03 (single card ✓), REF-API-06 (list ✓), REF-API-07 (card_type filter ✓), REF-API-10 (pagination ✓)
- Not yet tested: REF-API-01, REF-API-02, REF-API-04, REF-API-05, REF-API-08, REF-API-09
2. [~] Execute REF-01 through REF-06 (basic /refractor status)
- Tested 2026-04-07: REF-API-02 (tracks ✓), REF-API-04 (404 nonexistent ✓), REF-API-05 (evolution removed ✓), REF-API-08 (tier filter ✓), REF-API-09 (progress=close ✓)
- REF-API-01 (bot health) not tested via API (port conflict with adminer on localhost:8080), but bot confirmed healthy via logs
2. [x] Execute REF-01 through REF-06 (basic /refractor status)
- Tested 2026-03-25: REF-01 (embed appears ✓), REF-02 (batter entry format ✓), REF-05 (tier badges [BC] ✓)
- Bugs found and fixed: wrong response key ("cards" vs "items"), wrong field names (formula_value vs current_value, card_type nesting), limit=500 exceeding API max, floating point display
- Not yet tested: REF-03 (SP format), REF-04 (RP format), REF-06 (fully evolved)
3. [~] Execute REF-10 through REF-19 (filters)
- Tested 2026-04-07: REF-03 (SP format ✓), REF-04 (RP format ✓)
- Bugs found and fixed (2026-03-25): wrong response key ("cards" vs "items"), wrong field names (formula_value vs current_value, card_type nesting), limit=500 exceeding API max, floating point display
- Note: formula labels (IP+K, PA+TB x 2) from test spec are not rendered; format is value/threshold (pct%) only
- REF-06 (fully evolved) not testable — no T4 cards exist in test data
3. [x] Execute REF-10 through REF-19 (filters)
- Tested 2026-03-25: REF-10 (card_type=batter ✓ after fix)
- Tested 2026-04-07: REF-11 (sp ✓), REF-12 (rp ✓), REF-13 (tier=0 ✓), REF-14 (tier=1 ✓), REF-15 (tier=4 empty ✓), REF-16 (progress=close ✓), REF-17 (batter+T1 combined ✓), REF-18 (T4+close empty ✓)
- Choice dropdown menus added for all filter params (PR #126)
- Not yet tested: REF-11 through REF-19
4. [~] Execute REF-20 through REF-23 (pagination)
- REF-19 (season filter): N/A — season param not implemented in the slash command
4. [x] Execute REF-20 through REF-23 (pagination)
- Tested 2026-03-25: REF-20 (page 1 footer ✓), pagination buttons added (PR #127)
- Not yet tested: REF-21 (page 2), REF-22 (beyond total), REF-23 (page 0)
5. [ ] Execute REF-30 through REF-34 (edge cases)
6. [ ] Execute REF-40 through REF-45 (tier badges on card embeds)
- Tested 2026-04-07: REF-21 (page 2 ✓), REF-22 (page=999 clamps to last page ✓ — fixed in discord#141/#142), REF-23 (page 0 clamps to 1 ✓), Prev/Next buttons (✓)
5. [x] Execute REF-30 through REF-34 (edge cases)
- Tested 2026-04-07: REF-34 (page=-5 clamps to 1 ✓)
- REF-30 (no team), REF-31 (no refractor data), REF-32 (invalid card_type), REF-33 (negative tier): not tested — require alt account or manual API state manipulation
6. [N/A] Execute REF-40 through REF-45 (tier badges on card embeds)
- **Design gap**: `get_card_embeds()` looks up refractor state via `card['id']`, but all user-facing commands (`/player`, `/buy`) use `get_blank_team_card()` which has no `id` field. The `except Exception: pass` silently swallows the KeyError. Badges never appear outside `/refractor status`. `/open-packs` uses real card objects but results are random. No command currently surfaces badges on card embeds in practice.
7. [ ] Execute REF-50 through REF-55 (post-game hook -- requires live game)
8. [ ] Execute REF-60 through REF-64 (tier-up notifications -- requires threshold crossing)
9. [ ] Execute REF-70 through REF-72 (cross-command badge propagation)
10. [~] Execute REF-80 through REF-82 (force-evaluate API)
9. [N/A] Execute REF-70 through REF-72 (cross-command badge propagation)
- REF-70: `/team` shows team overview, not card embeds — badges not applicable
- REF-71: `/show-card defense` only works during active games — expected no badge (by design)
- REF-72: `/scout-tokens` shows token count, not card embeds — badges not applicable
10. [x] Execute REF-80 through REF-82 (force-evaluate API)
- Tested 2026-03-25: REF-80 (force evaluate ✓ — used to seed 100 cards for team 31)
- Not yet tested: REF-81, REF-82
- Tested 2026-04-07: REF-81 (no stats → 404 ✓), REF-82 (nonexistent card → 404 ✓)
### Approximate Time Estimates
- API health checks + list endpoint (REF-API-01 through REF-API-10): 2-3 minutes

View File

@ -14,7 +14,7 @@ STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://pddev.manticorum.com/ap
echo ""
echo "=== Discord Bot ==="
# Health check
curl -sf http://sba-bots:8080/health >/dev/null 2>&1 && echo "PASS: bot health OK" || echo "FAIL: bot health endpoint"
curl -sf http://sba-bots:8081/health >/dev/null 2>&1 && echo "PASS: bot health OK" || echo "FAIL: bot health endpoint"
# Recent refractor activity in logs
echo ""