RDEV STUDIO / DRAFT ANALYSER
DRAFT
Under the hood
How it's built
Both FPL APIs block browsers, so nothing in the page ever calls them. A daily cron writes into Supabase; the pages read Postgres. The live gameweek page is the exception - Vercel Hobby cannot run every five minutes, so that route hits the live endpoint server-side, stores the snapshot, and pushes it over Pusher when credentials exist. The tab also polls once a minute.
Availability, 0-100
base = { a:100, d:55, i:5, s:0, u:0, n:15 }[status]
cop = chance_next ?? chance_this ?? null
score = cop != null ? 0.55 * base + 0.45 * cop : base
score -= newsPenalty(news, age) // official FPL text only
score += minutesTrend(last4) // 0 until per-match minutes exist
score += reportedAbsence(signal) // RSS/Claude, labelled reported
score = clamp(0, 100)
if status == i: score = min(score, 40) // unofficial reports cannot green an injury
green >= 75 amber 40-74 red < 40Projected points
pStart = 0.55 * availability/100 + 0.45 * starts_per_90
xP = pStart * (appearance + xG * goalPts + xA * 3
+ CS_prob * csPts + defconProb * 2 + bonus)
fixMult = {1:1.25, 2:1.12, 3:1.00, 4:0.88, 5:0.75}[FDR]
Scoring values come from bootstrap settings, not hardcoded 10s.News layer
Daily cron pulls BBC/Guardian RSS (feeds and summaries only), keeps items from the last 48 hours, and asks Claude for a structured availability signal per club. Matches are scoped to that club. Stored rows never overwrite official FPL status, news, or chance fields. The UI labels every extract reported, not confirmed.
What is not here yet
- Per-match minutes history, so the availability minutes-trend term stays at zero.
- True five-minute in-play cron. Hobby is daily; on Pro set
/api/cron/liveto*/5 * * * *. Until then the live page refreshes itself, with Pusher when configured.