fix(feed): reflect content updates in source health confirmation and freshness
Ensure lastConfirmedAt never precedes contentChangedAt for fetched snapshots and calculate game-level lastConfirmedAt using effective pull times.
This commit is contained in:
+10
-2
@@ -47,12 +47,20 @@ async function latestFixture(adapterId: string, game: GameId) {
|
||||
async function documentFor(adapterId: string, game: GameId) {
|
||||
const cached = await snapshots.read(adapterId);
|
||||
if (cached !== null) {
|
||||
const rawConfirmed = cached.state.lastConfirmedAt;
|
||||
const contentChangedAt = cached.meta.contentChangedAt;
|
||||
const lastConfirmedAt =
|
||||
rawConfirmed !== null &&
|
||||
contentChangedAt !== null &&
|
||||
Date.parse(rawConfirmed) >= Date.parse(contentChangedAt)
|
||||
? rawConfirmed
|
||||
: (contentChangedAt ?? rawConfirmed);
|
||||
return {
|
||||
file: snapshots.bodyPath(adapterId),
|
||||
html: cached.html,
|
||||
at: freshnessAt(cached),
|
||||
lastConfirmedAt: cached.state.lastConfirmedAt,
|
||||
contentChangedAt: cached.meta.contentChangedAt,
|
||||
lastConfirmedAt,
|
||||
contentChangedAt,
|
||||
};
|
||||
}
|
||||
const { file, html } = await latestFixture(adapterId, game);
|
||||
|
||||
@@ -86,7 +86,12 @@ export function sourceHealth(
|
||||
// When the bytes were last confirmed live; a fixture's capture date when
|
||||
// this source has never been refreshed.
|
||||
lastSuccessAt: at,
|
||||
lastConfirmedAt: timestamps?.lastConfirmedAt ?? null,
|
||||
lastConfirmedAt:
|
||||
timestamps?.lastConfirmedAt != null &&
|
||||
(timestamps.contentChangedAt ?? at) != null &&
|
||||
Date.parse(timestamps.lastConfirmedAt) < Date.parse(timestamps.contentChangedAt ?? at!)
|
||||
? (timestamps.contentChangedAt ?? at)
|
||||
: (timestamps?.lastConfirmedAt ?? null),
|
||||
contentChangedAt: timestamps?.contentChangedAt ?? at,
|
||||
eventCount,
|
||||
parsedCount,
|
||||
|
||||
+13
-3
@@ -167,11 +167,21 @@ export function freshness(
|
||||
let lastConfirmedAt: string | null = null;
|
||||
let hasConfirmed = false;
|
||||
for (const s of sourcesInfo) {
|
||||
const pullAt =
|
||||
s.lastConfirmedAt !== null &&
|
||||
s.contentChangedAt !== null &&
|
||||
Date.parse(s.lastConfirmedAt) >= Date.parse(s.contentChangedAt)
|
||||
? s.lastConfirmedAt
|
||||
: (s.lastConfirmedAt ??
|
||||
(s.contentChangedAt && now - Date.parse(s.contentChangedAt) <= STALE_AFTER_MS
|
||||
? s.contentChangedAt
|
||||
: null));
|
||||
|
||||
if (!hasConfirmed) {
|
||||
lastConfirmedAt = s.lastConfirmedAt;
|
||||
lastConfirmedAt = pullAt;
|
||||
hasConfirmed = true;
|
||||
} else if (lastConfirmedAt !== null && (s.lastConfirmedAt === null || s.lastConfirmedAt < lastConfirmedAt)) {
|
||||
lastConfirmedAt = s.lastConfirmedAt;
|
||||
} else if (lastConfirmedAt !== null && (pullAt === null || pullAt < lastConfirmedAt)) {
|
||||
lastConfirmedAt = pullAt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -202,6 +202,31 @@ describe("freshness", () => {
|
||||
expect(staleEndfield.sources[0]?.contentChangedAt).toBe(OLD_SITE);
|
||||
});
|
||||
|
||||
test("differentiates blame across multiple sources when one updated recently and another confirmed 304", () => {
|
||||
const PULL_TIME = new Date(NOW - 11 * HOUR).toISOString();
|
||||
const OLD_SITE = new Date(NOW - 60 * HOUR).toISOString();
|
||||
const RECENT_CONTENT = new Date(NOW - 1 * HOUR).toISOString();
|
||||
const result = freshness(
|
||||
[
|
||||
{
|
||||
...source("endfield", OLD_SITE, "endfield-wikigg-events"),
|
||||
lastConfirmedAt: PULL_TIME,
|
||||
contentChangedAt: OLD_SITE,
|
||||
},
|
||||
{
|
||||
...source("endfield", RECENT_CONTENT, "endfield-game8-events"),
|
||||
lastConfirmedAt: null,
|
||||
contentChangedAt: RECENT_CONTENT,
|
||||
},
|
||||
],
|
||||
NOW,
|
||||
);
|
||||
expect(result.stale).toHaveLength(1);
|
||||
const staleEndfield = result.stale[0]!;
|
||||
expect(staleEndfield.lastConfirmedAt).toBe(PULL_TIME);
|
||||
expect(staleEndfield.contentChangedAt).toBe(OLD_SITE);
|
||||
});
|
||||
|
||||
test("an empty feed reports nothing rather than throwing", () => {
|
||||
expect(freshness([], NOW)).toEqual({ refreshedAt: null, stale: [] });
|
||||
});
|
||||
@@ -394,4 +419,14 @@ describe("recording a source's health at build time", () => {
|
||||
expect(health.statesNoEvents).toBe(false);
|
||||
expect(brokenSources([health])).toEqual([]);
|
||||
});
|
||||
|
||||
test("lastConfirmedAt is never older than contentChangedAt", () => {
|
||||
const OLD_CONFIRM = "2026-09-12T00:00:00.000Z";
|
||||
const NEW_CONTENT = "2026-09-18T00:00:00.000Z";
|
||||
const health = sourceHealth(adapter(), FULL, NEW_CONTENT, 1, {
|
||||
lastConfirmedAt: OLD_CONFIRM,
|
||||
contentChangedAt: NEW_CONTENT,
|
||||
});
|
||||
expect(health.lastConfirmedAt).toBe(NEW_CONTENT);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user