From 5c9839926ddb4c59c4ad39e72bbab20c7d746204 Mon Sep 17 00:00:00 2001 From: jjbrunton Date: Sun, 9 Aug 2026 09:14:52 +0100 Subject: [PATCH] Screen all older fallback candidates --- src/services/monitor.ts | 28 +++++++++++----------------- tests/monitor.test.ts | 12 ++++++------ 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/services/monitor.ts b/src/services/monitor.ts index 7148c9a..49d9cbe 100644 --- a/src/services/monitor.ts +++ b/src/services/monitor.ts @@ -19,7 +19,6 @@ interface ListingScreeningSummary { eligible: number; outsideRecentWindow: number; deferred: number; - deferredReason: 'selected-recent-candidate' | 'older-than-fallback' | null; } /** Coordinates permanent polling disablement across account runtimes. */ @@ -52,9 +51,10 @@ export class MonitorService { const recentCutoffSec = prioritizeRecent ? Math.floor(Date.now() / 1000) - this.config.reddit.recentWindowMinutes * 60 : 0; - // Older posts found while prioritizing recent ones — used as a fallback - // so the bot still has something to do if no recent posts exist anywhere. - let fallback: RedditPost | null = null; + // Older posts found while prioritizing recent ones. Screen every eligible + // older candidate so seller and recipient filters are applied consistently, + // then select the newest one only if no recent post exists anywhere. + const fallbackCandidates: RedditPost[] = []; for (const subreddit of subreddits) { try { @@ -70,7 +70,6 @@ export class MonitorService { eligible: 0, outsideRecentWindow: 0, deferred: 0, - deferredReason: null, }; let selected: RedditPost | null = null; @@ -140,18 +139,15 @@ export class MonitorService { if (!prioritizeRecent || post.created_utc >= recentCutoffSec) { selected = post; summary.deferred = newestFirst.length - index - 1; - summary.deferredReason = 'selected-recent-candidate'; break; } - // This is the newest eligible post in this subreddit. Keep it as a - // possible fallback, then move to the next subreddit to look for a - // recent candidate. Older posts in this batch cannot improve it. + // Keep every eligible older post. We deliberately finish screening + // the listing rather than stopping at its newest fallback candidate: + // later posts may be rejected, and this keeps the fallback decision + // based on the full set of available posts. summary.outsideRecentWindow += 1; - if (!fallback || post.created_utc > fallback.created_utc) fallback = post; - summary.deferred = newestFirst.length - index - 1; - summary.deferredReason = 'older-than-fallback'; - break; + fallbackCandidates.push(post); } this.logListingSummary(subreddit.name, posts.length, summary, selected !== null); @@ -179,6 +175,7 @@ export class MonitorService { } } + const fallback = fallbackCandidates.sort((a, b) => b.created_utc - a.created_utc)[0]; if (fallback) { this.logger.info( `No posts within last ${this.config.reddit.recentWindowMinutes}m — falling back to newest available (r/${fallback.subreddit})`, @@ -259,10 +256,7 @@ export class MonitorService { `${summary.outsideRecentWindow} outside recent window`, ]; if (summary.deferred > 0) { - const reason = summary.deferredReason === 'older-than-fallback' - ? 'older than eligible fallback' - : 'not evaluated after selected recent candidate'; - counts.push(`${summary.deferred} ${reason}`); + counts.push(`${summary.deferred} not evaluated after selected recent candidate`); } this.logger.info(`r/${subreddit} listing: ${counts.join('; ')}`); } diff --git a/tests/monitor.test.ts b/tests/monitor.test.ts index 3dc63f3..745ef2d 100644 --- a/tests/monitor.test.ts +++ b/tests/monitor.test.ts @@ -345,7 +345,7 @@ describe('MonitorService', () => { expect(result[0].id).toBe('t3_old'); }); - it('labels deferred listing posts as older than the eligible fallback', async () => { + it('screens every older fallback candidate before selecting the newest one', async () => { const now = Math.floor(Date.now() / 1000); const fallback: RedditPost = { id: 't3_fallback', subreddit: 'sub1', author: 'u_fallback', title: 'Fallback', @@ -360,14 +360,14 @@ describe('MonitorService', () => { recentWindowMinutes: 60, }, }); - monitor = new MonitorService( - createMockRedditApi([fallback, older]), createMockPostsRepo(), createMockMessagesRepo(), config, logger, 0, - ); + const redditApi = createMockRedditApi([fallback, older]); + monitor = new MonitorService(redditApi, createMockPostsRepo(), createMockMessagesRepo(), config, logger, 0); - await monitor.getUnprocessedPosts(); + await expect(monitor.getUnprocessedPosts()).resolves.toEqual([fallback]); + expect(redditApi.isSellerProfile).toHaveBeenCalledTimes(2); expect(logger.logs).toContainEqual(expect.objectContaining({ - message: expect.stringContaining('1 older than eligible fallback'), + message: expect.stringContaining('2 eligible; 2 outside recent window'), })); });