From 9adf8fa12aa9a6355eacb7ecb48832583d1b4f0c Mon Sep 17 00:00:00 2001 From: Dotta Date: Thu, 30 Apr 2026 13:39:46 -0500 Subject: [PATCH] Address merge review follow-ups Co-Authored-By: Paperclip --- packages/shared/src/index.ts | 2 ++ packages/shared/src/validators/index.ts | 2 ++ packages/shared/src/validators/issue.ts | 5 +++++ server/src/routes/issues.ts | 3 ++- server/src/services/costs.ts | 2 ++ server/src/services/issue-thread-interactions.ts | 6 ++++-- 6 files changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 86e12248959..4935257e25d 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -671,6 +671,7 @@ export { createIssueThreadInteractionSchema, acceptIssueThreadInteractionSchema, rejectIssueThreadInteractionSchema, + cancelIssueThreadInteractionSchema, respondIssueThreadInteractionSchema, linkIssueApprovalSchema, createIssueAttachmentMetadataSchema, @@ -705,6 +706,7 @@ export { type CreateIssueThreadInteraction, type AcceptIssueThreadInteraction, type RejectIssueThreadInteraction, + type CancelIssueThreadInteraction, type RespondIssueThreadInteraction, type LinkIssueApproval, type CreateIssueAttachmentMetadata, diff --git a/packages/shared/src/validators/index.ts b/packages/shared/src/validators/index.ts index e9141631466..dfa28d726ba 100644 --- a/packages/shared/src/validators/index.ts +++ b/packages/shared/src/validators/index.ts @@ -177,6 +177,7 @@ export { createIssueThreadInteractionSchema, acceptIssueThreadInteractionSchema, rejectIssueThreadInteractionSchema, + cancelIssueThreadInteractionSchema, respondIssueThreadInteractionSchema, linkIssueApprovalSchema, createIssueAttachmentMetadataSchema, @@ -194,6 +195,7 @@ export { type CreateIssueThreadInteraction, type AcceptIssueThreadInteraction, type RejectIssueThreadInteraction, + type CancelIssueThreadInteraction, type RespondIssueThreadInteraction, type LinkIssueApproval, type CreateIssueAttachmentMetadata, diff --git a/packages/shared/src/validators/issue.ts b/packages/shared/src/validators/issue.ts index 9cf3ffddb3a..882b3dd8dc4 100644 --- a/packages/shared/src/validators/issue.ts +++ b/packages/shared/src/validators/issue.ts @@ -448,6 +448,11 @@ export const rejectIssueThreadInteractionSchema = z.object({ }); export type RejectIssueThreadInteraction = z.infer; +export const cancelIssueThreadInteractionSchema = z.object({ + reason: z.string().trim().max(4000).optional(), +}); +export type CancelIssueThreadInteraction = z.infer; + export const respondIssueThreadInteractionSchema = z.object({ answers: z.array(askUserQuestionsAnswerSchema).max(20), summaryMarkdown: multilineTextSchema.pipe(z.string().max(20000)).nullable().optional(), diff --git a/server/src/routes/issues.ts b/server/src/routes/issues.ts index 3b3cce9938a..60916144bf6 100644 --- a/server/src/routes/issues.ts +++ b/server/src/routes/issues.ts @@ -7,6 +7,7 @@ import { issueExecutionDecisions } from "@paperclipai/db"; import { addIssueCommentSchema, acceptIssueThreadInteractionSchema, + cancelIssueThreadInteractionSchema, createIssueAttachmentMetadataSchema, createIssueThreadInteractionSchema, createIssueWorkProductSchema, @@ -3184,7 +3185,7 @@ export function issueRoutes( router.post( "/issues/:id/interactions/:interactionId/cancel", - validate(rejectIssueThreadInteractionSchema), + validate(cancelIssueThreadInteractionSchema), async (req, res) => { const id = req.params.id as string; const interactionId = req.params.interactionId as string; diff --git a/server/src/services/costs.ts b/server/src/services/costs.ts index 7739f3fbcac..abea444e2f1 100644 --- a/server/src/services/costs.ts +++ b/server/src/services/costs.ts @@ -136,6 +136,8 @@ export function costService(db: Db, budgetHooks: BudgetServiceHooks = {}) { }, issueTreeSummary: async (companyId: string, issueId: string) => { + // Callers must resolve and authorize a visible root issue before invoking this. + // The route does that so zero counts are not mistaken for a missing root. const childIssues = alias(issues, "child"); const issueTreeCondition = sql` ${issues.id} IN ( diff --git a/server/src/services/issue-thread-interactions.ts b/server/src/services/issue-thread-interactions.ts index db1f31b531a..de6e165487e 100644 --- a/server/src/services/issue-thread-interactions.ts +++ b/server/src/services/issue-thread-interactions.ts @@ -13,6 +13,7 @@ import type { AcceptIssueThreadInteraction, AskUserQuestionsAnswer, AskUserQuestionsInteraction, + CancelIssueThreadInteraction, CreateIssueThreadInteraction, IssueThreadInteraction, RequestConfirmationInteraction, @@ -26,6 +27,7 @@ import { acceptIssueThreadInteractionSchema, askUserQuestionsPayloadSchema, askUserQuestionsResultSchema, + cancelIssueThreadInteractionSchema, createIssueThreadInteractionSchema, rejectIssueThreadInteractionSchema, requestConfirmationPayloadSchema, @@ -1152,10 +1154,10 @@ export function issueThreadInteractionService(db: Db) { cancelQuestions: async ( issue: { id: string; companyId: string }, interactionId: string, - input: RejectIssueThreadInteraction, + input: CancelIssueThreadInteraction, actor: InteractionActor, ) => { - const data = rejectIssueThreadInteractionSchema.parse(input); + const data = cancelIssueThreadInteractionSchema.parse(input); const current = await db .select() .from(issueThreadInteractions)