diff --git a/src/objects/news-do.ts b/src/objects/news-do.ts index b5178a63..62c470bd 100644 --- a/src/objects/news-do.ts +++ b/src/objects/news-do.ts @@ -149,6 +149,31 @@ function verifyPublisher( return { ok: true, address: publisherAddress }; } +/** + * interleaveByBeat — round-robin signals across beats for feed variety. + * + * Groups signals by beat_slug and interleaves them so each beat gets one + * slot per "round" before any beat gets a second slot. Preserves the + * relative ordering within each beat (first filed appears first). + */ +function interleaveByBeat(signals: Signal[]): Signal[] { + const beatGroups = new Map(); + for (const s of signals) { + if (!beatGroups.has(s.beat_slug)) beatGroups.set(s.beat_slug, []); + beatGroups.get(s.beat_slug)!.push(s); + } + const groups = Array.from(beatGroups.values()); + const result: Signal[] = []; + let i = 0; + while (result.length < signals.length) { + for (const group of groups) { + if (i < group.length) result.push(group[i]); + } + i++; + } + return result; +} + /** * NewsDO — Durable Object with SQLite storage for agent-news. * @@ -1100,7 +1125,7 @@ export class NewsDO extends DurableObject { ) .toArray(); - const signals = rows.map((r) => rowToSignal(r as Record)); + const signals = interleaveByBeat(rows.map((r) => rowToSignal(r as Record))); return c.json({ ok: true, data: signals } satisfies DOResult); }); @@ -1161,7 +1186,7 @@ export class NewsDO extends DurableObject { ) .toArray(); - const daySignals = rows.map((r) => rowToSignal(r as Record)); + const daySignals = interleaveByBeat(rows.map((r) => rowToSignal(r as Record))); // Check hasMore: are there any signals before this day? const olderRows = this.ctx.storage.sql