Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7.2 KiB
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/summary → expected_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/*behindVYNDR_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=0kills); desk-ready ping after the day's first slot; daily pulse 13:00 UTC; missed-cron + 3-slot-failure + quota pagers → ntfyvyndr-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 001–022 applied, files insupabase/migrations/). - Deploys: gitea
git.builtbykev.com/builtbykev/vyndr→ Coolify webhook (HMAC secret fixed Jul 11; auto-deploy proven). GitHuboriginremote 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)
SNAPSHOT_EXPECTED_INTERVAL=1200— confirmed absent (fresh restart still served the 18000 default). SYNC badge tracks intraday cadence once set.DESK_OWNERS=kevdevelops@gmail.com— /desk 403s everyone until set.LISTMONK_URL/LISTMONK_USER/LISTMONK_TOKEN/LISTMONK_LIST_ID(all four together) — newsletter no-ops politely without them; box-side setup indocs/NEWSLETTER.md.- 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 3–4 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 —