import Foundation public struct ArticleRef: Codable, Sendable, Identifiable { public let id: Int public let title: String? } public struct TopicResponse: Codable, Sendable, Identifiable { public let topicRank: Int public let topicLabel: String public let summary: String public let articleIds: [Int]? public let articles: [ArticleRef] public let articleCount: Int? public let importanceScore: Double? public let rawWeightSum: Double? public let llmFallbackUsed: Bool? public var id: Int { topicRank } enum CodingKeys: String, CodingKey { case summary, articles case topicRank = "topic_rank" case topicLabel = "topic_label" case articleIds = "article_ids" case articleCount = "article_count" case importanceScore = "importance_score" case rawWeightSum = "raw_weight_sum" case llmFallbackUsed = "llm_fallback_used" } } public struct CountryGroup: Codable, Sendable, Identifiable { public let country: String public let topics: [TopicResponse] public var id: String { country } } public struct DigestResponse: Codable, Sendable { public let digestDateRaw: String? public let windowStartRaw: String? public let windowEndRaw: String? public let decayLambda: Double? public let totalArticles: Int? public let totalCountries: Int? public let totalTopics: Int? public let generationMs: Int? public let llmCalls: Int? public let llmFailures: Int? public let status: String? public let countries: [CountryGroup] /// date-only (B-1 r2): DISPLAY the raw string (no Date conversion → no KST off-by-one). public var digestDateDisplay: String { digestDateRaw ?? "" } /// Date conversions are for sort/window math only (UTC-fixed via DSDate). public var windowStart: Date? { DSDate.parse(windowStartRaw) } public var windowEnd: Date? { DSDate.parse(windowEndRaw) } enum CodingKeys: String, CodingKey { case status, countries case digestDateRaw = "digest_date" case windowStartRaw = "window_start" case windowEndRaw = "window_end" case decayLambda = "decay_lambda" case totalArticles = "total_articles" case totalCountries = "total_countries" case totalTopics = "total_topics" case generationMs = "generation_ms" case llmCalls = "llm_calls" case llmFailures = "llm_failures" } } public struct DigestDateSummary: Codable, Sendable { public let digestDateRaw: String? public let totalTopics: Int? public let totalCountries: Int? public let totalArticles: Int? public let status: String? enum CodingKeys: String, CodingKey { case status case digestDateRaw = "digest_date" case totalTopics = "total_topics" case totalCountries = "total_countries" case totalArticles = "total_articles" } }