Files
vyndr/specs/STATE.md
T
2026-07-12 13:44:36 -04:00

7.2 KiB
Raw Blame History

VYNDR — STATE OF THE WORLD

As of ec5ee3d (main, 2026-07-12). This file opens every future session. Update it when a train ships.

WHERE THINGS STAND

Tests: 2757 / 229 suites, all green. Web build exit 0. Baseline at the A1 board's start was 2398. Governing docs: specs/VYNDR-NORTH-STAR.md (v1.1) + specs/VOICE.md (v1.1) + specs/ROW-GRAMMAR.md — read them before building anything.

The record is live and writing itself. Day one (Jul 11): 24→25 MLB rows, real locks (line/odds/book), closing capture every snapshot + every 20-min intraday refresh, settlement each morning slot with signed CLV. No percentage renders anywhere under n≥20 — enforced in ledgerService.getModelAggregate, the single gate. WNBA/soccer rows pend honestly until Phase 4.5.

THE THREE A1 TRAINS (all merged to main, all pushed)

Train Range Carried
#1 4d2b27d → 219167e S0 verify · S1 promise audit (PROMISE-AUDIT.md: alt ladder + quarter-Kelly BUILT, analyst unlimited, "40+" claims made honest) · S2 compliance (/responsible-gambling rebuilt, /terms /privacy drafts, /methodology, 5 seed articles in content/articles/) · S3 affiliate (BOOK IT deep links organic-until-config-flip, best-price dots, ?ref= partner attribution) · S4 media engine (mediaEngine + executable VOICE lint, /desk arsenal + DATA BRIEF, Ghost DRAFTS-only publisher) · S5 viability (statsapi lineups → CONFIRMED/NOT-IN kills grades visibly; ESPN injury wire; Yesterday/Today/Tomorrow nav + Settle panel) · S7 newsletter (Listmonk capture + THE VYNDR REPORT assembly, env-gated) · S8 ops (settle alarm, 3-slot failure pager, quota/disk/mem, 9AM pulse — test alert delivered to the real ntfy channel) · S9 slip reader (tesseract.js OCR + per-book parsers, /slip page; synthetic-image acceptance passed) · S10 public profiles (/u/{handle}, private-by-default, no-existence-leak) · migrations 021/022
#2 219167e → 14dc9cf S6 display (ROW-GRAMMAR.md + slot-order fixes, line sparklines from intraday history, last-10 ●●○ dots, CLV distribution on MODEL tab, ⌘K SearchModal + mobile search, landing LCP fixes)
#3 14dc9cf → ec5ee3d S11 live tracking (statsapi/ESPN live box lines → ON PACE / NEEDS N / HIT ✓ in the outcome slot, live games float up, "TRACKING — READ LOCKED PRE-GAME"; real-live acceptance: Harper 3/1.5 TB ▼8th → HIT ✓). Grades never change in-game.

Deploy status: ALL LIVE as of 17fb981 (Jul 12 17:43 UTC). Fingerprints confirmed in prod: /api/live/mlb serves JSON with hasLive:true (S11 live tracking working — a real game was tracked at confirm time), /api/health healthy, /api/snapshot/summaryexpected_interval_s:1200 (env var now set).

P0 postmortem (17fb981): the API silently served a 14h-old image (4d2b27d) from Jul 11 ~20:00 to Jul 12 17:43. Root cause: the Dockerfile never copied content/, and mediaEngine.js read content/stark-lines.json with an unguarded module-load readFileSync → ENOENT at require time crashed app.js's eager route chain (app → routes/desk → deskService → mediaEngine) → boot failed → Coolify healthcheck rolled back. Every merge from S6 onward was merged-but-not-running for 14h. Fixed: Dockerfile COPYs content/; mediaEngine treats the file as optional garnish (loadStark try/catch → {}); src/preflight.js now prints [preflight] OK|DEGRADED at boot so a missing file/env is legible instead of masked by a rollback. LESSON: any module-load file read is a boot-crash risk — keep them lazy + try/catch, and the Dockerfile must copy every dir the runtime reads.

LIVE INFRA MAP (verified in prod)

  • VYNDR Web — Next.js :3000, vyndr.app. VYNDR API — Express :3001, api.vyndr.app (/api/internal/* behind VYNDR_INTERNAL_KEY).
  • Scheduler (in-process, API app, SNAPSHOT_CRON=1) — snapshot slots 14,19,22,1,3 UTC; settle pass (outcomes + ledger, idempotent) runs FIRST each slot; 20-min intraday odds refresh during slate hours (INTRADAY_REFRESH=0 kills); desk-ready ping after the day's first slot; daily pulse 13:00 UTC; missed-cron + 3-slot-failure + quota pagers → ntfy vyndr-pipeline-kev2026. Boot logs: [snapshotScheduler] armed + [settlement] armed.
  • Data: Redis (mastermind-cache) for all pipeline caches (SNAP_TTL 24h — do NOT shorten; the 11h overnight gap killed morning settles once). Supabase = the ledger (ledger_entries + public_profiles + user_profiles.partner_ref; RLS everywhere, service-role-only writes; migrations 001022 applied, files in supabase/migrations/).
  • Deploys: gitea git.builtbykev.com/builtbykev/vyndr → Coolify webhook (HMAC secret fixed Jul 11; auto-deploy proven). GitHub origin remote is dead-PAT hygiene debt only.
  • Free feeds (zero out-of-pocket law): PropLine ×3 keys (9k/day capacity; intraday uses ≤144/day), odds-api backup (quota-gated), statsapi.mlb.com, ESPN site API. tesseract.js OCR self-hosted (traineddata caches on first call — needs outbound network once).

ENV VARS STILL PENDING ON KEV'S SIDE (Coolify, API app)

  1. SNAPSHOT_EXPECTED_INTERVAL=1200confirmed absent (fresh restart still served the 18000 default). SYNC badge tracks intraday cadence once set.
  2. DESK_OWNERS=kevdevelops@gmail.com — /desk 403s everyone until set.
  3. LISTMONK_URL / LISTMONK_USER / LISTMONK_TOKEN / LISTMONK_LIST_ID (all four together) — newsletter no-ops politely without them; box-side setup in docs/NEWSLETTER.md.
  4. Optional: GHOST_URL + GHOST_ADMIN_API_KEY (drafts), PULSE_HOUR_UTC.

Entity placeholders (S2, blocked on Kev's values): [ENTITY NAME], [STATE OF FORMATION], [ARBITRATION VENUE], [CONTACT EMAIL] in web/src/app/terms/page.tsx (6×) + web/src/app/privacy/page.tsx (5×). A test keeps unverified entity names out until replaced.

HONEST OPEN ITEMS

  • Phase 4.5 — WNBA settlement via ESPN box scores. DUE ~Jul 24 (hard date). Until then WNBA/soccer/NBA ledger rows pend forever; accuracy = MLB only.
  • The record needs time: no percentage anywhere before n≥20 settles, by design. First percentages expected ~day 34 of MLB volume.
  • Slip reader: acceptance was a clean synthetic image; needs one real phone screenshot (DK) to validate OCR robustness.
  • Landing LCP: S6's fixes are static-analysis-provable but unmeasured — run PageSpeed mobile vs the 3.8s baseline; next suspect is the LiveHeroProp post-fetch swap.
  • Partner report endpoint returns real numbers only for signups AFTER migration 021 (metadata path live; OAuth signups carry no ref — known gap in docs/PARTNERS.md).
  • NBA Oct / NFL Sep readiness + soccer end-to-end: specs/vyndr-roadmap.md.
  • Killed permanently (founder ruling): AI chat assistant, light mode.

OPERATING LAWS (never relax)

Zero out-of-pocket · absent beats wrong, refusal beats hollow · n≥20 before any percentage · nothing auto-posts anywhere, ever · grades never change in-game (revisions are public via revised_from_grade) · one meaning per color, data in mono · no exclamation points, anywhere · the pipeline is the only source of numbers, including in marketing (mediaEngine lint enforces).

— STATE as of ec5ee3d · the record is writing —