paper-dynasty-discord/tests/refractor-integration-test-plan.md
Cal Corum 035cd8888f
All checks were successful
Ruff Lint / lint (pull_request) Successful in 22s
fix: move health server from port 8080 to 8081 (#130)
Adminer is exposed on host port 8080, shadowing the bot health endpoint.
Change health server default to 8081 to avoid the conflict.

Closes #130

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 23:33:09 -05:00

32 KiB

Refractor System -- In-App Integration Test Plan

Target environment: Dev Discord server (Guild ID: 613880856032968834) Dev API: pddev.manticorum.com Bot container: paper-dynasty_discord-app_1 on sba-bots Date created: 2026-03-25

This test plan is designed for browser automation (Playwright against the Discord web client) or manual execution. Each test case specifies an exact slash command, the expected bot response, and pass/fail criteria.


Table of Contents

  1. Prerequisites
  2. API Health Checks
  3. /refractor status -- Basic Functionality
  4. /refractor status -- Filters
  5. /refractor status -- Pagination
  6. /refractor status -- Edge Cases and Errors
  7. Tier Badges on Card Embeds
  8. Post-Game Hook -- Stat Accumulation and Evaluation
  9. Tier-Up Notifications
  10. Cross-Command Badge Propagation
  11. Known Gaps and Risks

Prerequisites

Before running these tests, ensure the following state exists:

Bot State

  • 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

Team and Card State

  • Test user owns a team (verify with /team or /myteam)
  • Team has at least 15 cards on its roster (needed for pagination tests)
  • At least one batter card, one SP card, and one RP card exist on the roster
  • At least one card has refractor state initialized in the database (the API must have a RefractorCardState row for this player+team pair)
  • Record the team ID, and at least 3 card IDs for use in tests:
    • CARD_BATTER -- a batter card ID with refractor state
    • CARD_SP -- a starting pitcher card ID with refractor state
    • CARD_RP -- a relief pitcher card ID with refractor state
    • CARD_NO_STATE -- a card ID that exists but has no RefractorCardState row
    • CARD_INVALID -- a card ID that does not exist (e.g. 999999)

API State

  • Refractor tracks are seeded: GET /api/v2/refractor/tracks returns at least 3 tracks (batter, sp, rp)
  • At least one RefractorCardState row exists for a card on the test team
  • Verify manually: GET /api/v2/refractor/cards/{CARD_BATTER} returns a valid response
  • Verify list endpoint: GET /api/v2/refractor/cards?team_id={TEAM_ID} returns cards for the test team

Data Setup Script (run against dev API)

If refractor state does not yet exist for test cards, trigger initialization:

# Force-evaluate a specific card to create its RefractorCardState
curl -X POST "https://pddev.manticorum.com/api/v2/refractor/cards/${CARD_BATTER}/evaluate" \
  -H "Authorization: Bearer ${API_TOKEN}"

1. API Health Checks

These are pre-flight checks run before any Discord interaction. They verify the 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:8081/health
Expected HTTP 200, body contains health status
Pass criteria Non-empty 200 response

REF-API-02: Refractor tracks endpoint responds

Field Value
Command curl -s "https://pddev.manticorum.com/api/v2/refractor/tracks" -H "Authorization: Bearer $TOKEN"
Expected JSON with count >= 3 and items array containing batter, sp, rp tracks
Pass criteria count field >= 3; each item has card_type, t1_threshold, t2_threshold, t3_threshold, t4_threshold

REF-API-03: Single card refractor state endpoint

Field Value
Command curl -s "https://pddev.manticorum.com/api/v2/refractor/cards/${CARD_BATTER}" -H "Authorization: Bearer $TOKEN"
Expected JSON with player_id, team_id, current_tier, current_value, fully_evolved, next_threshold, track
Pass criteria current_tier is an integer 0-4; track object exists with threshold fields

REF-API-04: Card state 404 for nonexistent card

Field Value
Command curl -s -o /dev/null -w "%{http_code}" "https://pddev.manticorum.com/api/v2/refractor/cards/999999" -H "Authorization: Bearer $TOKEN"
Expected HTTP 404
Pass criteria Status code is exactly 404

REF-API-05: Old evolution endpoint removed

Field Value
Command curl -s -o /dev/null -w "%{http_code}" "https://pddev.manticorum.com/api/v2/evolution/cards/1" -H "Authorization: Bearer $TOKEN"
Expected HTTP 404
Pass criteria Status code is 404 (confirms evolution->refractor rename is complete)

REF-API-06: Team-level card list endpoint

Field Value
Command curl -s "https://pddev.manticorum.com/api/v2/refractor/cards?team_id=${TEAM_ID}" -H "Authorization: Bearer $TOKEN"
Expected JSON with count >= 1 and items array containing card state objects
Pass criteria 1. count reflects total cards with refractor state for the team
2. Each item has player_id, team_id, current_tier, current_value, progress_pct, player_name
3. Items sorted by current_tier DESC, current_value DESC

REF-API-07: Card list with card_type filter

Field Value
Command curl -s "https://pddev.manticorum.com/api/v2/refractor/cards?team_id=${TEAM_ID}&card_type=batter" -H "Authorization: Bearer $TOKEN"
Expected JSON with only batter card states
Pass criteria All items have batter track; count <= total from REF-API-06

REF-API-08: Card list with tier filter

Field Value
Command curl -s "https://pddev.manticorum.com/api/v2/refractor/cards?team_id=${TEAM_ID}&tier=0" -H "Authorization: Bearer $TOKEN"
Expected JSON with only T0 card states
Pass criteria All items have current_tier: 0

REF-API-09: Card list with progress=close filter

Field Value
Command curl -s "https://pddev.manticorum.com/api/v2/refractor/cards?team_id=${TEAM_ID}&progress=close" -H "Authorization: Bearer $TOKEN"
Expected JSON with only cards at >= 80% of next tier threshold
Pass criteria Each item's progress_pct >= 80.0; no fully evolved cards

REF-API-10: Card list pagination

Field Value
Command curl -s "https://pddev.manticorum.com/api/v2/refractor/cards?team_id=${TEAM_ID}&limit=2&offset=0" -H "Authorization: Bearer $TOKEN"
Expected JSON with count reflecting total (not page size) and items array with at most 2 entries
Pass criteria 1. count same as REF-API-06 (total matching, not page size)
2. items length <= 2

2. /refractor status -- Basic Functionality

REF-01: Basic status command (no filters)

Field Value
Description Invoke /refractor status with no arguments; verify the embed appears
Discord command /refractor status
Expected result An ephemeral embed with:
- Title: {team short name} Refractor Status
- Purple embed color (hex 0x6F42C1 = RGB 111, 66, 193)
- Description containing card entries (player names, progress bars, tier labels)
- Footer: Page 1/N . M card(s) total
Pass criteria 1. Embed title contains team short name and "Refractor Status"
2. Embed color is purple (#6F42C1)
3. At least one card entry is visible in the description
4. Footer contains page number and total card count
5. Response is ephemeral (only visible to the invoking user)

REF-02: Card entry format -- batter

Field Value
Description Verify a batter card entry has correct format in the status embed
Discord command /refractor status card_type:batter
Expected result Each entry in the embed follows this pattern:
Line 1: **{badge} Player Name** (Tier Label)
Line 2: [====------] value/threshold (PA+TB x 2) -- T{n} -> T{n+1}
Pass criteria 1. Player name appears in bold (**...**)
2. Tier label is one of: Base Card, Base Chrome, Refractor, Gold Refractor, Superfractor
3. Progress bar has format [====------] (10 chars of = and - between brackets)
4. Formula label shows PA+TB x 2 for batters
5. Tier progression arrow shows T{current} -> T{next}

REF-03: Card entry format -- starting pitcher

Field Value
Description Verify SP cards show the correct formula label
Discord command /refractor status card_type:sp
Expected result SP card entries show IP+K as the formula label
Pass criteria Formula label in progress line is IP+K (not PA+TB x 2)

REF-04: Card entry format -- relief pitcher

Field Value
Description Verify RP cards show the correct formula label
Discord command /refractor status card_type:rp
Expected result RP card entries show IP+K as the formula label
Pass criteria Formula label in progress line is IP+K

REF-05: Tier badge display per tier

Field Value
Description Verify correct tier badges appear for each tier level
Discord command /refractor status (examine entries across tiers)
Expected result Badge mapping:
T0 (Base Card): no badge prefix
T1 (Base Chrome): [BC] prefix
T2 (Refractor): [R] prefix
T3 (Gold Refractor): [GR] prefix
T4 (Superfractor): [SF] prefix
Pass criteria Each card's badge matches its tier per the mapping above

REF-06: Fully evolved card display

Field Value
Description Verify T4 (Superfractor) cards show the fully evolved indicator
Discord command /refractor status tier:4
Expected result Fully evolved cards show:
Line 1: **[SF] Player Name** (Superfractor)
Line 2: [==========] FULLY EVOLVED (star)
Pass criteria 1. Progress bar is completely filled ([==========])
2. Text says "FULLY EVOLVED" with a star character
3. No tier progression arrow (no -> text)

3. /refractor status -- Filters

REF-10: Filter by card_type=batter

Field Value
Discord command /refractor status card_type:batter
Expected result Only batter cards appear; formula label is PA+TB x 2 on all entries
Pass criteria No entries show IP+K formula label

REF-11: Filter by card_type=sp

Field Value
Discord command /refractor status card_type:sp
Expected result Only SP cards appear; formula label is IP+K on all entries
Pass criteria No entries show PA+TB x 2 formula label

REF-12: Filter by card_type=rp

Field Value
Discord command /refractor status card_type:rp
Expected result Only RP cards appear; formula label is IP+K on all entries
Pass criteria No entries show PA+TB x 2 formula label

REF-13: Filter by tier=0

Field Value
Discord command /refractor status tier:0
Expected result Only T0 (Base Card) entries appear; no tier badges on any entry
Pass criteria No entries contain [BC], [R], [GR], or [SF] badges

REF-14: Filter by tier=1

Field Value
Discord command /refractor status tier:1
Expected result Only T1 entries appear; all show [BC] badge and (Base Chrome) label
Pass criteria Every entry contains [BC] and (Base Chrome)

REF-15: Filter by tier=4

Field Value
Discord command /refractor status tier:4
Expected result Only T4 entries appear; all show [SF] badge and FULLY EVOLVED
Pass criteria Every entry contains [SF], (Superfractor), and FULLY EVOLVED

REF-16: Filter by progress=close

Field Value
Discord command /refractor status progress:close
Expected result Only cards within 80% of their next tier threshold appear
Pass criteria 1. For each entry, the formula_value/next_threshold ratio >= 0.8
2. No fully evolved (T4) cards appear
3. If no cards qualify, message says "No cards are currently close to a tier advancement."

REF-17: Combined filter -- tier + card_type

Field Value
Discord command /refractor status card_type:batter tier:1
Expected result Only T1 batter cards appear
Pass criteria All entries have [BC] badge AND PA+TB x 2 formula label

REF-18: Combined filter -- tier=4 + progress=close (empty result)

Field Value
Discord command /refractor status tier:4 progress:close
Expected result Message: "No cards are currently close to a tier advancement."
Pass criteria No embed appears; plain text message about no close cards
Notes T4 cards are fully evolved and cannot be "close" to any threshold

REF-19: Filter by season

Field Value
Discord command /refractor status season:1
Expected result Only cards from season 1 appear (or empty message if none exist)
Pass criteria Response is either a valid embed or the "no data" message

4. /refractor status -- Pagination

REF-20: Page 1 shows first 10 cards

Field Value
Discord command /refractor status page:1
Expected result Embed shows up to 10 card entries; footer says Page 1/N
Pass criteria 1. At most 10 card entries in the description
2. Footer page number is 1
3. Total pages N matches ceil(total_cards / 10)

REF-21: Page 2 shows next batch

Field Value
Discord command /refractor status page:2
Expected result Embed shows cards 11-20; footer says Page 2/N
Pass criteria 1. Different cards than page 1
2. Footer shows Page 2/N
Prerequisite Team has > 10 cards with refractor state

REF-22: Page beyond total clamps to last page

Field Value
Discord command /refractor status page:999
Expected result Embed shows the last page of cards
Pass criteria 1. Footer shows Page N/N (last page)
2. No error or empty response

REF-23: Page 0 clamps to page 1

Field Value
Discord command /refractor status page:0
Expected result Embed shows page 1
Pass criteria Footer shows Page 1/N

5. /refractor status -- Edge Cases and Errors

REF-30: User with no team

Field Value
Description Invoke command as a user who does not own a team
Discord command /refractor status (from a user with no team)
Expected result Plain text message: "You don't have a team. Sign up with /newteam first."
Pass criteria 1. No embed appears
2. Message mentions /newteam
3. Response is ephemeral

REF-31: Team with no refractor data

Field Value
Description Invoke command for a team that has cards but no RefractorCardState rows
Discord command /refractor status (from a team with no refractor initialization)
Expected result Plain text message: "No refractor data found for your team."
Pass criteria 1. No embed appears
2. Message mentions "no refractor data"

REF-32: Invalid card_type filter

Field Value
Discord command /refractor status card_type:xyz
Expected result Empty result -- "No refractor data found for your team."
Pass criteria No crash; clean empty-state message

REF-33: Negative tier filter

Field Value
Discord command /refractor status tier:-1
Expected result Empty result or Discord input validation rejection
Pass criteria No crash; either a clean message or Discord prevents submission

REF-34: Negative page number

Field Value
Discord command /refractor status page:-5
Expected result Clamps to page 1
Pass criteria Footer shows Page 1/N; no crash

6. Tier Badges on Card Embeds

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)

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)
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
3. Embed color is still from the card's rarity (not refractor-related)

REF-41: No badge for T0 card

Field Value
Description Look up a card with current_tier=0
Discord command /card {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]

REF-42: No badge when refractor state is missing

Field Value
Description Look up a card that has no RefractorCardState row
Discord command /card {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
3. Card display is otherwise normal

REF-43: Badge on /buy confirmation embed

Field Value
Description Start a card purchase for a player with refractor state
Discord command /buy {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.

REF-44: Badge on pack opening cards

Field Value
Description Open a pack and check if revealed cards show tier badges
Discord command /openpack (or equivalent pack opening command)
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

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
Pass criteria Tier badge letter matches: T1=[BC], T2=[R], T3=[GR], T4=[SF]

7. Post-Game Hook -- Stat Accumulation and Evaluation

These tests verify the end-to-end flow: play a game -> stats update -> refractor evaluation -> optional tier-up notification.

Prerequisites for Game Tests

  • Two teams exist on the dev server (the test user's team + an AI opponent)
  • The test user's team has a valid lineup and starting pitcher set
  • Record the game ID from the game channel name after starting

Note: Cal will perform the test game manually in Discord. Sections 7 and 8 (REF-50 through REF-64) are not automated via Playwright — game simulation requires interactive play that is impractical to automate through the Discord web client. After the game completes, the verification checks (REF-52 through REF-55, REF-60 through REF-64) can be validated via API calls and bot logs.

REF-50: Start a game against AI

Field Value
Description Start a new game to create a game context
Discord command /new-game mlb-campaign league:Minor League away_team_abbrev:{user_team} home_team_abbrev:{ai_team}
Expected result Game channel is created; game starts successfully
Pass criteria A new channel appears; scorebug embed is posted
Notes This is setup for REF-51 through REF-54

REF-51: Complete a game (manual or auto-roll)

Field Value
Description Play the game through to completion
Discord command Use /log ab repeatedly or auto-roll to finish the game
Expected result Game ends; final score is posted; game summary embed appears
Pass criteria 1. Game over message appears
2. No errors in bot logs during the post-game hook

REF-52: Verify season stats updated post-game

Field Value
Description After game completion, check that season stats were updated
Verification Check bot logs for successful POST to season-stats/update-game/{game_id}
Pass criteria 1. Bot logs show the season-stats POST was made
2. No error logged for that call
API check curl "https://pddev.manticorum.com/api/v2/season-stats?team_id={team_id}" -H "Authorization: Bearer $TOKEN" returns updated stats

REF-53: Verify refractor evaluation triggered post-game

Field Value
Description After game completion, check that refractor evaluation was called
Verification Check bot logs for successful POST to refractor/evaluate-game/{game_id}
Pass criteria 1. Bot logs show the refractor evaluate-game POST was made
2. The call happened AFTER the season-stats call (ordering matters)
3. Log does not show "Post-game refractor processing failed"

REF-54: Verify refractor values changed after game

Field Value
Description After a completed game, check that formula values increased for participating players
Discord command /refractor status (compare before/after values for a participating player)
Expected result formula_value for batters who had PAs and pitchers who recorded outs should be higher than before the game
Pass criteria At least one card's formula_value has increased
API check curl "https://pddev.manticorum.com/api/v2/refractor/cards/{CARD_BATTER}" -H "Authorization: Bearer $TOKEN" -- compare current_value before and after

REF-55: Post-game hook is non-fatal

Field Value
Description Even if the refractor API fails, the game completion should succeed
Verification This is tested via unit tests (test_complete_game_hook.py). For integration: verify that if the API has a momentary error, the game result is still saved and the channel reflects the final score.
Pass criteria Game results persist even if refractor evaluation errors appear in logs

8. Tier-Up Notifications

REF-60: Tier-up embed format (T0 -> T1)

Field Value
Description When a card tiers up from T0 to T1 (Base Chrome), a notification embed is sent
Trigger Complete a game where a player's formula_value crosses the T1 threshold
Expected result An embed appears in the game channel with:
- Title: "Refractor Tier Up!"
- Description: **{Player Name}** reached **Tier 1 (Base Chrome)** on the **{Track Name}** track
- Color: green (0x2ECC71)
- Footer: "Paper Dynasty Refractor"
Pass criteria 1. Embed title is exactly "Refractor Tier Up!"
2. Player name appears bold in description
3. Tier number and name are correct
4. Track name is one of: Batter Track, Starting Pitcher Track, Relief Pitcher Track
5. Footer text is "Paper Dynasty Refractor"

REF-61: Tier-up embed colors per tier

Field Value
Description Each tier has a distinct embed color
Expected colors T1: green (0x2ECC71), T2: gold (0xF1C40F), T3: purple (0x9B59B6), T4: teal (0x1ABC9C)
Pass criteria Embed color matches the target tier
Notes May require manual API manipulation to trigger specific tier transitions

REF-62: Superfractor notification (T3 -> T4)

Field Value
Description The Superfractor tier-up has special formatting
Trigger A player crosses the T4 threshold
Expected result Embed with:
- Title: "SUPERFRACTOR!" (not "Refractor Tier Up!")
- Description: **{Player Name}** has reached maximum refractor tier on the **{Track Name}** track
- Color: teal (0x1ABC9C)
- Extra field: "Rating Boosts" with value "Rating boosts coming in a future update!"
Pass criteria 1. Title is "SUPERFRACTOR!"
2. Description mentions "maximum refractor tier"
3. "Rating Boosts" field is present

REF-63: Multiple tier-ups in one game

Field Value
Description When multiple players tier up in the same game, each gets a separate notification
Trigger Complete a game where 2+ players cross thresholds
Expected result One embed per tier-up, posted sequentially in the game channel
Pass criteria Each tier-up gets its own embed; no tier-ups are lost

REF-64: No notification when no tier-ups occur

Field Value
Description Most games will not produce any tier-ups; verify no spurious notifications
Trigger Complete a game where no thresholds are crossed
Expected result No tier-up embeds appear in the channel
Pass criteria The only game-end messages are the standard game summary and rewards

9. Cross-Command Badge Propagation

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

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
Pass criteria Cards at T1+ have badges; T0 cards have none

REF-71: /show-card defense (in-game) -- no badge expected

Field Value
Description During an active game, the /show-card defense command uses image_embed() directly, NOT get_card_embeds()
Discord command /show-card defense position:Catcher (during an active game)
Expected result Card image is shown without a tier badge in the embed title
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

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

10. Force-Evaluate Endpoint (Admin/Debug)

REF-80: Force evaluate a single card

Field Value
Description Use the API to force-recalculate a card's refractor state
Command curl -X POST "https://pddev.manticorum.com/api/v2/refractor/cards/${CARD_BATTER}/evaluate" -H "Authorization: Bearer $TOKEN"
Expected result JSON response with updated current_tier, current_value
Pass criteria Response includes tier and value fields; no 500 error

REF-81: Force evaluate a card with no stats

Field Value
Command curl -X POST "https://pddev.manticorum.com/api/v2/refractor/cards/${CARD_NO_STATS}/evaluate" -H "Authorization: Bearer $TOKEN"
Expected result Either 404 or a response with current_tier: 0 and current_value: 0
Pass criteria No 500 error; graceful handling

REF-82: Force evaluate nonexistent card

Field Value
Command curl -X POST "https://pddev.manticorum.com/api/v2/refractor/cards/999999/evaluate" -H "Authorization: Bearer $TOKEN"
Expected result HTTP 404 with "Card 999999 not found"
Pass criteria Status 404; clear error message

Known Gaps and Risks

RESOLVED: Team-level refractor cards list endpoint

The GET /api/v2/refractor/cards list endpoint was added in database PR #173 (merged 2026-03-25). It accepts team_id (required), card_type, tier, season, progress, limit, and offset query parameters. The response includes progress_pct (computed) and player_name (via LEFT JOIN on Player). Sorting: current_tier DESC, current_value DESC. A non-unique index on refractor_card_state.team_id was added for query performance.

Test cases REF-API-06 through REF-API-10 now cover this endpoint directly.

In-game card display does not show badges

The /show-card defense command in the gameplay cog uses image_embed() which renders the card image directly. It does not call get_card_embeds() and therefore does not fetch or display refractor tier badges. This is a design decision, not a bug, but should be documented as a known limitation.

Tier badge format inconsistency (by design)

Two TIER_BADGES dicts exist:

  • cogs/refractor.py: {1: "[BC]", 2: "[R]", 3: "[GR]", 4: "[SF]"} (with brackets)
  • helpers/main.py: {1: "BC", 2: "R", 3: "GR", 4: "SF"} (without brackets)

This is intentional -- helpers/main.py wraps the value in brackets when building the embed title (f"[{badge}] "). The existing unit test TestTierBadgesFormatConsistency in test_card_embed_refractor.py enforces this contract. Both dicts must stay in sync.

Notification delivery is non-fatal

The tier-up notification send is wrapped in try/except. If Discord's API has a momentary error, the notification is lost silently (logged but not retried). There is no notification queue or retry mechanism. This is acceptable for the current design but means tier-up notifications are best-effort.


Test Execution Checklist

Run order for Playwright automation:

  1. [~] 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-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-03-25: REF-10 (card_type=batter ✓ after fix)
    • 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)
    • 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)
  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)
    • Tested 2026-03-25: REF-80 (force evaluate ✓ — used to seed 100 cards for team 31)
    • Not yet tested: REF-81, REF-82

Approximate Time Estimates

  • API health checks + list endpoint (REF-API-01 through REF-API-10): 2-3 minutes
  • /refractor status tests (REF-01 through REF-34): 10-15 minutes
  • Tier badge tests (REF-40 through REF-45): 5-10 minutes
  • Game simulation tests (REF-50 through REF-55): 15-30 minutes (depends on game length)
  • Tier-up notification tests (REF-60 through REF-64): Requires setup; 10-20 minutes
  • Cross-command tests (REF-70 through REF-72): 5 minutes
  • Force-evaluate API tests (REF-80 through REF-82): 2-3 minutes

Total estimated time: 50-90 minutes for full suite (87 test cases)