fix: display story age from firstSeenAt, not updatedAt
Old stories were reading "1 hr ago" because updatedAt bumps every time the backend attaches another article to a cluster, however loosely related. firstSeenAt is when the cluster actually first appeared and is already in the API response — just wasn't decoded. Verified live: story_1a37c858235b (F1 Austria GP recap) has firstSeenAt 2026-06-16 but updatedAt 2026-07-11, freshnessScore 0.96 — looked brand new despite being 25 days old. Also confirmed the API's isStale field is unusable as a stopgap (always false regardless of age). Ranking still surfaces old stories at the top — that's server-side (signalScore/freshnessScore) and out of scope for the client per the architecture rule against re-ranking. Logged in BACKLOG #15. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -61,6 +61,11 @@ struct StorySummary: Codable, Identifiable, Hashable {
|
||||
let conflict: String?
|
||||
let updatedAt: Date
|
||||
let createdAt: Date
|
||||
/// When the cluster first appeared. `updatedAt` bumps on every article the
|
||||
/// backend attaches to the cluster (even a loosely-related one), so it can
|
||||
/// read "1 hr ago" on stories that are actually weeks old — `firstSeenAt`
|
||||
/// is the honest age. Optional so decoding tolerates older API responses.
|
||||
let firstSeenAt: Date?
|
||||
}
|
||||
|
||||
struct ScoreBreakdown: Codable, Hashable {
|
||||
@@ -185,6 +190,10 @@ final class CachedStory {
|
||||
/// Original publish timestamp. Defaults to updatedAt for rows cached before
|
||||
/// this field was added — SwiftData handles the automatic migration.
|
||||
var createdAt: Date = Date()
|
||||
/// When the cluster first appeared — the honest age, unlike `updatedAt` which
|
||||
/// bumps whenever the backend attaches another article. Defaults to `updatedAt`
|
||||
/// for rows cached before this field was added.
|
||||
var firstSeenAt: Date = Date()
|
||||
var cachedAt: Date
|
||||
|
||||
init(from summary: StorySummary) {
|
||||
@@ -199,6 +208,7 @@ final class CachedStory {
|
||||
self.conflict = summary.conflict
|
||||
self.updatedAt = summary.updatedAt
|
||||
self.createdAt = summary.createdAt
|
||||
self.firstSeenAt = summary.firstSeenAt ?? summary.updatedAt
|
||||
self.cachedAt = Date()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user