The why behind events: narrative context from the match report
'X is shown the red card' explains nothing. ESPN's summary carries the
full post-match report (Reuters-style narrative) that we fetched and
discarded — it has exactly the missing why ('red-carded for bringing
down Gutierrez just outside the box').
- normalizer keeps the report (headline + plain-text story, schema v4;
boot backfill re-stores played matches automatically)
- expanding an event surfaces the report sentences about that player,
scored by event vocabulary so a player's sending-off sentence beats
his goal mention; attribution line marks the source
- the raw no-reason fallback line is suppressed once the report
explains a booking; xG/momentum/VAR layers stay underneath
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -75,7 +75,7 @@ export interface EspnTimelineEvent {
|
||||
shootout?: boolean;
|
||||
}
|
||||
/** Current normalizer schema — bump to make the boot backfill re-store. */
|
||||
export const SUMMARY_V = 3;
|
||||
export const SUMMARY_V = 4;
|
||||
|
||||
export interface EspnCommentaryLine { minute: number | null; text: string }
|
||||
|
||||
@@ -95,11 +95,15 @@ export interface EspnSummary {
|
||||
events: EspnTimelineEvent[];
|
||||
/** Full play-by-play feed (attempts, fouls, corners, VAR…), kickoff first. */
|
||||
commentary?: EspnCommentaryLine[];
|
||||
/** Post-match report article (the narrative — why cards were shown, how
|
||||
* goals came about). Plain text, appears around full time. */
|
||||
report?: { headline: string; story: string } | null;
|
||||
}
|
||||
|
||||
export interface RawSummary {
|
||||
gameInfo?: { venue?: { fullName?: string } };
|
||||
commentary?: { sequence?: number | string; time?: { displayValue?: string }; text?: string }[];
|
||||
article?: { headline?: string; story?: string };
|
||||
header?: { competitions?: { competitors?: { id: string; team?: { displayName?: string }; homeAway: 'home' | 'away' }[] }[] };
|
||||
headToHeadGames?: { events?: { gameDate: string; homeTeamId: string; awayTeamId: string; homeTeamScore: string; awayTeamScore: string }[] }[];
|
||||
boxscore?: {
|
||||
@@ -182,5 +186,12 @@ export function normalizeSummary(raw: RawSummary): EspnSummary {
|
||||
})
|
||||
.filter((c) => c.text);
|
||||
|
||||
return { v: SUMMARY_V, fetchedAt: Date.now(), venue: raw.gameInfo?.venue?.fullName ?? null, teams, h2h, form, lineups, stats, events, commentary };
|
||||
const story = (raw.article?.story ?? '')
|
||||
.replace(/<[^>]+>/g, ' ')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim()
|
||||
.slice(0, 8000);
|
||||
const report = story ? { headline: raw.article?.headline ?? '', story } : null;
|
||||
|
||||
return { v: SUMMARY_V, fetchedAt: Date.now(), venue: raw.gameInfo?.venue?.fullName ?? null, teams, h2h, form, lineups, stats, events, commentary, report };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user