Commit Graph

158 Commits

Author SHA1 Message Date
josh 26678b164b style: fix ruff formatting in bracket_view and routes
CI / Lint (push) Successful in 6s
CI / Test (push) Successful in 14s
CI / Build & Push (push) Successful in 30s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 20:22:56 -04:00
josh 2da60e27ae feat: add 10 UX improvements from interface review
CI / Lint (push) Failing after 10s
CI / Test (push) Has been skipped
CI / Build & Push (push) Has been skipped
- Stale data banner after 3 consecutive fetch failures, auto-clears on recovery
- Date navigation with left/right arrows (Yesterday/Today/Tomorrow labels),
  fetches from NHL API for non-today dates, disables auto-refresh on history
- Empty state message when no games are scheduled
- Series detail page auto-refreshes every 30s when a game is live
- Notification permission deferred until a playoff OT actually occurs
- Scroll position saved/restored when navigating to/from series detail
- Team records rendered with better contrast and tabular nums
- Active bracket round highlighted with gold heading + underline,
  completed rounds dimmed more aggressively, mobile accordion auto-opens
  current round
- Browser tab title shows live game count (e.g. "NHL Scoreboard (3 Live)")
- Service worker update shows a dismissable toast instead of force-reloading

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 20:22:03 -04:00
josh 58b27ddd20 style: strip trailing periods from all series blurbs
CI / Lint (push) Successful in 13s
CI / Test (push) Successful in 16s
CI / Build & Push (push) Successful in 15s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 12:21:23 -04:00
josh b8819167f5 fix: remove unused variable g from series_blurb after Game X removal
CI / Lint (push) Successful in 13s
CI / Test (push) Successful in 14s
CI / Build & Push (push) Successful in 40s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 12:11:49 -04:00
josh fac1a0ecbc style: drop "— Game X" from all series blurbs
CI / Lint (push) Failing after 5s
CI / Test (push) Has been skipped
CI / Build & Push (push) Has been skipped
The game number is redundant with the series summary already shown on
the card. Blurbs now read cleaner: "Win-or-go-home." instead of
"Win-or-go-home — Game 7."

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 12:07:16 -04:00
josh c95bea879d feat: enforce 85% test coverage in CI and fix cross-platform strftime bug
CI / Lint (push) Successful in 11s
CI / Test (push) Successful in 13s
CI / Build & Push (push) Successful in 19s
Add pyproject.toml with pytest-cov config so CI fails if coverage drops
below 85%. Fix series_view _format_start using Linux-only %-I/%-d codes
that crash on Windows — use manual formatting instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-22 22:53:22 -04:00
josh 4e5fab654d fix: don't label a FINAL playoff card as CLINCHER — those stakes belong to the next game
CI / Lint (push) Successful in 11s
CI / Test (push) Successful in 14s
CI / Build & Push (push) Successful in 52s
seriesStatus updates with the just-played game's win, so once a card goes
FINAL the is_clincher / is_game7 / is_pivotal predicates point at the
upcoming game. Gate the stake badge, stake blurb, and elimination_count
tally on a non-FINAL gameState so a completed Game 3 that left the series
3-0 reads "Flyers lead 3-0" instead of "Flyers can close it out — Game 3."

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 22:35:32 -04:00
josh c7ba334bb9 fix: freeze PP clock on any stoppage, not just intermission
CI / Lint (push) Successful in 10s
CI / Test (push) Successful in 10s
CI / Build & Push (push) Successful in 31s
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 21:17:12 -04:00
josh dd1d9fe42d style: bump SOG legibility — bigger, brighter, with tabular nums; match PP size
CI / Lint (push) Successful in 11s
CI / Test (push) Successful in 13s
CI / Build & Push (push) Successful in 26s
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 20:20:18 -04:00
josh 7d1649d278 feat: cache-control overhaul so visual changes propagate immediately
CI / Lint (push) Successful in 14s
CI / Test (push) Successful in 12s
CI / Build & Push (push) Successful in 32s
Per-file content-hash versioning on every /static reference, immutable cache
headers on versioned URLs, no-cache on HTML, auto-bumped service worker cache
name with stale-while-revalidate for assets, and a controllerchange listener
that silently reloads the page when a new SW takes control.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 20:11:36 -04:00
josh aaa0899506 style: scale up the bracket on wide displays so it actually fills the screen
CI / Lint (push) Successful in 8s
CI / Test (push) Successful in 10s
CI / Build & Push (push) Successful in 21s
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 19:43:14 -04:00
josh 9b8b671e24 fix: even out the two team columns on the series page after dropping the middle versus block
CI / Lint (push) Successful in 6s
CI / Test (push) Successful in 10s
CI / Build & Push (push) Successful in 27s
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 19:22:57 -04:00
josh 303db46cc3 refactor: simplify series page — drop redundant versus/headline, blank out placeholder scores, make round badge the bracket link
CI / Lint (push) Successful in 10s
CI / Test (push) Successful in 16s
CI / Build & Push (push) Successful in 32s
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 19:18:41 -04:00
josh dc3bfd13b3 style: add soft white glow to team logos so dark crests (TBL) read on dark cards
CI / Lint (push) Successful in 12s
CI / Test (push) Successful in 20s
CI / Build & Push (push) Successful in 26s
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 19:01:15 -04:00
josh e0a1c033cf fix: freeze PP clock during intermission so it stops ticking toward zero
CI / Lint (push) Successful in 16s
CI / Test (push) Successful in 11s
CI / Build & Push (push) Successful in 25s
tickClocks iterates every [data-seconds][data-received-at] element. Rendering the PP indicator with those attrs during an intermission made the clock bleed seconds even though play is paused and the penalty isn't running. Drop the ticking attrs when game['Intermission'] is true — render a plain static "PP MM:SS" that resumes ticking on the next live payload.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 18:51:12 -04:00
josh b5ab318e05 fix: drop game_number by one for finished playoff cards
CI / Lint (push) Successful in 8s
CI / Test (push) Successful in 11s
CI / Build & Push (push) Successful in 19s
Scoreboard payloads don't include gameNumber, so the previous fix fell straight through to series_state['game_number'], which is hi+lo+1 — the *next* game. Once a game goes FINAL the win for this game is already banked in seriesStatus, so the card's own number is hi+lo. For the just-played Game 1 of Kings/Avalanche (series now 1-0), this brings the header back to "Game 1 of 7" instead of "Game 2 of 7".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 18:47:50 -04:00
josh 9eb8a8534a refactor: move power play indicator onto the team row, drop the team name
CI / Lint (push) Successful in 11s
CI / Test (push) Successful in 12s
CI / Build & Push (push) Successful in 27s
The header PP badge repeated the team name that was already visible a row below. Put the indicator on the team that actually has the advantage: "PP 01:47" appears inline next to SOG, and the old ppBadge + .badge-pp styling go away.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 18:45:14 -04:00
josh e908139323 fix: pin playoff card to its own gameNumber so the header doesn't tick forward after a final
CI / Lint (push) Successful in 10s
CI / Test (push) Successful in 10s
CI / Build & Push (push) Successful in 23s
series_state derives game_number from topSeedWins + bottomSeedWins + 1, which becomes the *next* game's number once the API advances seriesStatus post-final. The card for the just-finished game would then read "Game N+1 of 7". Prefer the raw gameNumber on the game payload, falling back to the derived value when it's missing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 18:41:04 -04:00
josh 13bb90b52b chore: gitignore .claude/ to keep local Claude Code settings out of the tree
CI / Lint (push) Successful in 7s
CI / Test (push) Successful in 11s
CI / Build & Push (push) Successful in 21s
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 18:37:32 -04:00
josh 0f1c558493 style: tighten playoff card copy — uniform Game X of 7 header, leaner blurbs
CI / Lint (push) Successful in 10s
CI / Test (push) Successful in 11s
CI / Build & Push (push) Successful in 23s
Top row now always reads "Game N of 7" (round is already shown by the R1/R2/CONF FINAL/CUP FINAL badge). Bottom blurb drops the trailing period on "Series opener" and uses "{Team} lead X-Y" (plural verb, no "— Game N" suffix) when a leader is established.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 18:36:11 -04:00
josh f1e11a2dc4 style: tighten playoff banner, series, and bracket at ≤480px
CI / Lint (push) Successful in 9s
CI / Test (push) Successful in 9s
CI / Build & Push (push) Successful in 21s
Adds a consolidated narrow-phone breakpoint so the playoff UI reads
cleanly on 375–428px viewports: banner meta stacks vertically (killing
the dangling dot separator), title and trophy shrink, series hero padding
and logos tighten, and the bracket accordion's matchup rows get more
breathing room.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 14:38:53 -04:00
josh 5cdcb2a319 style: soften playoff UI edges and harmonize banner
CI / Lint (push) Successful in 5s
CI / Test (push) Successful in 16s
CI / Build & Push (push) Successful in 15s
Swap border-image for the gradient-border trick on the banner and playoff
cards so rounded corners survive. Retone banner bg to a soft radial over
charcoal, replace the hard gold underline with a fading divider, normalize
radii (badges 6px, banner link 10px), add card depth + hover lift, and
rebalance gold usage toward the muted cup-gold-1 tone.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 13:48:06 -04:00
josh 8468655bcf refactor: make the whole playoff banner clickable instead of a Bracket pill
CI / Lint (push) Successful in 8s
CI / Test (push) Successful in 8s
CI / Build & Push (push) Successful in 14s
Wrap the trophy + title + meta group in the bracket link itself so the
whole Stanley Cup Playoffs element doubles as the entry point. Cleaner
banner, one fewer control to style.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 13:15:17 -04:00
josh 64b2e4b5e1 refactor: auto-prompt for notification permission, drop OT alerts button
CI / Lint (push) Successful in 7s
CI / Test (push) Successful in 10s
CI / Build & Push (push) Successful in 19s
Browsers already gate Notification.requestPermission behind a native
prompt, so a dedicated button was redundant UI clutter. Prompting on
load (only when permission state is "default") keeps the flow and
clears space in the banner for future notification types.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 13:12:01 -04:00
josh 4ea6b87326 style: center trophy + title + meta within playoff banner
CI / Lint (push) Successful in 7s
CI / Test (push) Successful in 10s
CI / Build & Push (push) Successful in 14s
Switch the banner to a 3-column grid (1fr auto 1fr) so the main group
sits truly centered regardless of the right-side action cluster width.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 13:08:27 -04:00
josh a88e2edef0 fix: anchor Day N to each round's first game instead of lazy first sighting
CI / Lint (push) Successful in 5s
CI / Test (push) Successful in 9s
CI / Build & Push (push) Successful in 19s
The banner read "Day 1 of ~60" on day 2 of the playoffs because the old
anchor recorded whatever date we first polled a playoff game as Day 1.
Now round start dates come from /v1/schedule/playoff-series, so Day N
is authoritative and resets at each round boundary. Drops the noisy
"of ~60" denominator.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 13:03:08 -04:00
josh 930247b32f style: apply ruff format and fix lint issues in playoff modules
CI / Lint (push) Successful in 8s
CI / Test (push) Successful in 10s
CI / Build & Push (push) Successful in 22s
- Rename single-letter `l` loop variables in bracket_view to satisfy E741
- Drop unused `json` import from test_playoff_cache (F401/F811)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 12:48:42 -04:00
josh ebe770fecd feat: make scoreboard playoff-aware with banner, bracket, and series drill-down
CI / Lint (push) Failing after 8s
CI / Test (push) Has been skipped
CI / Build & Push (push) Has been skipped
Turn a regular-season-looking Tuesday into a full playoff experience:

- Playoff banner with round + day + series + elimination counts, gold/silver
  Cup theme toggled by body.playoff-mode
- Series context on each playoff card: round chip, series score, stake badges
  (GAME 7, CLINCHER, PIVOTAL), and one-line blurb
- Game 7s pin to a new Spotlight section above Live
- Playoff OT renders with SUDDEN DEATH badge and pulsing gold border
- Client-side OT notifications via bell button in the banner
- New /series/<id> drill-down with headline, next-game, and game-by-game history
- New /bracket page: 7-column desktop grid, accordion on mobile
- Day N banner count auto-anchors on first playoff scoreboard hit
- SQLite cache for bracket + per-series schedules, stale-on-failure up to 24h

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 12:47:31 -04:00
josh e0db8f0859 refactor: recalibrate hype scoring to deflate gauge and add momentum signals
CI / Lint (push) Successful in 7s
CI / Test (push) Successful in 6s
CI / Build & Push (push) Successful in 15s
Unify overlapping late-P3 bonuses into a single score-state lookup, add
high-scoring and goal-spike signals, and tighten every component ceiling so
filling the hype bar is reserved for genuinely rare moments.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 11:26:07 -04:00
josh 108b77ed39 feat: inline power play indicator as compact badge in card header
CI / Lint (push) Successful in 45s
CI / Test (push) Successful in 8s
CI / Build & Push (push) Successful in 1m8s
Moves the PP team + countdown into the badges row next to period and
clock, freeing up a full line of vertical space on each live card.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 11:05:38 -04:00
josh 61202b2a70 feat: sort scheduled games by start time instead of hype
Pre-game listings are more intuitive in chronological order than ranked
by pregame importance. LIVE and FINAL keep sorting by Priority desc.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 11:05:35 -04:00
josh 7784eaf9ce feat: overhaul hype score algorithm with 9 hockey-driven improvements
CI / Lint (push) Successful in 6s
CI / Test (push) Successful in 6s
CI / Build & Push (push) Successful in 16s
- Empty net detection: pulled goalie triggers +150-250 bonus, stacks with PP
- Playoff series importance: Game 7 Cup Final = 200, elimination games scale
  by round; fallback of 100 when series data unavailable
- Period-aware score differential: 2-goal deficit penalty DECREASES in final
  2 min of P3 (goalie-pull zone), 3+ goal games get harsher penalties late
- Persistent comeback narrative: tracks max deficit, sustained bonus for 2+
  goal recoveries instead of one-shot spike (0-3 to 3-3 = 150 persistent)
- Shootout special handling: flat base 550 with no time component; ranks below
  dramatic close P3 games (skills competition, not hockey)
- Multi-man advantage: parses situationCode for 5v3/4v3, applies 1.6x PP mult
- Non-linear time priority: elapsed^1.5 curve weights final minutes more
- Matchup multiplier rebalance: P1/P2 from 2.0/1.65 to 1.5, tiebreaker not
  dominant factor
- Frontend gauge max raised from 700 to 1000 with adjusted color thresholds

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 19:02:43 -04:00
josh 6c098850f5 fix: use truthy check for intermission filter, add route test
CI / Lint (push) Successful in 7s
CI / Test (push) Successful in 6s
CI / Build & Push (push) Successful in 19s
`is True` strict identity fails if the NHL API returns an integer 1
instead of a JSON boolean. A truthy check is safe here since the
Intermission field is always False/0 for non-intermission live games.

Also adds a test that verifies intermission games are separated from
live games in the /scoreboard response.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 19:57:00 -04:00
josh f652743333 feat: add intermission section separate from live games
CI / Lint (push) Successful in 5s
CI / Test (push) Successful in 7s
CI / Build & Push (push) Successful in 18s
Games in intermission now appear in their own section between Live and
Scheduled. The section is hidden when no games are in intermission,
matching the behavior of the other section headings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 19:50:47 -04:00
josh 429c42e7b0 fix: scale badges and hype label at desktop breakpoints
CI / Lint (push) Successful in 6s
CI / Test (push) Successful in 8s
CI / Build & Push (push) Successful in 21s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 19:43:27 -04:00
josh 8e1c455ded fix: correct NHL API situation structure for power play detection
CI / Lint (push) Successful in 6s
CI / Test (push) Successful in 6s
CI / Build & Push (push) Successful in 22s
The NHL API nests situationDescriptions under situation.homeTeam /
situation.awayTeam, not at the top level. The old flat-structure
lookup always returned an empty list, silently breaking both the
PP indicator on the frontend and the PP bonus in the hype score.
Updated get_power_play_info, the _priority_components PP check,
and all test fixtures to match the real API shape.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 19:37:31 -04:00
josh 9edc9914a3 fix: invert matchup scoring so top-ranked teams boost priority
CI / Lint (push) Successful in 7s
CI / Test (push) Successful in 7s
CI / Build & Push (push) Successful in 19s
Previously league_sequence was summed raw and subtracted, meaning
rank-1 teams received the smallest penalty — directionally correct
but fragile and confusing. Now the rank is inverted (33 - sequence)
so rank 1 contributes 32 quality points and the result is added as
a bonus, making the intent explicit: better matchups = higher hype.
Also renames the breakdown field matchup → matchup_bonus.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 19:34:05 -04:00
josh cf0dec3513 fix: scale section headings with desktop breakpoints
CI / Lint (push) Successful in 6s
CI / Test (push) Successful in 8s
CI / Build & Push (push) Successful in 17s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 19:26:30 -04:00
josh 58c31d6766 feat: responsive desktop scaling for game cards
CI / Lint (push) Successful in 5s
CI / Test (push) Successful in 6s
CI / Build & Push (push) Successful in 18s
Adds two desktop breakpoints (900px, 1400px) that progressively
increase card width (290→340→400px), logo size (40→48→56px), score
font size (1.6→1.9→2.2rem), and team name size. Adds max-width on
main to keep layout centred on ultra-wide screens.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 19:23:47 -04:00
josh c9f5c7c929 feat: expose hype score breakdown in /scoreboard response
CI / Lint (push) Successful in 6s
CI / Test (push) Successful in 6s
CI / Build & Push (push) Successful in 19s
Adds a "Hype Breakdown" dict to every game in the API response with
the individual components that sum to Priority: base period score,
time priority, matchup penalty, closeness bonus, power play bonus,
comeback bonus, and importance sub-components (season weight, playoff
relevance, rivalry multiplier). Achieved by extracting private
_priority_components() and _importance_components() helpers; public
function signatures and all tests unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 19:13:05 -04:00
josh 3d77c7cd5a feat: PWA support with hockey puck icon
CI / Lint (push) Successful in 7s
CI / Test (push) Successful in 6s
CI / Build & Push (push) Successful in 17s
Adds full PWA compliance: web app manifest, service worker with
cache-first static / network-first scoreboard strategy, and a
generated hockey puck icon (512, 192, 180, 32px) on the app's
dark navy background. Includes all required meta tags for iOS
standalone mode and a /favicon.ico route.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 19:04:33 -04:00
josh 2f2b3f2d7e docs: update README with hype scoring and game importance details
CI / Lint (push) Successful in 6s
CI / Test (push) Successful in 7s
CI / Build & Push (push) Successful in 16s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 18:44:29 -04:00
josh bf39bb6bd5 style: apply ruff formatting
CI / Lint (push) Successful in 6s
CI / Test (push) Successful in 7s
CI / Build & Push (push) Successful in 18s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 18:41:10 -04:00
josh 47a8c34215 feat: game importance factor in hype scoring
CI / Lint (push) Failing after 6s
CI / Test (push) Has been skipped
CI / Build & Push (push) Has been skipped
Adds calculate_game_importance() that boosts Priority for high-stakes
regular-season matchups based on season progress (sharp ramp after game
55), playoff bubble proximity (wildcard rank ~17-19 = max relevance),
and divisional/conference rivalry (1.4x/1.2x multipliers). Max bonus
150 pts applied to both LIVE and PRE games; playoff and FINAL games
are unaffected. Extends standings schema with division, conference,
games_played, and wildcard_sequence fields fetched from the NHL API.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 18:39:55 -04:00
josh 8945b99782 feat: power play indicator with live countdown clock
CI / Lint (push) Successful in 5s
CI / Test (push) Successful in 5s
CI / Build & Push (push) Successful in 14s
Shows a red pill below the team rows when a PP is active, displaying
the team on the power play and a ticking countdown. PP clock always
resyncs from the API (no local anchoring) since 2-minute penalties
are short enough that accuracy matters throughout. Removed the old
inline PP text from team rows.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 14:58:31 -04:00
josh 257e2151c8 fix: smooth intermission clock by preserving local anchor across renders
CI / Lint (push) Successful in 5s
CI / Test (push) Successful in 6s
CI / Build & Push (push) Successful in 16s
Snapshot the locally-computed clock state before each re-render and
restore it afterwards, so the API response doesn't cause a visible
jump. Only resync to the API value in the final 60 seconds, where
accuracy matters.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 14:55:48 -04:00
josh 96529c4705 feat: smooth clock countdown for intermission and live play
CI / Lint (push) Successful in 6s
CI / Test (push) Successful in 6s
CI / Build & Push (push) Successful in 17s
Store seconds + received-at timestamp on time badge. A 1s interval
decrements locally so the clock never stutters between API polls.
Drift-corrected: always computed from the anchored API value, not
accumulated ticks. Re-render on each API response reanchors to the
real value.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 14:51:05 -04:00
josh e2d2c7dd97 feat: overhaul hype scoring algorithm
CI / Lint (push) Successful in 6s
CI / Test (push) Successful in 6s
CI / Build & Push (push) Successful in 15s
- Period base: playoff OT escalates indefinitely (P4=600, P5=750…),
  reg season P4=5-min OT (600), P5=shootout (700)
- Time priority range increased (max ~300 vs old ~120), calibrated
  to period length so 5-min reg season OT reads correctly
- Matchup multiplier inverted: higher period = less weight (any OT
  is exciting regardless of teams)
- Replace unconditional score_total with closeness bonus: rewards
  tight games regardless of goal volume (5-4 == 1-0 at same diff)
- Power play bonus: 30 (P1/P2) → 50/100/150 (P3 by time) → 200 (OT)
- Comeback bonus: one-time pulse (+50/75/100 by period) when trailing
  team scores to within 2 goals; keyed on team names, clears after
  firing, skips intermission

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 14:46:10 -04:00
josh 62afc1001e feat: amber top border for intermission games
CI / Lint (push) Successful in 7s
CI / Test (push) Successful in 6s
CI / Build & Push (push) Successful in 15s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 14:10:02 -04:00
josh 3169d1a1ff fix: resolve 4 logic bugs found in code review
CI / Lint (push) Successful in 5s
CI / Test (push) Successful in 5s
CI / Build & Push (push) Successful in 17s
- utc_to_eastern: use zoneinfo instead of hardcoded EDT offset (-4)
  so start times are correct in both EST and EDT
- standings: fetch before truncate so a failed API call doesn't wipe
  existing standings data
- routes: call parse_games() once per request instead of three times
- scheduler: wrap run_pending() in try/except so an unhandled exception
  doesn't kill the background thread

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 14:06:45 -04:00