mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-24 10:13:11 +02:00
fix(wake-queue): skip malformed queued comment ids so one bad id cannot block an issue's wakes (#13912)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The wake queue decides whether a finishing run's `@`-mention actually wakes the mentioned agent, by checking the liveness of the comment ids queued in the wake payload > - `getQueuedCommentLiveness` passes every queued comment id straight into an SQL `inArray`. Postgres rejects the whole statement on the first malformed uuid, so one bad id (for example an 8-char short form written into a wake payload) silently blocks every queued wake for that issue > - The run that triggers the check still records `succeeded`, so from the board the agent finished its work and the mentioned agent simply never responds; the reporter hit this twice on the same long-lived issue > - This pull request filters the queued ids with the existing `isUuidLike` helper before the query, and skips the query entirely when nothing valid remains > - The benefit is that a malformed id is skipped instead of poisoning the batch — it can never match a comment row anyway, so the downstream liveness semantics do not change Fixes: #13908 Related issue class (malformed ids reaching database queries): #887, #7639, #8093, #11018, #13504 — this is the first report for the wake-queue site. ## What Changed - `server/src/modules/wake-queue/adapters/postgres.ts`: in `getQueuedCommentLiveness`, filter `queuedCommentIds` through `isUuidLike` before building the `inArray` predicate; when no valid uuid remains, skip the query and return an empty row set. - The post-processing loops now iterate the filtered id list, which is equivalent because a malformed id can never match a comment row. ## Verification - New embedded-Postgres regression tests in `server/src/modules/wake-queue/adapters/postgres.test.ts`: - a batch mixing one live comment id, one malformed short-form id, and one valid-but-missing uuid returns only the live comment instead of throwing; - an all-malformed batch returns nothing live instead of generating `inArray ()`. - `./node_modules/.bin/vitest run server/src/modules/wake-queue/adapters/postgres.test.ts` — 58/58 pass. ## Risks Low risk. The only behavioral change is that a wake batch that would previously fail the whole statement now dispatches the valid entries. A malformed id previously matched no rows (the statement errored before any filtering), so treating it as not-live is exactly what the old downstream filters would have concluded had the query run. ## Model Used Codex (OpenAI GPT-5, coding agent, tool use, repo-level context) — assisted with locating the call site, authoring the guard, and the regression tests; human review before submission. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: 馨冉 <xinxincui239@gmail.com>
This commit is contained in:
1 parent
1b2632facc
commit
7c6d977929
2 files changed
+58
-4
No files matched your search
@@ -6,7 +6,7 @@ import { currentConversationCommentCondition } from "../../../services/agent-con
|
||||
import { getExecutionBlocker } from "../../../services/execution-blocker.js";
|
||||
import { and, asc, eq, inArray, isNull, notInArray, or, sql } from "drizzle-orm";
|
||||
import type { Db } from "@paperclipai/db";
|
||||
import { extractIssueReferenceIdentifiers } from "@paperclipai/shared";
|
||||
import { extractIssueReferenceIdentifiers, isUuidLike } from "@paperclipai/shared";
|
||||
import {
|
||||
activityLog,
|
||||
agentWakeupRequests,
|
||||
@@ -285,12 +285,20 @@ function buildTransaction(tx: Db, deps: WakeQueuePostgresAdapterDeps, db: Db, ru
|
||||
},
|
||||
|
||||
async getQueuedCommentLiveness({ companyId, issueId, wakeAgentId, finishingRunId, finishingRunAgentId, queuedCommentIds }) {
|
||||
const rows = await tx
|
||||
// Malformed ids (for example an 8-char short form written into a wake
|
||||
// payload) can never match a comment row, but Postgres rejects the whole
|
||||
// `inArray` statement on the first invalid uuid and blocks every queued
|
||||
// wake for the issue. Skip them up front so one bad id cannot take down
|
||||
// the batch; the liveness filters below already treat them as not live.
|
||||
const queryableCommentIds = queuedCommentIds
|
||||
.map((commentId) => commentId.trim())
|
||||
.filter((commentId) => isUuidLike(commentId));
|
||||
const rows = queryableCommentIds.length === 0 ? [] : await tx
|
||||
.select({ id: issueComments.id, deletedAt: issueComments.deletedAt, createdByRunId: issueComments.createdByRunId })
|
||||
.from(issueComments)
|
||||
.where(and(eq(issueComments.companyId, companyId), eq(issueComments.issueId, issueId), inArray(issueComments.id, queuedCommentIds), currentConversationCommentCondition()));
|
||||
.where(and(eq(issueComments.companyId, companyId), eq(issueComments.issueId, issueId), inArray(issueComments.id, queryableCommentIds), currentConversationCommentCondition()));
|
||||
const targetsFinishingRunAgent = wakeAgentId === finishingRunAgentId;
|
||||
const liveNonSelfCommentIds = queuedCommentIds.filter((commentId) => {
|
||||
const liveNonSelfCommentIds = queryableCommentIds.filter((commentId) => {
|
||||
const row = rows.find((candidate) => candidate.id === commentId);
|
||||
return Boolean(row && !row.deletedAt && (!targetsFinishingRunAgent || row.createdByRunId !== finishingRunId));
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user