S2 (a1): compliance + approval pack

- /responsible-gambling rebuilt sincerely: 21+, 1-800-GAMBLER primary,
  17-state resource list, warning signs, self-exclusion guidance, links
  to the existing /settings surfaces. No marketing adjacency.
- /terms + /privacy honest drafts with entity placeholders ([ENTITY NAME],
  [STATE OF FORMATION], [ARBITRATION VENUE], [CONTACT EMAIL]); privacy
  sub-processors match reality (adds Sentry, honest PostHog description).
- NEW /methodology: pipeline -> engine -> letter grades, refusals,
  VYNDR Originals, ledger settle + CLV + n>=20, why misses are public.
- /about audited to North Star framing (THE PROOF card, methodology link).
- Footer: 1-800-GAMBLER + Methodology link; compliance audit found zero
  pages suppressing the global footer.
- 5 Ghost seed articles in content/articles/ + docs/GHOST-PUBLISHING.md
  manual runbook (no Ghost access used).
- tests/unit/compliancePages.test.js (repo source-text style). 2429 tests
  green, web build exit 0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kev
2026-07-11 14:29:31 -04:00
parent e4d2e79f95
commit 4b262fdd65
15 changed files with 908 additions and 76 deletions
+173
View File
@@ -0,0 +1,173 @@
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Methodology',
description:
'How VYNDR grades a prop, what archetypes are, how the Ledger settles, and why the misses are public. Plain language, no hype.',
};
// Session 2 (A1 board) — the approval-pack methodology page. Server component.
// Plain-language description of the real pipeline (feature vector → engine →
// letter grade → locked ledger entry → box-score settle → CLV). Every claim
// here matches the code; if the pipeline changes, change this page in the
// same commit.
const h2: React.CSSProperties = { fontSize: 20, fontWeight: 700, marginBottom: 12, color: 'var(--text-0)' };
const body: React.CSSProperties = { color: 'var(--text-1)', lineHeight: 1.75, fontSize: 15, marginBottom: 12 };
const card: React.CSSProperties = {
background: 'var(--bg-1)',
border: '1px solid var(--border)',
borderRadius: 10,
padding: '16px 18px',
};
function Mono({ children }: { children: React.ReactNode }) {
return <span className="mono" style={{ color: 'var(--text-0)' }}>{children}</span>;
}
export default function MethodologyPage() {
return (
<section style={{ maxWidth: 720, margin: '0 auto', padding: '48px 16px 120px' }}>
<header style={{ marginBottom: 32 }}>
<h1 style={{ fontSize: 36, fontWeight: 700, letterSpacing: '-0.03em', marginBottom: 8, color: 'var(--text-0)' }}>
How the grades work.
</h1>
<p className="mono" style={{ fontSize: 12, color: 'var(--text-2)', letterSpacing: '0.05em' }}>
METHODOLOGY · PLAIN LANGUAGE · NO HYPE
</p>
</header>
<p style={{ ...body, fontSize: 16 }}>
This page describes what actually happens between a sportsbook posting a line and a letter
grade appearing on VYNDR. It is written so a claim made here can be checked against the
Ledger. If a sentence on this page ever stops being true, the page is wrong and we fix it.
</p>
{/* ── The pipeline ─────────────────────────────────────────── */}
<section style={{ marginTop: 36 }}>
<h2 style={h2}>The pipeline</h2>
<p style={body}>
Grades are produced by a scheduled pipeline, not on demand. Several times a day the
system pulls the current prop lines from sportsbook feeds, then builds a feature vector
for each prop the numbers the model reasons over. Depending on the sport, that includes
recent form (last-5 and last-20 averages, variance), opponent strength against the exact
stat, pace, home or away, rest days, schedule density, batter-versus-pitcher history for
MLB, and per-90 rates with expected-goals context for soccer.
</p>
<p style={body}>
The engine compares the model&apos;s projection to the posted line in both directions.
It grades the over and the under separately and keeps whichever side it has more
conviction in. The output is an 11-step letter grade, <Mono>F</Mono> through{' '}
<Mono>A+</Mono>, with a confidence score behind it. The letter is a probabilistic
assessment of one side of one line. It is not a prediction and it is never a guarantee.
</p>
<div style={card}>
<p className="mono" style={{ fontSize: 12.5, color: 'var(--text-1)', lineHeight: 1.8, margin: 0 }}>
LINE FEED FEATURE VECTOR PROJECTION vs LINE (BOTH SIDES) LETTER GRADE LOCKED TO
THE LEDGER SETTLED vs THE BOX SCORE
</p>
</div>
</section>
{/* ── Refusals ─────────────────────────────────────────────── */}
<section style={{ marginTop: 36 }}>
<h2 style={h2}>When the model refuses</h2>
<p style={body}>
If the pipeline cannot build a real projection for a prop not enough recent games, no
per-90 baseline, a data source down the model refuses to grade it. No letter renders,
the prop shows an absent state, and a free read is not consumed. A refusal is not a
failure mode we hide; it is the design. A grade with nothing behind it would still look
like a grade, and that is worse than no grade.
</p>
<p style={body}>
The same rule applies to every number on the platform: market values (lines, odds,
closes) are real book numbers captured at a timestamp, never computed by us. Model values
are labeled as model output. Where data is missing, the surface says less.
Absent beats wrong.
</p>
</section>
{/* ── Archetypes ───────────────────────────────────────────── */}
<section style={{ marginTop: 36 }}>
<h2 style={h2}>Archetypes the VYNDR Originals</h2>
<p style={body}>
Archetypes are VYNDR&apos;s proprietary classification of how a player produces 41
originals across NBA, WNBA, MLB, and soccer, built by scoring each player&apos;s real
season statistics against production patterns. A <Mono>TORCH</Mono> is a high-usage,
shot-dependent scorer whose points track his touches. A <Mono>BOMBER</Mono> is a power
bat whose home-run and total-base props behave differently from a contact hitter&apos;s.
A <Mono>GHOST</Mono> beats you with speed. A <Mono>CONDUCTOR</Mono> creates for everyone
else first.
</p>
<p style={body}>
The point is practical, not decorative: different archetypes have different reliable and
volatile props. Points for a TORCH and assists for a CONDUCTOR are stable; the inverse
legs swing with game script. Each classification carries a primary archetype, an optional
secondary, and a weighted blend because most players are not one thing. The
classification comes from the same stats pipeline that feeds the grades, so an archetype
is re-earned from real numbers, not assigned once and left to rot.
</p>
</section>
{/* ── The Ledger ───────────────────────────────────────────── */}
<section style={{ marginTop: 36 }}>
<h2 style={h2}>How the Ledger settles</h2>
<p style={body}>
Every grade the pipeline produces is written to the Ledger at the moment it is made,
locked with the exact line, the odds, and a timestamp. That entry never changes. If the
line moves hard against a graded side later in the day, the system may re-grade at the
real new line and when it does, the original letter stays on the record, struck
through, next to the revision. Nothing is revised silently.
</p>
<p style={body}>
After the games end, entries settle against the real box score the stat the player
actually produced, from league data. Hit, miss, or push, recorded once, idempotently.
Alongside the result we record closing line value: the pipeline captures the closing
line for each graded prop (the last pre-game snapshot of the book&apos;s number) and
measures whether the market moved toward or away from the graded side between our
timestamp and the close. Beating the close consistently is the standard evidence that a
model is finding real edge rather than getting lucky, which is why we track it on every
entry instead of just counting wins.
</p>
<div style={card}>
<p className="mono" style={{ fontSize: 12.5, color: 'var(--text-1)', lineHeight: 1.8, margin: 0 }}>
THE n20 RULE no hit percentage or CLV percentage renders anywhere on VYNDR until at
least 20 grades have settled in that window. Below that, the surface says
RECORD BUILDING. A percentage on a small sample is a marketing number, and we do not publish
marketing numbers.
</p>
</div>
</section>
{/* ── Misses ───────────────────────────────────────────────── */}
<section style={{ marginTop: 36 }}>
<h2 style={h2}>Why the misses are public</h2>
<p style={body}>
Every settled miss stays on the Ledger, by name, in the same format and the same
placement as the wins, permanently. There are two reasons. The honest one: a record you
curate is not a record, and the entire value of this product rests on the record being
real. The practical one: nobody else in this industry can afford to do it, because their
numbers do not survive it. Ours are built to. The model is wrong regularly the Ledger
shows exactly how regularly, and that transparency is the product working as intended,
not a bug in it.
</p>
</section>
{/* ── What we never do ─────────────────────────────────────── */}
<section style={{ marginTop: 36 }}>
<h2 style={h2}>What we never do</h2>
<ul style={{ display: 'grid', gap: 8, ...body, paddingLeft: 18, listStyle: 'disc' }}>
<li>Fabricate a line, an odd, or a result. Market numbers are captured, never invented.</li>
<li>Ship a grade the model has no projection for.</li>
<li>Render a percentage on fewer than 20 settled grades.</li>
<li>Edit or delete a settled entry, win or miss.</li>
<li>Take a bet. VYNDR is an analytics tool, not a sportsbook.</li>
</ul>
<p style={{ ...body, marginTop: 8 }}>
The record is at <a href="/ledger" style={{ color: 'var(--text-0)' }}>vyndr.app/ledger</a>.
Draw your own conclusion.
</p>
</section>
</section>
);
}