Skip to content

Commit 726a12e

Browse files
authored
fix(api): document ai-review-findings pull request route in openapi spec (#9417)
Closes #9305 The GET /v1/repos/{owner}/{repo}/pulls/{number}/ai-review-findings route existed and was live, but was never registered in the OpenAPI spec, unlike its maintainer-packet and reviewability siblings. Adds PullRequestAiReviewFindingsSchema, registers the path (including its login query param), and regenerates apps/loopover-ui/public/openapi.json.
1 parent 4164e09 commit 726a12e

4 files changed

Lines changed: 190 additions & 0 deletions

File tree

apps/loopover-ui/public/openapi.json

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14652,6 +14652,80 @@
1465214652
"privateSummary"
1465314653
]
1465414654
},
14655+
"PullRequestAiReviewFindings": {
14656+
"type": "object",
14657+
"properties": {
14658+
"status": {
14659+
"type": "string",
14660+
"enum": [
14661+
"ready",
14662+
"not_found",
14663+
"ai_review_off"
14664+
]
14665+
},
14666+
"repoFullName": {
14667+
"type": "string"
14668+
},
14669+
"pullNumber": {
14670+
"type": "number"
14671+
},
14672+
"login": {
14673+
"type": "string"
14674+
},
14675+
"headSha": {
14676+
"type": "string",
14677+
"nullable": true
14678+
},
14679+
"findings": {
14680+
"type": "array",
14681+
"items": {
14682+
"type": "object",
14683+
"properties": {
14684+
"category": {
14685+
"type": "string"
14686+
},
14687+
"path": {
14688+
"type": "string"
14689+
},
14690+
"severity": {
14691+
"type": "string",
14692+
"enum": [
14693+
"blocker",
14694+
"nit"
14695+
]
14696+
},
14697+
"line": {
14698+
"type": "number"
14699+
},
14700+
"body": {
14701+
"type": "string"
14702+
}
14703+
},
14704+
"required": [
14705+
"category",
14706+
"path",
14707+
"severity",
14708+
"line",
14709+
"body"
14710+
]
14711+
}
14712+
},
14713+
"categoryCounts": {
14714+
"type": "object",
14715+
"additionalProperties": {
14716+
"type": "number"
14717+
}
14718+
}
14719+
},
14720+
"required": [
14721+
"status",
14722+
"repoFullName",
14723+
"pullNumber",
14724+
"login",
14725+
"findings",
14726+
"categoryCounts"
14727+
]
14728+
},
1465514729
"FindingTaxonomyDocument": {
1465614730
"type": "object",
1465714731
"properties": {
@@ -17450,6 +17524,77 @@
1745017524
]
1745117525
}
1745217526
},
17527+
"/v1/repos/{owner}/{repo}/pulls/{number}/ai-review-findings": {
17528+
"get": {
17529+
"summary": "A PR author's own structured, published AI-review findings",
17530+
"parameters": [
17531+
{
17532+
"schema": {
17533+
"type": "string"
17534+
},
17535+
"required": true,
17536+
"name": "owner",
17537+
"in": "path"
17538+
},
17539+
{
17540+
"schema": {
17541+
"type": "string"
17542+
},
17543+
"required": true,
17544+
"name": "repo",
17545+
"in": "path"
17546+
},
17547+
{
17548+
"schema": {
17549+
"type": "string"
17550+
},
17551+
"required": true,
17552+
"name": "number",
17553+
"in": "path"
17554+
},
17555+
{
17556+
"schema": {
17557+
"type": "string",
17558+
"minLength": 1,
17559+
"example": "jsonbored"
17560+
},
17561+
"required": true,
17562+
"description": "GitHub login of the pull request's author -- the caller must be this same login.",
17563+
"name": "login",
17564+
"in": "query"
17565+
}
17566+
],
17567+
"responses": {
17568+
"200": {
17569+
"description": "Structured, published AI-review findings for the caller's own pull request",
17570+
"content": {
17571+
"application/json": {
17572+
"schema": {
17573+
"$ref": "#/components/schemas/PullRequestAiReviewFindings"
17574+
}
17575+
}
17576+
}
17577+
},
17578+
"400": {
17579+
"description": "Missing login"
17580+
},
17581+
"403": {
17582+
"description": "The pull request belongs to a different contributor"
17583+
},
17584+
"404": {
17585+
"description": "Pull request not found"
17586+
}
17587+
},
17588+
"security": [
17589+
{
17590+
"LoopOverBearer": []
17591+
},
17592+
{
17593+
"LoopOverSessionCookie": []
17594+
}
17595+
]
17596+
}
17597+
},
1745317598
"/v1/contributors/{login}/profile": {
1745417599
"get": {
1745517600
"summary": "Contributor evidence profile",

src/openapi/schemas.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2984,6 +2984,26 @@ export const PullRequestReviewabilitySchema = z
29842984
})
29852985
.openapi("PullRequestReviewability");
29862986

2987+
export const PullRequestAiReviewFindingsSchema = z
2988+
.object({
2989+
status: z.enum(["ready", "not_found", "ai_review_off"]),
2990+
repoFullName: z.string(),
2991+
pullNumber: z.number(),
2992+
login: z.string(),
2993+
headSha: z.string().nullable().optional(),
2994+
findings: z.array(
2995+
z.object({
2996+
category: z.string(),
2997+
path: z.string(),
2998+
severity: z.enum(["blocker", "nit"]),
2999+
line: z.number(),
3000+
body: z.string(),
3001+
}),
3002+
),
3003+
categoryCounts: z.record(z.string(), z.number()),
3004+
})
3005+
.openapi("PullRequestAiReviewFindings");
3006+
29873007
export const RegistryChangeReportSchema = z
29883008
.object({
29893009
generatedAt: z.string(),

src/openapi/spec.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import {
5858
MaintainerNoiseReportSchema,
5959
AmsMinerCohortComparisonSchema,
6060
McpCompatibilitySchema,
61+
PullRequestAiReviewFindingsSchema,
6162
PullRequestMaintainerPacketSchema,
6263
PullRequestReviewIntelligenceSchema,
6364
PullRequestReviewabilitySchema,
@@ -193,6 +194,7 @@ export function buildOpenApiSpec() {
193194
registry.register("MaintainerNoiseReport", MaintainerNoiseReportSchema);
194195
registry.register("AmsMinerCohortComparison", AmsMinerCohortComparisonSchema);
195196
registry.register("PullRequestReviewability", PullRequestReviewabilitySchema);
197+
registry.register("PullRequestAiReviewFindings", PullRequestAiReviewFindingsSchema);
196198

197199
registry.registerPath({
198200
method: "get",
@@ -868,6 +870,26 @@ export function buildOpenApiSpec() {
868870
200: { description: "Private PR reviewability score and maintainer action", content: { "application/json": { schema: PullRequestReviewabilitySchema } } },
869871
},
870872
});
873+
registry.registerPath({
874+
method: "get",
875+
path: "/v1/repos/{owner}/{repo}/pulls/{number}/ai-review-findings",
876+
summary: "A PR author's own structured, published AI-review findings",
877+
request: {
878+
params: z.object({ owner: z.string(), repo: z.string(), number: z.string() }),
879+
query: z.object({
880+
login: z.string().min(1).openapi({
881+
param: { description: "GitHub login of the pull request's author -- the caller must be this same login." },
882+
example: "jsonbored",
883+
}),
884+
}),
885+
},
886+
responses: {
887+
200: { description: "Structured, published AI-review findings for the caller's own pull request", content: { "application/json": { schema: PullRequestAiReviewFindingsSchema } } },
888+
400: { description: "Missing login" },
889+
403: { description: "The pull request belongs to a different contributor" },
890+
404: { description: "Pull request not found" },
891+
},
892+
});
871893
registry.registerPath({
872894
method: "get",
873895
path: "/v1/contributors/{login}/profile",

test/unit/openapi.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ describe("OpenAPI contract", () => {
3232
expect(spec.paths["/v1/repos/{owner}/{repo}/gittensor-config-recommendation"]).toBeDefined();
3333
expect(spec.paths["/v1/repos/{owner}/{repo}/pulls/{number}/maintainer-packet"]).toBeDefined();
3434
expect(spec.paths["/v1/repos/{owner}/{repo}/pulls/{number}/reviewability"]).toBeDefined();
35+
expect(spec.paths["/v1/repos/{owner}/{repo}/pulls/{number}/ai-review-findings"]).toBeDefined();
3536
expect(spec.paths["/v1/contributors/{login}/profile"]).toBeDefined();
3637
expect(spec.paths["/v1/contributors/{login}/decision-pack"]).toBeDefined();
3738
expect(spec.paths["/v1/contributors/{login}/open-pr-monitor"]).toBeDefined();
@@ -111,6 +112,8 @@ describe("OpenAPI contract", () => {
111112
expect(spec.components?.schemas?.GittensorConfigRecommendation).toBeDefined();
112113
expect(spec.components?.schemas?.PullRequestMaintainerPacket).toBeDefined();
113114
expect(spec.components?.schemas?.PullRequestReviewability).toBeDefined();
115+
expect(spec.components?.schemas?.PullRequestAiReviewFindings).toBeDefined();
116+
expect(JSON.stringify(spec.components?.schemas?.PullRequestAiReviewFindings)).toContain("categoryCounts");
114117
expect(spec.components?.schemas?.LocalBranchAnalysis).toBeDefined();
115118
expect(spec.components?.schemas?.RepoSettingsPreview).toBeDefined();
116119
expect(spec.components?.schemas?.InstallationRepair).toBeDefined();

0 commit comments

Comments
 (0)