From 4b459622e4d9c9e86326160bff8099283021fe4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Guti=C3=A9rrez?= <35082514+alezmad@users.noreply.github.com> Date: Sun, 3 May 2026 10:29:13 +0100 Subject: [PATCH] =?UTF-8?q?fix(api):=20/v1/me/tasks=20query=20=E2=80=94=20?= =?UTF-8?q?completedAt-based=20window=20+=20iso=20cast?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the previous form had drizzle render the date param as a js toString() value which postgres rejected (Fri Apr 03 2026 GMT+0000 doesn't parse as timestamp without help). fix: serialize to iso then cast ::timestamp inside the sql tag. simplified the where clause too — the prior conditional dance emitted "status != completed" three times redundantly. one "completed_at IS NULL OR > window" covers active + recent-done in one clause; status filtering happens client-side via the existing statusSet pass. also cleans up the debug probe scaffolding. Co-Authored-By: Claude Opus 4.7 (1M context) --- packages/api/src/modules/mesh/v1-router.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/api/src/modules/mesh/v1-router.ts b/packages/api/src/modules/mesh/v1-router.ts index cd56f8b..d924018 100644 --- a/packages/api/src/modules/mesh/v1-router.ts +++ b/packages/api/src/modules/mesh/v1-router.ts @@ -953,7 +953,9 @@ export const v1Router = new Hono() ? new Set(["open", "claimed"]) : new Set(statusFilter.split(",").map((s) => s.trim())); - const completedWindow = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); + const completedWindowIso = new Date( + Date.now() - 30 * 24 * 60 * 60 * 1000, + ).toISOString(); const rows = await db .select({ id: meshTask.id, @@ -974,18 +976,14 @@ export const v1Router = new Hono() .where( and( inArray(meshTask.meshId, meshIds), - // Bound the completed-task scan; open/claimed have no time filter. - ...(statusSet === null || statusSet.has("completed") - ? [] - : [sql`${meshTask.status} != 'completed'`]), - ...(statusFilter === "active" - ? [sql`${meshTask.status} != 'completed'`] - : []), - // Hide stale completed tasks beyond the window unless explicitly all. + // For "active" (default) and any non-"all" status filter: + // hide completed tasks older than 30 days. completedAt is + // null on open/claimed, so "completed_at IS NULL OR > window" + // keeps everything non-completed plus recent completions. ...(statusFilter === "all" ? [] : [ - sql`(${meshTask.status} != 'completed' OR ${meshTask.completedAt} > ${completedWindow})`, + sql`(${meshTask.completedAt} IS NULL OR ${meshTask.completedAt} > ${completedWindowIso}::timestamp)`, ]), ), )