From bf1884a2c755d8712478f9812c82cff1ba68ab18 Mon Sep 17 00:00:00 2001 From: Dotta Date: Sun, 7 Jun 2026 04:44:29 +0000 Subject: [PATCH] Fix server test:run regressions on the Documents branch The Documents feature wired documentReviewService(db) into issueRoutes (PAP-10523) and added the document review/suggestion routes, but two PR-blocking gaps remained: - 15 server route-test scaffolds mock ../services/index.js without the new documentReviewService export, so createApp threw "No documentReviewService export is defined" (129 failures). PAP-10578 only patched 2 of the affected files. Add the same remapOpenSuggestionsForDocument stub to the rest. - The OpenAPI spec (openapi-routes "covers the mounted server routes exactly") was missing the 9 document review/suggestion routes. Declare them via registerCurrentRoute with their validators, and list the four resource-creating POSTs in CREATED_OPERATIONS for 201 parity with the annotation routes. pnpm -r typecheck and the full server suite pass. Co-Authored-By: Claude Opus 4.8 --- .../issue-activity-events-routes.test.ts | 1 + ...ue-agent-mutation-ownership-routes.test.ts | 2 + ...e-assigned-backlog-contract-routes.test.ts | 1 + .../__tests__/issue-attachment-routes.test.ts | 1 + .../issue-closed-workspace-routes.test.ts | 1 + .../issue-comment-cancel-routes.test.ts | 1 + .../issue-comment-reopen-routes.test.ts | 1 + .../issue-dependency-wakeups-routes.test.ts | 1 + .../issue-execution-policy-routes.test.ts | 1 + .../__tests__/issue-feedback-routes.test.ts | 1 + .../__tests__/issue-telemetry-routes.test.ts | 1 + .../issue-thread-interaction-routes.test.ts | 1 + ...issue-update-comment-wakeup-routes.test.ts | 2 + .../issue-workspace-command-authz.test.ts | 1 + .../issues-goal-context-routes.test.ts | 1 + server/src/routes/openapi.ts | 88 +++++++++++++++++++ 16 files changed, 105 insertions(+) diff --git a/server/src/__tests__/issue-activity-events-routes.test.ts b/server/src/__tests__/issue-activity-events-routes.test.ts index 9b6daa189b1..1eb7d16d479 100644 --- a/server/src/__tests__/issue-activity-events-routes.test.ts +++ b/server/src/__tests__/issue-activity-events-routes.test.ts @@ -83,6 +83,7 @@ function registerModuleMocks() { getById: vi.fn(async () => null), }), documentAnnotationService: () => ({ remapOpenThreadsForDocument: async () => [] }), + documentReviewService: () => ({ remapOpenSuggestionsForDocument: async () => [] }), documentService: () => ({}), executionWorkspaceService: () => ({}), feedbackService: () => mockFeedbackService, diff --git a/server/src/__tests__/issue-agent-mutation-ownership-routes.test.ts b/server/src/__tests__/issue-agent-mutation-ownership-routes.test.ts index 31bf37ffe15..af2e50f2916 100644 --- a/server/src/__tests__/issue-agent-mutation-ownership-routes.test.ts +++ b/server/src/__tests__/issue-agent-mutation-ownership-routes.test.ts @@ -100,6 +100,7 @@ function registerRouteMocks() { vi.doMock("../services/documents.js", () => ({ documentAnnotationService: () => ({ remapOpenThreadsForDocument: async () => [] }), + documentReviewService: () => ({ remapOpenSuggestionsForDocument: async () => [] }), documentService: () => mockDocumentService, })); @@ -123,6 +124,7 @@ function registerRouteMocks() { clampIssueListLimit: (value: number) => Math.min(Math.max(value, 1), 500), companyService: () => mockCompanyService, documentAnnotationService: () => ({ remapOpenThreadsForDocument: async () => [] }), + documentReviewService: () => ({ remapOpenSuggestionsForDocument: async () => [] }), documentService: () => mockDocumentService, executionWorkspaceService: () => ({}), feedbackService: () => ({ diff --git a/server/src/__tests__/issue-assigned-backlog-contract-routes.test.ts b/server/src/__tests__/issue-assigned-backlog-contract-routes.test.ts index 13d8c727ead..377ac649ee9 100644 --- a/server/src/__tests__/issue-assigned-backlog-contract-routes.test.ts +++ b/server/src/__tests__/issue-assigned-backlog-contract-routes.test.ts @@ -46,6 +46,7 @@ vi.mock("../services/index.js", () => ({ getById: vi.fn(async () => ({ id: "company-1", attachmentMaxBytes: 10 * 1024 * 1024 })), }), documentAnnotationService: () => ({ remapOpenThreadsForDocument: async () => [] }), + documentReviewService: () => ({ remapOpenSuggestionsForDocument: async () => [] }), documentService: () => ({ getIssueDocumentPayload: vi.fn(async () => ({})), }), diff --git a/server/src/__tests__/issue-attachment-routes.test.ts b/server/src/__tests__/issue-attachment-routes.test.ts index 3b47cabe3ff..c390d24602f 100644 --- a/server/src/__tests__/issue-attachment-routes.test.ts +++ b/server/src/__tests__/issue-attachment-routes.test.ts @@ -50,6 +50,7 @@ function registerRouteMocks() { }), companyService: () => mockCompanyService, documentAnnotationService: () => ({ remapOpenThreadsForDocument: async () => [] }), + documentReviewService: () => ({ remapOpenSuggestionsForDocument: async () => [] }), documentService: () => ({}), executionWorkspaceService: () => ({}), feedbackService: () => ({ diff --git a/server/src/__tests__/issue-closed-workspace-routes.test.ts b/server/src/__tests__/issue-closed-workspace-routes.test.ts index fd322bc898d..ffaf17faaf7 100644 --- a/server/src/__tests__/issue-closed-workspace-routes.test.ts +++ b/server/src/__tests__/issue-closed-workspace-routes.test.ts @@ -82,6 +82,7 @@ function registerServiceMocks() { getById: vi.fn(async () => null), }), documentAnnotationService: () => ({ remapOpenThreadsForDocument: async () => [] }), + documentReviewService: () => ({ remapOpenSuggestionsForDocument: async () => [] }), documentService: () => ({}), executionWorkspaceService: () => mockExecutionWorkspaceService, feedbackService: () => ({ diff --git a/server/src/__tests__/issue-comment-cancel-routes.test.ts b/server/src/__tests__/issue-comment-cancel-routes.test.ts index 8c841f08d1a..93c35138b3e 100644 --- a/server/src/__tests__/issue-comment-cancel-routes.test.ts +++ b/server/src/__tests__/issue-comment-cancel-routes.test.ts @@ -99,6 +99,7 @@ function registerModuleMocks() { accessService: () => mockAccessService, agentService: () => ({ getById: vi.fn(async () => null) }), documentAnnotationService: () => mockDocumentAnnotationService, + documentReviewService: () => ({ remapOpenSuggestionsForDocument: async () => [] }), documentService: () => ({}), executionWorkspaceService: () => ({}), feedbackService: () => mockFeedbackService, diff --git a/server/src/__tests__/issue-comment-reopen-routes.test.ts b/server/src/__tests__/issue-comment-reopen-routes.test.ts index 4043d86a37b..57cbad01d1d 100644 --- a/server/src/__tests__/issue-comment-reopen-routes.test.ts +++ b/server/src/__tests__/issue-comment-reopen-routes.test.ts @@ -128,6 +128,7 @@ vi.mock("../services/index.js", () => ({ accessService: () => mockAccessService, agentService: () => mockAgentService, documentAnnotationService: () => ({ remapOpenThreadsForDocument: async () => [] }), + documentReviewService: () => ({ remapOpenSuggestionsForDocument: async () => [] }), documentService: () => ({}), executionWorkspaceService: () => ({}), feedbackService: () => mockFeedbackService, diff --git a/server/src/__tests__/issue-dependency-wakeups-routes.test.ts b/server/src/__tests__/issue-dependency-wakeups-routes.test.ts index a498265326a..12ff8929af8 100644 --- a/server/src/__tests__/issue-dependency-wakeups-routes.test.ts +++ b/server/src/__tests__/issue-dependency-wakeups-routes.test.ts @@ -28,6 +28,7 @@ vi.mock("../services/index.js", () => ({ getById: vi.fn(), }), documentAnnotationService: () => ({ remapOpenThreadsForDocument: async () => [] }), + documentReviewService: () => ({ remapOpenSuggestionsForDocument: async () => [] }), documentService: () => ({ getIssueDocumentPayload: vi.fn(async () => ({})), }), diff --git a/server/src/__tests__/issue-execution-policy-routes.test.ts b/server/src/__tests__/issue-execution-policy-routes.test.ts index cce87c1b4eb..792d769c2e2 100644 --- a/server/src/__tests__/issue-execution-policy-routes.test.ts +++ b/server/src/__tests__/issue-execution-policy-routes.test.ts @@ -76,6 +76,7 @@ function registerModuleMocks() { })), }), documentAnnotationService: () => ({ remapOpenThreadsForDocument: async () => [] }), + documentReviewService: () => ({ remapOpenSuggestionsForDocument: async () => [] }), documentService: () => ({}), executionWorkspaceService: () => ({}), feedbackService: () => ({ diff --git a/server/src/__tests__/issue-feedback-routes.test.ts b/server/src/__tests__/issue-feedback-routes.test.ts index 7e4107d6d84..a27774c1639 100644 --- a/server/src/__tests__/issue-feedback-routes.test.ts +++ b/server/src/__tests__/issue-feedback-routes.test.ts @@ -88,6 +88,7 @@ function registerModuleMocks() { accessService: () => mockAccessService, agentService: () => mockAgentService, documentAnnotationService: () => ({ remapOpenThreadsForDocument: async () => [] }), + documentReviewService: () => ({ remapOpenSuggestionsForDocument: async () => [] }), documentService: () => ({}), executionWorkspaceService: () => mockExecutionWorkspaceService, goalService: () => ({}), diff --git a/server/src/__tests__/issue-telemetry-routes.test.ts b/server/src/__tests__/issue-telemetry-routes.test.ts index 9c97818d830..e003ca17757 100644 --- a/server/src/__tests__/issue-telemetry-routes.test.ts +++ b/server/src/__tests__/issue-telemetry-routes.test.ts @@ -51,6 +51,7 @@ function registerModuleMocks() { }), agentService: () => mockAgentService, documentAnnotationService: () => ({ remapOpenThreadsForDocument: async () => [] }), + documentReviewService: () => ({ remapOpenSuggestionsForDocument: async () => [] }), documentService: () => ({}), executionWorkspaceService: () => ({}), feedbackService: () => ({}), diff --git a/server/src/__tests__/issue-thread-interaction-routes.test.ts b/server/src/__tests__/issue-thread-interaction-routes.test.ts index a0b12257e4c..fec940bd6e7 100644 --- a/server/src/__tests__/issue-thread-interaction-routes.test.ts +++ b/server/src/__tests__/issue-thread-interaction-routes.test.ts @@ -74,6 +74,7 @@ function registerModuleMocks() { ISSUE_LIST_DEFAULT_LIMIT: 500, ISSUE_LIST_MAX_LIMIT: 1000, documentAnnotationService: () => ({ remapOpenThreadsForDocument: async () => [] }), + documentReviewService: () => ({ remapOpenSuggestionsForDocument: async () => [] }), documentService: () => ({}), executionWorkspaceService: () => ({}), feedbackService: () => ({ diff --git a/server/src/__tests__/issue-update-comment-wakeup-routes.test.ts b/server/src/__tests__/issue-update-comment-wakeup-routes.test.ts index 89b1b257de2..64203bec50c 100644 --- a/server/src/__tests__/issue-update-comment-wakeup-routes.test.ts +++ b/server/src/__tests__/issue-update-comment-wakeup-routes.test.ts @@ -49,6 +49,7 @@ vi.mock("../services/index.js", () => ({ })), }), documentAnnotationService: () => ({ remapOpenThreadsForDocument: async () => [] }), + documentReviewService: () => ({ remapOpenSuggestionsForDocument: async () => [] }), documentService: () => ({}), executionWorkspaceService: () => ({}), feedbackService: () => ({ @@ -118,6 +119,7 @@ function registerModuleMocks() { })), }), documentAnnotationService: () => ({ remapOpenThreadsForDocument: async () => [] }), + documentReviewService: () => ({ remapOpenSuggestionsForDocument: async () => [] }), documentService: () => ({}), executionWorkspaceService: () => ({}), feedbackService: () => ({ diff --git a/server/src/__tests__/issue-workspace-command-authz.test.ts b/server/src/__tests__/issue-workspace-command-authz.test.ts index 18494d1a493..8f5457da853 100644 --- a/server/src/__tests__/issue-workspace-command-authz.test.ts +++ b/server/src/__tests__/issue-workspace-command-authz.test.ts @@ -110,6 +110,7 @@ function registerRouteMocks() { accessService: () => mockAccessService, agentService: () => mockAgentService, documentAnnotationService: () => ({ remapOpenThreadsForDocument: async () => [] }), + documentReviewService: () => ({ remapOpenSuggestionsForDocument: async () => [] }), documentService: () => ({}), executionWorkspaceService: () => mockExecutionWorkspaceService, feedbackService: () => mockFeedbackService, diff --git a/server/src/__tests__/issues-goal-context-routes.test.ts b/server/src/__tests__/issues-goal-context-routes.test.ts index 359269e4e43..5e210fed615 100644 --- a/server/src/__tests__/issues-goal-context-routes.test.ts +++ b/server/src/__tests__/issues-goal-context-routes.test.ts @@ -105,6 +105,7 @@ vi.mock("../services/index.js", () => ({ accessService: () => mockAccessService, agentService: () => mockAgentService, documentAnnotationService: () => ({ remapOpenThreadsForDocument: async () => [] }), + documentReviewService: () => ({ remapOpenSuggestionsForDocument: async () => [] }), documentService: () => mockDocumentsService, environmentService: () => mockEnvironmentService, executionWorkspaceService: () => mockExecutionWorkspaceService, diff --git a/server/src/routes/openapi.ts b/server/src/routes/openapi.ts index dba4263196f..c3e6b5c487b 100644 --- a/server/src/routes/openapi.ts +++ b/server/src/routes/openapi.ts @@ -119,6 +119,15 @@ import { createDocumentAnnotationCommentSchema, createDocumentAnnotationThreadSchema, updateDocumentAnnotationThreadSchema, + // Document review + createDocumentReviewThreadSchema, + createDocumentReviewCommentSchema, + updateDocumentReviewThreadSchema, + createDocumentSuggestionSchema, + createDocumentSuggestionCommentSchema, + acceptDocumentSuggestionSchema, + rejectDocumentSuggestionSchema, + resolveDocumentSuggestionSchema, // Issue recovery and decomposition createAcceptedPlanDecompositionSchema, resolveIssueRecoveryActionSchema, @@ -605,6 +614,10 @@ const CREATED_OPERATIONS = new Set([ "POST /api/companies/{companyId}/labels", "POST /api/issues/{id}/documents/{key}/annotations", "POST /api/issues/{id}/documents/{key}/annotations/{threadId}/comments", + "POST /api/issues/{id}/documents/{key}/review-comments", + "POST /api/issues/{id}/documents/{key}/review-comments/{threadId}/comments", + "POST /api/issues/{id}/documents/{key}/suggestions", + "POST /api/issues/{id}/documents/{key}/suggestions/{suggestionId}/comments", "POST /api/issues/{id}/work-products", "POST /api/issues/{id}/low-trust/promotions", "POST /api/issues/{id}/approvals", @@ -4373,6 +4386,81 @@ registerCurrentRoute({ body: updateDocumentAnnotationThreadSchema, }); +registerCurrentRoute({ + method: "get", + path: "/api/issues/{id}/documents/{key}/review-index", + tags: ["issues"], + summary: "Get the document review index", +}); + +registerCurrentRoute({ + method: "post", + path: "/api/issues/{id}/documents/{key}/review-comments", + tags: ["issues"], + summary: "Create a document review thread", + body: createDocumentReviewThreadSchema, + responses: { 201: r.ok(), 400: r.badRequest, 401: r.unauthorized, 404: r.notFound }, +}); + +registerCurrentRoute({ + method: "post", + path: "/api/issues/{id}/documents/{key}/review-comments/{threadId}/comments", + tags: ["issues"], + summary: "Add a document review comment", + body: createDocumentReviewCommentSchema, + responses: { 201: r.ok(), 400: r.badRequest, 401: r.unauthorized, 404: r.notFound }, +}); + +registerCurrentRoute({ + method: "patch", + path: "/api/issues/{id}/documents/{key}/review-comments/{threadId}", + tags: ["issues"], + summary: "Update a document review thread", + body: updateDocumentReviewThreadSchema, +}); + +registerCurrentRoute({ + method: "post", + path: "/api/issues/{id}/documents/{key}/suggestions", + tags: ["issues"], + summary: "Create a document suggestion", + body: createDocumentSuggestionSchema, + responses: { 201: r.ok(), 400: r.badRequest, 401: r.unauthorized, 404: r.notFound }, +}); + +registerCurrentRoute({ + method: "post", + path: "/api/issues/{id}/documents/{key}/suggestions/{suggestionId}/comments", + tags: ["issues"], + summary: "Add a document suggestion comment", + body: createDocumentSuggestionCommentSchema, + responses: { 201: r.ok(), 400: r.badRequest, 401: r.unauthorized, 404: r.notFound }, +}); + +registerCurrentRoute({ + method: "post", + path: "/api/issues/{id}/documents/{key}/suggestions/{suggestionId}/reject", + tags: ["issues"], + summary: "Reject a document suggestion", + body: rejectDocumentSuggestionSchema, +}); + +registerCurrentRoute({ + method: "post", + path: "/api/issues/{id}/documents/{key}/suggestions/{suggestionId}/resolve", + tags: ["issues"], + summary: "Resolve a document suggestion", + body: resolveDocumentSuggestionSchema, +}); + +registerCurrentRoute({ + method: "post", + path: "/api/issues/{id}/documents/{key}/suggestions/{suggestionId}/accept", + tags: ["issues"], + summary: "Accept a document suggestion", + body: acceptDocumentSuggestionSchema, +}); + registerCurrentRoute({ method: "get", path: "/api/issues/{id}/recovery-actions",