Session G (night2): Phase 6 — landing first-paint + content engine + OG

6.1 FIRST-PAINT ROOT CAUSE: the landing blocked its ENTIRE render on
    Supabase auth init ('loading || user') — anonymous visitors stared at
    'LOADING THE SLATE' for the whole auth roundtrip (~3-4s). Now a
    synchronous localStorage session check gates the suppression: only
    visitors who actually hold a session (and will redirect) wait;
    anonymous traffic paints the hero immediately. Full RSC conversion of
    the hero is deferred and logged — the blocker itself is dead.
    Proof Strip rules: top-3 by grade whatever they are; 'TONIGHT'S TOP
    SIGNALS' only with >=1 A-tier, else 'TONIGHT'S BOARD'; nothing graded
    yet → yesterday's SETTLED reads with outcome chips (misses included).
6.2 Content routes: /api/content/top-signals/:sport,
    /streak-watch/:sport (the zero-grade daily format off the aggregator),
    /daily-report/:sport — built but self-flagging do_not_post until the
    record clears n>=20. Flag, don't fake.
6.3 Per-player OG images: app/player/[name]/opengraph-image.tsx (Node
    runtime per the S53 rule) + server layout generateMetadata — every
    shared player link unfurls as an intelligence card.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kev
2026-07-11 02:26:45 -04:00
parent f110bd63f1
commit 1b4f2772d6
6 changed files with 285 additions and 9 deletions
+34 -5
View File
@@ -22,6 +22,8 @@ interface SnapGrade {
grade?: string;
confidence?: number;
archetype?: string | null;
// Session 60 (6.1) — settled outcome (yesterday's-proof fallback rows).
outcome?: { result: string; actual?: number | null } | null;
}
const SPORTS = ['mlb', 'nba', 'wnba'] as const;
@@ -38,6 +40,7 @@ const isTop = (g?: string) => g === 'A+' || g === 'A';
export default function TopSignals() {
const [signals, setSignals] = useState<SnapGrade[] | null>(null);
const [header, setHeader] = useState<'signals' | 'board' | 'proof'>('board');
useEffect(() => {
let active = true;
@@ -52,12 +55,28 @@ export default function TopSignals() {
);
if (!active) return;
const all: SnapGrade[] = [];
const settled: SnapGrade[] = [];
for (const res of results) {
const grades = res && Array.isArray(res.grades) ? res.grades : [];
for (const g of grades) if (isTop(g.grade)) all.push(g);
for (const g of grades) {
if (g.outcome) settled.push(g);
else if (g.grade) all.push(g);
}
}
all.sort((a, b) => (Number(b.confidence) || 0) - (Number(a.confidence) || 0));
setSignals(all.slice(0, 3));
// Session 60 (6.1) — never oversell: top 3 by grade whatever they
// are, but the TOP SIGNALS header only with ≥1 A-tier; otherwise
// "TONIGHT'S BOARD". Nothing graded yet → yesterday's settled reads
// WITH outcome chips (the proof strip carries the slate).
if (all.length > 0) {
setSignals(all.slice(0, 3));
setHeader(all.some((g) => isTop(g.grade)) ? 'signals' : 'board');
} else if (settled.length > 0) {
setSignals(settled.slice(0, 3));
setHeader('proof');
} else {
setSignals([]);
}
} catch {
if (active) setSignals([]);
}
@@ -67,16 +86,19 @@ export default function TopSignals() {
return () => { active = false; clearInterval(id); };
}, []);
// Self-hide off-hours (nothing graded A yet) — never an empty shell.
// Self-hide only when there's NOTHING real (no grades and no settles).
if (!signals || signals.length === 0) return null;
const headerText = header === 'signals' ? "TONIGHT'S TOP SIGNALS"
: header === 'proof' ? "YESTERDAY'S SETTLED READS" : "TONIGHT'S BOARD";
const headerSub = header === 'proof' ? '· MISSES INCLUDED' : '· LIVE FROM THE SLATE';
return (
<section style={{ maxWidth: 960, margin: '0 auto', padding: '8px 16px 24px' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap', marginBottom: 12 }}>
<div className="mono" style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 11, letterSpacing: '0.1em', color: 'var(--text-secondary, #8A8A9A)' }}>
<span className="live-dot" aria-hidden style={{ width: 7, height: 7, borderRadius: '50%', background: 'var(--grade-a, #00D4A0)', display: 'inline-block' }} />
<span style={{ color: 'var(--grade-a, #00D4A0)', fontWeight: 700 }}>TONIGHT&apos;S TOP SIGNALS</span>
<span style={{ color: 'var(--text-tertiary, #707080)' }}>· LIVE FROM THE SLATE</span>
<span style={{ color: 'var(--grade-a, #00D4A0)', fontWeight: 700 }}>{headerText}</span>
<span style={{ color: 'var(--text-tertiary, #707080)' }}>{headerSub}</span>
</div>
<AccuracyBadge variant="inline" />
</div>
@@ -104,6 +126,13 @@ export default function TopSignals() {
<div style={{ fontWeight: 700, fontSize: 14, color: '#fff', fontFamily: 'var(--sans, sans-serif)', marginBottom: 4 }}>{player}</div>
<div style={{ fontSize: 12, color: 'var(--text-secondary, #B8BCC8)' }}>
{shortStat(g.stat_type || g.stat)} {side}{g.line}
{/* Outcome chip on the proof-strip fallback — misses included. */}
{g.outcome && (
<span style={{ marginLeft: 8, fontWeight: 700, color: g.outcome.result === 'hit' ? 'var(--grade-a, #00D4A0)' : g.outcome.result === 'miss' ? 'var(--miss, #FF5252)' : 'var(--text-tertiary)' }}>
{g.outcome.result === 'hit' ? '✓ HIT' : g.outcome.result === 'miss' ? '✕ MISS' : ' PUSH'}
{g.outcome.actual != null ? ` (${g.outcome.actual})` : ''}
</span>
)}
</div>
</a>
);