diff --git a/apps/hq/src/repos-reminders.ts b/apps/hq/src/repos-reminders.ts index 796e89c..18eec35 100644 --- a/apps/hq/src/repos-reminders.ts +++ b/apps/hq/src/repos-reminders.ts @@ -157,7 +157,7 @@ export function resolveSchedule(db: DB, ruleKind: ScheduleRuleKind, today: strin const row = db.prepare( `SELECT day_offsets, subject, body FROM reminder_schedule WHERE rule_kind=? AND effective_from <= ? AND (effective_to IS NULL OR effective_to > ?) - ORDER BY effective_from DESC LIMIT 1`, + ORDER BY effective_from DESC, id DESC LIMIT 1`, // id DESC breaks effective_from ties deterministically (UUIDv7 is time-ordered → latest insert wins on any engine) ).get(ruleKind, today, today) as { day_offsets: string; subject: string | null; body: string | null } | undefined if (row !== undefined) { const dayOffsets = parseDayOffsets(row.day_offsets) diff --git a/apps/hq/test/reminder-schedule.test.ts b/apps/hq/test/reminder-schedule.test.ts index 5e31987..842838a 100644 --- a/apps/hq/test/reminder-schedule.test.ts +++ b/apps/hq/test/reminder-schedule.test.ts @@ -44,6 +44,19 @@ describe('resolveSchedule', () => { expect(resolveSchedule(db, 'quote_followup', '2025-12-31').source).toBe('default') }) + it('tied effective_from resolves deterministically: highest id wins on any engine', () => { + const db = openDb(':memory:') + const ins = (id: string, offsets: string) => db.prepare( + `INSERT INTO reminder_schedule (id, rule_kind, effective_from, effective_to, day_offsets, subject, body) + VALUES (?, 'quote_followup', '2026-01-01', NULL, ?, NULL, NULL)`, + ).run(id, offsets) + // Insert the higher id FIRST so plain scan order would pick the other row — + // the tiebreaker (id DESC; UUIDv7 ids are time-ordered) must decide, not the plan. + ins('zzzz-high', '2,4') + ins('aaaa-low', '5,10') + expect(resolveSchedule(db, 'quote_followup', '2026-07-17').dayOffsets).toEqual([2, 4]) + }) + it('effective_to closes the window: active requires effective_to > today', () => { const db = openDb(':memory:') insertSchedule(db, { ruleKind: 'quote_followup', from: '2026-01-01', to: '2026-07-01', offsets: '1,2' })