Commit Graph

434 Commits

Author SHA1 Message Date
Cal Corum
dc9269eeed fix: refractor card art post-merge fixes — cache bypass, template guards, dev server
- Skip PNG cache when ?tier= param is set to prevent serving stale T0 images
- Move {% if %} guard before diamond_colors dict in player_card.html
- Extract base #fullCard styles outside refractor conditional in tier_style.html
- Make run-local.sh DB host configurable, clean up Playwright check

Follow-up to PR #179

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 12:37:30 -05:00
cal
3e84a06b23 Merge pull request 'feat: refractor tier-specific card art rendering' (#179) from feature/refractor-card-art into main 2026-04-04 17:33:36 +00:00
Cal Corum
d92ab86aa7 fix: visual tuning from live preview — diamond position, borders, corners, header z-index
- Move diamond left to align bottom point with center column divider
- Keep all border widths uniform across tiers (remove T4 bold borders)
- Remove corner accents entirely (T4 differentiated by glow + prismatic)
- Fix T4 header z-index: don't override position on absolutely-positioned
  topright stat elements (stealing, running, bunting, hit & run)
- Add ?tier= query param for dev preview of tier styling on base cards
- Add run-local.sh for local API testing against dev database
- Add .env.local and .run-local.pid to .gitignore

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 11:20:05 -05:00
Cal Corum
830e703e76 fix: address PR #179 review — consolidate CSS, extract inline styles, add tests
- Consolidate T3 duplicate #header rule into single block with overflow/position
- Add explicit T2 #resultHeader border-bottom-width (4px) for clarity
- Move diamond quad filled box-shadow from inline styles to .diamond-quad.filled CSS rule
- Add TestResolveTier: 6 parametrized tests covering tier roundtrip, base card, unknown variant

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 00:43:27 -05:00
Cal Corum
b32e19a4ac feat: add refractor tier-specific card art rendering
Implement tier-aware visual styling for card PNG rendering (T0-T4).
Each refractor tier gets distinct borders, header backgrounds, column
header gradients, diamond tier indicators, and decorative effects.

- New tier_style.html template: per-tier CSS overrides (borders, headers,
  gradients, inset glow, diamond positioning, corner accents)
- Diamond indicator: 2x2 CSS grid rotated 45deg at header/result boundary,
  progressive fill (1B→2B→3B→Home) with tier-specific colors
- T4 Superfractor: bold gold borders, dual gold-teal glow, corner accents,
  purple diamond with glow pulse animation
- resolve_refractor_tier() helper: pure-math tier lookup from variant hash
- T3/T4 animations defined but paused for static PNG capture (APNG follow-up)

Relates-to: initiative #19

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 00:14:33 -05:00
cal
ffe07ec54c Merge pull request 'fix: auto-initialize RefractorCardState in evaluate-game' (#178) from fix/refractor-auto-init-missing-states into main
All checks were successful
Build Docker Image / build (push) Successful in 8m15s
2026-03-31 06:25:41 +00:00
Cal Corum
add175e528 fix: auto-initialize RefractorCardState in evaluate-game for legacy cards
Cards created before the refractor system was deployed have no
RefractorCardState row. Previously evaluate-game silently skipped these
players. Now it calls initialize_card_refractor on-the-fly so any card
used in a game gets refractor tracking regardless of when it was created.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 01:22:37 -05:00
cal
31c86525de Merge pull request 'feat: Refractor Phase 2 integration — wire boost into evaluate-game' (#177) from feature/refractor-phase2-integration into main
All checks were successful
Build Docker Image / build (push) Successful in 8m13s
2026-03-30 18:17:29 +00:00
Cal Corum
7f17c9b9f2 fix: address PR #177 review — move import os to top-level, add audit idempotency guard
- Move `import os` from inside evaluate_game() to module top-level imports
  (lazy imports are only for circular dependency avoidance)
- Add get_or_none idempotency guard before RefractorBoostAudit.create()
  inside db.atomic() to prevent IntegrityError on UNIQUE(card_state, tier)
  constraint in PostgreSQL when apply_tier_boost is called twice for the
  same tier
- Update atomicity test stub to provide card_state/tier attributes for
  the new Peewee expression in the idempotency guard

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:16:27 -05:00
Cal Corum
6a176af7da feat: Refractor Phase 2 integration — wire boost into evaluate-game
When a card reaches a new Refractor tier during game evaluation, the
system now creates a boosted variant card with modified ratings. This
connects the Phase 2 Foundation pure functions (PR #176) to the live
evaluate-game endpoint.

Key changes:
- evaluate_card() gains dry_run parameter so apply_tier_boost() is the
  sole writer of current_tier, ensuring atomicity with variant creation
- apply_tier_boost() orchestrates the full boost flow: source card
  lookup, boost application, variant card + ratings creation, audit
  record, and atomic state mutations inside db.atomic()
- evaluate_game() calls evaluate_card(dry_run=True) then loops through
  intermediate tiers on tier-up, with error isolation per player
- Display stat helpers compute fresh avg/obp/slg for variant cards
- REFRACTOR_BOOST_ENABLED env var provides a kill switch
- 51 new tests: unit tests for display stats, integration tests for
  orchestration, HTTP endpoint tests for multi-tier jumps, pitcher
  path, kill switch, atomicity, idempotency, and cross-player isolation
- Clarified all "79-sum" references to note the 108-total card invariant

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:04:52 -05:00
cal
70f984392d Merge pull request 'feat: Refractor Phase 2 foundation — boost functions, schema, tests' (#176) from feature/refractor-phase2-foundation into main 2026-03-30 16:11:07 +00:00
Cal Corum
a7d02aeb10 style: remove redundant parentheses on boost_delta_json declaration
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 11:07:19 -05:00
Cal Corum
776f1a5302 fix: address PR review findings — rename evolution_tier to refractor_tier
- Rename `evolution_tier` parameter to `refractor_tier` in compute_variant_hash()
  to match the refractor naming convention established in PR #131
- Update hash input dict key accordingly (safe: function is new, no stored hashes)
- Update test docstrings referencing the old parameter name
- Remove redundant parentheses on boost_delta_json TextField declaration

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 11:06:38 -05:00
Cal Corum
4a1251a734 feat: add Refractor Phase 2 foundation — boost functions, schema, tests
Pure functions for computing boosted card ratings when a player
reaches a new Refractor tier. Batter boost applies fixed +0.5 to
four offensive columns per tier; pitcher boost uses a 1.5 TB-budget
priority algorithm. Both preserve the 108-sum invariant.

- Create refractor_boost.py with apply_batter_boost, apply_pitcher_boost,
  and compute_variant_hash (Decimal arithmetic, zero-floor truncation)
- Add RefractorBoostAudit model, Card.variant, BattingCard/PitchingCard
  image_url, RefractorCardState.variant fields to db_engine.py
- Add migration SQL for refractor_card_state.variant column and
  refractor_boost_audit table (JSONB, UNIQUE constraint, transactional)
- 26 unit tests covering 108-sum invariant, deltas, truncation, TB
  accounting, determinism, x-check protection, and variant hash behavior

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 13:39:03 -05:00
cal
c2c978ac47 Merge pull request 'feat: add evaluated_only filter to GET /api/v2/refractor/cards (#174)' (#175) from issue/174-get-api-v2-refractor-cards-add-evaluated-only-filt into main
All checks were successful
Build Docker Image / build (push) Successful in 8m11s
2026-03-25 22:53:05 +00:00
Cal Corum
537eabcc4d feat: add evaluated_only filter to GET /api/v2/refractor/cards (#174)
Closes #174

Adds `evaluated_only: bool = Query(default=True)` to `list_card_states()`.
When True (the default), cards with `last_evaluated_at IS NULL` are excluded —
these are placeholder rows created at pack-open time but never run through the
evaluator. At team scale this eliminates ~2739 zero-value rows from the
default response, making the Discord /refractor status command efficient
without any bot-side changes.

Set `evaluated_only=false` to include all rows (admin/pipeline use case).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 17:32:59 -05:00
cal
7e7ff960e2 Merge pull request 'feat: add limit/pagination to paperdex endpoint (#143)' (#167) from issue/143-feat-add-limit-pagination-to-paperdex-endpoint into main
All checks were successful
Build Docker Image / build (push) Successful in 7m53s
2026-03-25 14:52:57 +00:00
cal
792c6b96f9 Merge pull request 'feat: add limit/pagination to cardpositions endpoint (#142)' (#168) from issue/142-feat-add-limit-pagination-to-cardpositions-endpoin into main 2026-03-25 14:52:55 +00:00
cal
2c077d0fd3 Merge branch 'main' into issue/143-feat-add-limit-pagination-to-paperdex-endpoint 2026-03-25 14:52:41 +00:00
cal
3d0c99b183 Merge branch 'main' into issue/142-feat-add-limit-pagination-to-cardpositions-endpoin 2026-03-25 14:52:34 +00:00
cal
eefd4afa37 Merge pull request 'feat: add GET /api/v2/refractor/cards list endpoint (#172)' (#173) from issue/172-feat-add-get-api-v2-refractor-cards-list-endpoint into main 2026-03-25 14:52:24 +00:00
Cal Corum
0b5d0b474b feat: add GET /api/v2/refractor/cards list endpoint (#172)
Closes #172

- New GET /api/v2/refractor/cards endpoint in refractor router with
  team_id (required), card_type, tier, season, progress, limit, offset filters
- season filter uses EXISTS subquery against batting/pitching_season_stats
- progress=close filter uses CASE expression to compare current_value
  against next tier threshold (>= 80%)
- LEFT JOIN on Player so deleted players return player_name: null
- Sorting: current_tier DESC, current_value DESC
- count reflects total matching rows before pagination
- Extended _build_card_state_response() with progress_pct (computed) and
  optional player_name; single-card endpoint gains progress_pct automatically
- Added non-unique team_id index on refractor_card_state in db_engine.py
- Migration: 2026-03-25_add_refractor_card_state_team_index.sql
- Removed pre-existing unused RefractorTrack import in evaluate_game (ruff)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 01:35:18 -05:00
cal
de9b511ae9 Merge pull request 'test: refractor system Tier 3 test coverage' (#171) from test/refractor-tier3 into main
All checks were successful
Build Docker Image / build (push) Successful in 8m11s
2026-03-25 04:13:17 +00:00
Cal Corum
906d6e575a test: add Tier 3 refractor test cases (T3-1, T3-6, T3-7, T3-8)
Adds four Tier 3 (medium-priority) test cases to the existing refractor test
suite.  All tests use SQLite in-memory databases and run without a PostgreSQL
connection.

T3-1 (test_refractor_track_api.py): Two tests verifying that
  GET /api/v2/refractor/tracks?card_type= returns 200 with count=0 for both
  an unrecognised card_type value ('foo') and an empty string, rather than
  a 4xx/5xx.  A full SQLite-backed TestClient is added to the track API test
  module for these cases.

T3-6 (test_refractor_state_api.py): Verifies that
  GET /api/v2/refractor/cards/{card_id} returns last_evaluated_at: null (not
  a crash or missing key) when the RefractorCardState was initialised but
  never evaluated.  Adds the SQLite test infrastructure (models, fixtures,
  helper factories, TestClient) to the state API test module.

T3-7 (test_refractor_evaluator.py): Two tests covering fully_evolved/tier
  mismatch correction.  When the database has fully_evolved=True but
  current_tier=3 (corruption), evaluate_card must re-derive fully_evolved
  from the freshly-computed tier (False for tier 3, True for tier 4).

T3-8 (test_refractor_evaluator.py): Two tests confirming per-team stat
  isolation.  A player with BattingSeasonStats on two different teams must
  have each team's RefractorCardState reflect only that team's stats — not
  a combined total.  Covers both same-season and multi-season scenarios.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 21:38:25 -05:00
cal
74284fe5a3 Merge pull request 'test: refractor system Tier 1+2 test coverage' (#170) from test/refractor-tier1-tier2 into main 2026-03-24 21:18:13 +00:00
Cal Corum
569dc53c00 test: add Tier 1 and Tier 2 refractor system test cases
Implements all gap tests identified in the PO review for the refractor
card progression system (Phase 1 foundation).

TIER 1 (critical):
- T1-1: Negative singles guard in compute_batter_value — documents that
  hits=1, doubles=1, triples=1 produces singles=-1 and flows through
  unclamped (value=8.0, not 10.0)
- T1-2: SP tier boundary precision with floats — outs=29 (IP=9.666) stays
  T0, outs=30 (IP=10.0) promotes to T1; also covers T2 float boundary
- T1-3: evaluate-game with non-existent game_id returns 200 with empty results
- T1-4: Seed threshold ordering + positivity invariant (t1<t2<t3<t4, all >0)

TIER 2 (high):
- T2-1: fully_evolved=True persists when stats are zeroed or drop below
  previous tier — no-regression applies to both tier and fully_evolved flag
- T2-2: Parametrized edge cases for _determine_card_type: DH, C, 2B, empty
  string, None, and compound "SP/RP" (resolves to "sp", SP checked first)
- T2-3: evaluate-game with zero StratPlay rows returns empty batch result
- T2-4: GET /teams/{id}/refractors with valid team and zero states is empty
- T2-5: GET /teams/99999/refractors documents 200+empty (no team existence check)
- T2-6: POST /cards/{id}/evaluate with zero season stats stays at T0 value=0.0
- T2-9: Per-player error isolation — patches source module so router's local
  from-import picks up the patched version; one failure, one success = evaluated=1
- T2-10: Each card_type has exactly one RefractorTrack after seeding

All 101 tests pass (15 PostgreSQL-only tests skip without POSTGRES_HOST).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 09:02:30 -05:00
cal
bc6c23ef2e Merge pull request 'feat: capture total_count before limit across all paginated endpoints' (#169) from enhancement/total-count-pagination into main
All checks were successful
Build Docker Image / build (push) Successful in 8m22s
2026-03-24 12:45:53 +00:00
Cal Corum
1e21894898 fix: skip total_count query for CSV requests and consolidate rewards.py counts
- Guard total_count with `if not csv` ternary to avoid unnecessary
  COUNT query on CSV export paths (10 files)
- Consolidate rewards.py from 3 COUNT queries to 1 (used for both
  empty-check and response)
- Clean up scout_claims.py double `if limit is not None` block
- Normalize scout_opportunities.py from max(1,...) to max(0,...)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 07:43:14 -05:00
Cal Corum
54dccd1981 feat: capture total_count before limit across all paginated endpoints
Ensures the `count` field in JSON responses reflects total matching
records rather than the page size, consistent with the notifications
endpoint pattern from PR #150.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 07:37:26 -05:00
Cal Corum
8af43273d2 feat: add limit/pagination to cardpositions endpoint (#142)
Closes #142

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 07:31:59 -05:00
cal
a3ca22b277 Merge pull request 'feat: add limit/pagination to notifications endpoint (#140)' (#150) from issue/140-feat-add-limit-pagination-to-notifications-endpoin into main 2026-03-24 12:13:06 +00:00
cal
268b81aea4 Merge branch 'main' into issue/140-feat-add-limit-pagination-to-notifications-endpoin 2026-03-24 12:12:53 +00:00
cal
b14907d018 Merge pull request 'feat: add limit/pagination to gauntletrewards endpoint (#145)' (#165) from issue/145-feat-add-limit-pagination-to-gauntletrewards-endpo into main 2026-03-24 12:12:32 +00:00
cal
ff132564c2 Merge branch 'main' into issue/145-feat-add-limit-pagination-to-gauntletrewards-endpo 2026-03-24 12:12:07 +00:00
cal
66505915a7 fix: capture total_count before applying limit so response count reflects matching records not page size 2026-03-24 12:11:18 +00:00
cal
f2ff85556a Merge pull request 'feat: add limit/pagination to pitstats endpoint (#134)' (#158) from issue/134-feat-add-limit-pagination-to-pitstats-endpoint into main 2026-03-24 12:10:59 +00:00
cal
dbd61a6957 Merge branch 'main' into issue/134-feat-add-limit-pagination-to-pitstats-endpoint 2026-03-24 12:10:37 +00:00
cal
11794d8c2a Merge pull request 'feat: add limit/pagination to rewards endpoint (#139)' (#152) from issue/139-feat-add-limit-pagination-to-rewards-endpoint into main 2026-03-24 12:09:58 +00:00
cal
85e8b3f37b Merge branch 'main' into issue/139-feat-add-limit-pagination-to-rewards-endpoint 2026-03-24 12:09:54 +00:00
cal
f2e10bcf2f Merge pull request 'feat: add limit/pagination to events endpoint (#147)' (#156) from issue/147-feat-add-limit-pagination-to-events-endpoint into main 2026-03-24 12:09:45 +00:00
cal
88c0d0cc13 Merge branch 'main' into issue/134-feat-add-limit-pagination-to-pitstats-endpoint 2026-03-24 12:09:43 +00:00
cal
457189fcd8 Merge branch 'main' into issue/145-feat-add-limit-pagination-to-gauntletrewards-endpo 2026-03-24 12:09:31 +00:00
cal
c64f389d64 Merge branch 'main' into issue/147-feat-add-limit-pagination-to-events-endpoint 2026-03-24 12:09:22 +00:00
cal
67af5cd94a Merge branch 'main' into issue/139-feat-add-limit-pagination-to-rewards-endpoint 2026-03-24 12:08:51 +00:00
cal
15ee0764d6 Merge branch 'main' into issue/134-feat-add-limit-pagination-to-pitstats-endpoint 2026-03-24 12:08:49 +00:00
cal
ed35773dd0 Merge pull request 'feat: add limit/pagination to gauntletruns endpoint (#146)' (#160) from issue/146-feat-add-limit-pagination-to-gauntletruns-endpoint into main 2026-03-24 12:08:47 +00:00
cal
c1a8808cd3 Merge pull request 'feat: add limit/pagination to pitchingcardratings endpoint (#136)' (#161) from issue/136-feat-add-limit-pagination-to-pitchingcardratings-e into main 2026-03-24 12:08:43 +00:00
cal
23b95f2d3d Merge branch 'main' into issue/139-feat-add-limit-pagination-to-rewards-endpoint 2026-03-24 12:08:39 +00:00
cal
ae2e7320c5 Merge branch 'main' into issue/147-feat-add-limit-pagination-to-events-endpoint 2026-03-24 12:08:37 +00:00
Cal Corum
e7fcf611da feat: add limit/pagination to gauntletruns endpoint (#146)
Closes #146

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 07:08:37 -05:00