Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
13 KiB
VYNDR — STATE OF THE WORLD
As of e9c0a59 (main) + wiring/data-train READY, 2026-07-13. This file opens every future session. Update it when a train ships.
READY TO MERGE — WIRING & DATA TRAIN (branch wiring/data-train, NOT on main yet)
Governed by specs/wiring-data-train.md (the Step-0 MAP + build plans) + specs/combat-intelligence.md + the global visual reference specs/design-reference/vyndr-system.html (build toward it; live wordmark kept). All 6 waves DONE, merged onto wiring/data-train, green (253 suites / 3069 tests) + next build exit 0. Awaiting the founder's word before main. Real assets verified live (MLB/ESPN headshot CDNs, ESPN-MMA feed, Baseball Savant CSV).
- Wave 1 — trust bugs: billing renewal honest render (
billingDisplay.classifyRenewal— no far-future placeholder); James Wood nameKey-collision fixed (mlbStatsAdapterteamHint disambiguation + streaks join-invariant); DeskShowcase "$1M terminal" → deadpan copy. - Wave 2 — sport-agnostic entity layer: real player headshots threaded from ingestion (MLB MLBAM + NBA/WNBA ESPN athlete ids that were fetched-and-discarded) across slate/scan/hotlist/search/grade card; soccer = honest monogram (no free id); 8 self-authored SVG book wordmarks (
web/public/books/*.svg, swappable for official art) + all 10 book keys resolve; team-logo abbr aliases. Storage: id on theenrichedgrade atsnapshotService(zero new I/O). - Wave 3 — record by grade tier (Addition 2): ONE shared
TierRecord(lib/tierRecord.js+ component) on dashboard + /u + ledger; per-tier W-L always, hit-% only at n≥20 per tier (gate stays ingetModelAggregate). - Wave 4 — missing surfaces: Outlook mode (grid never blank → yesterday receipts / tomorrow schedule); Market-Breadth median-consensus-vs-model strip (self-hides <2 books); Parlay Lab
/parlay(slate-independent leg source); live Grade-Shift timeline (GradeShift). - Wave 5 — /u house-mode + arsenal: house handle
vyndrsurfaces the realuser_id=NULLpublic model record + per-tier calibration + 1080×1350 portrait/OG (user-handle privacy 404s stay byte-identical); Baseball Savant pitcher-arsenal (savantAdapter, free CSV, verified) →PitcherArsenalcard, self-hides on absent. - Wave 6 — combat v1 (MMA): ESPN-MMA fight cards + tale-of-the-tape + style-blend archetypes (sport-scoped
COMBAT_ARCHETYPES— FINISHER color collided w/ soccer + tripped the ΔE gate, so kept separate) + odds-api ML/round-totals + style-edge verdict. NOT in the snapshot/settle loop; method/round/props + fighter photos + matchup-GRADE engine + ufcstats scraping all DEFERRED, flagged data-limited in-UI. New routes:/fight/[id],/parlay,/u/[handle]/portrait. POST-MERGE TODO: NBA/WNBA headshot coverage + combat depth need prod runtime verification; soccer headshots blocked onAPI_FOOTBALL_KEY; combat settlement + matchup-grade engine are the next combat sub-wave.
SHIPPED — DESIGN TRAIN v2 (merged to main e9c0a59, deployed & fingerprint-verified live)
Governed by specs/DESIGN-SPEC.md v2 (the raised standard: entities render as
themselves, color contract, sub-200ms, screenshot-first billboards). All six
sessions DS0–DS5 shipped: merged to main, pushed to gitea, Coolify auto-deploy
LANDED — verified live via /pricing DeskShowcase ("A $1M terminal") + /u
route serving the unified EmptyState. 238 suites / 2885 tests green,
next build exit 0. Post-ship TODO: re-run the Chrome design audit against
prod v2 to confirm all 22 audit findings closed (env here can't screenshot —
WSL2↔Windows-Chrome localhost unreachable).
- DS0 Entity Layer (
24af247):teamMeta.js(real logos+colors for 30 MLB / 30 NBA / 13 WNBA / 48 WC nations via ESPN CDNs),TeamLogo/PlayerAvatar(team-colored monogram fallback, no gray silhouette) /BookWordmark, swapped into GameCard/StatStrip/StreaksPanel/TeamHub. - DS1 Speed + Trust Bugs (
1c681df): React #418 hydration fix (mounted-flag guard), layout-matchedSkeletons replace text-wall loaders, scan→ledger persistence viasession.access_token. DS1 follow-up (cf91c04): closed the sb-token trust-bug CLASS —lib/authToken.jscurrentAccessToken()reads the REAL Supabase session (not the OAuth-onlysb-tokenkey) across profile/slip/dashboard/settings/tracker. - DS3 Color Contract (
49a3323):lib/colorContract.js— green = one meaning (edge/A-tier/CTA), edge/CLV by sign, glow A/A+ only, archetype greens deduped. Enforced bycolorContract.test.js(fails on violation). - DS4 Billboards (
45bafbc): STREAKS row (length as mono hero), grade reveal (sign-colored edge), CLV reframe (flat says so),/upublic profile + OG. - DS2 Dashboard Slate Rebuild (
fe294a5): never-empty hero (falls back to yesterday's A-tier settled receipts), one bold hero per card, pending-filler collapse, ranked tonight-grades.slateAdapter.jsengine + 21 tests. - DS5 Pricing + Motion + States (
a18a3f3): Desk $44.99 as the hero tier (single green CTA,DeskShowcase), ticker → punctuated stillness (≥4.2s hold, one idle motion), unifiedEmptyState(404 grammar) at TeamHub/game/ledger, archetype glyphs propagated to streaks/ledger. NOTE: WSL2↔Windows-Chrome localhost is unreachable in this env, so visual proof was SSR-render + source-assertion tests + live prod fingerprint curls, not pixel screenshots. Thedesign/v2-train+ per-DS worktree branches can be pruned. StaleoriginGitHub remote still carries the long-dead leaked PAT — deploy runs offgitea, so it's inert, but rotate it when convenient.
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 —