Skip to main content

Season management rollout

This page covers the coordinated change in fantasy-web-ui, fantasy-core-pipeline and fantasy-browser-worker. Use it to see what shipped, roll it out in order and understand how outcomes are verified.

What it delivered​

AreaBehavior
NavigationLineup home, grouped desktop navigation and a mobile drawer.
PresentationShared palette and score presentation; mobile matchup cards and contained tables.
Week selectionDynamic current week, explicit URL selection and a return to the current week.
WaiversCards identify the player being added and the player being dropped.
Move reviewCompares current and resulting rosters and eligible starting lineups across four weeks or the remaining season. Shows injury, availability, bye and incomplete-data warnings. Waiver confirmation refreshes the preview before submitting.
TradesRemain evaluations. This screen does not send trade offers.
Standings and rankingsLeague standings and NFL player fantasy point rankings use the league's ESPN scoring, with weekly and season totals and position, roster and player filters.
ActivityRetains submissions, events, execution state, separately verified external outcome and saved LLM sessions. Details link related sessions and allow a fresh status check. Chat sessions support follow-up with freshly computed roster context.
Queue workDurable acceptance, outbox delivery and worker ownership by tracking ID. Scheduled worker entrypoints also record observable runs.
Worker completion is not an ESPN transaction

A completed worker does not imply an ESPN transaction completed. See How outcomes are verified.

How do I roll it out?​

Release in this order. The core migration must run before the new worker starts.

StepActionNotes
1Back up PostgreSQL with the existing operational procedure. Then run python -m src.migrations in the configured core environment.Adds activity_actions, activity_events, activity_outbox, activity_sessions and activity_reads, plus their indexes. Imports up to 1,000 explicitly league-scoped historical execution records with unknown external outcomes. Unscoped history is not attributed to a league.
2Release the worker with activity ownership and result recording.Its database user needs access to the new tables and event sequence. Keep existing bot approval, dry-run and draft deadline settings.
3Release the core API with durable submission handlers, activity and dashboard routes, and its background runner.Needs the existing PostgreSQL, RabbitMQ, Redis and ESPN settings. Each API process attempts pending deliveries and reconciliation every 60 seconds. Outbox row locks stop concurrent publishers claiming the same row; worker tracking IDs protect against delivery ambiguity.
4Release the UI and nginx template together.The server-side bot-key proxy allowlist now includes lineup updates and draft picks as well as waiver submissions.
5Smoke-check current week, standings, a move preview, saved chat and Activity with the configured league.See Smoke-check in a dry-run environment.
Keep the bot key server-side

Don't expose the bot key to browser configuration.

Smoke-check in a dry-run environment​

  1. Verify queued → worker events → skipped in a controlled dry-run environment.
  2. Separately verify a permitted transaction's ESPN evidence.
  3. Check broker-disconnection recovery.
  4. Check repeated delivery with the same tracking ID.

Roll back​

Rollback

The migration is additive, and a UI rollback is independent. During a backend rollback, retain the activity tables and pending outbox records.

Don't drain the outbox through an older worker that lacks tracking-ID ownership. Review pending actions before resuming an older transaction path.

How is data cached?​

Client​

BehaviorDetail
OwnershipClient query hooks own in-memory caching and clear on league, team or season configuration changes.
TransportStays uncached, so polling, cancellation and explicit refresh reach the network.
ReadsActive queries deduplicate reads, use page-specific freshness and refetch stale data on focus.
Refresh cadenceCurrent week every five minutes. Standings poll once a minute. Expensive player rankings refresh on demand.
MutationsNot automatically retried.
InvalidationNewly verified outcomes invalidate related roster, matchup, waiver, move-preview and league queries once per batch.

Core (Redis)​

DataTTL
League standings and player leaders60 seconds
Current league context5 minutes
  • Per-key in-flight guards avoid blocking unrelated keys.
  • Player ranking fetches have an elapsed-time budget and label partial coverage.
  • Keys include league and request context. Successful reconciliation advances a league cache version.
  • Redis failure falls back to the source, and errors are not cached.
  • Worker-immediate confirmations may stay in server read caches until their short TTL expires.
  • Move previews refresh directly and are not stored in this Redis cache.

How outcomes are verified​

Projections​

  • Totals optimize eligible starting slots using ESPN projected fantasy points.
  • Where ESPN has no projection, the service labels an estimate from up to three prior completed games. It does not turn VORP into points.
  • Missing required data leaves totals unknown.
  • Future injury changes and roster moves can't be predicted.

Completion evidence​

ActionVerified when
WaiverBoth the addition and the requested drop appear in ESPN roster state.
LineupAll requested changes appear.
TradeReconciliation checks both teams' resulting ownership.
DraftExplicit confirmation evidence exists: a matching SELECTED result or draft-board verification. A generic successful click stays awaiting processing.

A pending, rejected or cancelled transaction without authoritative transaction evidence remains unresolved. Generic queue success never marks it verified. Activity supports checking unresolved submissions again.

Delivery and attention​

  • Delivery is recorded separately from worker ownership.
  • Stale undelivered or unconsumed work appears in Needs attention.
  • Needs attention filters failed or uncertain actions and approval-required work. LLM errors are visible in the LLM sessions tab.
  • Poison outbox rows back off without blocking later deliveries.
  • Draft delivery failures return 503, so the pick-clock caller can retry immediately.

LLM history​

SettingBehavior
Chat historyRecords observable prompts, context, provider attempts, responses and errors, with credential redaction. Hidden reasoning is not collected.
Background LLM callsDefault to content hashes and sizes. Set LLM_HISTORY_CAPTURE_CONTENT=true to capture content.
Event sizeCaptured LLM events are capped at 16,000 characters.
RetentionContent defaults to 90 days (LLM_CONTENT_RETENTION_DAYS). Action history is retained.
OrderingWorker observations run in order outside the provider hot path, with bounded database queries.
AccessAssumes the existing authenticated single-league deployment. Per-user read markers use trusted proxy identity headers, with a shared operator fallback when they're absent.
What was validated

Validation used mocked ESPN, broker and database boundaries and mocked browser API responses. No live ESPN transaction or production deployment was performed. Production PostgreSQL migration execution and live external reconciliation remain rollout checks.

Test coverage​

RepoResult
UI25 tests, production TypeScript/Vite build, oxlint (existing React warnings remain).
Core1002 tests, including durable acceptance, broker failure, deadline checks, waiver reconciliation, projection constraints and credential redaction.
Worker566 tests, including duplicate ownership and best-effort outcome recording after external writes.
Browser14 routes at 320, 375, 768, 1024 and 1440px, with no page-wide overflow or runtime errors. Mobile drawer navigation also checked.

Screenshots are in screenshots/ux-overhaul/ and use synthetic fixture data.

Review corrections
  • Live GET polling and explicit refresh bypass the transport cache. Caller cancellation is preserved.
  • Lineup drafts are week-scoped. Submissions require the current week and retain their idempotency key after a timeout.
  • Waivers support one addition with an optional drop. Fresh warnings and exact player identities are displayed before confirmation.
  • Activity seeds existing completions without refetch storms, acknowledges read errors and stops polling terminal actions.
  • Outbox failures record attempts and backoff. Reconciliation leases rows, excludes historical imports, shares one league read per season per tick and normalizes numbered and FLEX slots.
  • Worker ownership uses a PostgreSQL session advisory lock. Failed or crashed jobs can retry when ownership is released.
  • Pending waiver writes with uncertain outcomes require manual verification rather than a blind replay. Failures have a bounded retry count.
  • Background LLM recording is configurable and bounded. Keyword prompt= calls have a regression test.
  • Unrelated formatting-only changes were removed from the behavioral diffs.

Internal rollout, implementation and review notes belong in this project repository. Product repositories keep public-facing README, setup and developer reference material.