OUT-3736 | Eligibility SQL: single-day reminder query#1236
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR adds
Confidence Score: 3/5Safe to merge in terms of runtime impact (no cron wiring), but the module will not function correctly once wired without fixes. The module is net-new and not yet imported anywhere, so merging introduces no immediate runtime regression. However, two defects mean it cannot be wired up as-is: the TaskReminderType enum is absent from every Prisma schema file and migration, and the unguarded parent LEFT JOIN will silently drop subtask reminders whenever a parent task has been soft-deleted. src/jobs/notifications/eligibility.ts requires attention for both the TaskReminderType schema gap and the soft-deleted parent join filter. Important Files Changed
Reviews (1): Last reviewed commit: "feat(OUT-3736): add eligibility SQL for ..." | Re-trigger Greptile |
|
Deployment failed with the following error: Learn More: https://vercel.link/multiple-function-regions |
cc71a88 to
ff14b29
Compare
Adds getEligibleReminders() that returns one row per (task, assignee, reminderType) eligible for a task reminder today, across the six exact-day windows defined in the Reminder Emails PRD. The EligibilityRow carries the companyId derived per assigneeType so the future sender can stamp ClientNotifications.companyId and Copilot's recipientCompanyId without a follow-up task lookup. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Without this, a same-assignee subtask under a soft-deleted (or archived / completed) parent is silently dropped: the parent itself is filtered out by the main WHERE, but the LEFT JOIN still returns its assigneeId, which fails IS DISTINCT FROM and drops the subtask. Filtering parent lifecycle in the JOIN makes parent.assigneeId come back NULL for dead parents, so subtasks correctly emit their own reminder. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
I think these comments are too much. Also the name of the file. Maybe it should be get-tasks-for-reminder, or something else rather that just eligibility.ts. The name is very generic imo.
Changes
src/jobs/notifications/eligibility.tsexposinggetEligibleReminders()— a single raw-SQL query that returns one row per(task, assignee, reminderType)eligible for a task reminder today.NO_DUE_DATE_3D,NO_DUE_DATE_7D,DUE_DATE_BEFORE_3D,DUE_DATE_TODAY,DUE_DATE_OVERDUE_3D,DUE_DATE_OVERDUE_7D.IS DISTINCT FROMso a NULL parent assignee still counts as "different").Task.dueDate(VARCHAR(10)) before::datecast so one bad row can't poison the query.EligibilityRowcarriescompanyIdderived perassigneeType(client →task.companyId; company →task.assigneeId; internalUser →null) so the future sender can stampClientNotifications.companyIdand Copilot'srecipientCompanyIdwithout re-fetching the task.eligibility.test.tscovering the function's behavior (mocked$queryRaw).Linear: https://linear.app/assemblycom/issue/OUT-3736/eligibility-sql-single-day-reminder-query
Testing Criteria
yarn test src/jobs/notifications/eligibility.test.ts— 4 passing, 100% coverage on the module.assigneeTypecompanyIdderivation matches whatnotification.service.ts:558andClientNotifications's unique key(taskId, clientId, companyId, deletedAt)expect.Boundary fixtures (D-3 hit, D-2 / D-4 miss) are deferred to the consumer ticket where a Postgres-backed integration test is more useful — this module is a thin SQL wrapper and is currently not wired into any cron.
Notes
TaskReminderSentsunique constraint is the dedupe primitive at insert time, so a retried cron run is naturally idempotent. The exact-day windows mean a given (task, window) pair only matches on one calendar day, so day-N reminders don't repeat in normal operation.copilot.getCompanyClients(...). Keeping the SQL Copilot-free mirrors the pattern insrc/jobs/auto-archive/auto-archive-completed-tasks.ts:31-82.Impact & Surface Area of Change
🤖 Generated with Claude Code