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:
@@ -0,0 +1,68 @@
|
||||
// Session 60 (night2/G) — the aggregator's content formats (spec §12).
|
||||
// streak-watch is the ZERO-GRADE daily format; daily-report flags itself
|
||||
// DO-NOT-POST until the record is real (n>=20).
|
||||
|
||||
const express = require('express');
|
||||
const request = require('supertest');
|
||||
|
||||
const mockStore = new Map();
|
||||
jest.mock('../../src/utils/redis', () => ({
|
||||
cacheGet: async (k) => (mockStore.has(k) ? mockStore.get(k) : null),
|
||||
cacheSet: async (k, v) => { mockStore.set(k, v); return true; },
|
||||
getRedisClient: () => null,
|
||||
isDegraded: () => true,
|
||||
}));
|
||||
jest.mock('../../src/services/rosterLogs', () => ({ loadRosterLogs: jest.fn(async () => []) }));
|
||||
const { loadRosterLogs } = require('../../src/services/rosterLogs');
|
||||
|
||||
function mountApp() {
|
||||
delete require.cache[require.resolve('../../src/routes/content')];
|
||||
const app = express();
|
||||
app.use('/api/content', require('../../src/routes/content'));
|
||||
return app;
|
||||
}
|
||||
|
||||
beforeEach(() => { mockStore.clear(); jest.clearAllMocks(); });
|
||||
|
||||
describe('GET /api/content/top-signals/:sport', () => {
|
||||
test('returns tonight top graded props from the snapshot cache', async () => {
|
||||
mockStore.set('snapshot:mlb:latest', {
|
||||
updated_at: 'x',
|
||||
grades: [
|
||||
{ player: 'Aaron Judge', stat_type: 'home_runs', line: 0.5, direction: 'over', grade: 'A', confidence: 80, gradedAt: { timestamp: 't1' } },
|
||||
{ player: 'Settled Guy', stat_type: 'hits', line: 1.5, grade: 'A', confidence: 90, outcome: { result: 'hit' } },
|
||||
],
|
||||
});
|
||||
const res = await request(mountApp()).get('/api/content/top-signals/mlb');
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body.dataLevel).toBe('full');
|
||||
expect(res.body.signals).toHaveLength(1); // settled props excluded
|
||||
expect(res.body.signals[0].player).toBe('Aaron Judge');
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /api/content/streak-watch/:sport', () => {
|
||||
test('the zero-grade format: real streaks through the lens', async () => {
|
||||
loadRosterLogs.mockResolvedValue([
|
||||
{ name: 'Streaky Guy', team: 'Tampa Bay Rays', games: [
|
||||
{ date: '2026-07-10', opponent: 'Boston Red Sox', hits: 2 },
|
||||
{ date: '2026-07-09', opponent: 'Boston Red Sox', hits: 1 },
|
||||
{ date: '2026-07-08', opponent: 'New York Yankees', hits: 1 },
|
||||
] },
|
||||
]);
|
||||
const res = await request(mountApp()).get('/api/content/streak-watch/mlb');
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body.dataLevel).toBe('full');
|
||||
expect(res.body.streaks[0].player).toBe('Streaky Guy');
|
||||
expect(res.body.streaks[0].read).toContain('hit streak');
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /api/content/daily-report/:sport', () => {
|
||||
test('flags DO-NOT-POST while the record is building', async () => {
|
||||
const res = await request(mountApp()).get('/api/content/daily-report/mlb');
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body.do_not_post).toBe(true);
|
||||
expect(res.body.reason).toContain('record building');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user