export type CheckCategory = 'lint' | 'specs' | 'e2e' | 'other'; export type CategoryState = 'fail' | 'running' | 'pending' | 'pass' | 'skipped' | 'none'; export interface CheckInfo { name: string; state: CategoryState; url: string | null; } export interface CategoryStatus { category: CheckCategory; state: CategoryState; passed: number; /** Non-skipped check count (drives the "7/9" chip summary). */ total: number; checks: CheckInfo[]; } export type ReviewState = 'no_review' | 'outstanding' | 'addressed'; export interface ReviewerVerdict { reviewer: string; state: 'APPROVED' | 'CHANGES_REQUESTED'; url: string; submittedAt: string; } export interface PrSnapshot { id: string; repo: string; number: number; title: string; url: string; author: string; isDraft: boolean; branch: string; updatedAt: string; reviewState: ReviewState; unresolvedThreads: number; totalThreads: number; verdicts: ReviewerVerdict[]; categories: CategoryStatus[]; } export type TimelineKind = 'issue_comment' | 'review_comment' | 'review'; export interface TimelineEvent { id: string; prId: string; repo: string; prNumber: number; prTitle: string; kind: TimelineKind; actor: string; createdAt: string; bodyExcerpt: string; url: string; reviewState: string | null; path: string | null; read: boolean; } export interface StatePayload { prs: PrSnapshot[]; lastSyncAt: string | null; lastSyncError: string | null; unreadCountsByPr: Record; unreadTotal: number; } export interface TimelinePage { events: TimelineEvent[]; nextCursor: string | null; } export interface SyncEventPayload { lastSyncAt: string | null; error: string | null; changedPrIds: string[]; newEventCount: number; unreadCount: number; }