From 75bbffdb3aeeb8f46a1c7d301ab8e5bf222de96c Mon Sep 17 00:00:00 2001 From: RealDiligent Date: Tue, 28 Jul 2026 02:50:29 +0800 Subject: [PATCH] docs(openapi): document validate-linked-issue + check-before-start routes Two live POST /v1/repos/:owner/:repo pre-work-check routes (validate-linked-issue, check-before-start) each already back an MCP tool with its own Zod shapes but were absent from the OpenAPI spec. Add ValidateLinkedIssue/CheckBeforeStart request+response schemas in schemas.ts (field-level parity with the MCP inputSchema/outputSchema), register both as components and registerPath entries in spec.ts (mirroring the gate-config/effective + evaluate-escalation patterns), and regenerate the committed apps/loopover-ui/public/openapi.json. --- apps/loopover-ui/public/openapi.json | 253 +++++++++++++++++++++++++++ src/openapi/schemas.ts | 70 ++++++++ src/openapi/spec.ts | 48 +++++ 3 files changed, 371 insertions(+) diff --git a/apps/loopover-ui/public/openapi.json b/apps/loopover-ui/public/openapi.json index bd6783535..fd1900a07 100644 --- a/apps/loopover-ui/public/openapi.json +++ b/apps/loopover-ui/public/openapi.json @@ -16134,6 +16134,137 @@ ] } } + }, + "ValidateLinkedIssueRequest": { + "type": "object", + "properties": { + "owner": { + "type": "string" + }, + "repo": { + "type": "string" + }, + "issueNumber": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, + "plannedChange": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "changedFiles": { + "type": "array", + "items": { + "type": "string" + } + }, + "contributorLogin": { + "type": "string" + } + } + } + }, + "required": [ + "owner", + "repo", + "issueNumber" + ] + }, + "ValidateLinkedIssueResponse": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "repoFullName": { + "type": "string" + }, + "issueNumber": { + "type": "number" + }, + "found": { + "type": "boolean" + }, + "multiplierStatus": { + "type": "string" + }, + "multiplierWouldApply": { + "type": "boolean" + }, + "blockingReason": { + "type": "string" + }, + "reasons": { + "nullable": true + }, + "report": { + "nullable": true + } + } + }, + "CheckBeforeStartRequest": { + "type": "object", + "properties": { + "owner": { + "type": "string" + }, + "repo": { + "type": "string" + }, + "issueNumber": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, + "title": { + "type": "string" + }, + "plannedPaths": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "owner", + "repo" + ] + }, + "CheckBeforeStartResponse": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "repoFullName": { + "type": "string" + }, + "found": { + "type": "boolean" + }, + "claimStatus": { + "type": "string" + }, + "duplicateClusterRisk": { + "type": "string" + }, + "recommendation": { + "type": "string" + }, + "reasons": { + "nullable": true + }, + "blockers": { + "nullable": true + }, + "report": { + "nullable": true + } + } } }, "parameters": {}, @@ -21768,6 +21899,128 @@ } ] } + }, + "/v1/repos/{owner}/{repo}/validate-linked-issue": { + "post": { + "summary": "Validate a linked issue for a planned change — REST mirror of loopover_validate_linked_issue (#9304)", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "owner", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "repo", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidateLinkedIssueRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Linked-issue validation over the planned change — mirrors the loopover_validate_linked_issue MCP tool's output shape", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidateLinkedIssueResponse" + } + } + } + }, + "400": { + "description": "Invalid validate-linked-issue request body" + }, + "401": { + "description": "Missing or invalid static protected API token" + }, + "403": { + "description": "Static mcp credential is outside MCP_READ_REPO_ALLOWLIST for this repo" + } + }, + "security": [ + { + "LoopOverBearer": [] + }, + { + "LoopOverSessionCookie": [] + } + ] + } + }, + "/v1/repos/{owner}/{repo}/check-before-start": { + "post": { + "summary": "Pre-work claim/duplicate check before starting an issue — REST mirror of loopover_check_before_start (#9304)", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "owner", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "repo", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CheckBeforeStartRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Claim status, duplicate-cluster risk, and a start recommendation — mirrors the loopover_check_before_start MCP tool's output shape", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CheckBeforeStartResponse" + } + } + } + }, + "400": { + "description": "Invalid check-before-start request body" + }, + "401": { + "description": "Missing or invalid static protected API token" + }, + "403": { + "description": "Static mcp credential is outside MCP_READ_REPO_ALLOWLIST for this repo" + } + }, + "security": [ + { + "LoopOverBearer": [] + }, + { + "LoopOverSessionCookie": [] + } + ] + } } }, "servers": [ diff --git a/src/openapi/schemas.ts b/src/openapi/schemas.ts index 5ed13dd4b..31bbd06c7 100644 --- a/src/openapi/schemas.ts +++ b/src/openapi/schemas.ts @@ -2039,6 +2039,76 @@ export const EvaluateEscalationResponseSchema = z }) .openapi("EvaluateEscalationResponse"); +/** + * Request body for POST /v1/repos/{owner}/{repo}/validate-linked-issue. Field-level parity with + * `validateLinkedIssueShape` (the `loopover_validate_linked_issue` MCP tool `inputSchema`) in + * src/mcp/server.ts — #9304. owner/repo are also path params; the body carries the planned-change context. + */ +export const ValidateLinkedIssueRequestSchema = z + .object({ + owner: z.string(), + repo: z.string(), + issueNumber: z.number().int().positive(), + plannedChange: z + .object({ + title: z.string().optional(), + changedFiles: z.array(z.string()).optional(), + contributorLogin: z.string().optional(), + }) + .optional(), + }) + .openapi("ValidateLinkedIssueRequest"); + +/** + * Response body for POST /v1/repos/{owner}/{repo}/validate-linked-issue. Field-level parity with + * `validateLinkedIssueOutputSchema` (the `loopover_validate_linked_issue` MCP tool `outputSchema`) — #9304. + */ +export const ValidateLinkedIssueResponseSchema = z + .object({ + status: z.string().optional(), + repoFullName: z.string().optional(), + issueNumber: z.number().optional(), + found: z.boolean().optional(), + multiplierStatus: z.string().optional(), + multiplierWouldApply: z.boolean().optional(), + blockingReason: z.string().optional(), + reasons: z.unknown().optional(), + report: z.unknown().optional(), + }) + .openapi("ValidateLinkedIssueResponse"); + +/** + * Request body for POST /v1/repos/{owner}/{repo}/check-before-start. Field-level parity with + * `checkBeforeStartShape` (the `loopover_check_before_start` MCP tool `inputSchema`) in src/mcp/server.ts — #9304. + */ +export const CheckBeforeStartRequestSchema = z + .object({ + owner: z.string(), + repo: z.string(), + issueNumber: z.number().int().positive().optional(), + title: z.string().optional(), + plannedPaths: z.array(z.string()).optional(), + }) + .openapi("CheckBeforeStartRequest"); + +/** + * Response body for POST /v1/repos/{owner}/{repo}/check-before-start. Field-level parity with + * `checkBeforeStartOutputSchema` (the `loopover_check_before_start` MCP tool `outputSchema`) — #9304. + */ +export const CheckBeforeStartResponseSchema = z + .object({ + status: z.string().optional(), + repoFullName: z.string().optional(), + found: z.boolean().optional(), + claimStatus: z.string().optional(), + duplicateClusterRisk: z.string().optional(), + recommendation: z.string().optional(), + reasons: z.unknown().optional(), + blockers: z.unknown().optional(), + report: z.unknown().optional(), + }) + .openapi("CheckBeforeStartResponse"); + /** * Request body for POST /v1/loop/results-payload. Field-level parity with `buildResultsPayloadShape` * (the `loopover_build_results_payload` MCP tool `inputSchema`) in src/mcp/server.ts — #9309. diff --git a/src/openapi/spec.ts b/src/openapi/spec.ts index 1b0df5732..8e229221b 100644 --- a/src/openapi/spec.ts +++ b/src/openapi/spec.ts @@ -41,6 +41,10 @@ import { ScoreBreakdownResponseSchema, EvaluateEscalationRequestSchema, EvaluateEscalationResponseSchema, + ValidateLinkedIssueRequestSchema, + ValidateLinkedIssueResponseSchema, + CheckBeforeStartRequestSchema, + CheckBeforeStartResponseSchema, BuildResultsPayloadRequestSchema, BuildResultsPayloadResponseSchema, BuildProgressSnapshotRequestSchema, @@ -207,6 +211,10 @@ export function buildOpenApiSpec() { registry.register("ScoreBreakdownResponse", ScoreBreakdownResponseSchema); registry.register("EvaluateEscalationRequest", EvaluateEscalationRequestSchema); registry.register("EvaluateEscalationResponse", EvaluateEscalationResponseSchema); + registry.register("ValidateLinkedIssueRequest", ValidateLinkedIssueRequestSchema); + registry.register("ValidateLinkedIssueResponse", ValidateLinkedIssueResponseSchema); + registry.register("CheckBeforeStartRequest", CheckBeforeStartRequestSchema); + registry.register("CheckBeforeStartResponse", CheckBeforeStartResponseSchema); registry.register("BuildResultsPayloadRequest", BuildResultsPayloadRequestSchema); registry.register("BuildResultsPayloadResponse", BuildResultsPayloadResponseSchema); registry.register("BuildProgressSnapshotRequest", BuildProgressSnapshotRequestSchema); @@ -564,6 +572,46 @@ export function buildOpenApiSpec() { 403: { description: "Static mcp credential is outside MCP_READ_REPO_ALLOWLIST for this repo" }, }, }); + registry.registerPath({ + method: "post", + path: "/v1/repos/{owner}/{repo}/validate-linked-issue", + summary: "Validate a linked issue for a planned change — REST mirror of loopover_validate_linked_issue (#9304)", + request: { + params: z.object({ owner: z.string(), repo: z.string() }), + body: { + content: { "application/json": { schema: ValidateLinkedIssueRequestSchema } }, + }, + }, + responses: { + 200: { + description: "Linked-issue validation over the planned change — mirrors the loopover_validate_linked_issue MCP tool's output shape", + content: { "application/json": { schema: ValidateLinkedIssueResponseSchema } }, + }, + 400: { description: "Invalid validate-linked-issue request body" }, + 401: { description: "Missing or invalid static protected API token" }, + 403: { description: "Static mcp credential is outside MCP_READ_REPO_ALLOWLIST for this repo" }, + }, + }); + registry.registerPath({ + method: "post", + path: "/v1/repos/{owner}/{repo}/check-before-start", + summary: "Pre-work claim/duplicate check before starting an issue — REST mirror of loopover_check_before_start (#9304)", + request: { + params: z.object({ owner: z.string(), repo: z.string() }), + body: { + content: { "application/json": { schema: CheckBeforeStartRequestSchema } }, + }, + }, + responses: { + 200: { + description: "Claim status, duplicate-cluster risk, and a start recommendation — mirrors the loopover_check_before_start MCP tool's output shape", + content: { "application/json": { schema: CheckBeforeStartResponseSchema } }, + }, + 400: { description: "Invalid check-before-start request body" }, + 401: { description: "Missing or invalid static protected API token" }, + 403: { description: "Static mcp credential is outside MCP_READ_REPO_ALLOWLIST for this repo" }, + }, + }); registry.registerPath({ method: "post", path: "/v1/loop/evaluate-escalation",