System Updates

A running log of patches, features, and improvements deployed to the Chaos League network.

2026-02-27
Introduce email drip engine proposal, new API routes for casino, chaos, invitations, leagues, and Yahoo, and email strategy documentation.
feature
v1.5.0

Maintenance update.

2026-02-27
CHAOS Cup nav + Ledger UI discoverability fixes (#293) * fix(nav): wire CHAOS Cup button to global leaderboard page * fix(nav): add Cup Standings link to modules dropdown * fix(nav): add CHAOS Cup entry to mobile bottom nav drawer * fix(ledger): add missing TYPE_LABELS for PURCHASE, SHADOW_FEE, REFUND * feat(oracle): add module ledger transaction history widget * feat(audit): add module ledger transaction history widget * feat(dashboard): add 'View all' link to transaction history widget * fix(review): filterTypes in useCallback dep array, min-height on Audit ledger widget
feature
v1.5.0

Maintenance update.

2026-02-26
implement weekly results share card frontend with sharing actions, OG metadata, and dashboard/email entry points.
feature
v1.5.0

Maintenance update.

2026-02-26
Weekly results recap share card (#292) * feat: Add weekly results recap share card (T0-T9) - New page at /play/recap/[username]/[week] — shareable performance card - RecapCard component: Oracle pick grid, Headhunters players, stats bar with win streak tooltip - ShareActions: PNG download (html2canvas), copy share link, Share on X - Privacy model: recap_public toggle (default on) + UUID share token with view tracking - Share token API: POST /api/recap/[week]/share-token — upsert-based, race-safe - Recap data API: GET /api/recap/[week] — oracle + headhunter results, win streak calc - OG image route: /api/og/weekly-recap (1200x630, Satori-compatible flexbox) - Migration: recap_share_tokens table + UNIQUE(user_id,week,sport) + increment_recap_view_count RPC - profiles.recap_public column (default true) - Security hardening: username regex validation, atomic view_count RPC, upsert idempotency - Deduplicated fetch via React cache() (generateMetadata + page share one request) - Entry points: dashboard PerformanceOverview, WeeklyPredictionsTable, HH history, email CTA - Settings: recap_public privacy toggle in Profile tab - Sponsor: 3 SponsorSlot placements on recap card Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: Guard decodeURIComponent in OG route, add critic review - wrap decodeURIComponent in try/catch (URIError on malformed %XX sequences) - cap name length at 64 chars to match username validation - add critic review doc (S2-A fixed pre-deploy, 4 S2 warnings tracked post-launch) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: address all must-fix + should-fix items on weekly recap share card Security hardening (H-1, H-2): - UUID regex validation for ?token= param before passing to admin client - VALID_SPORTS allowlist in recap route + share-token route - sport param silently falls back to 'nba' on invalid input Auth fix (M-1): - fetchRecapData forwards session cookie via headers() from next/headers - Fixes owner with recap_public=false seeing their own card as 404 Calendar week fix (M-3): - Replace hardcoded 14-week NFL assumption with calendar-week-of-year - Fixes incorrect week number for NBA (~26 weeks) and NHL seasons - Remove data.performance?.currentWeek cast (property doesn't exist in type) Migration (H-3): - 20260226130000: re-create validate_invitation with SET search_path=public,pg_temp Correctness: - notFound() for invalid/out-of-range week path param (page.tsx) - oracle_picks capped at .limit(24) before DB fetch - oracle_weekly_results win streak capped at .limit(52) - WeeklyPredictionsTable: rename bets prop → predictions (CHAOS language) - OG route: username capped at 64 chars Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: correct migration syntax errors blocking prod db push - 20260226120000: move UNIQUE constraint inline into CREATE TABLE (ADD CONSTRAINT IF NOT EXISTS is not valid PostgreSQL syntax) - 20260226130000: convert to no-op (superseded by 20260226140000) - 20260226140000: new migration — DROP + CREATE validate_invitation with buyin_amount OUT param + SET search_path + IS DISTINCT FROM fix (CREATE OR REPLACE cannot change return type — DROP required) All 6 pending migrations now applied to production. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: CodeRabbit round 5 — a11y + recap slug correctness - history/page.tsx: use username only for recap slug (drop display_name fallback) prevents /play/recap/[display_name]/[week] 404s for users without a username - SettingsClient.tsx: add type="button" to recap-public toggle switch - PerformanceOverview.tsx: add aria-hidden="true" to decorative chevron SVG - RecapCard.tsx: add type="button" to show-all/collapse pick toggle buttons Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-26
Native league join flow, settings & roster pages Squashed from feat/join-flow-settings-roster. Includes 4 CRITICAL security fixes, H1/H5 data fixes, and 2 rounds of CodeRabbit hardening.
feature
v1.5.0

Maintenance update.

2026-02-26
Sponsor Protocol OpenSpec — self-serve auction marketplace for prediction card sponsorships * feat: Sponsor Protocol OpenSpec — Prediction Exchange marketplace Full OpenSpec for self-serve sponsor marketplace where creators bid USD (via Stripe) to brand prediction cards and module slots. Spec includes: - proposal.md: Problem statement, user stories, 30 acceptance criteria - design.md: Migration SQL (3 new tables, 2 ALTERs), 10 API routes, Stripe hold/capture flow, auction resolution engine, component tree - tasks.md: 68 tasks across 12 phases, 5 agent assignments - monetization-analysis.md: Revenue projections, surface rankings Security review applied (16 fixes): - Removed stripe_client_secret from DB schema (ephemeral only) - Added 'resolving' status for optimistic locking on auction resolution - Added SECURITY DEFINER RPCs for atomic bid placement - Removed user UPDATE RLS on sponsor_bids - Added sponsor_profiles_public view (excludes stripe_customer_id) - Removed SPONSOR_BID_* from Cred ledger (USD/Cred separation) - Added URL validation (HTTPS-only, SSRF protection) - Added rate limiting spec (10 bids/user/hour) Note: Stripe not yet configured — Phase 1-2 (DB + marketplace UI) can ship independently before Stripe integration in Phase 3. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: Multi-brand packages, share card integration, critic v2 fixes Multi-brand support: - New sponsor_brands table (max 3 per user via trigger) - sponsor_profiles stripped to account-level (stripe_customer_id only) - sponsor_campaigns FKs to sponsor_brand_id (not profile_id) - BrandPackageEditor with live card preview (split layout) - BrandPackageSelector for choosing brand per bid - Fields: brand_name, logo, banner, cta_url, cta_label, twitter, brand_color (hex), bio (280 char max) Share card integration: - Sponsored card page is view-only showcase + "Join CHAOS" CTA - Integrates with weekly-results-share-card spec SponsorSlot placements - V1: "Presented by" banner + footer (base tier) - Future: brand_color takeover (premium tier, timeboxed) Critic v2 fixes (8 warnings resolved): - S2-1: Removed contradictory SPONSOR_BID_* note in Section 10 - S2-2: Specified /sponsor route group (app, no session guard) - S2-3: BidPanel shows "Add payment method" CTA when no stripe_customer_id - S2-4: OG image SSRF restriction (whitelisted CDN domains) - S2-5: Multi-brand replaces single-profile (was undocumented V1 constraint) - S2-6: Added campaign deactivation task S32b in Phase 5 - S2-7: Reordered settlement (status updates before campaign creation) + null guard on brand lookup with fallback - S2-8: Added meta_lineage_map, meta_calculation_logic, meta_quality_rules Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address 8 CodeRabbit findings on Sponsor Protocol spec CRITICAL fixes: - Add sponsor_brand_id FK to sponsor_bids table schema - Fix sponsor_profiles_public view (remove brand columns moved to sponsor_brands) - Replace select-then-iterate with atomic claim_expired_auctions RPC (UPDATE...SET status='resolving' RETURNING *) HIGH fixes: - Fix raise-bid descriptions to show safe order (create new PI, then cancel old) - Fix proposal.md webhook criterion to say "idempotent backup" - Add SSRF private IP/DNS blocking to S17 task description MEDIUM fixes: - Fix module auction close time from Monday 00:00 to 06:00 UTC MINOR fixes: - Add text language identifier to fenced code block Additional consistency improvements: - Add claim_expired_auctions RPC definition to migration SQL - Add S9c task for the new RPC - Add SponsorBrand interface and /api/sponsor/brands CRUD route - Update SponsorProfile interface to account-level only - Update S28 dependency to include S9c Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: address CodeRabbit round 4 — 10 findings across spec + support docs design.md (6 fixes): - Add brand_id to PlaceBidRequest interface (CRITICAL) - Add pre-PI brand ownership validation in implementation notes - Fix winning_bid['brand_id'] → winning_bid['sponsor_brand_id'] (CRITICAL) - Fix raise-bid lifecycle in Section 5.1 to safe order (CRITICAL) - Fix JOIN sponsor_profiles → JOIN sponsor_brands for display names - Add brand_id field to bid response tasks.md (3 fixes): - S21: strip brand validation (account-level only, brand CRUD in S43c) - S43c: add explicit brand field validation requirements - Second fenced code block: add text language identifier Support docs (4 fixes): - brainstorm doc: add SUPERSEDED banner pointing to OpenSpec - critic-v2: mark S2-1 as RESOLVED - security: fix 'settling' → 'resolving' with RESOLVED note - monetization: fix stale sponsor-marketplace ref → sponsor-protocol Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: address CodeRabbit round 5 — 4 findings design.md: - Add brand_id to Section 5.1 USER PLACES BID request shape - Move /sponsor/card/[id] from (app) to (public) route group monetization-analysis.md: - Replace all stale brainstorm doc refs with OpenSpec path critic-v2.md: - Mark S2-4 (OG SSRF), S2-5 (multi-brand), S2-6, S2-7, S2-8 as RESOLVED - Update summary to show only 2 remaining open items (S2-2, S2-3) tasks.md: - S50: note public route group requirement Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: add DEFERRED.md for nice-to-haves, clean up critic-v2 priority list - Create DEFERRED.md tracking items from 6 CodeRabbit rounds:
feature
v1.5.0

PI expiry reconciliation (Phase 3 enhancement) - Route group + auth strategy for /sponsor (Phase 6, S2-2) - Payment method onboarding in BidPanel (Phase 6, S2-3) - Cosmetic: brainstorm doc ASCII block language tags - Fix critic-v2 priority list: mark S2-1/S2-6/S2-7/S2-8 resolved, keep only S2-2 and S2-3 as open items Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: update DEFERRED.md with round 7 findings Add 3 implementation fixes to address during build: - InventoryItem.status missing 'resolving' in API type - S33/S36 missing dependency on S14/S44 (payment onboarding) - URL construction should use URL API in checkout session Add 3 cosmetic items: - Monetization analysis: code fence tag + table sort - Security doc: markdown blank lines - Critic-v2: S2-6/S2-7/S2-8 body sections need RESOLVED markers Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: apply critic final-review findings — S1+S2 spec fixes Resolves all S1 blockers and S2 warnings from the internal blind-spot critic review: S1-1/S1-2: Added full SQL DDL for place_sponsor_bid + raise_sponsor_bid RPCs (auth guard, SELECT FOR UPDATE, REVOKE/GRANT FROM PUBLIC) S1-3: Escalated S10b to HOTFIX priority in tasks.md with corrected sponsor_events RLS policy spec (remove OR auth.uid() IS NULL bypass) S2-1: Added ORDER BY amount_cents DESC, created_at ASC tiebreaker to Section 2.3 docs and settle_auction() Python code S2-2: cta_url fallback changed to 'https://chaosleague.io' (never blank); brand DELETE FK violation (SQLSTATE 23503) handling documented as 409 S2-3: Fixed analytics JOIN chain (sponsor_campaigns.sponsor_brand_id → sponsor_brands.user_id — no sponsor_profile_id column exists) S2-4: UNIQUE constraint split into two partial UNIQUE indexes — card rows include sport, module_slot rows exclude sport (prevents duplicate slots) generate_module_inventory upsert on_conflict updated to match S2-5: Stuck-resolving inventory recovery path added to DEFERRED.md S2-6: SponsorSlot.tsx typed interface prerequisite added to Section 8.3 S2-7: CI if: always() replaced with sync-step success/skipped; Stripe key masking instruction added S2-8: is_highest computation rule added to UserBid interface (Section 4.5) S2-9: proposal.md acceptance criteria updated with module qualifier S2-10: S61b task added for pre-existing sponsor_campaigns column governance Final review doc updated with PASS verdict and resolution status for all items. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: add blank lines around DEFERRED.md headings (MD022 markdownlint) Fixes CodeRabbit round 8 finding: all ### headings must be surrounded by blank lines per markdownlint MD022 rule. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: address CodeRabbit round 9 — 4 findings - design.md: Add 'resolving' to InventoryItem.status union with filter note - design.md: Replace string concatenation with URL API for success/cancel_url - tasks.md: Add S14 dependency to S33 (marketplace); add S14 + S44 to S36 (BidPanel) - tasks.md: Extend S28 with pre-capture PI validity check spec (validate status == 'requires_capture' + capture_method == 'manual' before capture) - docs/plans: Add 'text' lang tag to 3 ASCII art fenced blocks (markdownlint) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: address CodeRabbit round 10 — cosmetic/duplicate findings - sponsor-protocol-security.md: Add blank lines around ### headings and fenced code blocks (MD022/MD031) — 21 new blank lines added - monetization-analysis.md: Add 'text' lang tag to creator flywheel block - monetization-analysis.md: Re-sort Top 20 placement table by Total column descending (ranks 8-18 were out of order) Note: 'settling' → 'resolving' finding is a false positive — security doc already uses 'resolving' (was fixed in earlier round). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: address CodeRabbit round 11 — 2 critical + 2 duplicate fixes CRITICAL fixes: - design.md: Fix Python SyntaxError — backslash continuation cannot precede inline comment; changed to parenthesized implicit continuation for settle_auction() bids query - design.md: Add SET search_path=public + REVOKE/GRANT to claim_expired_auctions RPC (matches security pattern of place_sponsor_bid and raise_sponsor_bid — service_role only, prevents name resolution attack) Duplicate/cosmetic fixes: - proposal.md: Add blank lines around all ### headings (MD022 — 13 new lines) - critic-v2.md: Mark S2-6/S2-7/S2-8 as STATUS: RESOLVED (alignment with current spec state, reducing stale-finding confusion) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: CR round 12 — reconciliation gates, security/critic doc cleanup, design constraints Round 12 actionable fixes: - DEFERRED.md: gate resolving->expired behind Stripe PI + campaign reconciliation checks - final-review.md: convert S1 blockers to resolved historical entries (consistent PASS verdict) - security.md: add STATUS: RESOLVED to all four S1 items and resolved S2-1/S2-6/S2-9 - critic-v2.md: move S2-6/7/8 full narratives to Resolved/Historical appendix; fix hyphen - monetization-analysis.md: rename heading (drop 'No Engineering Required'); casino compliance - design.md: add bid_count+1 in raise_sponsor_bid UPDATE; stripe_payment_intent_id CHECK - proposal.md: add PI authorization expiry / 7-day cap acceptance criterion - 2026-02-25-sponsor-protocol-design.md: MD031 blank line before SQL fenced block Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: CR round 13 — security matrix, Stripe capture_before, phase heading spacing - security.md: update RLS matrix, data governance, USD/Cred, and summary sections to reflect all four S1 RESOLVED; remaining open items clearly labeled - monetization-analysis.md:165: add compliance gate to casino:sponsored-pool prose - 2026-02-25-sponsor-protocol-design.md: add blank lines after all Phase headings (MD022) - DEFERRED.md: replace hardcoded 7-day PI expiry with charge.capture_before live field - proposal.md: replace hardcoded '7 days' with capture_before / max_auth_window - tasks.md:26: clarify 'transaction types' = chaos_feed only, not SPONSOR_BID_* - tasks.md S28: add capture_before timestamp precheck (3rd validation criterion) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: CR round 14 — GRANT/REVOKE signatures, webhook semantics, logger, requires_capture - design.md: add parenthesized signatures to all GRANT/REVOKE statements (claim_expired_auctions(), place_sponsor_bid(UUID,UUID,UUID,INT,TEXT), raise_sponsor_bid(UUID,UUID,INT,TEXT)) — PostgreSQL requires these to resolve function - design.md: expand webhook Response comment with correct 400/500/200 semantics per failure mode - design.md: add 'import logging' + 'logger = logging.getLogger(__name__)' before resolve_auctions - security.md: mark S2-7 RESOLVED (task S17 implements 10 bids/hr limit, HTTP 429) - DEFERRED.md: fix requires_capture semantics — authorization pending, not charged; attempt capture first - proposal.md: seed data criterion 15+ rows -> 9+ rows (3 modules x 3 placements, Casino/Gauntlet deferred) - final-review.md: note GRANT/REVOKE signature fix in S1-2 resolution entry Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: CR round 15 — add design.md syntax verification note to final-review verdict Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: CR round 16 — capture_before field path, trigger race lock, webhook semantics, resolved-item cleanup - DEFERRED.md: fix charge.capture_before → latest_charge.payment_method_details.card.capture_before with card_present fallback and amount_capturable==0 as tertiary check - DEFERRED.md: mark InventoryItem.status 'resolving' and URL construction items as RESOLVED - design.md: fix BidHistoryEntry.bidder_display_name fallback chain comment - design.md: add pg_advisory_xact_lock per-user serialization to enforce_max_sponsor_brands trigger - design.md: correct webhook response semantics (Stripe retries on any non-2xx including 400) - security.md: correct sponsor_profiles_public view column list (account-level only) - final-review.md: label Summary as historical context with [RESOLVED] markers on S1 blockers - proposal.md: narrow scope statement to currently-built modules (Oracle/HH/Audit) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

2026-02-26
add dashboard as primary entry point for recap card (T7a) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
improvement
v1.5.0

Maintenance update.

2026-02-26
add entry point task (T7a) to recap spec Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
improvement
v1.5.0

Maintenance update.

2026-02-26
Add onboarding module architecture document Comprehensive writeup of the signup → wallet → welcome bonus → global league auto-join → invite acceptance (with buy-in) → daily stipend flow. Documents all decisions, trigger chain, RPC behavior, error states, and file references. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
improvement
v1.5.0

Maintenance update.

2026-02-26
Welcome bonus on signup + buy-in enforcement on invite acceptance (#289) * feat: Welcome bonus on signup + buy-in enforcement on invite acceptance New users receive 500 Cred automatically on signup via a trigger on profiles INSERT. Invitation acceptance now enforces league buy-in atomically — deducting Cred before membership is created, with proper insufficient-balance handling (402 + shortfall details). The join page shows entry fee, user balance, and disables the CTA when funds are low. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: Address code review — ON CONFLICT constraint, race guard, search_path, redirect - C1+C2: Fix ON CONFLICT to target (user_id, league_id) instead of league_members_pkey (UUID id). Add GET DIAGNOSTICS row count check to detect race condition and return already_member (rolls back buy-in). - H1: Upgrade RAISE WARNING to RAISE LOG for Supabase dashboard visibility. Add monitoring query in comment. - H3: Add composite index on ledger_transactions(type, reference_id) for the idempotency check in the signup bonus trigger. - H4: Redirect to /league/{id}/dashboard after successful join instead of generic /dashboard. - M4: Add pg_temp to search_path in accept_invitation_with_buyin. - M5: validate_invitation now rejects all non-pending statuses (not just 'accepted'), with specific messages for revoked invites. - L2: Add role="alert" to error div for screen reader accessibility. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: RAISE EXCEPTION on race condition to ensure buy-in rollback RETURN does not abort the PL/pgSQL transaction — the buy-in debit would persist even when membership INSERT was suppressed by ON CONFLICT. Changed to RAISE EXCEPTION which aborts the entire transaction, atomically rolling back the wallet debit and ledger entry. Also: pg_temp added to award_signup_bonus search_path for consistency, and API route now handles the raised exception with a 409 response. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: CodeRabbit round 2 — NULL-safe auth guard, REVOKE/GRANT, button disable - NULL-safe auth check: `IS DISTINCT FROM` instead of `!=` prevents bypass when auth.uid() returns NULL (unauthenticated caller). - REVOKE EXECUTE FROM PUBLIC on all 3 functions. GRANT to authenticated + service_role (accept/validate). validate_invitation also granted to anon since the GET handler uses anon key for invite preview. - Button disabled while balance is still loading for buy-in leagues (userBalance === null disables instead of allowing click). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-26
add weekly results share card spec + playground - OpenSpec proposal, design, and tasks for /play/recap/[username]/[week] - Privacy model: recap_public toggle (default on) + UUID share token with view tracking - Oracle pick grid: responsive auto-fill, first 24 shown, +N more expand toggle - Win streak: week-over-week, Oracle W% > 50%, no week filter (multi-week query) - No Cred on card — predictions award CP only - Playground at docs/playgrounds/weekly-results-card.html with generate N picks, add/remove, tooltips Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
improvement
v1.5.0

Maintenance update.

2026-02-26
trigger Vercel deploy with authorized git author The changelog automation used a GitHub noreply email that lacks Vercel team access. This empty commit restores the authorized author for deployment. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
improvement
v1.5.0

Maintenance update.

2026-02-26
Introduce global dashboard API, league management and shop components, user profile menu, and oracle grading workflow.
feature
v1.5.0

Maintenance update.

2026-02-25
Audit entry fee (50 Cred) + confirmation modal + hardening (#283) * feat: add Audit entry fee (50 Cred) + confirmation modal + bug fixes - Add atomic pay_audit_entry_fee RPC (idempotent, FOR UPDATE wallet lock) - Add audit_entry_fees table with per-day uniqueness constraint - Add AUDIT_ENTRY to valid_transaction_type constraint - Build ConfirmPickModal showing picks summary, fee, and balance - Wire entry fee into POST /api/audit/picks before saving picks - Add GET /api/wallet/balance lightweight endpoint - Pick page: submit button opens confirmation modal first - Pick page: loads existing picks into editable sidebar - Pick page: delete saved picks (server DELETE + local removal) - Pick page: random pick button (auto-select player + 2 stats + avg) - Fix BUG-1: sort by submitted_at instead of nonexistent created_at - Fix BUG-3: lock_time -> locked_at in response mapping + types - Fix BUG-4: ghost slip module 'precision' -> 'audit' in grade.py - Fix BUG-5: hub page shows intermediate state for ungraded entries - Fix BUG-7: comment updated to match actual status values - Fix BUG-8: removed redundant manual updated_at assignments - Add cross-module consistency OpenSpec (proposal + design + tasks) - Add full Audit module README and ARCHITECTURE docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve lint errors + CodeRabbit findings on PR #283 - Fix nested <p> tags in Oracle leaderboard page (parsing error) - Fix synchronous setState in useEffect in CHAOS Cup leaderboard - Add role="dialog", aria-modal, aria-labelledby, Escape key to ConfirmPickModal - Add alreadyPaid prop so re-submissions show "Confirm Changes" not "Pay 50 Cred" - Add updated_at column to audit_entry_fees table - Make constraint migration idempotent (check before drop+recreate) - Include future transaction types in constraint to prevent silent drops Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address CodeRabbit MUST-FIX + SHOULD-FIX findings on PR #283 - Add compensating refund_audit_entry_fee RPC for atomicity (fee + picks) - Restrict pay_audit_entry_fee to service_role only (prevent user_id spoofing) - Dynamic constraint update: reads existing types, unions new ones, no silent drops - Validate game_id resolution before DB write (fail early, refund if needed) - Refund entry fee when user deletes all picks (symmetric with charge) - Add focus trap to ConfirmPickModal (Tab/Shift+Tab loop, initial + restore focus) - Block backdrop close during loading (matches Escape key behavior) - Extract AUDIT_ENTRY_FEE_DEFAULT to shared constants.ts (single source of truth) - Source alreadyPaid from API fee_paid field (not inferred from picks count) - Add fee_paid + fee_amount to GET /api/audit/picks response - Use server-provided fee in insufficient funds error message Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address code review findings — refund gap, row lock, FK, defensive fixes - Add compensating refund on audit_entries insert failure (was missing) - Add FOR UPDATE on fee record in refund_audit_entry_fee (prevent double-refund) - Add FK constraint on audit_entry_fees.league_id -> leagues(id) - Check refund result in DELETE handler before claiming refunded=true - Remove anon grant from get_audit_day_info (auth-only) - Replace balance! non-null assertions with balance ?? 0 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: CodeRabbit round 3 — entry deletion guard, transaction_id FK, path alias import - Gate audit_entries deletion on successful refund (don't orphan entry if refund fails) - Add transaction_id FK reference to ledger_transactions on audit_entry_fees table - Change relative import to @/ path alias in ConfirmPickModal Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: always delete orphaned audit_entries on delete-all, log failed refunds for reconciliation Entry with 0 picks is garbage data regardless of refund status. Previously gated deletion on refund success, which orphaned entries when refund failed. Now always cleans up, surfaces refunded:false in response, and logs full context for support reconciliation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: check refund success in all 3 compensating-refund paths, log failures for reconciliation All three POST failure paths (entry creation, game_id resolution, upsert) now capture refundResult + refundError, verify success, log full context on failure, and surface honest refunded boolean in the response instead of claiming "fee refunded" unconditionally. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: handle fee query errors in GET /api/audit/picks instead of silent default Destructure error from audit_entry_fees query and return 500 if it fails, instead of silently defaulting fee_paid to false which could cause double-charge on retry. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add 'audit' to ghost_slips module CHECK + handle fee query errors in compensating refunds - Add 'audit' to ghost_slips module CHECK constraint (was missing, would reject all Audit Ghost Slip inserts at runtime) - Keep entry['id'] as pick_id — Audit awards Ghost Slips at the entry level (aggregate accuracy), not per individual pick. Using entry ID is correct semantics for one-slip-per-entry. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-25
remove Jules lint scan artifacts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
improvement
v1.5.0

Maintenance update.

2026-02-25
league settings v2 — unified chaos_settings JSONB, economy model, commissioner UI (#284) * feat: league settings v2 — unified chaos_settings JSONB, economy model, commissioner UI Consolidate all C.H.A.O.S. settings into a single chaos_settings JSONB column on the leagues table, replacing scattered boolean/numeric columns. Implements the corrected economy model: native/global leagues get fixed 50 Cred/module entry with no vig, private leagues get 10% prize pool vig + optional degen mode (5% burned, 95% to pool, no base module entry). Migration: vig functions, CHECK constraint fix, economy RPC, full backfill with legacy key preservation. Types centralized in chaos-settings.ts. API route: deep-merge PATCH with validation + legacy boolean sync. UI: league-type-aware tabs (native/imported/global), module toggles in C.H.A.O.S. order, economy settings, payout editor, global read-only view. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: remove setState-in-effect lint error in CommissionerTerminal Replace useEffect tab reset with derived effectiveTab that falls back to the first tab when the current selection is not in the tab set. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address CodeRabbit findings — single DEFAULT_SETTINGS, scalar validation, deep merge - Export DEFAULT_SETTINGS from chaos-settings.ts (single source of truth) - Remove duplicate DEFAULT_SETTINGS from CommissionerTerminal, ChaoSettings, route.ts - Add scalar validation for enabled, scoring_mode, payout_mode, headhunters.mode - Fix GET handler: 404 only for PGRST116, 500 for other errors, deep-merge nested objects - Fix GlobalLeagueReadOnly: vig display 0% (was incorrectly showing 5%) - Fix PayoutEditor: allow pct up to 100 (was capped at 99), init new places at 1 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: native leagues should show fixed 50 Cred entry, not private UI Native leagues use the same economy model as global (fixed 50 Cred/module, no vig). Only imported leagues are "private" with buy-in + degen mode. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * revert: native leagues ARE private — restore buy-in + degen UI Native leagues (created directly in CHAOS) use the same commissioner- controlled economy as imported leagues: buy-in, 10% vig, optional degen. Only global leagues use the fixed 50 Cred model. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-25
Migrate CodeRabbit configuration to `.coderabbit.yaml`, change review profile to assertive, and enable request changes workflow.
feature
v1.5.0

Maintenance update.

2026-02-25
add StreakFlame component, update ledger UI, HH docs, and League Settings V2 spec - New StreakFlame SVG component with 4 intensity levels and flicker animation - CredBalancePill: replace emoji streak with StreakFlame component - CredRefillStation: replace Lucide Flame array with StreakFlame, improved layout - Headhunters ARCHITECTURE.md: correct CP tiers for global vs private leagues - Headhunters CODE_REVIEW.md: expand vig burn fix with metadata requirements - New OpenSpec: League Settings V2 (27 tasks, 7 phases) for unified commissioner settings - New brainstorm plan: league-settings-architecture-design Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-25
commit pending specs, pSEO data, nav updates, and architecture docs - 5 Headhunters OpenSpec proposals (affiliate links, creator vig, sponsor slots, POTW, power-ups) - Headhunters ARCHITECTURE.md + CODE_REVIEW.md - Oracle module architecture audit plan - RoundRobinSimulator component (orphaned, wiring later) - pSEO data: injury_changes, sleeper_players_nba_prev, top100 - BottomNav, ModulesDropdown, LeagueContextSwitcher nav updates Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
improvement
v1.5.0

Maintenance update.

2026-02-25
add nightly lint fix pipeline + update weekly scan for Jules - Add nightly_lint_fix.yml workflow (cron 6AM UTC weeknights) - Add .jules/nightly-lint-fix.md with fix priorities and safe patterns - Update weekly-scan-prompt.md: output PR with report file instead of GitHub Issue (Jules can't create issues) - Update JULES.md: add SCAN mode (PR with report) and FIX mode (nightly lint) - Add docs/scans/ directory for scan report history Pipeline: Jules scheduled task → lint/typecheck → fix → PR → CodeRabbit reviews Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-25
Oracle production hardening (#279) * feat: add "Throw a Flag" feedback widget for beta users Floating amber flag button (bottom-right) opens a modal where authenticated users can report bugs, suggest ideas, or flag bad data. Submissions auto-capture page context and create labeled GitHub issues via the REST API. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: Oracle production hardening — ghost_slips redesign, shadow view fixes, NHL aliases Redesign ghost_slips table (empty in prod) with pick linkage, outcome tracking (win/loss/push), and denormalized display labels. Fix shadow_oracle_scores to include push picks (graded_at filter) and solo players (LEFT JOIN). Make team aliases sport-aware to resolve NHL LA conflict. Wire all ghost slip callers (Oracle grade, audit grade, Headhunters engine) to new RPC signature. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address CodeRabbit review findings on PR #279 - engine_v2.py: deterministic UUID per slot (uuid5) to avoid UNIQUE dedup - engine_v2.py: fix slot_mult_map/slot_key_map keys to match SLOTS tuple - grade/route.ts: use was_duplicate from RPC to avoid counting dupes - grade/route.ts: use cumulative cumCorrect for ghost_slips_issued - ghost_slips_redesign.sql: add updated_at column Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: CodeRabbit round 2 — RPC hardening, least-privilege grants, moneyline label - issue_ghost_slip: SET search_path, service_role guard, REVOKE/GRANT - ghost_slips table: GRANT SELECT only to anon/authenticated (was ALL) - audit_entries: add FK index on ghost_slip_id - grade/route.ts: handle moneyline predLabel separately (was showing "TEAM null") Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: CodeRabbit round 3 — auth.role() GUC fix, idempotent index - issue_ghost_slip: use auth.role() instead of legacy request.jwt.claim.role (legacy GUC returns NULL on modern Supabase, breaking all callers) - shadow view index: add IF NOT EXISTS + include sport column Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-24
Week 1 March launch — experience layer for NBA testing (#278) ## Summary - Post-login redirect to /play - Predictions landing page with SEO metadata + JSON-LD - CHAOS Cup leaderboard (sport-tabbed, shadow_leaderboard view) - Shareable PickCard + Ghost Slip ReceiptCard components - Dead code cleanup (OracleBoard.tsx, fantasy_bot.py Oracle import) - Bug fixes: forceLocked re-lock, toast copy, getSession→getUser, nested interactive elements, week filter, a11y ## Review 5 rounds of CodeRabbit review — all actionable findings resolved. Closeout: docs/plans/2026-02-24-week1-sprint-closeout.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-24
reset Headhunters pick state when switching weeks Without the else branch, selectedIds and locked retained the previous week's values when navigating to a week with no picks — making it appear that one week's picks applied to all weeks. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-24
Throw a Flag feedback widget (#277) * feat: add "Throw a Flag" feedback widget for beta users Floating amber flag button (bottom-right) opens a modal where authenticated users can report bugs, suggest ideas, or flag bad data. Submissions auto-capture page context and create labeled GitHub issues via the REST API. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address CodeRabbit review — rate limiting + shadcn components - Add in-memory per-user rate limiter (5 submissions/hour, 429 response) - Replace raw button/textarea with shadcn Button (isLoading) and Textarea - Use cn() for conditional class composition throughout widget Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-24
Oracle pipeline — two-phase grading, CodeRabbit fixes, lint cleanup (#273) ## Summary - Rewrote Oracle grading as two-phase pipeline (daily grade + end-of-week CP finalize) - Fixed 10 CodeRabbit findings across 3 review rounds - Fixed all 9 pre-existing lint errors (SlotCard refs, GamePredictionCta setState) - Dynamic NFL season start (Labor Day calculation) + NHL sync step - Workflow permissions + week validation ## CodeRabbit Findings Resolved 1. Idempotency guard: percentile_rank IS NOT NULL (not cp_earned > 0) 2. Push picks: graded_at IS NULL filter (not is_correct IS NULL) 3. CP on RPC error: skip percentile_rank write on failure 4. Lock results: preserve on re-run via existing weekly result fallback 5. lock_bonus: derive from persisted lock_correct 6. Standings: log get_team_display RPC error 7. Season start: dynamic Labor Day + kickoff calculation 8. NHL sync: add workflow step 9. allGradedPicks: graded_at filter to include pushes 10. gradeOverUnderPick: null guard + skip in grading loop ## Deferred to Hardening PR - `any` types → typed OraclePick/OracleGame interfaces - N+1 rank updates → batch RPC - leaderboard_preview scope on finalize-only runs - Season stats on finalize-only runs ## Test plan - [x] `npm run typecheck` passes - [x] `npm run lint` — 0 errors (was 9) - [x] Frontend unit tests pass - [x] Backend unit tests pass (69 passed, 2 pre-existing failures unrelated) - [x] Vercel preview deploys successfully 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix
v1.5.0

Maintenance update.

2026-02-24
upgrade pSEO player pages — Supabase manifest + rich data (#275) * feat: upgrade pSEO player pages — Supabase manifest + rich data - Add pseo_pages table (migration 20260223180000) — replaces JSON manifest with queryable Supabase storage. 3,089 pages upserted (527 NBA + 2,548 NFL) - Rewrite manifest.ts to query Supabase first, JSON fallback for build time - Add fetchPlayerPageData() shared data fetcher (6 parallel Supabase queries: game log, schedule, projections, defensive factors, trending events) - New components: FptsChart (Recharts area chart with opponent+date axis), SeasonAveragesTable (all/home/away splits), UpcomingSchedule (sidebar with matchup ratings), PlayerNewsFeed (trending events), GamePredictionCta (who-wins picker with live countdown timer) - Upgrade page.tsx with manifest-first/DB-fallback pattern — any player in player_pool gets a page with auto-generated SEO meta - Add /api/pseo/player/[slug] API route with CDN cache headers - Add /players, /games, /trending, /api/pseo to middleware public routes - Generator supports --supabase flag for DB upsert, --sport for single sport - Add NBA Sleeper player cache (527 players) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address CodeRabbit findings on PR #275 - pseo_generator.py: wrap upsert execute() in try/except, count only rows returned in result.data instead of fallback len(batch) on failure - FptsChart.tsx: use React useId() for SVG gradient id to prevent collisions when multiple instances render on the same page - GamePredictionCta.tsx: remove redundant synchronous tick() call in useEffect — useState lazy initializer already computes initial state - PlayerNewsFeed.tsx: add isNaN guard in timeAgo() to return empty string instead of 'NaNd ago' on invalid date strings - UpcomingSchedule.tsx: remove unused playerTeam prop from interface and remove it from the call site in players/[slug]/page.tsx - player-data.ts: sanitize slug before interpolating into .or() filter; improve resolveHomeAway fallback to compare g.team vs playerTeam before defaulting to 'home'; filter DNP games (minutes === null) before computing season averages to prevent deflated stats - 20260223180000_pseo_pages.sql: add DROP TRIGGER IF EXISTS before CREATE TRIGGER for idempotent migration re-runs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-24
daily scoring_period for leagues — auto-finalize CP after each game day (#274) * feat: daily scoring_period for leagues — auto-finalize CP after each game day Adds leagues.scoring_period ('weekly' | 'daily', default 'weekly'). Daily leagues (e.g. single-day NBA pick'ems) get CP awarded the morning after each game day without waiting for the weekly finalize batch. Weekly leagues (global NBA/NFL/NHL) are unchanged. - Migration: ADD COLUMN scoring_period TEXT DEFAULT 'weekly' CHECK IN ('weekly','daily') - oracle_grade.yml: discover step now fetches id,scoring_period per league and writes "id|scoring_period" to the league file. Grade loop parses both fields — daily leagues always pass finalize_week:true regardless of the global FINALIZE_WEEK schedule flag. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: add down migration for scoring_period column per CodeRabbit Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-23
trending_events upsert 409 — add on_conflict=slug param PostgREST's resolution=merge-duplicates needs on_conflict query param to know which unique column to merge on. Without it, returns 409 Conflict. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-23
disable Reddit scan cron — Reddit API blocked from CI Reddit returns 403 from datacenter IPs and their Responsible Builder Policy makes free API registration difficult. Disabled the weekly cron but kept workflow_dispatch and the script for local/manual use. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
improvement
v1.5.0

Maintenance update.

2026-02-23
add Reddit OAuth for CI — unauthenticated API blocked from datacenter IPs Reddit returns 403 for unauthenticated .json requests from GitHub Actions. Added app-only OAuth (client_credentials grant) that acquires a bearer token when REDDIT_CLIENT_ID and REDDIT_CLIENT_SECRET are set, then hits oauth.reddit.com instead. Falls back to unauthenticated for local use. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-23
lock RPC missing params and maybeSingle Python method name - lock_headhunter_picks was called with (p_season, p_week) but the actual function requires (p_season, p_week, p_sport, p_lock_time) - maybeSingle() is JS syntax; Python supabase client uses maybe_single() Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-23
accumulate grading errors and exit non-zero on failures grade_and_distribute and its helpers (issue_cp, _issue_ghost_slips, _upsert_weekly_result, _update_season_stats, shadow feed) previously swallowed exceptions — logged them but continued silently, causing the GitHub Actions workflow to report success even when operations failed. Now each helper returns error info, errors propagate up through the summary dict, and the CLI exits with code 1 if any failures occurred. Processing still continues through all users/leagues (no premature abort). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-23
headhunters grade runs Python directly, no Vercel middleman - Replace curl-to-Vercel with direct engine_v2.py grade call - Grade previous week (not current) since cron runs Monday morning - Remove CRON_SECRET/VERCEL_FRONTEND_URL dependency Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-23
remove Yahoo trademark from reddit scanner User-Agent Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-23
audit governance migration uses invalid scope/frequency enums - scope: 'user' -> 'player' (valid CHECK constraint values) - update_frequency: 'on_change'/'on_grade'/'on_event' -> 'on_sync' Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-23
reddit scan needs contents:write for private repo checkout Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-23
repair 5 failing cron workflows - Game Schedule Poll: add continue-on-error to audit steps (table not on prod yet) - Reddit Scan: add issues:write permission, ensure labels exist, fix User-Agent - Headhunters Grade: VERCEL_FRONTEND_URL secret set (done separately) - Sentinel: demote CRON_SECRET rejection from error to warning - pSEO: fix _load_json -> _load_cached import in trending_detector.py - Add .claude/worktrees/ to .gitignore to prevent submodule warnings Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-23
build Audit module — the 'A' in CHAOS (#267) * feat: build Audit module — the "A" in CHAOS Open-slate prediction game: pick players (min 3, no max), choose 2 of 5 stats each (PTS/AST/REB/STL/BLK), predict exact numbers. Score = sum of absolute error. Lowest error wins. More picks = more risk. Includes: - Schema migration (audit_entries, audit_picks, weekly_results, season_stats, shadow view) - 4 API routes (players, picks, leaderboard, standings) - Grading engine with closeness tiers, tiebreaker, CP/Ghost Slip issuance - Lock engine (auto-lock picks at game tip-off) - 8 frontend components + 3 pages (hub, pick flow, leaderboard) - Governance migration (28 columns in meta_attribute_registry) - Workflow integration (lock + grade steps in game_schedule_poll) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve all 16 CodeRabbit findings on Audit module Critical fixes: - grade.py: STATUS_FINAL → completed (match game_schedule convention) - lock.py: start_time → game_time, STATUS_SCHEDULED → scheduled - players/route.ts: add auth guard, Eastern date, scheduled/live statuses - leaderboard/route.ts: add auth guard, use get_user_profiles RPC - standings/route.ts: add auth guard, use get_user_profiles RPC Schema fixes: - audit_entries: add is_locked, submitted_at, locked_at columns - audit_picks: rename lock_time → locked_at, add submitted_at - audit_weekly_results: add picks_submitted/correct, total_points, prize_cred, updated_at - audit_season_stats: add total_points, worst_streak - Add user_id indexes on weekly_results + season_stats - Add service-role RLS policies for lock/grade engine access Backend fixes: - grade.py: compute accuracy_pct, current/best/worst_streak in season stats - governance.sql: add missing season_stats entries, down migration, lock_time → locked_at Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: trigger CodeRabbit re-review * fix(security): replace partial-match auth check with strict equality in sync-oracle-games The Authorization header check used `includes()` which allowed partial matches (e.g. a token wrapping the real key would bypass auth). Replaced with strict equality against the expected `Bearer <key>` format, and added a guard for undefined SUPABASE_SERVICE_ROLE_KEY. Fixes M5 from PR #267 pre-production audit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve all CodeRabbit re-review findings (19 fixes across 3 priority groups) MUST-FIX (6): - Replace STATUS_SCHEDULED with normalized 'scheduled' in picks API - Fix UTC→Eastern date calculation in GET, POST handlers + hub/leaderboard pages - Strict equality auth check in sync-oracle-games edge function - Replace ISO week (date +%V) with Sleeper API week in game_schedule_poll workflow SHOULD-FIX (8): - Add league membership checks in GET and POST (skip for global leagues) - Validate all picks share same entry_id in DELETE handler - Use regular supabase client (RLS) instead of admin in POST handler - Add Zod validation for GET query params (league_id, date format) - Extract now_iso outside loop in lock.py - Type-safe error handling in sync-oracle-games - Fix invalid Tailwind bg-white/3 → bg-white/[3%] across 3 components NICE-TO-HAVE (5): - Remove unused Decimal import from grade.py - Add exc_info=True to exception logging in grade.py - Simplify dead ternary in PredictionInput (step always 1) - Use alias import for ClosenessBadge in ResultsCard - Delete placeholder audit-module-critic.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve remaining CodeRabbit findings (round 3) - Add league membership check to DELETE handler (was missing vs GET/POST) - Remove admin client from DELETE — use RLS-bound supabase client throughout - Add sport filter to game_schedule queries in POST (prevent cross-sport mismatch) - Use Intl.DateTimeFormat for robust Eastern date in leaderboard page Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: Tailwind v4 hover:bg-white/8 → hover:bg-white/[8%] in PlayerSearch Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-23
HeadhuntersWidget uses DB weeks instead of client-side calendar math Widget was showing empty slots because deriveCurrentWeek() returned week 19 while actual active week in headhunters_weeks table is 18. Now fetches weeks from new /api/headhunters/weeks endpoint (matching the Headhunters page pattern) and shows both current + next week picks, league-scoped. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-23
Dashboard Redesign v2
feature
v1.5.0

Dark Ops Command Center (#268) * feat: Game Projection Engine integration specs + best practices addendums - Feature coverage matrix for all 5 modules - Interconnection map showing data flow - Best practices addendums for Casino, Oracle, Precision, Accuracy - Precision module playground and spec * feat: Dashboard Redesign v2 - Dark Ops Command Center - Add TopNavBridge component with Cred/CP stats - Add BottomDock navigation with 5 CHAOS modules - Implement 12-column responsive grid layout - Create CHAOS-first dashboard cards: * IdentityCard (CP rank, accuracy, Ghost Slips) * CHAOSStanding (league position, module breakdown) * TheLabCard (module performance metrics) * TreasuryWidget (Cred balance, transactions) - Add game module widgets: * HeadhuntersWidget (pick slots) * OracleWidget (matchup spreads) * PrecisionWidget (stat predictions) * SurvivorWidget (ALIVE/ELIMINATED status) * CasinoWidget (prop markets) - Add FantasyIntelBar for imported leagues - Add WeeklyPulse (Fraud/Tactician/Ice Cold) - Add WireFeed live activity stream - Add ChaosTerminal chat component - Update design tokens with Dark Ops color system - Add scanline background effect * refactor: Rename Precision module to Audit - Rename PrecisionWidget → AuditWidget - Update color tokens: precision-blue → audit-cyan - Update BottomDock navigation - Update CHAOSStanding module breakdown - Update WireFeed event types - All components now use cyan color scheme * fix: wire dashboard widgets to real data, add Coming Soon overlays - Remove all mock/hardcoded data from 12 dashboard widgets (-1,440 lines net) - Wire Oracle widget to getGames() API with loading/error states - Wire Headhunters widget to /api/headhunters/picks with 3-slot display - Wire Treasury, Identity, CHAOS Standing, The Lab, Fantasy Intel Bar to server-side getDashboardData() props (zero client fetches) - Add ComingSoonOverlay component for 5 unbuilt modules: Audit, Gauntlet, Weekly Pulse, Wire Feed, Chaos Terminal - Delete dead PrecisionWidget.tsx duplicate (renamed to Audit) - Remove CasinoWidget import (build blocker fix) - Fix BottomDock: 6 items → 5 (remove Casino) - Fix InviteButton touch target: 32px → 44px (WCAG) - Fix scanline opacity: 0.015 → 0.02 - Add error boundaries at dashboard and league route levels Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address CodeRabbit review findings on PR #268 - Remove unnecessary "use client" from 5 static Coming Soon widgets (AuditWidget, SurvivorWidget, WeeklyPulse, WireFeed, ChaosTerminal) - Fix FantasyIntelBar setState-in-effect lint error (use lazy initializer) - Simplify isGhost prop (always false after redirect guard) - Fix pre-existing ChaosTerminal missing leagueId prop in global dashboard Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct moduleStandings shape mismatch and null platform guard - Fix Critical: moduleStandings query returns { metric_value, team: { id } } not { points, team_id } — was causing all standings to be undefined - Fix Minor: add null coalescing for league.platform to prevent runtime crash Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: guard against NaN week query param Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

2026-02-23
update PM artifacts for dashboard redesign v2 (PR #268) - PROJECT_CONFIG.md: Add Dashboard v2, Game Projection Engine to services table; update current state with 12-widget architecture details - LEAGUES_DASHBOARD_PRD.md: Full rewrite to v2 — server props architecture, widget catalog, CHAOS Cup computation, CodeRabbit review history - FEATURE_COVERAGE_MATRIX.md: Add League Dashboard v2 section with all 12 widgets and their data source status Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
improvement
v1.5.0

Maintenance update.

2026-02-23
standardize oracle_games on Sleeper abbreviations, ESPN as single source - Remove alias hack from callback (PHO/PHX bridge no longer needed) - Fix Odds-API edge function: Phoenix Suns → PHO (Sleeper format) - Simplify team-pair matching to direct key lookup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-23
oracle score sync — match by team pair, not external_id The oracle_games_seed_callback was matching by external_id, but oracle_games rows (from The-Odds-API) have different IDs than game_schedule rows (from ESPN). This meant the 15-min poller NEVER matched existing rows and could never update scores. Fix: match by (home_team, away_team, season, week) with team alias normalization (PHO↔PHX) to bridge Sleeper and Odds-API abbreviation differences. Bulk-fetches oracle_games per week instead of per-game queries. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-23
revert Oracle entry fee RPC to adminClient, sync migration race-condition fix The authenticated client (`supabase`) can't reliably call SECURITY DEFINER RPCs that touch tables with restrictive RLS. Reverts to `adminClient` (service_role) which matches the Headhunters place_headhunter_entry pattern. Also syncs the on-disk migration with what's deployed (post-lock idempotency re-check) and documents Oracle power-up stubs in module architecture. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-23
use authenticated client for pay_oracle_entry_fee RPC The RPC is SECURITY DEFINER (runs as owner, bypasses RLS) and granted to authenticated — no need for service_role adminClient. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-23
keep Oracle on current week when games are still pickable The weeks route was marking entire weeks as 'live' once the first game started, causing current_week to skip ahead to the next open week. For NBA (games every day, Tue-Mon weeks), this meant users couldn't access mid-week games that hadn't kicked off yet. - Add 'in_progress' status: some games started, others still pickable - Track pickable_count and next_pickable_game per week - Deadline now shows next pickable game, not first (already started) game - current_week prioritizes in_progress over open/closing_soon - Hub badges: "X GAMES LEFT" for in_progress, "IN PROGRESS — PICKS OPEN" in list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-23
atomic Oracle entry fee RPC, font readability, weekly picks UI overhaul - Replace multi-step JS entry fee logic with idempotent pay_oracle_entry_fee RPC (mirrors Headhunters pattern: wallet FOR UPDATE lock, atomic debit, UPSERT fee record — no more double-charges on re-save) - Add get_oracle_week_info RPC for entry count + pot (SECURITY DEFINER) - Fix font readability: text-[10px] → text-xs, text-zinc-500/600 → text-zinc-400/300, reduce tracking-widest → tracking-wide across Oracle hub page - Oracle hub: show weekly player count, dynamic pot/CP rewards card - Weekly picks pages: collapsible day groups, randomize button, Lock of Week sidebar, sponsor slot integration, partial-batch pick rejection - Fix migration timestamp collision (seed_headhunters_sport_config) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-23
rename Precision to Audit, open-slate model specs (#266) * feat: Game Projection Engine integration specs + best practices addendums - Feature coverage matrix for all 5 modules - Interconnection map showing data flow - Best practices addendums for Casino, Oracle, Precision, Accuracy - Precision module playground and spec * docs: add critic reviews and dashboard redesign updates - SEO/AEO overhaul critic review - Dashboard precision critic review - Dashboard redesign design + tasks updates Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: rename Precision module to Audit, update specs with open-slate model - Rename "Precision" to "Audit" (the A in CHAOS: Casino, Headhunters, Audit, Oracle, Survivor) - Change from fixed 3-player parlay to open-slate model (min 3, no max) - Add tiebreaker: more predictions at same total error wins - Add closeness tiers: BULLSEYE / DIALED IN / CLOSE / OFF / MISS - Add player pool filtering: top 100 active, not injured, games today - DNP = voided (not zero error), min 3 non-voided to qualify - Ghost Slip threshold scales with prediction count (avg error <= 2.5) - Remove engine comparison from results (engine only on pick builder) - Rename tables: precision_picks -> audit_picks, precision_parlays -> audit_entries - Update playground with desktop view, CHAOS-order dock, all design changes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
improvement
v1.5.0

Maintenance update.

2026-02-23
add critic reviews and dashboard redesign updates - SEO/AEO overhaul critic review - Dashboard precision critic review - Dashboard redesign design + tasks updates Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
improvement
v1.5.0

Maintenance update.

2026-02-23
remove gambling language, preserve Casino module name (#265) * fix: remove gambling language flagged by CodeRabbit on PR #262 Addresses all CodeRabbit inline findings (7 Critical, 7 Major, 8 Minor) plus additional violations found via codebase scan. Changes across 25 files: - Replace "Casino" labels with "Prediction Pools" in user-facing copy - Replace "parimutuel" with "pool-based" in marketing/help pages - Replace "bankroll" with "Cred balance", "side pots" with "prediction contests" - Replace gambling emoji (slot machine) with prediction emoji (dart) - Fix "THE HOUSE DOESN'T ALWAYS WIN" slogan to "THE CROWD SETS THE PRICE" - Fix transaction labels: "Casino Entry/Payout" → "Pool Entry/Payout" - Fix blog metadata: remove "odds", "cash" references - Fix GlobalTreasuryWidgetClient loading state bug (stays true when user null) - Replace "$50" with "50 Cred" in help content (virtual currency, not USD) Legal compliance: ensures all public-facing content uses fantasy prediction language per CLAUDE.md Development Guardrails section. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: revert Casino module name, restore parimutuel, fix help-content corruption - Revert "Prediction Pools" back to "Casino" where it's the CHAOS module name (the C in C.H.A.O.S. must stay Casino) - Restore "parimutuel" — it's a legitimate technical term, not gambling language - Revert help-content.ts fully and re-apply only the targeted fix (sed had corrupted Tailwind classes and numbers: yellow-400 → yellow-450 Cred, etc.) - Keep non-module gambling fixes: "the house", "bankroll", "side pots", "cash out" Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-23
economy model overhaul — terminology, vig rates, CP tiers, weekly tax removal (#264) * docs: update economy model across all documentation Remove weekly tax (does not exist), replace with correct economy: - Module entry fees: 50 Cred/module/week for global leagues - Private/creator leagues: 10% vig BURNED (Cred sink) - Universal percentile CP model across all modules (top 5%=500, 15%=350, 30%=200, 50%=100) - Casino: global=0% vig, private=10% vig burned - New transaction types: VIG_BURN, CASINO_ENTRY, CASINO_PRIZE Updated 17 files: CLAUDE.md, GEMINI.md, PROJECT_CONFIG.md, module READMEs (5), CHAOS_MODULE_ARCHITECTURE.md, OpenSpec proposals (4), roadmap docs (2), backend/CLAUDE.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address CodeRabbit review findings on PR #264 - Remove duplicate Item Shop entry in backend/CLAUDE.md and PROJECT_CONFIG.md - Add "Bottom 50% = 0 CP" to CP summary in CLAUDE.md - Expand HH and Gauntlet CP lines to full tier set with small-field fallback - Update analytics scoring examples to include percentile column - Add transaction types and entry fee details to casino vig section - Fix survivor "200 CP" → universal percentile reference - Replace gambling terms (wager/bet) with compliant terms (entry/pick) - Update league-buyin-prizes acceptance criteria: 5% → 10%/0% dual-rate - Fix economy-foundation "wager" → "entry" language Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address remaining CodeRabbit findings on PR #264 Round 2 fixes: - Casino rebuild: settlement flow uses CASINO_PRIZE + VIG_BURN (not PAYOUT + casino_jackpot) - Module architecture: Casino tx types CASINO_ENTRY/CASINO_PRIZE in protocol table, legacy note added - Survivor: Zombie Mode CP references Universal Percentile Model (not hardcoded 100/200) - League buyin: Desired State + Audit Trail use VIG_BURN (not PLATFORM_FEE), correct rates - Economy foundation: Phase 3 Weekly Tax fully deprecated, replaced by VIG_BURN model. T1/T7 task references cleaned, balance analysis updated, risk table updated. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: replace all wager/WAGER terminology with entry/CASINO_ENTRY in casino specs CodeRabbit Round 3 — compliance terminology sweep: - casino_wagers table → casino_entries - place_casino_wager/cancel_casino_wager RPCs → place_casino_entry/cancel_casino_entry - WagerSlip.tsx → EntrySlip.tsx - WAGER/PAYOUT TransactionTypes → CASINO_ENTRY/CASINO_PRIZE - All wager references in acceptance criteria, SQL, routes, and risk table Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
improvement
v1.5.0

Maintenance update.

2026-02-23
add 4 OpenSpec proposals for Game Projection Engine features New proposals unlocked by the shared game_projections table: - casino-prop-lines: Auto-generate O/U player prop markets from adj_stats - precision-projection-baselines: Surface engine projections as context in Precision module - oracle-matchup-context: Enrich Oracle cards with projection-based matchup ratings - projection-accuracy-tracking: Compare engine predictions vs actuals (MAE/RMSE) Each follows 3-file OpenSpec structure (proposal.md, design.md, tasks.md). Total: 66 tasks across 23 phases with agent assignments. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
improvement
v1.5.0

Maintenance update.

2026-02-22
SEO + AEO full overhaul — language, schema, authority pages, routes (#262) feat: SEO + AEO full overhaul — language, schema, authority pages, routes
feature
v1.5.0

Maintenance update.

2026-02-22
sync player box scores during live games, not just completed Live games are always re-fetched every poll cycle so player stats update in real-time. Completed games still skip if already synced. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-22
stop .env.development from overriding GitHub Actions secrets Changed load_dotenv(override=True) to override=False in all production scripts. The override=True was causing CI workflows to use DEV Supabase credentials even when PROD secrets were set in GitHub Actions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-22
ID-based ESPN player matching, replaces fragile name matching Adds espn_id column to player_pool and rewrites sync_player_game_stats.py to use 3-tier matching: stored ESPN ID > team+normalized name > name-only. Auto-saves ESPN IDs on first match for instant future lookups. Fixes players like "Derrick Jones Jr." not matching "Derrick Jones". Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-22
game schedule poll auto-seeds from ESPN, fixes dead polling Root cause: poll gate queried DB for today's games, but the daily sync only seeded NEXT week — current-week games were never in the table. Gate always returned "no games", so scores and box stats never updated. Changes: - poll() auto-seeds from ESPN when DB has no games (self-healing) - Gate checks ESPN directly instead of DB (no more silent failures) - Cron skips dead hours 9-15 UTC (saves ~28 Actions min/day) - headhunters_sync adds Step 0a: sync current-day schedule (--days-ahead 3) - Fix null safety in oracle_games_seed_callback Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-22
add operations runbook covering deployment, rollback, incidents, and monitoring Comprehensive playbook consolidating scattered operational knowledge into docs/RUNBOOK.md. Covers: environments, deployment procedures, CI/CD pipeline, code review process, migration safety, rollback procedures (4 options), cron jobs, incident response (P0-P3), monitoring, troubleshooting, and escalation paths. Includes past incidents and prevention measures. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
improvement
v1.5.0

Maintenance update.

2026-02-22
harden CI pipeline with test gates and migration safety - ci.yml: Add frontend unit tests (Playwright tests/unit/ + tests/onboarding/) - ci.yml: Add backend unit tests (pytest test_headhunters_v2.py, mock-based) - next.config.mjs: Remove typescript.ignoreBuildErrors — type errors now block builds - TerminalShell.tsx: Fix unused _initialYear prop destructuring (was the only TS error) - frontend/CLAUDE.md: Update commands section to reflect build now catches type errors - scripts/pre-push-migration-check.sh: New safety script — verifies project-ref, migration timestamps, idempotent DDL, RLS policies before `supabase db push` Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-22
add Jules agent system, CodeRabbit integration, and workflow docs to CLAUDE.md and GEMINI.md - CLAUDE.md: Added Jules Agent System section (modes, roster, weekly scan flow), CodeRabbit Integration section (features, path severity, Jules feedback loop), and GitHub Actions Workflows table - GEMINI.md: Full rewrite to match current project state (Next.js 16, React 19, operational modules, global leagues, Jules agents, CodeRabbit, legal compliance) - .coderabbit.yaml: Expanded code_guidelines to include GEMINI.md, AGENTS.md, frontend/AGENTS.md, product_strategy.md, MODULE_ARCHITECTURE.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
improvement
v1.5.0

Maintenance update.

2026-02-22
enable CodeRabbit knowledge base, tools, and learnings - Knowledge Base: reads CLAUDE.md files as code guidelines, uses past PRs/issues for context, enables web search for docs - Tools: enables ESLint + Gitleaks (secret detection) alongside AI - Learnings: scoped to repo so feedback accumulates over time - Path filters: skip changelog.json and minified files Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-22
restore Jules review protocol as path_instructions The Jules <> CodeRabbit feedback loop was removed when trimming tone_instructions to 250 chars. Re-added as a catch-all path instruction (**) which supports up to 20k chars and is where CodeRabbit actually applies per-PR review logic. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-22
trim tone_instructions to 250 char limit CodeRabbit validation rejects strings over 250 chars in tone_instructions. Moved the Jules bot review protocol out (it was never honored there anyway — path_instructions is where CodeRabbit applies per-PR logic). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-22
rewrite Bolt performance agent for directed mode Replaces the old autonomous Bolt journal with a full agent config matching the new Jules directed model (BUILD/CHECK/SCAN). Includes priority table, codebase-specific patterns, hard rules, and accumulated journal entries from this session. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feature
v1.5.0

Rewrites the Bolt performance agent configuration to use the Jules directed mode workflow (BUILD/CHECK/SCAN).

2026-02-22
Jules workflow reset + Reddit sentiment scanner + pSEO pipeline - Reset Jules from autonomous PR spam to directed BUILD/CHECK/SCAN modes - New .jules/JULES.md agent instructions (no auto-PRs, OpenSpec required) - New .jules/weekly-scan-prompt.md (5-task weekly scan -> GitHub Issue) - New backend/scripts/reddit_sentiment_scan.py (NFL + NBA subreddit scanner with keyword clusters, co-occurrences, competitor mentions, and engagement-weighted pSEO keyword opportunities with route suggestions) - New .github/workflows/reddit_scan.yml (Monday cron -> GitHub Issue) - Updated jules-handoff.md with BUILD/CHECK/SCAN protocol - Reset jules_audit.md (old entries from autonomous era) - Added daily-stipend tasks.md and pseo-receipts-layer OpenSpec Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-22
add error isolation to instant sync league processing (#261) Wrap per-league processing in try/catch so one failed league doesn't crash the entire sync operation. Also removes dead auto-link code that was already disabled via block comment. Closes #259 Co-authored-by: Twinuno <lentinia3@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-22
Remove redundant all-play calculation from sync (#195) - Removed `calculate_all_play.py` execution from `post_sync_workflow.py`. - `sync_next_gen.py` already calculates `all_play_win_pct` and `luck_index` and writes them to the same table, making the previous step redundant. - This saves ~16 separate API calls and database upserts during league onboarding. - Created `.jules/bolt.md` to document this performance learning. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: lentinia3 <213437175+lentinia3@users.noreply.github.com>
improvement
v1.5.0

Maintenance update.

2026-02-22
Address CodeRabbit review on #260 — unused import, unused var, <a> → <Link> - Remove unused useCallback import from CredBalancePill - Use date var in ghost-slip OG footer (was _date unused) - Replace <a href="/signup"> with <Link> in LeagueAuditClient Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-22
Resolve all ESLint errors (14 → 0) (#260) - 8x setState in useEffect: wrap in queueMicrotask() per React 19 rules - login/page: Extract LoginContent with useSearchParams + Suspense, fix duplicate content from Jules, replace <a> with <Link> - wizard/layout: Add id to inline <Script> - og/ghost-slip/route: Rename reserved module variable - MemberInviteWidget: Reorder declarations - SponsorSlot: Fix TypeScript parsing error - CredRefillStation: queueMicrotask wrapper for async fetch - LeagueAuditClient: queueMicrotask wrapper for setState block - profile/[username]: Replace <a> with <Link> Lint: 14 errors → 0 errors. Build passes. Co-authored-by: Twinuno <lentinia3@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-22
restore commissioner terminal with tabbed UI
feature
v1.5.0

Maintenance update.

2026-02-22
Manage page restructure, stale link fixes, and receipts syntax fix - Manage page: Add InviteConsole + StaffManager sections, reorder layout - StaffManager + LeaguesPanel: Fix stale /dashboard/manage?league= links to /league/[id]/manage - receipts/page.tsx: Fix duplicate const + missing semicolon/newline Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-21
Headhunters fee logic, dashboard layout, bug fixes, and orphan cleanup * feat: Introduce Headhunters and Oracle features with new frontend components, API routes, database migrations, and Sleeper debugging/testing scripts. * fix: Headhunters swarm cleanup — fee logic, bugs, orphans, and missing features - API: Relax UUID validation for global league IDs (non-RFC 4122 variant) - API: Differentiate global (50 Cred) vs private (0) entry fees, remove advance surcharge - API: Add new_balance to entry_fee_receipt response - UI: Gradient Lock Picks button with dynamic fee text (fee > 0 shows amount) - UI: Instant balance deduction + lock state via displayBalance/forceLocked - UI: Global league CTA after private pick submission - UI: Configurable weekly rewards (CP + Cred + items) in EntryFeeConfirmation - UI: Wire SeasonStats into history page with parallel data fetch - API: Fix ConsensusBar type mismatch — add headshot_url/projected_points to consensus route - CI: Fix grade cron accepting HTTP 202 (was only 200) - DB: Seed headhunters_sport_config for NBA (per_game_avg), NFL (weekly_total), NHL (per_game_avg) - Cleanup: Delete 5 orphaned V1 components (686 lines), fix hardcoded global league UUID Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: Restore dashboard 3-column layout, global league badges, and headhunter bet history - Dashboard page: 3-column layout (Performance & Stats | Active Betting & Markets | Financial Dashboard) with section headers, transaction history placeholder, and Bet History & Activity bottom row - PerformanceOverview: Half-gauge design with TrophyMetric and stats list - ActiveLeaguesList: isGlobal flag, cyan avatar/badge for global leagues, cyan progress bar, global leagues link to /headhunters instead of /dashboard - global_dashboard.ts: isGlobal field, headhunter_picks query for Bet History table, global leagues sorted to top Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: Add null pick validation to handleSubmitPrivate Mirrors the guard in handleSubmit — aborts with toast error if any of the 3 picks are null, preventing nulls from reaching the API. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Twinuno <lentinia3@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-21
Ghost Slip receipts page for Reddit sharing (#256) Public page where users create customizable Ghost Slip cards and get shareable URLs with rich OG image previews for Reddit/Twitter/Discord. Land grab phase — no auth required, drives to /landgrab CTA. - New /receipts page with interactive controls and live card preview - URL-param encoded state for unique shareable links per card - Enhanced OG image route with tier badge, accuracy, streak, record - Three presets: Sharp Shooter, The Legend, Underdog Co-authored-by: Twinuno <lentinia3@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-21
consolidate Headhunters into single league route - Enforce league-level mode on pick submission (API overrides client mode) - Add global league guard + deep merge for chaos-settings PATCH - Upgrade /league/[id]/headhunters with entry fee modal, mode badge, Cred balance - Create LeagueHeadhuntersClient wrapper component - Add /league/[id]/headhunters/leaderboard sub-route - Convert /play/headhunters/* to redirects into league routes - Fix ModulesDropdown to link to league headhunters when in league context - Add Headhunters Mode selector to commissioner ManagerConsole - Make HeadhuntersNav.leagueId required (always league-scoped) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feature
v1.5.0

Maintenance update.

2026-02-21
Implement Headhunters feature including UI, API, backend sync, and database migrations, alongside new strategic planning documents and a ledger transaction history component.
feature
v1.5.0

Maintenance update.

2026-02-21
Introduce Oracle weekly picks, Headhunters player selection, and user credit wallet migration with new navigation components.
feature
v1.5.0

Maintenance update.

2026-02-21
make Lock Picks button full-width and prominent below picks - Move submit CTA from inline header to full-width block below picks summary - Shows "Select N more players" when incomplete, full-width cyan "Lock Picks — 50 Cred Entry" when ready - After locking: green confirmation banner with "Cancel & Refund" option - Week 19 set to active on PROD for advance picks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-21
add missing nav redirects and wire up Headhunters pick submission - Add /dashboard/casino and /dashboard/survivor redirect pages (were 404 from ModulesDropdown) - Fix Sidebar: remove broken /dashboard/lab, /matchups, /settings/profile links - Fix Sidebar buildHref: /dashboard/* paths go to server-side redirects, not client rewrite - Fix shadow/LeagueCard: /league/[id]/shadow → /league/[id]/dashboard (shadow route doesn't exist) - Fix PlayerPicker: submit picks directly via API when no onRequestConfirm callback provided - Add cancel button to unlock/refund picks after submission - Fix sitemap.ts: handle V2 manifest format ({ pages: [] } object vs flat array) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-21
restore Oracle dashboard pages and add error handling to headhunters redirect Oracle pages (hub, board, leaderboard, week picker) were accidentally deleted in 9577d65. Restores them from the parent commit. Also adds proper error handling to the headhunters redirect page. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-21
add dashboard redirect pages for moved league routes Adds redirect pages at /dashboard/* that find the user's most recent league and redirect to /league/[id]/*. Includes new /dashboard/headhunters redirect that prefers the global NBA league. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-21
update demo luck-matrix imports after page move to league/[id]/ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-21
widen teams.team_key to TEXT and upsert global leagues on PROD - Migration 130000: Changed ON CONFLICT to DO UPDATE so global leagues get league_type='global' even if already inserted as 'native' - Migration 130200: Added ALTER TABLE teams.team_key/external_id to TEXT before the backfill INSERT, preventing varchar(50) overflow - Relinked Supabase CLI to PROD (was incorrectly linked to DEV) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-21
update marketing page, agents config, PlayerPicker UI, and theme Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
improvement
v1.5.0

Maintenance update.

2026-02-20
remove Slack notification steps from Oracle workflows Slack is not connected — SLACK_WEBHOOK_URL secret is not set. The missing secret caused oracle_grade.yml to fail on its Feb 19 scheduled run even though grading itself succeeded. Removed 3 Slack steps: - oracle_grade.yml: success notification + failure notification - oracle_sync.yml: failure notification Job summaries (GitHub Step Summary) still provide run visibility. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-20
optimize cron schedules and multi-sport box score sync Headhunters Grade: - Changed from daily (0 11 * * *) to weekly Monday 3 AM ET (0 8 * * 1) - All Sunday night NBA games are finished by then - Users see grading results when they wake up Monday morning - Saves ~6 unnecessary daily runs per week Game Schedule Poll: - Box score sync now loops over nba/nfl/nhl instead of hardcoded --sport nba - Script exits immediately with "No games to process" for sports without active games in game_schedule, so no wasted API calls - Future-proofs for NFL/NHL seasons without workflow changes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-20
prevent Oracle double-charge on rapid Save Picks clicks Root cause: two concurrent requests both passed the existingFee SELECT check before either wrote a fee record, so both called transact_user_cred. Backend fix: INSERT-first pattern — the UNIQUE constraint on oracle_entry_fees serializes concurrent requests. Only the request that successfully INSERTs the claim row proceeds to deduct Cred. The loser sees a 23505 conflict and skips deduction. Frontend fix: useRef guard prevents handleSubmit re-entry before React re-renders the disabled button state. Also fixes CredTransactionHistory loading overlay positioning (relative). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-20
handle league_pot_summary view dependency in reference_id migration The ALTER COLUMN reference_id UUID→TEXT failed because league_pot_summary view depends on that column. Now drops and recreates the view around the ALTER. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-20
Introduce Headhunters V2, Oracle Pickems, and a new ledger system with corresponding UI, API endpoints, and database migrations.
feature
v1.5.0

Maintenance update.

2026-02-19
Introduce Headhunters v2, unify subscriptions, and revamp the settings user interface with new components and a sticky save bar.
feature
v1.5.0

Maintenance update.

2026-02-19
Resolve all native league creation constraint issues Fixes 4 issues found during QA: 1. Add missing teams_team_key_key UNIQUE constraint (from baseline) 2. Ensure valid_platform_teams CHECK includes 'CHAOS' 3. Use ON CONFLICT for league_settings INSERT (trigger already creates row) 4. Use constraint name in handle_native_league_join for reliable conflict resolution Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-19
Generate league_key and external_id in create_native_league RPC The leagues table requires league_key and external_id (NOT NULL). The RPC was missing both columns, causing insert failure. Now auto-generates CHAOS_{8-char-uuid} for native leagues and sets league_type to 'native'. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-19
Pass p_buyin_amount to create_native_league RPC and surface error details The RPC call was missing the p_buyin_amount parameter after old overloads were dropped, causing PostgREST to fail silently. Also surfaces actual error messages instead of generic "Failed to create league". Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix
v1.5.0

Maintenance update.

2026-02-19
Introduce new Claude AI agents, skills, and commands, and add extensive documentation and specifications for project planning, a new chaos module, and a backend ledger.
feature
v1.5.0

Maintenance update.

2026-02-17
implement Headhunters V2 with Chaos Market scoring and dedicated frontend pages
feature
v1.5.0

Maintenance update.

2026-02-17
Implement core league management, onboarding, and dashboard features, alongside extensive design and specification for future enhancements and a new chaos product.
feature
v1.5.0

Maintenance update.

2026-02-07
Add `audit_league.py` script for comprehensive Yahoo Fantasy league auditing, data syncing, metric calculation, and report generation.
feature
v1.5.0

Maintenance update.

2026-02-06
add rate limiting to league import endpoint (#176) Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: lentinia3 <213437175+lentinia3@users.noreply.github.com>
feature
v1.5.0

Maintenance update.

2026-02-06
Introduce League Infamy Widget, referral code API, and terminal interface components.
feature
v1.5.0

Maintenance update.

2026-02-06
introduce league infamy widget with shareable audit cards and download functionality
feature
v1.5.0

Maintenance update.

2026-02-06
Implement Yahoo Fantasy Bot with league auditing, comprehensive sync logging, and essential maintenance scripts.
feature
v1.5.0

Maintenance update.

2026-02-06
Add comprehensive utility scripts for data inspection, new frontend authentication components, and extensive project documentation.
feature
v1.5.0

Maintenance update.

2026-02-02
Add frontend page for displaying league audit results and a backend script to list Supabase users.
feature
v1.5.0

Maintenance update.

2026-02-02
Introduce league audit functionality with a dedicated frontend page, backend processing, data synchronization scripts, and user deletion tools.
feature
v1.5.0

Maintenance update.

2026-02-01
Implement a comprehensive post-sync workflow for advanced league data processing, integrate email notification utilities, and introduce new dashboard UI components.
feature
v1.5.0

Maintenance update.

2026-02-01
Introduce Resend email sending and receiving skills with comprehensive documentation and agent configuration.
feature
v1.5.0

Maintenance update.

2026-01-31
add LeagueInfamyCard component to display league volatility, archetype, and detailed breakdown statistics.
feature
v1.5.0

Maintenance update.

2026-01-31
Implement league audit functionality with backend processing and a dedicated frontend page.
feature
v1.5.0

Maintenance update.

2026-01-31
Add `AuditPageClient` component to manage the fantasy league audit workflow, including connection, scanning, and result display.
feature
v1.5.0

Maintenance update.

2026-01-30
Initialize new Next.js frontend application with league dashboard, Infamy analysis, and Sleeper integration
feature
v1.5.0

Launched the foundational Next.js architecture featuring a real-time league dashboard, the Infamy analysis engine, and native Sleeper API connectivity.

2026-01-30
Implement `SyncLogger` for detailed sync job tracking, add instant sync API, and introduce new frontend settings, marketing, and league invite components.
feature
v1.5.0

Enhanced backend observability with SyncLogger and added core frontend infrastructure for user settings and league growth.

2026-01-28
Initialize frontend application with dashboard API, audit page, changelog, and foundational project structure files.
feature
v1.5.0

Maintenance update.

2026-01-27
League Selector & Ledger Optimization
fix
v1.5.1

Fixed duplicate league entries via smart deduplication, updated Active Season to be system-driven (no more hardcoding), and enhanced the wallet activation UI.

2026-01-28
League Audit & Dashboard Enhancements
feature
v1.5.2

implemented league audit with luck scoring and infamy, added ledger components for wallet and betting analytics, and enhanced the dashboard with new widgets.

2026-01-27
Implement user authentication callback with post-login processing, foundational navigation components, and the main dashboard page.
feature
v1.5.0

Maintenance update.

2026-01-27
restore jules directory
improvement
v1.5.0

Maintenance update.

2026-01-27
Weekly Awards Enhanced
feature
v1.5.0

Added detailed tooltips and glossary definitions for all Chaos Badges (Fraud Win, Tragic Loss, etc.) to help you understand your accolades.

2026-01-25
Survivor Pool: Zombie Mode
feature
v1.4.2

Launched Weekly Survivor Pools. Eliminated teams can now buy back in using Cred for a shot at the 'Zombie' title.

2026-01-23
Multi-League Portfolio
feature
v1.4.0

A new unified dashboard to view your Cred balance, earnings, and transaction history across all your leagues in one place.

2026-01-22
Shadow Economy: Daily Claims
feature
v1.4.0

Earn daily free Cred just by logging in. Shadow Players can now accumulate wealth to bet on leagues they don't own.

2026-01-20
League Infamy Cards
feature
v1.3.5

Visual 'Share Cards' for your league's history. Show off your league's Chaos Score and viral stats to the world.