fix(classifier): match flashback/throwback after publisher brand prefix#3480
Conversation
Brief 2026-04-28-0801 surfaced "CBS News Radio flashback: D-Day, Invasion of Normandy in 1944" as severity=critical in slot #3, two days after PR #3429 shipped the historical-retrospective downgrade. Root cause: HISTORICAL_PREFIX_RE was anchored with `^` — `/^(?:science history|throwback|flashback)\s*:?/i` — so flashback / throwback only matched at title position 0. Publishers prepend their brand ("CBS News Radio", "BBC", "NPR") before the marker token, which defeated the anchor. The keyword path then matched `invasion` unimpeded → critical. Fix: word-boundary match for flashback / throwback (unambiguous markers regardless of position); science history stays anchored since it's an editorial-slot prefix that's only retrospective at the start of a headline. /(?:^science history\s*:?|\b(?:throwback|flashback)\b)/i Regression test added under the existing news-classifier-historical-downgrade suite covering CBS News Radio, BBC, and NPR brand-prefix forms. All 56 cases in that file plus the 56 cases across the historical-downgrade + LLM-cache-guard tests still pass.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR fixes a regex anchor bug in Confidence Score: 4/5Safe to merge; the fix is surgical and well-tested with only a minor speculative false-positive edge case at P2. No P0 or P1 issues found. The one P2 comment flags that No files require special attention; the P2 concern is in Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["Incoming headline\ne.g. 'CBS News Radio flashback: D-Day...'"] --> B["classifyByKeyword(title)"]
B --> C["hasHistoricalMarker(title)"]
C --> D{"HISTORICAL_PREFIX_RE\n/(?:^science history\\s*:?|\\b(?:throwback|flashback)\\b)/i"}
D -- "match (e.g. 'flashback' word boundary)" --> E["isRetrospective = true"]
D -- "no match" --> F["Check other markers\n(HISTORICAL_PHRASE_RE, FULL_DATE_RE, …)"]
F --> G{"Any marker?"}
G -- yes --> E
G -- no --> H["isRetrospective = false"]
B --> I["matchKeywords(lower, CRITICAL_KEYWORDS)\ne.g. 'invasion' → match"]
E --> J{"isRetrospective?"}
H --> J
I --> J
J -- true --> K["Return info / keyword-historical-downgrade\nconfidence 0.85"]
J -- false --> L["Return critical / keyword\nconfidence 0.9"]
style K fill:#90EE90
style L fill:#FF6961
Reviews (1): Last reviewed commit: "fix(classifier): match flashback/throwba..." | Re-trigger Greptile |
| const HISTORICAL_PREFIX_RE = | ||
| /(?:^science history\s*:?|\b(?:throwback|flashback)\b)/i; |
There was a problem hiding this comment.
\bflashback\b can fire on non-retrospective medical/narrative uses
flashback can appear in current-event headlines outside of the retrospective-segment context — e.g. "Veteran's flashback triggers meltdown on base" or "Abuse survivor's flashback described in court". If any CRITICAL/HIGH keyword also appears (here meltdown), the title would be downgraded to info, suppressing a real alert.
The risk is low given how rarely such phrasing appears alongside CRITICAL keywords in hard-news syndication, but the assertion in the comment that flashback is "always retrospective by definition" is slightly overstated. A negative regression test covering a non-retrospective mid-sentence flashback (e.g. "Veteran flashback triggers meltdown on base" → level critical) would document the accepted boundary explicitly and catch any future broadening of the pattern.
There was a problem hiding this comment.
Good catch. Tightened in f61fae5.
Replaced the bare word-boundary form with two explicit branches:
- ANCHORED (original behavior): marker at title position 0 —
Throwback Thursday:,Flashback:,Science history:. - BRAND-PREFIX: 1-4 Title-Case prefix words + marker + optional qualifier word + colon. Catches
CBS News Radio flashback:,BBC Throwback Thursday:,NPR Flashback Friday:while rejecting sentence-form occurrences.
const HISTORICAL_ANCHORED_PREFIX_RE =
/^(?:science history|throwback|flashback)\s*:?/i;
// No `i` flag — Title-Case enforcement on the brand prefix is load-bearing.
const HISTORICAL_BRAND_PREFIX_RE =
/^(?:[A-Z][\w'&-]*\s+){1,4}(?:[Tt]hrowback|[Ff]lashback)(?:\s+[A-Za-z]+)?\s*:/;The brand-prefix branch deliberately requires (a) Title-Case prefix words and (b) an editorial-slot colon after the marker. Both gates together reject the realistic false-positive shapes you were worried about for the L3b LLM-cache guard.
Added 5 negative tests covering them:
Markets see flashback to 2008 crisis as bonds tumble→ false (no colon)Stocks suffer flashback to March 2020 crash→ false (no colon)Tesla stock throwback after split→ false (no colon)AI flashback to 2023 boom: Nvidia earnings beat→ false (qualifier slot overruns; colon not adjacent)markets see flashback: bonds tumble→ false (lowercase first word fails Title-Case gate)
All existing positive tests still pass (61/61 across news-classifier-historical-downgrade.test.mts + news-classifier-llm-historical-guard.test.mts).
Reviewer P2 on PR #3480: widening flashback/throwback to bare word-boundary match also broadens the L3b LLM-cache guard at list-feed-digest.ts:547, which force-demotes ANY cached LLM hit to info when hasHistoricalMarker is true. A current-event headline that incidentally uses "flashback" / "throwback" as a comparison word ("Markets see flashback to 2008 crisis as bonds tumble") would be wrongly suppressed even though the marker isn't acting as a retrospective framing token. Replace the broad word-boundary form with two explicit branches: 1. ANCHORED: marker at title position 0 (original behavior — "Throwback Thursday:", "Flashback:", "Science history:"). 2. BRAND-PREFIX: 1-4 Title-Case prefix words + marker + optional qualifier word + colon. Catches the brand-prefixed forms ("CBS News Radio flashback:", "BBC Throwback Thursday:", "NPR Flashback Friday:") while rejecting sentence-form uses. The brand-prefix branch deliberately requires (a) Title-Case prefix words (rejects "markets see flashback…"), AND (b) an editorial-slot colon after the marker (rejects "Markets See Flashback To 2008 Crisis As Bonds Tumble"). The Title-Case gate uses a non-i regex so [A-Z] enforces actual capitalization rather than getting case-folded. Adds 5 negative tests for the realistic false-positive cases the reviewer was worried about — "Markets see flashback to 2008 crisis", "Stocks suffer flashback to March 2020 crash", "Tesla stock throwback after split", "AI flashback to 2023 boom: Nvidia earnings beat", and a lowercase-leading sentence form. All existing positive tests still pass (61/61 in the historical- downgrade + LLM-cache-guard suite).
Evicts cache entries that landed under the pre-publisher-prefix-fix classifier — brand-prefixed retrospective titles like "CBS News Radio flashback: D-Day, Invasion of Normandy in 1944" had been promoted to severity=critical via the `invasion` keyword and persisted in the classify cache. The new brand-prefix branch in _classifier.ts (PR #3480 commits 5ec9892 + f61fae5) re-rules those rows on next touch; v5 forces immediate eviction rather than waiting for natural TTL on every poisoned entry. Three lockstep sites updated atomically per the cache-prefix-bump- propagation-scope learning: - server/worldmonitor/intelligence/v1/_shared.ts:20 (canonical writer) - server/worldmonitor/news/v1/list-feed-digest.ts:511 (doc-comment) - scripts/ais-relay.cjs:3172 (relay inline helper) The news-classify-cache-prefix-audit static-analysis test enforces lockstep — passes after this change.
…ix (koala73#3480) * fix(classifier): match flashback/throwback after publisher brand prefix Brief 2026-04-28-0801 surfaced "CBS News Radio flashback: D-Day, Invasion of Normandy in 1944" as severity=critical in slot #3, two days after PR koala73#3429 shipped the historical-retrospective downgrade. Root cause: HISTORICAL_PREFIX_RE was anchored with `^` — `/^(?:science history|throwback|flashback)\s*:?/i` — so flashback / throwback only matched at title position 0. Publishers prepend their brand ("CBS News Radio", "BBC", "NPR") before the marker token, which defeated the anchor. The keyword path then matched `invasion` unimpeded → critical. Fix: word-boundary match for flashback / throwback (unambiguous markers regardless of position); science history stays anchored since it's an editorial-slot prefix that's only retrospective at the start of a headline. /(?:^science history\s*:?|\b(?:throwback|flashback)\b)/i Regression test added under the existing news-classifier-historical-downgrade suite covering CBS News Radio, BBC, and NPR brand-prefix forms. All 56 cases in that file plus the 56 cases across the historical-downgrade + LLM-cache-guard tests still pass. * fix(classifier): tighten flashback/throwback to editorial-slot syntax Reviewer P2 on PR koala73#3480: widening flashback/throwback to bare word-boundary match also broadens the L3b LLM-cache guard at list-feed-digest.ts:547, which force-demotes ANY cached LLM hit to info when hasHistoricalMarker is true. A current-event headline that incidentally uses "flashback" / "throwback" as a comparison word ("Markets see flashback to 2008 crisis as bonds tumble") would be wrongly suppressed even though the marker isn't acting as a retrospective framing token. Replace the broad word-boundary form with two explicit branches: 1. ANCHORED: marker at title position 0 (original behavior — "Throwback Thursday:", "Flashback:", "Science history:"). 2. BRAND-PREFIX: 1-4 Title-Case prefix words + marker + optional qualifier word + colon. Catches the brand-prefixed forms ("CBS News Radio flashback:", "BBC Throwback Thursday:", "NPR Flashback Friday:") while rejecting sentence-form uses. The brand-prefix branch deliberately requires (a) Title-Case prefix words (rejects "markets see flashback…"), AND (b) an editorial-slot colon after the marker (rejects "Markets See Flashback To 2008 Crisis As Bonds Tumble"). The Title-Case gate uses a non-i regex so [A-Z] enforces actual capitalization rather than getting case-folded. Adds 5 negative tests for the realistic false-positive cases the reviewer was worried about — "Markets see flashback to 2008 crisis", "Stocks suffer flashback to March 2020 crash", "Tesla stock throwback after split", "AI flashback to 2023 boom: Nvidia earnings beat", and a lowercase-leading sentence form. All existing positive tests still pass (61/61 in the historical- downgrade + LLM-cache-guard suite). * chore(classifier): bump CLASSIFY_CACHE_PREFIX v4 → v5 Evicts cache entries that landed under the pre-publisher-prefix-fix classifier — brand-prefixed retrospective titles like "CBS News Radio flashback: D-Day, Invasion of Normandy in 1944" had been promoted to severity=critical via the `invasion` keyword and persisted in the classify cache. The new brand-prefix branch in _classifier.ts (PR koala73#3480 commits 5ec9892 + f61fae5) re-rules those rows on next touch; v5 forces immediate eviction rather than waiting for natural TTL on every poisoned entry. Three lockstep sites updated atomically per the cache-prefix-bump- propagation-scope learning: - server/worldmonitor/intelligence/v1/_shared.ts:20 (canonical writer) - server/worldmonitor/news/v1/list-feed-digest.ts:511 (doc-comment) - scripts/ais-relay.cjs:3172 (relay inline helper) The news-classify-cache-prefix-audit static-analysis test enforces lockstep — passes after this change.
Summary
"CBS News Radio flashback: D-Day, Invasion of Normandy in 1944"as severity=critical in slot Add shareable map state URLs and Copy Link button #3, two days after PR fix(classifier): two-layer historical-retrospective downgrade (L1 + L3) #3429 (f37216d04) shipped the historical-retrospective downgrade.HISTORICAL_PREFIX_REin_classifier.tswas anchored with^soflashback/throwbackonly matched at title position 0. Publishers prepend their brand ("CBS News Radio", "BBC", "NPR") before the marker token, defeating the anchor. The keyword path then matchedinvasionunimpeded → critical.list-feed-digest.ts:547doesn't widen its blast radius.CLASSIFY_CACHE_PREFIXv4 → v5 in lockstep across all three sites (_shared.ts,list-feed-digest.tsdoc-comment,ais-relay.cjs) so existing cache entries that promoted these titles to critical evict immediately rather than waiting for natural TTL.Test plan
news-classifier-historical-downgrade.test.mts:Markets see flashback to 2008 crisis…,Stocks suffer flashback to March 2020 crash,Tesla stock throwback after split,AI flashback to 2023 boom: Nvidia earnings beat, lowercase-leading sentencenews-classifier-historical-downgrade.test.mts+news-classifier-llm-historical-guard.test.mtspassnews-classify-cache-prefix-audit.test.mjspasses — all 3 sites in lockstep on v5npm run typecheck+npm run typecheck:api— passnpm run test:data— 7601 / 7601 passnode --test tests/edge-functions.test.mjs— 178 / 178 passnpm run lint:md— passnpm run version:check— pass