33 KiB
Executable File
VYNDR — Build State
Last Updated
2026-06-10
Current Phase
SHIP BUILD v7.2 — Soccer Intelligence + World Cup 2026 (Session 7j)
Session 7j (2026-06-10) — SHIPPED
Permanent soccer sport vertical, launching with FIFA World Cup 2026 (opens June 11). League-agnostic architecture supports WC, EPL, La Liga, Bundesliga, Serie A, Ligue 1, UCL, MLS, Liga MX from the same code paths.
Files created
src/data/worldcup2026.js— 16 venues + altitudes + climate, CONCACAF- CONMEBOL teams, penalty/corner/free-kick takers (top 25 teams),
tournament players (≥3 career WC goals). All frozen. Helpers:
isPenaltyTaker,isCornerTaker,isFreeKickTaker,getTournamentHistory,isHomeContinent,getVenue,altitudeImpact.
- CONMEBOL teams, penalty/corner/free-kick takers (top 25 teams),
tournament players (≥3 career WC goals). All frozen. Helpers:
src/services/adapters/footballDataAdapter.js— football-data.org v4 REST adapter. 8/min token bucket (2-req safety margin vs the 10/min upstream cap). Tier-matched Redis TTLs (fixtures 6h, standings 12h, squads 24h, scorers 6h). Stale-while-revalidate fallback when the bucket is drained or the API 5xx's. Returns null when no API key — callers degrade gracefully.src/services/intelligence/soccerFeatureExtractor.js— reads from prefetch-populated Redis cache (NEVER hits external APIs on the user request path). Builds the engine1 feature vector + a soccer overlay (goals_per_90, xG, penalty/corner/FK role, altitude, referee, tournament history, rest_days).poller/soccer.js— league-agnostic fixture poller. WC pulls from the rezarahiminia/worldcup2026 OSS API (no rate limit) and falls back to football-data.org. Other leagues use the adapter directly. Writessoccer:nextmatch:{team}(24h TTL) +soccer:lastfixture:{team}(7d TTL) per fixture. Self-rescheduling: 5-min ticks during live matches, 30-min otherwise. PM2-managed.scripts/soccer-data-prefetch.js— daily batch job. Pulls standings- scorers per configured league, computes per-team defensive
aggregate (
goals_conceded_per_game,defensive_rank_normon a 0..1 scale that slots into engine1'sopp_rank_stat) and per-player per-90 rates. Writessoccer:teamdefense:{league}:{team}andsoccer:player:{normalizedName}.--leagues=WC,PL --dry-runflags supported. xG fields left null on Day 1 (soccerdata-Python bridge is a follow-up; engine handles nulls gracefully).
- scorers per configured league, computes per-team defensive
aggregate (
tests/unit/worldcup2026.test.js(20 tests)tests/unit/footballDataAdapter.test.js(15 tests)tests/unit/soccerFeatureExtractor.test.js(17 tests)tests/unit/trapDetectionSoccer.test.js(21 tests)tests/unit/computeFeaturesSoccerBranch.test.js(4 tests)tests/unit/analyzeViaEngine1Soccer.test.js(8 tests)tests/unit/soccerPoller.test.js(22 tests)tests/unit/soccerDataPrefetch.test.js(14 tests)tests/integration/oddsSoccer.test.js(6 tests)
Files modified
src/utils/oddsNormalizer.js—MARKET_MAPgains 10 soccer market keys (player_goals,player_shots_on_target, etc →goals,shots_on_target, etc). Existing NBA mappings untouched.src/routes/analyze.js,src/routes/scan.js—VALID_STAT_TYPESset extended with 10 soccer stat types.'assists'is shared with NBA;sportfield discriminates downstream.src/routes/odds.js— newGET /api/odds/soccer/:leagueroute. Validates league againstSOCCER_SPORT_KEYS(9 leagues), surfaces 405 valid-list hint on miss.src/services/oddsService.js—SPORT_KEYSgains 9 soccer entries mappingsoccer_wc→soccer_fifa_world_cup,soccer_epl→soccer_epl, etc.SOCCER_SPORT_KEYSexported as a frozen list.src/services/intelligence/computeFeatures.js—sport ∈ {'soccer','football'}dispatches toextractSoccerFeatures. NBA path unchanged.src/services/intelligence/trapDetection.js— six soccer signals (xg_regression, altitude_risk, rotation_risk, minute_discount, referee_card_bias [positive — excluded from composite], strong_defense).getTrapScorebranches oninput.sport.src/services/intelligence/analyzeViaEngine1.js— soccer reasoning branch (buildSoccerReasoningLines). Uses "matches" not "games", surfaces xG / penalty taker / altitude / referee / minutes / WC pedigree. NBA-specific sentences (back-to-back, injury report) guarded by!isSoccer.poller/ecosystem.config.js—poller-soccerPM2 app added. Same restart policy as box-score pollers;SOCCER_LEAGUESenv wired..env.example— soccer block (FOOTBALL_DATA_API_KEY,SOCCER_LEAGUES,WORLDCUP_API_URL,RAPID_API_KEY).docs/SYSTEM-MANIFEST.md—/api/odds/soccer/:leaguerow in §2, Soccer env block in §3, soccer poller in poller-set, four new external API rows in §6,[ARCH-3]soccer-pipeline note in §8.
Quality gates (all green)
npm test: 1173 / 1173 passing (1042 baseline + 131 new soccer tests across 9 new suites), 91 suites, 0 failuresweb/npm run build: clean- License audit: only permissive third-party licenses
Session 7i (2026-06-10) — SHIPPED
Stripe checkout + webhook (no new routes — gap-fill on existing)
Pre-audit revealed Session 3.4 already shipped a fuller Stripe
integration than this session's spec asked for: route, sig verify,
all 4 event handlers with 48h grace, customer create + persist,
portal + status endpoints, founder-code system, and users ↔
user_profiles dual writes. Raw-body middleware was already correctly
positioned at src/app.js:52 (before global express.json()).
What this session added on top:
tests/integration/stripe.test.js— refactored stripe mock to a singleton handle, then added two route-level tests:constructEventthrows → route returns 400 with{ error: /signature/i }- valid signature → route dispatches to
handleWebhookEventand returns{ received: true }
tests/unit/stripeService.test.js— addedcustomer.subscription.updatedtest covering portal-driven plan-change: mapsitems.data[0].price.idback to a tier viaPRICE_MAP, writes to bothusers+user_profiles, clears grace.docs/SYSTEM-MANIFEST.md— appended a Payments: dual-provider divergence subsection under § 8 Findings → Frontend ↔ Backend contract, documenting that the Next.js/api/checkoutstill routes to NexaPay while Express Stripe is wired but uncalled by the frontend, with a 4-step cutover punch list for a follow-up session.
Quality gates (all green)
npm test: 1042 / 1042 passing (delta +3 from 1039 baseline, 0 regressions)web/npm run build: clean- License audit: third-party deps only permissive (MIT/Apache-2.0/BSD/ISC/MPL/BlueOak/CC-BY/0BSD)
curl https://api.vyndr.app/api/health→{"status":"healthy"}
Session 7h (2026-06-10) — SHIPPED
Stripe (test mode)
Resources created against sk_test_* via direct REST API (Stripe MCP plugin OAuth flow was non-functional in this environment; bypassed by hitting https://api.stripe.com/v1 with the secret key in a single shell subprocess, then shredding the on-disk key file).
prod_UgBel9RYTROCxr— VYNDR (metadata.tier=analyst)price_1TgpGxIp1Mec3r2E6Wh6oeaP— $14.99/mo recurring (metadata.tier=analyst)
prod_UgBeSBYw2j9oXL— VYNDR Desk (metadata.tier=desk)price_1TgpGyIp1Mec3r2EQq50KKhF— $44.99/mo recurring (metadata.tier=desk)
we_1TgpGzIp1Mec3r2ERtDIF2n2— webhook →https://api.vyndr.app/api/stripe/webhook- Subscribed events:
checkout.session.completed,customer.subscription.updated,customer.subscription.deleted,invoice.payment_failed - Signing secret saved to
~/.stripe-webhook-secret(chmod 600) — read once, paste into Coolify, thenshred -u.
- Subscribed events:
Tier infrastructure
src/config/tiers.js— frozen access matrix (free/analyst/desk);api_access:falseon every tier (non-negotiable consumer-product invariant)src/middleware/scanLimit.js— 24h rolling per-user/IP quota (free=3, analyst=15, desk=∞); 429 +Retry-After+X-Scans-Used/Limitheaders on overflow; in-memory LRU withMAX_TRACKED=50_000src/utils/tierGating.js— pure response gating; free tier keeps grade/confidence/edge_pct, redactsreasoning+kill_conditions_triggered; paid tiers pass through- Wired into
src/routes/scan.js(/parlayafterrequireAuth) andsrc/routes/analyze.js(/prop+/batch, gating applied per-result)
SQL (run manually in Supabase SQL Editor)
docs/sql/pricing_slots.sql— createspricing_slotstable + RLS + price IDs seeded. Not added to the migrations chain per session policy.
Tests
tests/unit/tiers.test.js(10 tests) — frozen matrix,api_access=falseinvariant, fallback behaviortests/unit/tierGating.test.js(9 tests) — free-tier redaction, paid passthrough, no input mutationtests/unit/scanLimit.test.js(10 tests) — per-tier limits, anonymous IP fallback, independent quotas, desk skip- Existing suites adapted for the new middleware:
tests/unit/analyzeCache.test.js,tests/integration/analyze.test.js,tests/integration/scan.test.jsreset the scan-limit map inbeforeEach; the integration suite for/api/analyzemocksapplyTierGatingas pass-through so engine-shape assertions stay focused on the engine contract (gating has its own suite).
Quality gates (all green)
npm test: 1039 / 1039 passing, 82 suites, 0 failuresweb/npm run build: production build clean, all 24 routes prerendered- License audit: only permissive third-party licenses (MIT/Apache-2.0/BSD/ISC/etc.); single UNLICENSED entry is our own
vyndr-webworkspace
Web Tier v6 (2026-05-18) — SHIPPED
Complete frontend overhaul. 18 pages, 22 API routes. npm run build passes with zero errors.
New pages
/dashboard— post-login slate (sport tabs, top grades, tonight's games, most parlayed, recent scans, first-time onboarding)/game/[id]— game preview with spread/total/ML, starting lineups with injury flags, expandable prop list, add-to-parlay/profile— tier status, subscription state, founder badge, cancel-at-period-end flow/intelligence— Desk-tier timeline of evolution/coaching/cascade/ABS/line-movement signals (blurred for non-Desk)/terms,/privacy,/responsible-gambling— branded legal pages with brand voice/scan— full rebuild (sport tabs, real /api/scan with tier gating, parlay tray hook)/login,/signup— wired to Supabase Auth via AuthContext (Google OAuth + email/password + age check)/marketplace— coming-soon waitlist (API access, custom alerts, capsule drop)/ledger,/tracker— design system refresh, accuracy buckets, miss autopsy, quick-slip/— auth-aware: logged-in users redirect to/dashboard; anonymous see marketing
New API routes
/api/games/tonight,/api/games/[id],/api/games/[id]/props/api/props/top-graded,/api/props/most-parlayed/api/players/search/api/user/recent-scans/api/intelligence/feed/api/parlay/add-leg,/api/parlay/grade/api/ledger,/api/ledger/accuracy- All cached via Supabase
odds_cachetable (5-min TTL) — never hit Odds API directly
Services + middleware
services/odds-cache.ts— Supabase-backed TTL cache for upstream calls (loader + stale-fallback)services/email.ts— Resend wrapper:sendWelcomeEmail,sendPaymentReceipt,sendRenewalRemindermiddleware/rateLimit.ts— per-tier per-minute scan throttle (5/30/60 free/analyst/desk)services/nexapay.ts— already shipped (createPaymentLink + HMAC webhook verify), now wired to email receipts
Components
GradeCard.tsx— premium grade card with tier-gated blur (factors locked for free; alt-lines locked for non-Desk)ParlayContext.tsx+ParlayTray.tsx— cross-page parlay state, slide-up tray, /api/parlay/grade integrationBottomTabBar.tsx— mobile-only 5-tab navigation (Home/Scan/Parlay/Ledger/Profile) with parlay badgeShareCard.tsx— canvas-rendered 1200x630 OG share image with grade letter; download + copy-to-clipboardNav.tsx,Hero.tsx,LivePropsStrip.tsx,Features.tsx,Pricing.tsx,HowItWorks.tsx,FAQ.tsx,Footer.tsx— design system refresh already shipped
PWA + meta
public/manifest.json(192/512/maskable icons)public/icons/icon-{192,512,maskable-512}.png,apple-touch-icon.png,favicon.ico,favicon.pngpublic/og-image.png— 1200x630 social share cardappleWebApp+manifest+ theme-color wired inlayout.tsx
Supabase migrations
011_user_profiles_web.sql(already deployed):user_profiles(+RLS+trigger),parlay_leg_frequency(+RPC),scan_history012_web_caching_waitlist.sql(NEW):odds_cache(TTL cache),waitlist_signups,founder_pricing_seatsview,prune_expired_odds_cache()helper
Backend
src/app.js— CORS middleware added (localhost dev + vyndr.app + *.vercel.app + FRONTEND_ORIGINS env var)package.json— addedcors@2.8.5
Bug fixes
- Scan page sibling-div JSX bug fixed (rewritten from scratch)
- Lockfile warning silenced via
next.config.tsturbopack.root(already in place) - Auth callback rewritten to use Supabase JS session API instead of raw localStorage parse
Environment variables (set in Vercel + Railway)
Vercel (Next.js)
NEXT_PUBLIC_SUPABASE_URL— Supabase project URLNEXT_PUBLIC_SUPABASE_ANON_KEY— Supabase anon keySUPABASE_SERVICE_ROLE_KEY— service role (server-only, NEVER expose to client)NEXT_PUBLIC_SITE_URL—https://vyndr.appBACKEND_URL— Railway URL of Express grading engineNEXT_PUBLIC_API_URL— same as BACKEND_URL (for legacy client fetches)NEXT_PUBLIC_NBA_SERVICE_URL— FastAPI nba_api wrapper URLNEXAPAY_API_KEY— bearer token from NexaPay dashboardNEXAPAY_WEBHOOK_SECRET— HMAC secret from NexaPay dashboardNEXAPAY_API_URL— defaults tohttps://api.nexapay.one/v1RESEND_API_KEY— from resend.comRESEND_FROM_EMAIL— defaults toVYNDR <grades@vyndr.app>NEXT_PUBLIC_POSTHOG_KEY— PostHog project key (optional)NEXT_PUBLIC_POSTHOG_HOST— defaults tohttps://us.i.posthog.com
Railway (Express backend)
- All existing engine vars (Odds API key, Supabase, etc.)
FRONTEND_ORIGINS— comma-separated additional CORS origins (optional; defaults cover localhost + vyndr.app + *.vercel.app)
Vercel deployment
- Repo root →
/home/kev/mastermind/vyndr - Root Directory in Vercel project settings:
web - Framework Preset: Next.js (auto-detected)
- Build Command:
npm run build(default) - Install Command:
npm install(default) - Output Directory:
.next(default; we useoutput: 'standalone') - Node version: 20.x or 22.x
- Add all env vars from the list above
Railway deployment (backend)
railway.tomlalready configured in repo root- Connect GitHub → Deploy from
main - Set env vars (same as Vercel backend list)
- Get URL → set
BACKEND_URLin Vercel
NexaPay configuration
- Create NexaPay account → get API key + webhook secret
- Webhook URL:
https://vyndr.app/api/webhook/nexapay - Webhook events to enable:
payment.succeeded,payment.failed,payment.refunded,subscription.canceled - Settlement wallet: USDC on Polygon (or your preferred chain)
- Set
NEXAPAY_*env vars in Vercel
Resend configuration
- Create Resend account → verify
vyndr.appdomain - Add DNS records (SPF, DKIM, DMARC) from Resend dashboard
- Create API key → set
RESEND_API_KEYin Vercel - Test: trigger a signup, check the welcome email arrives
Supabase Auth setup
- Run migrations
011_user_profiles_web.sqland012_web_caching_waitlist.sql(Supabase SQL editor or CLI) - Auth → Providers → enable Email/Password (default)
- Auth → Providers → enable Google: paste client ID/secret from Google Cloud Console
- Auth → URL Configuration → Site URL:
https://vyndr.app - Auth → URL Configuration → Redirect URLs:
https://vyndr.app/auth/callback,http://localhost:3001/auth/callback
What Has Shipped (Backend — Already Live)
Phase 1 — Foundation (COMPLETE)
- Feature 1.1 — Odds API Integration
- Feature 1.2 — NBA_API Stats Wrapper (FastAPI microservice)
- Feature 1.3 — Prop Analysis Engine (6-step grading pipeline)
- Feature 1.4 — Database Schema (9 tables, RLS, triggers)
- Feature 1.5 — Bet Submission (3 methods + performance tracking)
Phase 2 — Core Product (COMPLETE)
- Feature 2.1 — Parlay Scan (correlation detection, monetization)
- Feature 2.2 — Line Movement + Cascade Detection
Phase 3 — Web MVP (COMPLETE)
- Feature 3.1 — Landing Page + Blog (Next.js, MDX, VYNDR voice, SEO)
- Feature 3.2 — Scan UI (leg builder, grade results, upgrade pitch)
- Feature 3.3 — Bet Tracker (performance dashboard, quick slip, settle flow)
- Feature 3.4 — Stripe Integration (checkout, webhooks, portal, founder codes)
Also Shipped (Separate Repo)
Mastermind Agency Site
/home/kev/mastermind/agency-site/- Glitch aesthetic, scan lines, CRT flicker, JetBrains Mono
- Home, VYNDR case study, Contact pages
Phase 1 Additions — Intelligence Engine (COMPLETE)
- Addition 1 — Stats endpoints (parlays-graded, public, live props)
- Addition 2 — Dynamic role profile system (8 roles, Shannon entropy, conditional profiles)
- Addition 3 — Player selector (placeholder — Cowork handles design)
- Addition 4 — Parlay probability (phi coefficient, juice-adjusted EV, correlation math)
- Addition 5 — MLB prop grading (14 stat types, 10 kill conditions, 30 parks, weather API)
- Addition 6 — Intelligence engine (similarity, evolution/PELT, line discrepancy, alt line, Bayesian, model trainer)
- Addition 7 — Lineup watch speed (role activation detection framework)
- Addition 8 — Database additions (7 new tables, migration 003, indexes, RLS)
- Addition 9 — Design system update (forest green, Hero tagline, live props strip, DemoScan result card)
- Addition 10 — Accuracy ledger page (/ledger)
- Addition 11 — Marketplace page (/marketplace, waitlist, honeypot)
- Addition 12 — ARCHITECTURE.md v1.0
- Permanent: FOUNDER_NOTE constant (immutable, tested for integrity)
- Permanent: X-VYNDR-Mission header on all API responses
Also Shipped (Separate Repo)
Mastermind Agency Site
/home/kev/mastermind/agency-site/- Glitch aesthetic, scan lines, CRT flicker, JetBrains Mono
- Home, VYNDR case study, Contact pages
Test Summary
- Node.js: 662 tests passing (unit + integration) — 357 original + 187 ship + 65 supplement + 35 patch + 45 security
- Python: 27 tests passing
- Total: 689 tests, all green
- 8 new test files: shipInfrastructure, shipGradingEngine, shipDataSources, shipResolution, shipSchemeClassifier, supplementSystems, patchIntegration, securityAudit
- Next.js project builds (pending Vercel deploy)
Active Blockers
- BLOCKER-003: WSL2 DNS cannot resolve *.supabase.co
- Migrations 003-010 need manual apply via Supabase SQL Editor
Phase 1 Additions Part 2 (COMPLETE)
- Addition 13 — Simplified scan selector (sport toggle NBA/MLB, player search, stat dropdown, line pre-fill from Odds API)
- Addition 14 — PostHog analytics integration (5 events: scan_completed, grade_viewed, upgrade_cta_clicked, prop_shared, alt_line_viewed)
- Addition 15 — Affiliate database (Migration 004: referral_codes, referral_conversions, affiliate_payouts, wallet_addresses, RLS on all)
- Addition 16 — Scheme intelligence data layer (schemeClassifier.js: PnR coverage classification DROP/SWITCH/HEDGE/MIXED/UNKNOWN, 8-possession min, 6hr cache, graceful degradation, silent logging to model_predictions_extended)
- Scheme intelligence: data layer active, user activation pending Day 31
Phase 2 Pending
- Model learning loop (Feature 4.1 spec exists)
- Player selector UI completion (Cowork handles design)
- Full parlay probability UI integration
- Real-time lineup watch CRON implementation
- Evolution watch UI on ledger page
- Pre-registered predictions system activation
- Physical ledger fulfillment
- Education library content
Manual Actions Required
- Paste SQL migrations 003-010 in Supabase SQL Editor (in order)
- Run
node scripts/seedRoleProfiles.jsafter NBA API access configured - Set Stripe env vars (STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, price IDs)
- Set NEXT_PUBLIC_POSTHOG_KEY env var for PostHog analytics
- Set ODDS_API_KEY env var for Odds API
- Set SUPABASE_URL + SUPABASE_SERVICE_ROLE_KEY for Python service
- Deploy Next.js frontend to Vercel
- Start Python service:
cd src/services/python && pip install -r requirements.txt && python3 app.py - Set up GitHub Actions crons: lineup monitoring (15min), morning odds (10am ET), pre-game odds (90min), weather (30min), nightly resolution (2am ET)
- Run cold_start_boot() on first launch (seeds reporters, loads data files)
- SHADOW_MODE=True for first 2 weeks — grades logged but not published to capper
Session Log
Sessions 1-6 — 2026-03-21/22
- Built all backend: Phase 1 + Phase 2 + Feature 1.5
- 221 backend tests passing
Session 7 — 2026-03-22
- Built Feature 3.1: Landing page + blog (Hero, Pricing, Blog/MDX, Auth pages)
- Built Mastermind Agency Site (glitch aesthetic, 5 pages)
- Built Features 3.2 + 3.3: Scan UI + Bet Tracker
- Built Feature 3.4: Stripe Integration (checkout, webhooks, portal, founder codes)
- ALL FEATURES COMPLETE
- Total: 237 tests (210 Node.js + 27 Python), all green
Session 8 — 2026-03-28
- Built all 12 Phase 1 additions in single session
- 68 new tests (305 total), all green
- New services: roleProfileEngine, roleStabilityEngine, similarityEngine, evolutionEngine, lineDiscrepancyDetector, altLineScanner, bayesianEngine, modelTrainer, correlationMath, mlbGrader, mlbKillConditions, mlbStatsClient
- New routes: stats, props, waitlist
- New frontend: LivePropsStrip, ledger page, marketplace page
- New constants: founderNote, mlbParks
- New middleware: mission header
- Migration 003: 7 new tables with indexes and RLS
- Python microservice: evolutionEngine.py (Flask/PELT on port 5001)
- ARCHITECTURE.md v1.0 created
Session 9 — 2026-04-12
- Built 4 Phase 1 Part 2 additions
- 52 new tests (357 total), all green
- New component: SimplifiedSelector (sport toggle, player search, stat dropdown, line pre-fill)
- PostHog analytics: 5 tracked events, initialized in layout.tsx
- Migration 004: 4 affiliate tables (referral_codes, referral_conversions, affiliate_payouts, wallet_addresses)
- New service: schemeClassifier.js (PnR coverage classification, 6hr cache, graceful degradation)
- Scheme intelligence: data layer active, user activation pending Day 31
Session 10 — 2026-04-13 (SHIP BUILD v5.1)
- Built complete dual-sport grading engine from vyndr-SHIP.md spec
- 187 new tests (544 total), all green across 38 test suites
- Phase 1 — Infrastructure:
- Flask app.py with blueprints, health check, rate limiting (60/min default, 20/min grade), flask-cors, /api/docs
- evolutionEngine.py moved to blueprints/evolution.py (structural only — logic unchanged)
- utils: retry.py, data_warehouse.py (game-day TTL), bayesian.py (per-stat-type weights, skewness, data sufficiency curve), edge_calculator.py (real edge + quarter-Kelly), context_aggregator.py (15 factors), similarity.py (min 0.7), regime_detector.py (disabled <20 games), blind_spot_detector.py (worst 5%), supabase_client.py
- Data files: park_factors.json (30 parks, lat/lng, roof_status), reporter_database.json (80+ handles), timezone_map.json (30 arenas), grade_thresholds.json, odds_api_config.json
- requirements.txt with all 15 dependencies
- Cold start boot sequence with reporter seeding
- Phase 2 — Data Sources:
- blueprints/synergy.py (team play types, matchup, tracking, defensive scheme)
- blueprints/nba_context.py (teammate impact, game script, home/road, rest/travel, matchup pace, foul trouble, B2B stat-specific, positional defense, usage-efficiency, playoff modifiers, NBA sub-scores endpoint)
- blueprints/lineup_intelligence.py (3-source architecture, reporter trust tiers, tweet parsing, two-stage grading, reporter-line correlation)
- blueprints/odds_scanner.py (free tier 2 pulls/day, odds warehouse, line movement detection, slate scanner)
- utils/weather.py (Open-Meteo, continuous 30min, dome detection, regrade triggers)
- utils/archetypes.py (5 pitcher dimensions, 5 batter dimensions, 6 NBA dimensions — ALL with weight_profiles, batting order, batter approach, pitcher identity, weight blending)
- schemeClassifier.js enhanced: Synergy-first with regex fallback, backward compatible
- Phase 3 — Grading Engines:
- blueprints/mlb.py (14-step pipeline, pitcher/batter profiles, ABS challenge system with player-specific discipline score, TTO decay, platoon-specific opponent quality, lineup protection, day/night, bullpen state, catcher framing)
- blueprints/image_grade.py (OCR pipeline with low-confidence confirmation)
- utils/sportsbooks.py (10 books, parlay grading with correlation check, phi coefficient)
- utils/capper.py (pick numbers, breaking alerts, daily recap, miss autopsy)
- Phase 4 — Self-Improving Loop:
- blueprints/resolution.py (nightly job: actuals from nba_api/MLB-StatsAPI, hit/miss, CLV, alignment, joint outcomes, calibration triggers)
- blueprints/calibration.py (point-biserial weights, global offset, Brier score, blind spots, CLV/alignment reports)
- Phase 5 — Database + Tests:
- Migration 005: lineup_scheme_data
- Migration 006: nba_data_cache, mlb_data_cache, grade_outcomes (ALL ship columns incl discipline_score, CLV, alignment), player_calibrated_weights
- Migration 007: lineup_updates, reporter_trust (with source_type + starting_trust), odds_warehouse, ship_line_movements, reporter_line_correlation, api_health_log, global_calibration, ship_joint_outcomes
- 5 new test files covering infrastructure, grading engine, data sources, resolution pipeline, scheme classifier enhancement
- Key Spec Compliance:
- Grade thresholds LOCKED (A+ through F)
- SHADOW_MODE = True (first 2 weeks)
- Bayesian weights are INITIAL ESTIMATES (marked as such)
- Abstention check BEFORE data cap
- Point-biserial bounds 0.05-0.50, global offset ±0.15
- Real edge with vig + quarter-Kelly
- Brier + CLV from day one
- Capper A- and above ONLY
- ABS is CHALLENGE system (successful challenges don't deplete)
- Foul trouble widens std, not mean
- Stat-specific B2B adjustments
- Matchup-specific pace (home 60/40)
- Positional defense (tracking > roster position)
- Usage-efficiency tradeoff (-1.5% TS per +5% usage)
- Tier limits documented but NOT enforced (gate manually later)
- Node.js stays Node.js, Python is data/utility layer via HTTP
Session 10c — 2026-04-13 (FINAL INTEGRATION PATCH)
- Applied 15-item integration patch — wiring + features + infrastructure
- 35 new tests (644 total), all green across 40 test suites
- Wiring (items 1-5):
- Scratch → redistribution → re-grade → alt line scan → alert chain in lineup_intelligence.py
- Slate scan → alt line auto-scan for A-grades in odds_scanner.py
- Nightly resolution steps 14-18: coaching update, player-out history, evolution scan, unconventional data collection, monthly validation
- Migration 009: supplement columns on grade_outcomes (coaching_context, redistribution_context, evolution_flag, alt_line_opportunity, unconventional_factors) + unconventional_factor_data table
- API docs updated with 7 supplement endpoints
- Features (items 6-10):
- MLB lineup shift logic (PA multiplier changes when player scratched)
- high_leverage_hook_tendency added to MLB coaching schema
- Evolution persistence check (3 games before public promotion, false positive detection)
- Unconventional daily data collection + monthly validation functions
- Alt line ladder mode (ALT_LINE_MODE env var — 'manual' generates probability ladder)
- Infrastructure (items 11-15):
- 5 GitHub Actions YAML files: nightly (2am ET), morning odds (10am ET), pre-game (3pm/5pm/6:30pm ET), reporter poll (every 15min), weather (every 30min)
- scripts/seed_historical.py — one-time historical data seeder (NBA 2024-25 + MLB 2024)
- railway.toml (Flask service, port 5001, health check)
- web/vercel.json (Next.js deployment)
- MLB coaching helper functions for historical seeding
- Product is DEPLOYMENT-READY
Session 10d — 2026-04-13 (SECURITY AUDIT)
- Applied 19-item security hardening pass — Ryan Montgomery panel reviewed
- 45 new tests (689 total), all green across 41 test suites
- Authentication (items 1, 8, 11):
- utils/auth.py: require_auth (JWT with issuer check) + require_service_role (BETONBLK_INTERNAL_KEY)
- PyJWT added to requirements.txt
- BETONBLK_INTERNAL_KEY separates cron auth from service key — service key never leaves Railway
- Input Security (items 3, 10, 13):
- utils/validation.py: whitelist stat types, sanitize strings (strip SQL/HTML), validate line 0-500, image upload (magic bytes, 10MB max, PNG/JPEG/GIF), parlay legs 2-12
- OCR rate limit 3/min, max 2 concurrent
- MAX_CONTENT_LENGTH 1MB globally, 413 JSON response
- Network Security (items 2, 12):
- CORS locked to ALLOWED_ORIGINS env var (no more wildcard)
- Real IP from X-Forwarded-For for rate limiter and security logger
- Error Handling (item 9):
- Production returns generic "Internal server error" — no stack traces
- 404, 405, 413, 429 all return JSON
- Monitoring (items 4, 5, 6, 15, 17, 18):
- Security headers: X-Frame-Options DENY, HSTS, CSP, nosniff, XSS protection, Server removed
- utils/security_logger.py: request logging, rate tracking, SQL injection detection, security_events table
- utils/env_check.py: startup validation, exits on missing required vars, never logs secrets
- security-scan.yml: weekly pip-audit + npm audit
- security.txt: /.well-known/security.txt with contact
- 90-day security event retention cleanup + weekly security digest (50+ events per IP = action required)
- Infrastructure (items 7, 14, 16, 19):
- Migration 010: security_events table with RLS
- Supabase client timeout guidance, retry with 30s default timeout
- Source code secret scan test (sk_live_, eyJhbGci, sbp_)
- .gitignore: .env, .env.local, .env.production, *.pem, *.key, .vercel/
Session 10b — 2026-04-13 (SUPPLEMENT BUILD)
- Built 5 intelligence supplement systems — ADDITIVE, no existing code modified
- 65 new tests (609 total), all green across 39 test suites
- System 1 — Coaching Tendency Database:
- blueprints/coaching.py (NEW) — per-coach NBA + MLB tendencies, nightly update from game logs, shift detection (15%+ threshold on last 15 vs season baseline)
- 12 NBA fields (pace, 3PT rate, ISO freq, PnR usage, rotation depth, late-game player, score-state lineups, second-unit patterns, redistribution profile, shot location, timeout tendency)
- 10 MLB fields (starter hook, quick hook, bullpen philosophy, IBB rate, PH freq, bunts, closer-only, platoon, lineup consistency, challenge aggressiveness)
- System 2 — Usage Redistribution Engine:
- blueprints/redistribution.py (NEW) — two-layer calculation (Layer A: minutes redistribution from historical player-out data + coaching rotation depth; Layer B: offensive system change from archetype shifts)
- Uses coaching database, applies usage-efficiency tradeoff (-1.5% TS per +5% usage)
- Three tiers: primary (>=0.20 boost, >=0.75 confidence), secondary (>=0.10, >=0.60), tertiary (>=0.05)
- Auto-grades at 15%+ boost / 0.65+ confidence, formats 60-second absorption alerts
- System 3 — Alt Line Scanner:
- Added to existing odds_scanner.py — auto-runs on A-grade props after slate scan
- Pulls alt lines from odds_warehouse, calculates model probability via Bayesian norm_cdf
- Real edge with vig on each alt, finds optimal (best EV/dollar)
- Only recommends if alt edge exceeds standard by 3%+
- System 4 — Unconventional Data Pipeline:
- blueprints/unconventional.py (NEW) — validation gate for non-traditional correlates
- 500 instance minimum, Pearson r > 0.15, Bonferroni-corrected p-value
- 5 tracked factors: altitude, contract year, referee crew history, travel distance (pre-validated), arena altitude
- Factors only enter grading engine AFTER passing validation
- System 5 — Player Evolution Alerting:
- Added to existing evolution.py — daily scan across multiple metrics simultaneously
- NBA: usage_rate, assist_rate, three_pa_rate, fg_pct, minutes
- MLB: k_rate, bb_rate, exit_velocity, hard_hit_pct, fb_velo
- PLAYER_EVOLUTION_DETECTED when 2+ metrics show concurrent inflection (10%+ change, 15 game minimum)
- Timestamped records in evolution_detections table, Evolution Watch content formatter
- Migration 008: coaching_tendencies, player_out_history, evolution_detections, unconventional_validations (all with indexes + RLS)
- Integration: 3 new blueprints registered in app.py (coaching_bp, redistribution_bp, unconventional_bp), evolution + odds_scanner extended with new endpoints