Skip to content

feat(ui): importanceScore relevance sort + phase badges in NewsPanel#2608

Merged
koala73 merged 1 commit intomainfrom
feat/news-alerts-ui
Apr 2, 2026
Merged

feat(ui): importanceScore relevance sort + phase badges in NewsPanel#2608
koala73 merged 1 commit intomainfrom
feat/news-alerts-ui

Conversation

@koala73
Copy link
Copy Markdown
Owner

@koala73 koala73 commented Apr 2, 2026

Summary

  • src/styles/main.css: adds .phase-badge, .phase-badge.breaking (pulsing orange), .phase-badge.developing (yellow), .phase-badge.sustained (slate) CSS classes used by NewsPanel.

All other feature work landed in main via prerequisite PRs:

This PR was rebased onto main after those merges; the CSS was the only missing piece.

Test plan

  • npm run typecheck passes
  • npm run lint passes (no errors)
  • Diff is CSS-only (27 lines added)

Post-Deploy Monitoring & Validation

  • What to monitor: Phase badges render in NewsPanel for breaking/developing/sustained stories
  • Expected healthy behavior: BREAKING badge (orange, pulsing) appears on first-cycle stories; DEVELOPING ×N (yellow) on repeat stories; ONGOING (slate) on sustained stories
  • Failure signal: No visual badges despite storyMeta being populated in digest → check CSS selector specificity
  • No additional operational monitoring required: pure CSS addition, no backend impact

🤖 Generated with Claude Sonnet 4.6 via Claude Code + Compound Engineering v2.49.0

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 2, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
worldmonitor Ready Ready Preview, Comment Apr 2, 2026 5:56pm

Request Review

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 2, 2026

Greptile Summary

This PR wires up three new proto scoring fields (importanceScore, corroborationCount, storyPhase) through the client type layer and into the NewsPanel UI — adding a relevance-first sort and phase badges — while gracefully falling back when the upstream scoring PR (#2604) has not yet deployed. The approach is well-structured and the fallback behaviour is solid.

Key changes:

  • src/types/index.ts: Adds StoryPhase union and three optional fields to NewsItem.
  • src/app/data-loader.ts: Maps the new proto fields via a type-cast IIFE; uses falsy checks that will silently drop zero-valued importanceScore/corroborationCount fields.
  • src/components/NewsPanel.ts: Relevance sort (importanceScore → threat level → recency) and BREAKING/DEVELOPING phase badges in renderFlat().
  • src/styles/main.css: Three new CSS classes; .phase-breaking reuses the existing pulse-alert keyframe correctly.

Issues found:

  • The truthiness check on importanceScore and corroborationCount in data-loader.ts drops valid zero values — undefined checks should be used instead.
  • StoryPhase includes STORY_PHASE_UNSPECIFIED but items with that value are filtered before being stored on NewsItem, making the type on that field misleading; splitting into a proto-layer type and a narrower ActiveStoryPhase for NewsItem would be cleaner.

Confidence Score: 4/5

Important Files Changed

Filename Overview
src/app/data-loader.ts Maps new proto scoring fields to NewsItem via type cast; falsy check on importanceScore/corroborationCount will silently drop zero values.
src/components/NewsPanel.ts Adds relevance sort by importanceScore → threat level → recency, and injects BREAKING/DEVELOPING phase badges; logic is correct and gracefully falls back when scores are absent.
src/types/index.ts Adds StoryPhase union and three optional fields to NewsItem; StoryPhase includes STORY_PHASE_UNSPECIFIED which is filtered out in practice, making the field type slightly misleading.
src/styles/main.css Adds .phase-badge, .phase-breaking (pulsing, reuses existing pulse-alert keyframe), and .phase-developing CSS classes; straightforward and correct.

Sequence Diagram

sequenceDiagram
    participant Proto as ProtoNewsItem (wire)
    participant DL as data-loader.ts<br/>protoItemToNewsItem()
    participant NI as NewsItem (client)
    participant NP as NewsPanel<br/>renderFlat()
    participant UI as DOM

    Proto->>DL: importanceScore, corroborationCount, storyPhase
    Note over DL: Type-cast IIFE<br/>filters STORY_PHASE_UNSPECIFIED<br/>⚠ falsy check drops score=0
    DL->>NI: importanceScore?, corroborationCount?, storyPhase?
    NI->>NP: items[]
    Note over NP: sortMode === 'relevance'?<br/>Sort: importanceScore desc<br/>→ threat level desc<br/>→ recency desc
    NP->>UI: Sorted HTML list
    Note over UI: storyPhase=BREAKING → pulsing orange badge<br/>storyPhase=DEVELOPING → yellow badge
Loading

Reviews (1): Last reviewed commit: "revert(gen): restore service_client.ts t..." | Re-trigger Greptile

Comment on lines +222 to +223
...(ext.importanceScore ? { importanceScore: ext.importanceScore } : {}),
...(ext.corroborationCount ? { corroborationCount: ext.corroborationCount } : {}),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Falsy check silently drops zero-valued scores

Both importanceScore and corroborationCount use a truthiness check (ext.field ? ...), which means a valid value of 0 is treated as absent and dropped from the mapped NewsItem.

For importanceScore, the downstream sort comparator uses a.importanceScore ?? 0, so the ordering is the same whether the field is 0 or undefined — but the distinction between "scored at 0" and "unscored" is lost.

For corroborationCount, this is more meaningful: 0 corroborations is semantically different from "corroboration not computed", and a future consumer could make wrong decisions based on the missing value.

Suggested change
...(ext.importanceScore ? { importanceScore: ext.importanceScore } : {}),
...(ext.corroborationCount ? { corroborationCount: ext.corroborationCount } : {}),
...(ext.importanceScore !== undefined ? { importanceScore: ext.importanceScore } : {}),
...(ext.corroborationCount !== undefined ? { corroborationCount: ext.corroborationCount } : {}),

source: 'keyword' | 'ml' | 'llm';
}

export type StoryPhase = 'STORY_PHASE_UNSPECIFIED' | 'STORY_PHASE_BREAKING' | 'STORY_PHASE_DEVELOPING' | 'STORY_PHASE_SUSTAINED' | 'STORY_PHASE_FADING';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 STORY_PHASE_UNSPECIFIED included in type but never stored on NewsItem

StoryPhase includes 'STORY_PHASE_UNSPECIFIED' as a valid member. However, data-loader.ts explicitly filters this value out before assigning storyPhase to a NewsItem, meaning a NewsItem will never actually carry STORY_PHASE_UNSPECIFIED at runtime. The type on the storyPhase field of NewsItem therefore misleads future callers into thinking they need to handle that sentinel.

Consider narrowing the field type to exclude the sentinel:

Suggested change
export type StoryPhase = 'STORY_PHASE_UNSPECIFIED' | 'STORY_PHASE_BREAKING' | 'STORY_PHASE_DEVELOPING' | 'STORY_PHASE_SUSTAINED' | 'STORY_PHASE_FADING';
export type StoryPhase = 'STORY_PHASE_UNSPECIFIED' | 'STORY_PHASE_BREAKING' | 'STORY_PHASE_DEVELOPING' | 'STORY_PHASE_SUSTAINED' | 'STORY_PHASE_FADING';
export type ActiveStoryPhase = Exclude<StoryPhase, 'STORY_PHASE_UNSPECIFIED'>;

Then use ActiveStoryPhase for the storyPhase field on NewsItem (line 112), keeping the full StoryPhase union available for proto-layer casting in data-loader.ts.

…dges

All other PR changes (types, data-loader cast, NewsPanel) are now in main via
E3 (#2620) and E1 (#2621). Only the CSS for .phase-badge.breaking/.developing/.sustained
was missing. Class names corrected to match NewsPanel.ts output (phase-badge + modifier
vs the original phase-breaking/phase-developing selectors).
@koala73 koala73 force-pushed the feat/news-alerts-ui branch from 9d78894 to 828277e Compare April 2, 2026 17:53
@koala73 koala73 merged commit 718f466 into main Apr 2, 2026
6 of 7 checks passed
@koala73 koala73 deleted the feat/news-alerts-ui branch April 2, 2026 17:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant